summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdoc/contributions.txt1
-rwxr-xr-xindra/llcommon/llmemory.cpp3
-rwxr-xr-xindra/llcommon/llmemory.h2
-rw-r--r--indra/llcommon/lluriparser.cpp10
-rwxr-xr-xindra/llimage/llimagebmp.cpp14
-rwxr-xr-xindra/llimage/llimagetga.cpp6
-rwxr-xr-xindra/llmath/llvolume.cpp12
-rwxr-xr-xindra/llmath/llvolume.h4
-rwxr-xr-xindra/llplugin/llpluginclassmedia.cpp8
-rwxr-xr-xindra/llplugin/llpluginclassmedia.h9
-rwxr-xr-xindra/llprimitive/llprimitive.cpp52
-rwxr-xr-xindra/llprimitive/llprimitive.h5
-rwxr-xr-xindra/llprimitive/llprimtexturelist.cpp11
-rwxr-xr-xindra/llprimitive/llprimtexturelist.h2
-rwxr-xr-xindra/llprimitive/lltextureentry.cpp4
-rwxr-xr-xindra/llprimitive/lltextureentry.h4
-rwxr-xr-xindra/llui/lldockablefloater.cpp2
-rw-r--r--indra/llui/llfolderviewitem.cpp45
-rwxr-xr-xindra/llui/llfolderviewitem.h4
-rwxr-xr-xindra/llui/llfolderviewmodel.h2
-rwxr-xr-xindra/llui/llmenugl.cpp53
-rwxr-xr-xindra/llui/llmenugl.h4
-rwxr-xr-xindra/llui/llsearcheditor.cpp13
-rwxr-xr-xindra/llui/llsearcheditor.h2
-rwxr-xr-xindra/llui/lltextbase.cpp53
-rwxr-xr-xindra/llui/lltextbase.h8
-rwxr-xr-xindra/llui/llurlentry.cpp88
-rwxr-xr-xindra/llui/llurlentry.h24
-rwxr-xr-xindra/llui/llurlregistry.cpp47
-rwxr-xr-xindra/llui/tests/llurlentry_test.cpp172
-rwxr-xr-xindra/llwindow/llwindow.cpp4
-rwxr-xr-xindra/llwindow/llwindowmacosx-objc.h1
-rwxr-xr-xindra/newview/app_settings/settings.xml22
-rwxr-xr-xindra/newview/app_settings/shaders/class1/deferred/bumpF.glsl24
-rwxr-xr-xindra/newview/installers/windows/installer_template.nsi4
-rwxr-xr-xindra/newview/llagent.cpp2
-rwxr-xr-xindra/newview/llagentdata.cpp1
-rwxr-xr-xindra/newview/llagentdata.h1
-rwxr-xr-xindra/newview/llappearancemgr.cpp4
-rwxr-xr-xindra/newview/llappviewer.cpp9
-rwxr-xr-xindra/newview/llappviewermacosx.cpp50
-rwxr-xr-xindra/newview/llavatarlist.cpp14
-rwxr-xr-xindra/newview/llavatarlist.h2
-rwxr-xr-xindra/newview/llcallingcard.cpp25
-rwxr-xr-xindra/newview/llcallingcard.h3
-rwxr-xr-xindra/newview/llchathistory.cpp4
-rwxr-xr-xindra/newview/llcofwearables.cpp2
-rwxr-xr-xindra/newview/llconversationlog.h3
-rwxr-xr-xindra/newview/llconversationmodel.cpp19
-rw-r--r--indra/newview/llconversationview.cpp81
-rw-r--r--indra/newview/llconversationview.h5
-rwxr-xr-xindra/newview/lldrawpoolbump.cpp1
-rw-r--r--indra/newview/llexperienceassociationresponder.cpp9
-rw-r--r--indra/newview/llexperiencelog.cpp31
-rw-r--r--indra/newview/llexperiencelog.h5
-rwxr-xr-xindra/newview/llfavoritesbar.cpp384
-rwxr-xr-xindra/newview/llfavoritesbar.h26
-rwxr-xr-xindra/newview/llfloaterabout.cpp93
-rwxr-xr-xindra/newview/llfloaterabout.h3
-rwxr-xr-xindra/newview/llfloaterbump.cpp32
-rwxr-xr-xindra/newview/llfloaterbump.h4
-rw-r--r--indra/newview/llfloaterfacebook.cpp6
-rwxr-xr-xindra/newview/llfloaterimcontainer.cpp83
-rwxr-xr-xindra/newview/llfloaterimcontainer.h2
-rwxr-xr-xindra/newview/llfloaterjoystick.cpp14
-rwxr-xr-xindra/newview/llfloaterjoystick.h5
-rwxr-xr-xindra/newview/llfloaterland.cpp3
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp3125
-rwxr-xr-xindra/newview/llfloatermodelpreview.h134
-rwxr-xr-xindra/newview/llfloaterperms.cpp86
-rwxr-xr-xindra/newview/llfloaterperms.h33
-rwxr-xr-xindra/newview/llfloaterpreference.cpp25
-rwxr-xr-xindra/newview/llfloaterpreference.h3
-rwxr-xr-xindra/newview/llfloaterreporter.cpp2
-rwxr-xr-xindra/newview/llfloatersnapshot.cpp8
-rwxr-xr-xindra/newview/llfloatertos.cpp6
-rwxr-xr-xindra/newview/llfloaterworldmap.cpp6
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.cpp23
-rwxr-xr-xindra/newview/llfolderviewmodelinventory.h1
-rwxr-xr-xindra/newview/llgroupmgr.cpp88
-rwxr-xr-xindra/newview/llgroupmgr.h7
-rwxr-xr-xindra/newview/llinventorybridge.cpp56
-rwxr-xr-xindra/newview/llinventorybridge.h2
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp2
-rwxr-xr-xindra/newview/llinventoryfunctions.h6
-rwxr-xr-xindra/newview/lllocalbitmaps.cpp2
-rwxr-xr-xindra/newview/lllocationinputctrl.cpp5
-rwxr-xr-xindra/newview/lllogchat.cpp16
-rwxr-xr-xindra/newview/lllogchat.h1
-rwxr-xr-xindra/newview/llmanipscale.cpp16
-rwxr-xr-xindra/newview/llmaniptranslate.cpp8
-rwxr-xr-xindra/newview/llmediactrl.cpp23
-rwxr-xr-xindra/newview/llmediactrl.h3
-rwxr-xr-xindra/newview/llmoveview.cpp10
-rwxr-xr-xindra/newview/llnamelistctrl.cpp15
-rwxr-xr-xindra/newview/llnamelistctrl.h17
-rwxr-xr-xindra/newview/llpaneleditwearable.cpp3
-rw-r--r--indra/newview/llpanelexperiencelisteditor.cpp6
-rw-r--r--indra/newview/llpanelexperiencelisteditor.h3
-rw-r--r--indra/newview/llpanelexperiencelog.cpp17
-rw-r--r--indra/newview/llpanelexperiencepicker.cpp42
-rwxr-xr-xindra/newview/llpanelface.h2
-rwxr-xr-xindra/newview/llpanelgroup.cpp4
-rwxr-xr-xindra/newview/llpanelgroupgeneral.cpp5
-rwxr-xr-xindra/newview/llpanelgroupinvite.cpp92
-rwxr-xr-xindra/newview/llpanelgrouproles.cpp136
-rwxr-xr-xindra/newview/llpanelgrouproles.h3
-rwxr-xr-xindra/newview/llpanellandmarkinfo.cpp1
-rwxr-xr-xindra/newview/llpanelmaininventory.cpp2
-rwxr-xr-xindra/newview/llpanelmediasettingsgeneral.cpp4
-rwxr-xr-xindra/newview/llpanelobject.cpp11
-rwxr-xr-xindra/newview/llpaneloutfitedit.cpp3
-rwxr-xr-xindra/newview/llpaneloutfitedit.h1
-rwxr-xr-xindra/newview/llpanelpeople.cpp42
-rwxr-xr-xindra/newview/llpanelpeople.h1
-rwxr-xr-xindra/newview/llpanelpicks.cpp2
-rwxr-xr-xindra/newview/llpanelplaces.cpp16
-rwxr-xr-xindra/newview/llpaneltopinfobar.cpp5
-rwxr-xr-xindra/newview/llpanelwearing.cpp2
-rwxr-xr-xindra/newview/llpreviewscript.cpp10
-rwxr-xr-xindra/newview/llpreviewtexture.cpp1
-rwxr-xr-xindra/newview/llselectmgr.cpp27
-rwxr-xr-xindra/newview/llsidepaneltaskinfo.cpp24
-rwxr-xr-xindra/newview/llslurl.cpp7
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp114
-rw-r--r--indra/newview/llsnapshotlivepreview.h2
-rwxr-xr-xindra/newview/llspeakers.cpp17
-rwxr-xr-xindra/newview/llstartup.cpp22
-rwxr-xr-xindra/newview/lltexturecache.cpp9
-rwxr-xr-xindra/newview/lltooldraganddrop.cpp22
-rwxr-xr-xindra/newview/llurllineeditorctrl.cpp2
-rwxr-xr-xindra/newview/llviewermedia.h1
-rwxr-xr-xindra/newview/llviewermenu.cpp25
-rwxr-xr-xindra/newview/llviewermessage.cpp32
-rwxr-xr-xindra/newview/llviewerobject.cpp48
-rwxr-xr-xindra/newview/llviewerobject.h7
-rwxr-xr-xindra/newview/llviewerstats.cpp5
-rwxr-xr-xindra/newview/llvoavatar.cpp22
-rwxr-xr-xindra/newview/llvoavatar.h2
-rwxr-xr-xindra/newview/llvovolume.cpp146
-rwxr-xr-xindra/newview/llvovolume.h6
-rwxr-xr-xindra/newview/llwearableitemslist.cpp9
-rwxr-xr-xindra/newview/llwearableitemslist.h4
-rwxr-xr-xindra/newview/llworldmap.cpp1
-rwxr-xr-xindra/newview/skins/default/xui/da/menu_viewer.xml2
-rwxr-xr-xindra/newview/skins/default/xui/da/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/de/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/de/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_about.xml8
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_about_land.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_bumps.xml6
-rw-r--r--indra/newview/skins/default/xui/en/floater_experiences.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_inventory.xml8
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_login.xml6
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_participant_view.xml13
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_people_friends_view.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_people_nearby_view.xml4
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_people_recent_view.xml4
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_email.xml21
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml12
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml98
-rw-r--r--indra/newview/skins/default/xui/en/panel_experience_list_editor.xml6
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_main_inventory.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_people.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_advanced.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_preferences_setup.xml28
-rwxr-xr-xindra/newview/skins/default/xui/en/strings.xml2
-rwxr-xr-xindra/newview/skins/default/xui/es/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/es/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/fr/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/fr/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/fr/panel_login.xml3
-rwxr-xr-xindra/newview/skins/default/xui/it/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/it/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/ja/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/ja/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/pl/menu_viewer.xml2
-rwxr-xr-xindra/newview/skins/default/xui/pl/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/pt/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/pt/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/ru/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/ru/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/tr/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/tr/notifications.xml3
-rwxr-xr-xindra/newview/skins/default/xui/zh/menu_viewer.xml4
-rwxr-xr-xindra/newview/skins/default/xui/zh/notifications.xml3
-rwxr-xr-xindra/viewer_components/updater/llupdaterservice.cpp56
-rwxr-xr-xindra/viewer_components/updater/llupdaterservice.h1
188 files changed, 5028 insertions, 1679 deletions
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 211d4fcf08..7493e96c39 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -185,6 +185,7 @@ Ansariel Hiller
BUG-3764
STORM-1984
STORM-1979
+ MAINT-5533
Aralara Rajal
Arare Chantilly
CHUIBUG-191
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index ae11988df8..3a8eabac09 100755
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -2176,8 +2176,7 @@ void* ll_aligned_malloc_fallback( size_t size, int align )
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
- unsigned int for_alloc = sysinfo.dwPageSize;
- while(for_alloc < size) for_alloc += sysinfo.dwPageSize;
+ unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize;
void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
if(NULL == p) {
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index d3a9bbc4ae..0fb257aab1 100755
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -98,7 +98,7 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
// for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library
- // change preprocessro code to: #if 1 && defined(LL_WINDOWS)
+ // change preprocessor code to: #if 1 && defined(LL_WINDOWS)
#if 0 && defined(LL_WINDOWS)
void* ll_aligned_malloc_fallback( size_t size, int align );
diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp
index d98bc297e5..82d0dc8b4b 100644
--- a/indra/llcommon/lluriparser.cpp
+++ b/indra/llcommon/lluriparser.cpp
@@ -238,12 +238,12 @@ void LLUriParser::glueSecond(std::string& uri) const
{
uri += '?';
uri += mQuery;
+ }
- if (mFragment.size())
- {
- uri += '#';
- uri += mFragment;
- }
+ if (mFragment.size())
+ {
+ uri += '#';
+ uri += mFragment;
}
}
diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp
index 8573fe0d91..a2ce2fee86 100755
--- a/indra/llimage/llimagebmp.cpp
+++ b/indra/llimage/llimagebmp.cpp
@@ -443,6 +443,10 @@ BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )
mBitfieldMask[2] = 0x000000FF;
}
+ if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
S32 src_row_span = getWidth() * 4;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
@@ -476,6 +480,11 @@ BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )
S32 src_row_span = getWidth() * 1;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
+ if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
+
for( S32 row = 0; row < getHeight(); row++ )
{
for( S32 col = 0; col < getWidth(); col++ )
@@ -501,6 +510,11 @@ BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
S32 src_row_span = getWidth() * 3;
S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4
+ if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
+
for( S32 row = 0; row < getHeight(); row++ )
{
for( S32 col = 0; col < getWidth(); col++ )
diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp
index 4eb8dc7440..d0ae105ba7 100755
--- a/indra/llimage/llimagetga.cpp
+++ b/indra/llimage/llimagetga.cpp
@@ -437,7 +437,13 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu
// Origin is the bottom left
U8* dst = raw_image->getData();
U8* src = getData() + mDataOffset;
+
S32 pixels = getWidth() * getHeight();
+
+ if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset)
+ { //here we have situation when data size in src less than actually needed
+ return FALSE;
+ }
if (getComponents() == 4)
{
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 4703e6cf1a..edf5a1b75c 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -5584,7 +5584,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
{
resizeVertices(num_vertices+1);
- if (!partial_build)
+ //if (!partial_build)
{
resizeIndices(num_indices+3);
}
@@ -5592,7 +5592,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
else
{
resizeVertices(num_vertices);
- if (!partial_build)
+ //if (!partial_build)
{
resizeIndices(num_indices);
}
@@ -5714,10 +5714,10 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
LL_CHECK_MEMORY
- if (partial_build)
- {
- return TRUE;
- }
+ //if (partial_build)
+ //{
+ // return TRUE;
+ //}
if (mTypeMask & HOLLOW_MASK)
{
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 625f7cff02..1da2d0c6b1 100755
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -190,8 +190,12 @@ const U8 LL_SCULPT_TYPE_MESH = 5;
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
+// for value checks, assign new value after adding new types
+const U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH;
+
const U8 LL_SCULPT_FLAG_INVERT = 64;
const U8 LL_SCULPT_FLAG_MIRROR = 128;
+const U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR;
const S32 LL_SCULPT_MESH_MAX_FACES = 8;
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 52626b0302..4bfd0de81e 100755
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -146,6 +146,8 @@ void LLPluginClassMedia::reset()
mClickTarget.clear();
mClickUUID.clear();
mStatusCode = 0;
+
+ mClickEnforceTarget = false;
// media_time class
mCurrentTime = 0.0f;
@@ -1358,6 +1360,12 @@ void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
sendMessage(message);
}
+void LLPluginClassMedia::setOverrideClickTarget(const std::string &target)
+{
+ mClickEnforceTarget = true;
+ mOverrideClickTarget = target;
+}
+
void LLPluginClassMedia::crashPlugin()
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 5fe8254331..96d577f43c 100755
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -249,6 +249,13 @@ public:
// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE
std::string getClickUUID() const { return mClickUUID; };
+ // mClickTarget is received from message and governs how link will be opened
+ // use this to enforce your own way of opening links inside plugins
+ void setOverrideClickTarget(const std::string &target);
+ void resetOverrideClickTarget() { mClickEnforceTarget = false; };
+ bool isOverrideClickTarget() const { return mClickEnforceTarget; }
+ std::string getOverrideClickTarget() const { return mOverrideClickTarget; };
+
// These are valid during MEDIA_EVENT_DEBUG_MESSAGE
std::string getDebugMessageText() const { return mDebugMessageText; };
std::string getDebugMessageLevel() const { return mDebugMessageLevel; };
@@ -404,6 +411,8 @@ protected:
std::string mClickNavType;
std::string mClickTarget;
std::string mClickUUID;
+ bool mClickEnforceTarget;
+ std::string mOverrideClickTarget;
std::string mDebugMessageText;
std::string mDebugMessageLevel;
S32 mGeometryX;
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 29747cb09c..9eff74f1e8 100755
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -317,9 +317,9 @@ S32 LLPrimitive::setTEMaterialID(const U8 index, const LLMaterialID& pMaterialID
return mTextureList.setMaterialID(index, pMaterialID);
}
-S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams)
+S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
- return mTextureList.setMaterialParams(index, pMaterialParams);
+ return mTextureList.setMaterialParams(index, pMaterialParams, isInitFromServer);
}
LLMaterialPtr LLPrimitive::getTEMaterialParams(const U8 index)
@@ -1869,9 +1869,12 @@ BOOL LLSculptParams::pack(LLDataPacker &dp) const
BOOL LLSculptParams::unpack(LLDataPacker &dp)
{
- dp.unpackUUID(mSculptTexture, "texture");
- dp.unpackU8(mSculptType, "type");
-
+ U8 type;
+ LLUUID id;
+ dp.unpackUUID(id, "texture");
+ dp.unpackU8(type, "type");
+
+ setSculptTexture(id, type);
return TRUE;
}
@@ -1896,8 +1899,7 @@ bool LLSculptParams::operator==(const LLNetworkData& data) const
void LLSculptParams::copy(const LLNetworkData& data)
{
const LLSculptParams *param = (LLSculptParams*)&data;
- mSculptTexture = param->mSculptTexture;
- mSculptType = param->mSculptType;
+ setSculptTexture(param->mSculptTexture, param->mSculptType);
}
@@ -1915,20 +1917,38 @@ LLSD LLSculptParams::asLLSD() const
bool LLSculptParams::fromLLSD(LLSD& sd)
{
const char *w;
- w = "texture";
+ U8 type;
+ w = "type";
if (sd.has(w))
{
- setSculptTexture( sd[w] );
- } else goto fail;
- w = "type";
+ type = sd[w].asInteger();
+ }
+ else return false;
+
+ w = "texture";
if (sd.has(w))
{
- setSculptType( (U8)sd[w].asInteger() );
- } else goto fail;
-
+ setSculptTexture(sd[w], type);
+ }
+ else return false;
+
return true;
- fail:
- return false;
+}
+
+void LLSculptParams::setSculptTexture(const LLUUID& texture_id, U8 sculpt_type)
+{
+ U8 type = sculpt_type & LL_SCULPT_TYPE_MASK;
+ U8 flags = sculpt_type & LL_SCULPT_FLAG_MASK;
+ if (sculpt_type != (type | flags) || type > LL_SCULPT_TYPE_MAX)
+ {
+ mSculptTexture.set(SCULPT_DEFAULT_TEXTURE);
+ mSculptType = LL_SCULPT_TYPE_SPHERE;
+ }
+ else
+ {
+ mSculptTexture = texture_id;
+ mSculptType = sculpt_type;
+ }
}
//============================================================================
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 1bf83e36b4..54870fbb10 100755
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -259,9 +259,8 @@ public:
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
- void setSculptTexture(const LLUUID& id) { mSculptTexture = id; }
+ void setSculptTexture(const LLUUID& texture_id, U8 sculpt_type);
LLUUID getSculptTexture() const { return mSculptTexture; }
- void setSculptType(U8 type) { mSculptType = type; }
U8 getSculptType() const { return mSculptType; }
};
@@ -385,7 +384,7 @@ public:
virtual S32 setTEMediaFlags(const U8 te, const U8 flags);
virtual S32 setTEGlow(const U8 te, const F32 glow);
virtual S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
- virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams);
+ virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed
virtual void setTESelected(const U8 te, bool sel);
diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp
index f4f08248b8..6aae2f97c6 100755
--- a/indra/llprimitive/llprimtexturelist.cpp
+++ b/indra/llprimitive/llprimtexturelist.cpp
@@ -368,11 +368,18 @@ S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMateri
return TEM_CHANGE_NONE;
}
-S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams)
+S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
if (index < mEntryList.size())
{
- return mEntryList[index]->setMaterialParams(pMaterialParams);
+ if (!isInitFromServer && mEntryList[index]->isMatParamsInitFromServer())
+ {
+ return TEM_CHANGE_NONE;
+ }
+ else
+ {
+ return mEntryList[index]->setMaterialParams(pMaterialParams);
+ }
}
return TEM_CHANGE_NONE;
}
diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h
index 49c636e40f..63e6372405 100755
--- a/indra/llprimitive/llprimtexturelist.h
+++ b/indra/llprimitive/llprimtexturelist.h
@@ -105,7 +105,7 @@ public:
S32 setMediaFlags(const U8 index, const U8 media_flags);
S32 setGlow(const U8 index, const F32 glow);
S32 setMaterialID(const U8 index, const LLMaterialID& pMaterialID);
- S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams);
+ S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
LLMaterialPtr getMaterialParams(const U8 index);
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index 284dfc15f4..6020031099 100755
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -63,6 +63,7 @@ LLTextureEntry::LLTextureEntry()
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
+ , mInitMatParamsFromServer(false)
{
init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
}
@@ -71,6 +72,7 @@ LLTextureEntry::LLTextureEntry(const LLUUID& tex_id)
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
+ , mInitMatParamsFromServer(false)
{
init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
}
@@ -79,6 +81,7 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
: mMediaEntry(NULL)
, mSelected(false)
, mMaterialUpdatePending(false)
+ , mInitMatParamsFromServer(false)
{
mID = rhs.mID;
mScaleS = rhs.mScaleS;
@@ -562,6 +565,7 @@ S32 LLTextureEntry::setMaterialParams(const LLMaterialPtr pMaterialParams)
mMaterialUpdatePending = true;
}
mMaterial = pMaterialParams;
+ this->mInitMatParamsFromServer = TRUE;
return TEM_CHANGE_TEXTURE;
}
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
index a40c3988f2..81e2e8a5a2 100755
--- a/indra/llprimitive/lltextureentry.h
+++ b/indra/llprimitive/lltextureentry.h
@@ -160,6 +160,8 @@ public:
const LLMaterialID& getMaterialID() const { return mMaterialID; };
const LLMaterialPtr getMaterialParams() const { return mMaterial; };
+ bool isMatParamsInitFromServer() const { return mInitMatParamsFromServer; };
+
// *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL.
// CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData()
// to NOT return NULL.
@@ -217,6 +219,8 @@ protected:
bool mMaterialUpdatePending;
LLMaterialID mMaterialID;
LLMaterialPtr mMaterial;
+ bool mInitMatParamsFromServer; // Flag to identification when material paramas initialized from
+
// Note the media data is not sent via the same message structure as the rest of the TE
LLMediaEntry* mMediaEntry; // The media data for the face
diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp
index 3396213f1c..c937d190c6 100755
--- a/indra/llui/lldockablefloater.cpp
+++ b/indra/llui/lldockablefloater.cpp
@@ -153,7 +153,7 @@ void LLDockableFloater::setVisible(BOOL visible)
mDockControl.get()->repositionDockable();
}
- if (visible)
+ if (visible && !isMinimized())
{
LLFloater::setFrontmost(getAutoFocus());
}
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 81a0204bc5..3def0386e1 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -129,6 +129,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
mSelectPending(FALSE),
mLabelStyle( LLFontGL::NORMAL ),
mHasVisibleChildren(FALSE),
+ mIsFolderComplete(true),
mLocalIndentation(p.folder_indentation),
mIndentation(0),
mItemHeight(p.item_height),
@@ -674,7 +675,7 @@ void LLFolderViewItem::drawOpenFolderArrow(const Params& default_params, const L
//
const S32 TOP_PAD = default_params.item_top_pad;
- if (hasVisibleChildren())
+ if (hasVisibleChildren() || !isFolderComplete())
{
LLUIImage* arrow_image = default_params.folder_arrow_image;
gl_draw_scaled_rotated_image(
@@ -934,6 +935,8 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ):
mLastArrangeGeneration( -1 ),
mLastCalculatedWidth(0)
{
+ // folder might have children that are not loaded yet. Mark it as incomplete until chance to check it.
+ mIsFolderComplete = false;
}
void LLFolderViewFolder::updateLabelRotation()
@@ -1016,6 +1019,12 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height )
mHasVisibleChildren = found;
}
+ if (!mIsFolderComplete)
+ {
+ mIsFolderComplete = getFolderViewModel()->isFolderComplete(this);
+ }
+
+
// calculate height as a single item (without any children), and reshapes rectangle to match
LLFolderViewItem::arrange( width, height );
@@ -1463,31 +1472,37 @@ void LLFolderViewFolder::extendSelectionTo(LLFolderViewItem* new_selection)
LLFolderView* root = getRoot();
- for (std::vector<LLFolderViewItem*>::iterator it = items_to_select_forward.begin(), end_it = items_to_select_forward.end();
+ BOOL selection_reverse = new_selection->isSelected(); //indication that some elements are being deselected
+
+ // array always go from 'will be selected' to ' will be unselected', iterate
+ // in opposite direction to simplify identification of 'point of origin' in
+ // case it is in the list we are working with
+ for (std::vector<LLFolderViewItem*>::reverse_iterator it = items_to_select_forward.rbegin(), end_it = items_to_select_forward.rend();
it != end_it;
++it)
{
LLFolderViewItem* item = *it;
- if (item->isSelected())
+ BOOL selected = item->isSelected();
+ if (!selection_reverse && selected)
{
- root->removeFromSelectionList(item);
+ // it is our 'point of origin' where we shift/expand from
+ // don't deselect it
+ selection_reverse = TRUE;
}
else
{
- item->selectItem();
+ root->changeSelection(item, !selected);
}
- root->addToSelectionList(item);
}
- if (new_selection->isSelected())
+ if (selection_reverse)
{
- root->removeFromSelectionList(new_selection);
+ // at some point we reversed selection, first element should be deselected
+ root->changeSelection(last_selected_item_from_cur, FALSE);
}
- else
- {
- new_selection->selectItem();
- }
- root->addToSelectionList(new_selection);
+
+ // element we expand to should always be selected
+ root->changeSelection(new_selection, TRUE);
}
@@ -1677,7 +1692,9 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r
mIsOpen = openitem;
if(!was_open && openitem)
{
- getViewModelItem()->openItem();
+ getViewModelItem()->openItem();
+ // openItem() will request content, it won't be incomplete
+ mIsFolderComplete = true;
}
else if(was_open && !openitem)
{
diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h
index ed4496cfaa..0322c8836d 100755
--- a/indra/llui/llfolderviewitem.h
+++ b/indra/llui/llfolderviewitem.h
@@ -115,6 +115,7 @@ protected:
F32 mControlLabelRotation;
LLFolderView* mRoot;
bool mHasVisibleChildren,
+ mIsFolderComplete, // indicates that some children were not loaded/added yet
mIsCurSelection,
mDragAndDropTarget,
mIsMouseOverTitle,
@@ -212,6 +213,9 @@ public:
BOOL hasVisibleChildren() { return mHasVisibleChildren; }
+ // true if object can't have children
+ BOOL isFolderComplete() { return mIsFolderComplete; }
+
// Call through to the viewed object and return true if it can be
// removed. Returns true if it's removed.
//virtual BOOL removeRecursively(BOOL single_item);
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index d60e36183b..a395af537a 100755
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -122,6 +122,7 @@ public:
virtual void filter() = 0;
virtual bool contentsReady() = 0;
+ virtual bool isFolderComplete(class LLFolderViewFolder*) = 0;
virtual void setFolderView(LLFolderView* folder_view) = 0;
virtual LLFolderViewFilter& getFilter() = 0;
virtual const LLFolderViewFilter& getFilter() const = 0;
@@ -444,6 +445,7 @@ public:
// By default, we assume the content is available. If a network fetch mechanism is implemented for the model,
// this method needs to be overloaded and return the relevant fetch status.
virtual bool contentsReady() { return true; }
+ virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; }
struct ViewModelCompare
{
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 7cdbcb0621..3b8d282445 100755
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -225,7 +225,6 @@ BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
BOOL LLMenuItemGL::handleHover(S32 x, S32 y, MASK mask)
{
- setHover(TRUE);
getWindow()->setCursor(UI_CURSOR_ARROW);
return TRUE;
}
@@ -236,6 +235,18 @@ BOOL LLMenuItemGL::handleRightMouseDown(S32 x, S32 y, MASK mask)
return LLUICtrl::handleRightMouseDown(x,y,mask);
}
+void LLMenuItemGL::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ setHover(TRUE);
+ LLUICtrl::onMouseEnter(x,y,mask);
+}
+
+void LLMenuItemGL::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ setHover(FALSE);
+ LLUICtrl::onMouseLeave(x,y,mask);
+}
+
//virtual
BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask)
{
@@ -533,9 +544,6 @@ void LLMenuItemGL::draw( void )
gl_line_2d(x_begin, (MENU_ITEM_PADDING / 2) + 1, x_end, (MENU_ITEM_PADDING / 2) + 1);
}
}
-
- // clear got hover every frame
- setHover(FALSE);
}
BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit& text )
@@ -1043,7 +1051,7 @@ void LLMenuItemBranchGL::onCommit( void )
// keyboard navigation automatically propagates highlight to sub-menu
// to facilitate fast menu control via jump keys
- if (LLMenuGL::getKeyboardMode() && getBranch()&& !getBranch()->getHighlightedItem())
+ if (LLMenuGL::getKeyboardMode() && getBranch() && !getBranch()->getHighlightedItem())
{
getBranch()->highlightNextItem(NULL);
}
@@ -1456,7 +1464,16 @@ BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask )
{
// switch to mouse control mode
LLMenuGL::setKeyboardMode(FALSE);
- onCommit();
+
+ if (getVisible() && isOpen())
+ {
+ LLMenuGL::sMenuContainer->hideMenus();
+ }
+ else
+ {
+ onCommit();
+ }
+
make_ui_sound("UISndClick");
return TRUE;
}
@@ -1588,10 +1605,6 @@ void LLMenuItemBranchDownGL::draw( void )
gl_line_2d(x_begin, LABEL_BOTTOM_PAD_PIXELS, x_end, LABEL_BOTTOM_PAD_PIXELS);
}
}
-
- // reset every frame so that we only show highlight
- // when we get hover events on that frame
- setHover(FALSE);
}
@@ -3625,8 +3638,24 @@ BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask )
BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
if (!handled)
{
- // clicked off of menu, hide them all
- hideMenus();
+ LLMenuGL* visible_menu = (LLMenuGL*)getVisibleMenu();
+ LLMenuItemGL* parent_menu = visible_menu ? visible_menu->getParentMenuItem() : NULL;
+ if (parent_menu && parent_menu->getVisible())
+ {
+ // don't hide menu if parent was hit
+ LLRect parent_rect;
+ parent_menu->localRectToOtherView(parent_menu->getLocalRect(), &parent_rect, this);
+ if (!parent_rect.pointInRect(x, y))
+ {
+ // clicked off of menu and parent, hide them all
+ hideMenus();
+ }
+ }
+ else
+ {
+ // no visible parent, clicked off of menu, hide them all
+ hideMenus();
+ }
}
return handled;
}
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index ae9b169691..28f9e3b6e9 100755
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -158,6 +158,10 @@ public:
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );
virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
+
+ virtual void onMouseEnter(S32 x, S32 y, MASK mask);
+ virtual void onMouseLeave(S32 x, S32 y, MASK mask);
+
virtual void draw( void );
BOOL getHover() const { return mGotHover; }
diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp
index ea96fc573d..1fdd05a11c 100755
--- a/indra/llui/llsearcheditor.cpp
+++ b/indra/llui/llsearcheditor.cpp
@@ -29,6 +29,7 @@
#include "linden_common.h"
#include "llsearcheditor.h"
+#include "llkeyboard.h"
LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p)
: LLUICtrl(p),
@@ -166,4 +167,16 @@ void LLSearchEditor::handleKeystroke()
{
mKeystrokeCallback(this, getValue());
}
+
+ KEY key = gKeyboard->currentKey();
+ if (key == KEY_LEFT ||
+ key == KEY_RIGHT)
+ {
+ return;
+ }
+
+ if (mTextChangedCallback)
+ {
+ mTextChangedCallback(this, getValue());
+ }
}
diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h
index c2d7916938..3b12868225 100755
--- a/indra/llui/llsearcheditor.h
+++ b/indra/llui/llsearcheditor.h
@@ -82,12 +82,14 @@ public:
virtual void setFocus( BOOL b );
void setKeystrokeCallback( commit_callback_t cb ) { mKeystrokeCallback = cb; }
+ void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; }
protected:
void onClearButtonClick(const LLSD& data);
virtual void handleKeystroke();
commit_callback_t mKeystrokeCallback;
+ commit_callback_t mTextChangedCallback;
LLLineEditor* mSearchEditor;
LLButton* mSearchButton;
LLButton* mClearButton;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 602a703450..bf660849c4 100755
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -37,6 +37,7 @@
#include "lltextparser.h"
#include "lltextutil.h"
#include "lltooltip.h"
+#include "lltrans.h"
#include "lluictrl.h"
#include "llurlaction.h"
#include "llurlregistry.h"
@@ -2060,27 +2061,33 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
// add icon before url if need
LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted());
+ if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() )
+ {
+ setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon"));
+ }
// output the styled Url
appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
+ bool tooltip_required = !match.getTooltip().empty();
+
+ // set the tooltip for the Url label
+ if (tooltip_required)
+ {
+ setLastSegmentToolTip(match.getTooltip());
+ }
- // show query part of url with gray color only for LLUrlEntryHTTP and LLUrlEntryHTTPNoProtocol url entries
+ // show query part of url with gray color only for LLUrlEntryHTTP url entries
std::string label = match.getQuery();
if (label.size())
{
link_params.color = LLColor4::grey;
link_params.readonly_color = LLColor4::grey;
appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly());
- }
-
- // set the tooltip for the Url label
- if (! match.getTooltip().empty())
- {
- segment_set_t::iterator it = getSegIterContaining(getLength()-1);
- if (it != mSegments.end())
+
+ // set the tooltip for the query part of url
+ if (tooltip_required)
{
- LLTextSegmentPtr segment = *it;
- segment->setToolTip(match.getTooltip());
+ setLastSegmentToolTip(match.getTooltip());
}
}
@@ -2107,6 +2114,16 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
}
}
+void LLTextBase::setLastSegmentToolTip(const std::string &tooltip)
+{
+ segment_set_t::iterator it = getSegIterContaining(getLength()-1);
+ if (it != mSegments.end())
+ {
+ LLTextSegmentPtr segment = *it;
+ segment->setToolTip(tooltip);
+ }
+}
+
static LLTrace::BlockTimerStatHandle FTM_APPEND_TEXT("Append Text");
void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
@@ -3557,6 +3574,22 @@ S32 LLImageTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
return 0;
}
+BOOL LLImageTextSegment::handleToolTip(S32 x, S32 y, MASK mask)
+{
+ if (!mTooltip.empty())
+ {
+ LLToolTipMgr::instance().show(mTooltip);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void LLImageTextSegment::setToolTip(const std::string& tooltip)
+{
+ mTooltip = tooltip;
+}
+
F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
{
if ( (start >= 0) && (end <= mEnd - mStart))
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index dfc10923f3..87809aa8fb 100755
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -241,9 +241,15 @@ public:
S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+ /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
+ /*virtual*/ void setToolTip(const std::string& tooltip);
+
private:
class LLTextBase& mEditor;
LLStyleConstSP mStyle;
+
+protected:
+ std::string mTooltip;
};
typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
@@ -392,6 +398,8 @@ public:
const std::string& getLabel() { return mLabel.getString(); }
const LLWString& getWlabel() { return mLabel.getWString();}
+ void setLastSegmentToolTip(const std::string &tooltip);
+
/**
* If label is set, draws text label (which is LLLabelTextSegment)
* that is visible when no user text provided
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 6db0d88998..7f6cc22e90 100755
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -203,10 +203,10 @@ std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const
{
LLUriParser up(unescapeUrl(url));
- std::string query;
+ std::string label;
up.extractParts();
- up.glueSecond(query);
-
+ up.glueFirst(label);
+ std::string query = url.substr(label.size());
return query;
}
@@ -229,7 +229,7 @@ static std::string getStringAfterToken(const std::string str, const std::string
LLUrlEntryHTTP::LLUrlEntryHTTP()
: LLUrlEntryBase()
{
- mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*",
+ mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?\\.[a-z](:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
@@ -287,46 +287,6 @@ std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const
return getUrlFromWikiLink(string);
}
-//
-// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com
-//
-LLUrlEntryHTTPNoProtocol::LLUrlEntryHTTPNoProtocol()
- : LLUrlEntryBase()
-{
- mPattern = boost::regex("("
- "\\bwww\\.\\S+\\.\\S+" // i.e. www.FOO.BAR
- "|" // or
- "(?<!@)\\b[^[:space:]:@/>]+\\.(?:com|net|edu|org)([/:][^[:space:]<]*)?\\b" // i.e. FOO.net
- ")",
- boost::regex::perl|boost::regex::icase);
- mMenuName = "menu_url_http.xml";
- mTooltip = LLTrans::getString("TooltipHttpUrl");
-}
-
-std::string LLUrlEntryHTTPNoProtocol::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
-{
- return urlToLabelWithGreyQuery(url);
-}
-
-std::string LLUrlEntryHTTPNoProtocol::getQuery(const std::string &url) const
-{
- return urlToGreyQuery(url);
-}
-
-std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const
-{
- if (string.find("://") == std::string::npos)
- {
- return "http://" + escapeUrl(string);
- }
- return escapeUrl(string);
-}
-
-std::string LLUrlEntryHTTPNoProtocol::getTooltip(const std::string &url) const
-{
- return unescapeUrl(url);
-}
-
LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL()
: LLUrlEntryBase()
{
@@ -489,7 +449,7 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
//
LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL()
{
- mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?\\/\\S*",
+ mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?\\/\\S*",
boost::regex::perl|boost::regex::icase);
mIcon = "Hand";
@@ -527,7 +487,7 @@ std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const
//
LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL()
{
- mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)",
+ mPattern = boost::regex("https?://([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)",
boost::regex::perl|boost::regex::icase);
mIcon = "Hand";
@@ -1401,9 +1361,43 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url)
return mIcon;
}
+//
+// LLUrlEntryEmail Describes a generic mailto: Urls
+//
+LLUrlEntryEmail::LLUrlEntryEmail()
+ : LLUrlEntryBase()
+{
+ mPattern = boost::regex("(mailto:)?[\\w\\.\\-]+@[\\w\\.\\-]+\\.[a-z]{2,6}",
+ boost::regex::perl | boost::regex::icase);
+ mMenuName = "menu_url_email.xml";
+ mTooltip = LLTrans::getString("TooltipEmail");
+}
+
+std::string LLUrlEntryEmail::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ int pos = url.find("mailto:");
+
+ if (pos == std::string::npos)
+ {
+ return escapeUrl(url);
+ }
+
+ std::string ret = escapeUrl(url.substr(pos + 7, url.length() - pos + 8));
+ return ret;
+}
+
+std::string LLUrlEntryEmail::getUrl(const std::string &string) const
+{
+ if (string.find("mailto:") == std::string::npos)
+ {
+ return "mailto:" + escapeUrl(string);
+ }
+ return escapeUrl(string);
+}
+
LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile()
{
- mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/\\w+\\S*",
+ mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/profile",
boost::regex::perl|boost::regex::icase);
mIcon = "Generic_Experience";
mMenuName = "menu_url_experience.xml";
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index dd1f257a3d..413c20a657 100755
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -157,19 +157,6 @@ public:
/*virtual*/ std::string getUrl(const std::string &string) const;
};
-///
-/// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com
-///
-class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase
-{
-public:
- LLUrlEntryHTTPNoProtocol();
- /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
- /*virtual*/ std::string getQuery(const std::string &url) const;
- /*virtual*/ std::string getUrl(const std::string &string) const;
- /*virtual*/ std::string getTooltip(const std::string &url) const;
-};
-
class LLUrlEntryInvalidSLURL : public LLUrlEntryBase
{
public:
@@ -506,5 +493,16 @@ public:
/*virtual*/ std::string getIcon(const std::string &url);
};
+///
+/// LLUrlEntryEmail Describes a generic mailto: Urls
+///
+class LLUrlEntryEmail : public LLUrlEntryBase
+{
+public:
+ LLUrlEntryEmail();
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getUrl(const std::string &string) const;
+};
+
#endif
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 2085505947..69eefa736c 100755
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -76,9 +76,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntrySL());
mUrlEntrySLLabel = new LLUrlEntrySLLabel();
registerUrl(mUrlEntrySLLabel);
- // most common pattern is a URL without any protocol,
- // e.g., "secondlife.com"
- registerUrl(new LLUrlEntryHTTPNoProtocol());
+ registerUrl(new LLUrlEntryEmail());
}
LLUrlRegistry::~LLUrlRegistry()
@@ -155,11 +153,9 @@ static bool stringHasUrl(const std::string &text)
return (text.find("://") != std::string::npos ||
text.find("www.") != std::string::npos ||
text.find(".com") != std::string::npos ||
- text.find(".net") != std::string::npos ||
- text.find(".edu") != std::string::npos ||
- text.find(".org") != std::string::npos ||
text.find("<nolink>") != std::string::npos ||
- text.find("<icon") != std::string::npos);
+ text.find("<icon") != std::string::npos ||
+ text.find("@") != std::string::npos);
}
bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted)
@@ -218,9 +214,40 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
// did we find a match? if so, return its details in the match object
if (match_entry)
{
+
+ // Skip if link is an email with an empty username (starting with @). See MAINT-5371.
+ if (match_start > 0 && text.substr(match_start - 1, 1) == "@")
+ return false;
+
// fill in the LLUrlMatch object and return it
std::string url = text.substr(match_start, match_end - match_start + 1);
+ LLUrlEntryBase *stripped_entry = NULL;
+ if(LLStringUtil::containsNonprintable(url))
+ {
+ LLStringUtil::stripNonprintable(url);
+
+ std::vector<LLUrlEntryBase *>::iterator iter;
+ for (iter = mUrlEntry.begin(); iter != mUrlEntry.end(); ++iter)
+ {
+ LLUrlEntryBase *url_entry = *iter;
+ U32 start = 0, end = 0;
+ if (matchRegex(url.c_str(), url_entry->getPattern(), start, end))
+ {
+ if (mLLUrlEntryInvalidSLURL == *iter)
+ {
+ if(url_entry && url_entry->isSLURLvalid(url))
+ {
+ continue;
+ }
+ }
+ stripped_entry = url_entry;
+ break;
+ }
+ }
+ }
+
+
if (match_entry == mUrlEntryTrusted)
{
LLUriParser up(url);
@@ -228,10 +255,12 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
url = up.normalizedUri();
}
+ std::string url_label = stripped_entry? stripped_entry->getLabel(url, cb) : match_entry->getLabel(url, cb);
+ std::string url_query = stripped_entry? stripped_entry->getQuery(url) : match_entry->getQuery(url);
match.setValues(match_start, match_end,
match_entry->getUrl(url),
- match_entry->getLabel(url, cb),
- match_entry->getQuery(url),
+ url_label,
+ url_query,
match_entry->getTooltip(url),
match_entry->getIcon(url),
match_entry->getStyle(),
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 15f2354552..96e94c0f80 100755
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -653,79 +653,6 @@ namespace tut
void object::test<11>()
{
//
- // test LLUrlEntryHTTPNoProtocol - general URLs without a protocol
- //
- LLUrlEntryHTTPNoProtocol url;
-
- testRegex("naked .com URL", url,
- "see google.com",
- "http://google.com");
-
- testRegex("naked .org URL", url,
- "see en.wikipedia.org for details",
- "http://en.wikipedia.org");
-
- testRegex("naked .net URL", url,
- "example.net",
- "http://example.net");
-
- testRegex("naked .edu URL (2 instances)", url,
- "MIT web site is at web.mit.edu and also www.mit.edu",
- "http://web.mit.edu");
-
- testRegex("don't match e-mail addresses", url,
- "test@lindenlab.com",
- "");
-
- testRegex(".com URL with path", url,
- "see secondlife.com/status for grid status",
- "http://secondlife.com/status");
-
- testRegex(".com URL with port", url,
- "secondlife.com:80",
- "http://secondlife.com:80");
-
- testRegex(".com URL with port and path", url,
- "see secondlife.com:80/status",
- "http://secondlife.com:80/status");
-
- testRegex("www.*.com URL with port and path", url,
- "see www.secondlife.com:80/status",
- "http://www.secondlife.com:80/status");
-
- testRegex("invalid .com URL [1]", url,
- "..com",
- "");
-
- testRegex("invalid .com URL [2]", url,
- "you.come",
- "");
-
- testRegex("invalid .com URL [3]", url,
- "recommended",
- "");
-
- testRegex("invalid .edu URL", url,
- "hi there scheduled maitenance has begun",
- "");
-
- testRegex("invalid .net URL", url,
- "foo.netty",
- "");
-
- testRegex("XML tags around URL [1]", url,
- "<foo>secondlife.com</foo>",
- "http://secondlife.com");
-
- testRegex("XML tags around URL [2]", url,
- "<foo>secondlife.com/status?bar=1</foo>",
- "http://secondlife.com/status?bar=1");
- }
-
- template<> template<>
- void object::test<12>()
- {
- //
// test LLUrlEntryNoLink - turn off hyperlinking
//
LLUrlEntryNoLink url;
@@ -752,7 +679,7 @@ namespace tut
}
template<> template<>
- void object::test<13>()
+ void object::test<12>()
{
//
// test LLUrlEntryRegion - secondlife:///app/region/<location> URLs
@@ -860,4 +787,101 @@ namespace tut
"secondlife:///app/region/Product%20Engine",
"Product Engine");
}
+
+ template<> template<>
+ void object::test<13>()
+ {
+ //
+ // test LLUrlEntryemail - general emails
+ //
+ LLUrlEntryEmail url;
+
+ // Regex tests.
+ testRegex("match e-mail addresses", url,
+ "test@lindenlab.com",
+ "mailto:test@lindenlab.com");
+
+ testRegex("match e-mail addresses with mailto: prefix", url,
+ "mailto:test@lindenlab.com",
+ "mailto:test@lindenlab.com");
+
+ testRegex("match e-mail addresses with different domains", url,
+ "test@foo.org.us",
+ "mailto:test@foo.org.us");
+
+ testRegex("match e-mail addresses with different domains", url,
+ "test@foo.bar",
+ "mailto:test@foo.bar");
+
+ testRegex("don't match incorrect e-mail addresses", url,
+ "test @foo.com",
+ "");
+
+ testRegex("don't match incorrect e-mail addresses", url,
+ "test@ foo.com",
+ "");
+ }
+
+ template<> template<>
+ void object::test<14>()
+ {
+ //
+ // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com/* and http://*lindenlab.com/* urls
+ //
+ LLUrlEntrySecondlifeURL url;
+
+ testRegex("match urls with protocol", url,
+ "this url should match http://lindenlab.com/products/second-life",
+ "http://lindenlab.com/products/second-life");
+
+ testRegex("match urls with protocol", url,
+ "search something https://marketplace.secondlife.com/products/search on marketplace and test the https",
+ "https://marketplace.secondlife.com/products/search");
+
+ testRegex("match urls with port", url,
+ "let's specify some port http://secondlife.com:888/status",
+ "http://secondlife.com:888/status");
+
+ testRegex("don't match urls w/o protocol", url,
+ "looks like an url something www.marketplace.secondlife.com/products but no https prefix",
+ "");
+
+ testRegex("but with a protocol www is fine", url,
+ "so let's add a protocol http://www.marketplace.secondlife.com:8888/products",
+ "http://www.marketplace.secondlife.com:8888/products");
+
+ testRegex("don't match urls w/o protocol", url,
+ "and even no www something secondlife.com/status",
+ "");
+ }
+
+ template<> template<>
+ void object::test<15>()
+ {
+ //
+ // test LLUrlEntrySimpleSecondlifeURL - http://*.secondlife.com and http://*lindenlab.com urls
+ //
+
+ LLUrlEntrySimpleSecondlifeURL url;
+
+ testRegex("match urls with a protocol", url,
+ "this url should match http://lindenlab.com",
+ "http://lindenlab.com");
+
+ testRegex("match urls with a protocol", url,
+ "search something https://marketplace.secondlife.com on marketplace and test the https",
+ "https://marketplace.secondlife.com");
+
+ testRegex("don't match urls w/o protocol", url,
+ "looks like an url something www.marketplace.secondlife.com but no https prefix",
+ "");
+
+ testRegex("but with a protocol www is fine", url,
+ "so let's add a protocol http://www.marketplace.secondlife.com",
+ "http://www.marketplace.secondlife.com");
+
+ testRegex("don't match urls w/o protocol", url,
+ "and even no www something lindenlab.com",
+ "");
+ }
}
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 5720660034..1b24250618 100755
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -49,8 +49,8 @@ LLSplashScreen *gSplashScreenp = NULL;
BOOL gDebugClicks = FALSE;
BOOL gDebugWindowProc = FALSE;
-const S32 gURLProtocolWhitelistCount = 4;
-const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:" };
+const S32 gURLProtocolWhitelistCount = 5;
+const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:", "mailto:" };
// CP: added a handler list - this is what's used to open the protocol and is based on registry entry
// only meaningful difference currently is that file: protocols are opened using http:
diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h
index f02052ca6a..e6e8f27f53 100755
--- a/indra/llwindow/llwindowmacosx-objc.h
+++ b/indra/llwindow/llwindowmacosx-objc.h
@@ -53,6 +53,7 @@ bool runMainLoop();
void initMainLoop();
void cleanupViewer();
void handleUrl(const char* url);
+void dispatchUrl(std::string url);
/* Defined in llwindowmacosx-objc.mm: */
int createNSApp(int argc, const char **argv);
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 98d0ba53f6..f05836742a 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1730,6 +1730,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>ChatShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide people icons in chat</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>CheesyBeacon</key>
<map>
<key>Comment</key>
@@ -11029,6 +11040,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>GlobalShowIconsOverride</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide people icons in any list. This option should be set back to 0 when icons are enabled locally for the lists</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>FriendsSortOrder</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index 595c11fae2..58fb01d200 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -29,6 +29,7 @@ out vec4 frag_data[3];
#define frag_data gl_FragData
#endif
+uniform float minimum_alpha;
uniform sampler2D diffuseMap;
uniform sampler2D bumpMap;
@@ -47,16 +48,23 @@ vec2 encode_normal(vec3 n)
void main()
{
- vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb;
- vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0;
+ vec4 col = texture2D(diffuseMap, vary_texcoord0.xy);
+
+ if(col.a < minimum_alpha)
+ {
+ discard;
+ }
+ col *= vertex_color;
+
+ vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0;
- vec3 tnorm = vec3(dot(norm,vary_mat0),
+ vec3 tnorm = vec3(dot(norm,vary_mat0),
dot(norm,vary_mat1),
dot(norm,vary_mat2));
- frag_data[0] = vec4(col, 0.0);
- frag_data[1] = vertex_color.aaaa; // spec
- //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
- vec3 nvn = normalize(tnorm);
- frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0);
+ frag_data[0] = vec4(col.rgb, 0.0);
+ frag_data[1] = vertex_color.aaaa; // spec
+ //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
+ vec3 nvn = normalize(tnorm);
+ frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, 0.0);
}
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 95cdf90e99..b8677fd9e4 100755
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -165,7 +165,9 @@ lbl_configure_default_lang:
StrCpy $LANGUAGE $0
# For silent installs, no language prompt, use default
- IfSilent lbl_return
+ IfSilent 0 +3
+ StrCpy $SKIP_AUTORUN "true"
+ Goto lbl_return
StrCmp $SKIP_DIALOGS "true" lbl_return
lbl_build_menu:
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 092d868bb9..297bd9a05b 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -2843,7 +2843,7 @@ BOOL LLAgent::isInGroup(const LLUUID& group_id, BOOL ignore_god_mode /* FALSE */
// This implementation should mirror LLAgentInfo::hasPowerInGroup
BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const
{
- if (isGodlike())
+ if (isGodlikeWithoutAdminMenuFakery())
return true;
// GP_NO_POWERS can also mean no power is enough to grant an ability.
diff --git a/indra/newview/llagentdata.cpp b/indra/newview/llagentdata.cpp
index 5f6a082d75..d2c644a06f 100755
--- a/indra/newview/llagentdata.cpp
+++ b/indra/newview/llagentdata.cpp
@@ -31,3 +31,4 @@
LLUUID gAgentID;
LLUUID gAgentSessionID;
+std::string gAgentUsername;
diff --git a/indra/newview/llagentdata.h b/indra/newview/llagentdata.h
index 83d6a53d5e..efdd97f6c4 100755
--- a/indra/newview/llagentdata.h
+++ b/indra/newview/llagentdata.h
@@ -30,5 +30,6 @@
extern LLUUID gAgentID;
extern LLUUID gAgentSessionID;
+extern std::string gAgentUsername;
#endif
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 35593dd4ff..53ae3c62ec 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1869,6 +1869,10 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids)
{
++n_clothes;
}
+ else if (item->getType() == LLAssetType::AT_BODYPART || item->getType() == LLAssetType::AT_GESTURE)
+ {
+ return isAgentAvatarValid();
+ }
else
{
LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 9b9b591cd1..fbf2a04bcc 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2784,10 +2784,12 @@ bool LLAppViewer::initConfiguration()
//
gWindowTitle = LLTrans::getString("APP_NAME");
#if LL_DEBUG
- gWindowTitle += std::string(" [DEBUG] ") + gArgs;
-#else
- gWindowTitle += std::string(" ") + gArgs;
+ gWindowTitle += std::string(" [DEBUG]")
#endif
+ if (!gArgs.empty())
+ {
+ gWindowTitle += std::string(" ") + gArgs;
+ }
LLStringUtil::truncate(gWindowTitle, 255);
//RN: if we received a URL, hand it off to the existing instance.
@@ -4948,6 +4950,7 @@ void LLAppViewer::idle()
gIdleCallbacks.callFunctions();
gInventory.idleNotifyObservers();
+ LLAvatarTracker::instance().idleNotifyObservers();
}
// Metrics logging (LLViewerAssetStats, etc.)
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 56154a2de3..09227806fd 100755
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -62,9 +62,10 @@ namespace
// They are not used immediately by the app.
int gArgC;
char** gArgV;
- LLAppViewerMacOSX* gViewerAppPtr;
+ LLAppViewerMacOSX* gViewerAppPtr = NULL;
void (*gOldTerminateHandler)() = NULL;
+ std::string gHandleSLURL;
}
static void exceptionTerminateHandler()
@@ -107,7 +108,11 @@ bool initViewer()
{
LL_WARNS() << "Application init failed." << LL_ENDL;
}
-
+ else if (!gHandleSLURL.empty())
+ {
+ dispatchUrl(gHandleSLURL);
+ gHandleSLURL = "";
+ }
return ok;
}
@@ -393,22 +398,31 @@ bool LLAppViewerMacOSX::getMasterSystemAudioMute()
void handleUrl(const char* url_utf8)
{
- if (url_utf8)
+ if (url_utf8 && gViewerAppPtr)
{
- std::string url = url_utf8;
- // Safari 3.2 silently mangles secondlife:///app/ URLs into
- // secondlife:/app/ (only one leading slash).
- // Fix them up to meet the URL specification. JC
- const std::string prefix = "secondlife:/app/";
- std::string test_prefix = url.substr(0, prefix.length());
- LLStringUtil::toLower(test_prefix);
- if (test_prefix == prefix)
- {
- url.replace(0, prefix.length(), "secondlife:///app/");
- }
-
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- LLURLDispatcher::dispatch(url, "", web, trusted_browser);
+ gHandleSLURL = "";
+ dispatchUrl(url_utf8);
}
+ else if (url_utf8)
+ {
+ gHandleSLURL = url_utf8;
+ }
+}
+
+void dispatchUrl(std::string url)
+{
+ // Safari 3.2 silently mangles secondlife:///app/ URLs into
+ // secondlife:/app/ (only one leading slash).
+ // Fix them up to meet the URL specification. JC
+ const std::string prefix = "secondlife:/app/";
+ std::string test_prefix = url.substr(0, prefix.length());
+ LLStringUtil::toLower(test_prefix);
+ if (test_prefix == prefix)
+ {
+ url.replace(0, prefix.length(), "secondlife:///app/");
+ }
+
+ LLMediaCtrl* web = NULL;
+ const bool trusted_browser = false;
+ LLURLDispatcher::dispatch(url, "", web, trusted_browser);
}
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index 8846d1317d..c7fa375ada 100755
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -63,16 +63,18 @@ bool LLAvatarList::contains(const LLUUID& id)
return std::find(ids.begin(), ids.end(), id) != ids.end();
}
-void LLAvatarList::toggleIcons()
+void LLAvatarList::setIconsVisible(bool visible)
{
+ if (visible == mShowIcons) // nothing to be done here.
+ return;
+
// Save the new value for new items to use.
- mShowIcons = !mShowIcons;
- gSavedSettings.setBOOL(mIconParamName, mShowIcons);
-
+ mShowIcons = visible;
+
// Show/hide icons for all existing items.
std::vector<LLPanel*> items;
getItems(items);
- for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)
+ for (std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)
{
static_cast<LLAvatarListItem*>(*it)->setAvatarIconVisible(mShowIcons);
}
@@ -187,6 +189,8 @@ void LLAvatarList::draw()
updateAvatarNames();
}
+ setIconsVisible(gSavedSettings.getBOOL(mIconParamName) && !gSavedSettings.getBOOL("GlobalShowIconsOverride"));
+
if (mDirty)
refresh();
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index 3542577ae3..159ff991e6 100755
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -76,7 +76,7 @@ public:
void setSessionID(const LLUUID& session_id) { mSessionID = session_id; }
const LLUUID& getSessionID() { return mSessionID; }
- void toggleIcons();
+ void setIconsVisible(bool visible);
void setSpeakingIndicatorsVisible(bool visible);
void showPermissions(bool visible);
void sortByName();
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index b6c5496c17..f79d1aa609 100755
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -97,7 +97,8 @@ static void on_avatar_name_cache_notify(const LLUUID& agent_id,
LLAvatarTracker::LLAvatarTracker() :
mTrackingData(NULL),
mTrackedAgentValid(false),
- mModifyMask(0x0)
+ mModifyMask(0x0),
+ mIsNotifyObservers(FALSE)
{
}
@@ -272,7 +273,7 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
<< "]" << LL_ENDL;
}
}
- notifyObservers();
+ // do not notify observers here - list can be large so let it be done on idle.
return new_buddy_count;
}
@@ -473,8 +474,25 @@ void LLAvatarTracker::removeObserver(LLFriendObserver* observer)
mObservers.end());
}
+void LLAvatarTracker::idleNotifyObservers()
+{
+ if (mModifyMask == LLFriendObserver::NONE && mChangedBuddyIDs.size() == 0)
+ {
+ return;
+ }
+ notifyObservers();
+}
+
void LLAvatarTracker::notifyObservers()
{
+ if (mIsNotifyObservers)
+ {
+ // Don't allow multiple calls.
+ // new masks and ids will be processed later from idle.
+ return;
+ }
+ mIsNotifyObservers = TRUE;
+
observer_list_t observers(mObservers);
observer_list_t::iterator it = observers.begin();
observer_list_t::iterator end = observers.end();
@@ -490,6 +508,7 @@ void LLAvatarTracker::notifyObservers()
mModifyMask = LLFriendObserver::NONE;
mChangedBuddyIDs.clear();
+ mIsNotifyObservers = FALSE;
}
void LLAvatarTracker::addParticularFriendObserver(const LLUUID& buddy_id, LLFriendObserver* observer)
@@ -531,7 +550,7 @@ void LLAvatarTracker::notifyParticularFriendObservers(const LLUUID& buddy_id)
// store flag for change
// and id of object change applies to
void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent)
-{
+{
mModifyMask |= mask;
if (referent.notNull())
{
diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h
index 6e5fc01cd8..1f819a42fd 100755
--- a/indra/newview/llcallingcard.h
+++ b/indra/newview/llcallingcard.h
@@ -143,6 +143,7 @@ public:
// observers left behind.
void addObserver(LLFriendObserver* observer);
void removeObserver(LLFriendObserver* observer);
+ void idleNotifyObservers();
void notifyObservers();
// Observers interested in updates of a particular avatar.
@@ -209,6 +210,8 @@ private:
LLAvatarTracker(const LLAvatarTracker&);
bool operator==(const LLAvatarTracker&);
+ BOOL mIsNotifyObservers;
+
public:
// don't you dare create or delete this object
LLAvatarTracker();
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index b81b95462e..dc0835eb1c 100755
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -376,6 +376,10 @@ public:
|| mSourceType == CHAT_SOURCE_SYSTEM)
{
mFrom = LLTrans::getString("SECOND_LIFE");
+ if(!chat.mFromName.empty() && (mFrom != chat.mFromName))
+ {
+ mFrom += " (" + chat.mFromName + ")";
+ }
user_name->setValue(mFrom);
updateMinUserNameWidth();
}
diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp
index 8ce5aca909..307f93e28c 100755
--- a/indra/newview/llcofwearables.cpp
+++ b/indra/newview/llcofwearables.cpp
@@ -483,7 +483,7 @@ void LLCOFWearables::populateAttachmentsAndBodypartsLists(const LLInventoryModel
const LLAssetType::EType item_type = item->getType();
if (item_type == LLAssetType::AT_CLOTHING) continue;
LLPanelInventoryListItemBase* item_panel = NULL;
- if (item_type == LLAssetType::AT_OBJECT)
+ if (item_type == LLAssetType::AT_OBJECT || item_type == LLAssetType::AT_GESTURE)
{
item_panel = buildAttachemntListItem(item);
mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h
index b38d472156..62f08144b9 100755
--- a/indra/newview/llconversationlog.h
+++ b/indra/newview/llconversationlog.h
@@ -153,6 +153,7 @@ public:
* file name is conversation.log
*/
std::string getFileName();
+ LLConversation* findConversation(const LLIMModel::LLIMSession* session);
private:
@@ -184,7 +185,7 @@ private:
void updateConversationName(const LLIMModel::LLIMSession* session, const std::string& name);
void updateOfflineIMs(const LLIMModel::LLIMSession* session, BOOL new_messages);
- LLConversation* findConversation(const LLIMModel::LLIMSession* session);
+
typedef std::vector<LLConversation> conversations_vec_t;
std::vector<LLConversation> mConversations;
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index 6e32ce60ec..328a638f2f 100755
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -136,7 +136,24 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32
items.push_back(std::string("im"));
items.push_back(std::string("offer_teleport"));
items.push_back(std::string("request_teleport"));
- items.push_back(std::string("voice_call"));
+
+ if (getType() != CONV_SESSION_1_ON_1)
+ {
+ items.push_back(std::string("voice_call"));
+ }
+ else
+ {
+ LLVoiceChannel* voice_channel = LLIMModel::getInstance() ? LLIMModel::getInstance()->getVoiceChannel(this->getUUID()) : NULL;
+ if(voice_channel != LLVoiceChannel::getCurrentVoiceChannel())
+ {
+ items.push_back(std::string("voice_call"));
+ }
+ else
+ {
+ items.push_back(std::string("disconnect_from_voice"));
+ }
+ }
+
items.push_back(std::string("chat_history"));
items.push_back(std::string("separator_chat_history"));
items.push_back(std::string("add_friend"));
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index b18e543f0a..3a6e4c4dfe 100644
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -85,7 +85,8 @@ LLConversationViewSession::LLConversationViewSession(const LLConversationViewSes
mHasArrow(true),
mIsInActiveVoiceChannel(false),
mFlashStateOn(false),
- mFlashStarted(false)
+ mFlashStarted(false),
+ mShowIcons(true)
{
mFlashTimer = new LLFlashTimer();
}
@@ -173,7 +174,7 @@ BOOL LLConversationViewSession::postBuild()
if (session)
{
LLAvatarIconCtrl* icon = mItemPanel->getChild<LLAvatarIconCtrl>("avatar_icon");
- icon->setVisible(true);
+ icon->setVisible(mShowIcons);
icon->setValue(session->mOtherParticipantID);
mSpeakingIndicator->setSpeakerId(gAgentID, session->mSessionID, true);
mHasArrow = false;
@@ -426,6 +427,49 @@ void LLConversationViewSession::showVoiceIndicator(bool visible)
requestArrange();
}
+void LLConversationViewSession::setIconsVisible(bool visible)
+{
+ if (visible == mShowIcons) // nothing to be done here.
+ return;
+
+ // Save the new value for new items to use.
+ mShowIcons = visible;
+
+ // Show/hide icons for the 1-n-1 chat.
+ LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
+ if (vmi)
+ {
+ switch (vmi->getType())
+ {
+ case LLConversationItem::CONV_PARTICIPANT:
+ case LLConversationItem::CONV_SESSION_1_ON_1:
+ {
+ LLIconCtrl* icon = mItemPanel->getChild<LLIconCtrl>("avatar_icon");
+ icon->setVisible(mShowIcons);
+ break;
+ }
+ /*
+ case LLConversationItem::CONV_SESSION_AD_HOC:
+ case LLConversationItem::CONV_SESSION_GROUP:
+ {
+ LLIconCtrl* icon = mItemPanel->getChild<LLIconCtrl>("group_icon");
+ icon->setVisible(mShowIcons);
+ break;
+ }
+ */
+ default:
+ break;
+ }
+ }
+
+ // Show/hide icons for all existing items.
+ items_t::const_iterator iter;
+ for (iter = getItemsBegin(); iter != getItemsEnd(); iter++)
+ {
+ dynamic_cast<LLConversationViewParticipant*>(*iter)->setAvatarIconVisible(mShowIcons);
+ }
+}
+
void LLConversationViewSession::refresh()
{
// Refresh the session view from its model data
@@ -458,6 +502,9 @@ void LLConversationViewSession::refresh()
}
}
}
+
+ setIconsVisible(gSavedSettings.getBOOL("ChatShowIcons") && !gSavedSettings.getBOOL("GlobalShowIconsOverride"));
+
requestArrange();
// Do the regular upstream refresh
LLFolderViewFolder::refresh();
@@ -509,7 +556,7 @@ void LLConversationViewParticipant::initFromParams(const LLConversationViewParti
LLAvatarIconCtrl::Params avatar_icon_params(params.avatar_icon());
applyXUILayout(avatar_icon_params, this);
LLAvatarIconCtrl * avatarIcon = LLUICtrlFactory::create<LLAvatarIconCtrl>(avatar_icon_params);
- addChild(avatarIcon);
+ addChild(avatarIcon);
LLButton::Params info_button_params(params.info_button());
applyXUILayout(info_button_params, this);
@@ -525,6 +572,7 @@ void LLConversationViewParticipant::initFromParams(const LLConversationViewParti
BOOL LLConversationViewParticipant::postBuild()
{
mAvatarIcon = getChild<LLAvatarIconCtrl>("avatar_icon");
+ mAvatarIcon->setVisible(gSavedSettings.getBOOL("ChatShowIcons") && !gSavedSettings.getBOOL("GlobalShowIconsOverride"));
mInfoBtn = getChild<LLButton>("info_btn");
mInfoBtn->setClickedCallback(boost::bind(&LLConversationViewParticipant::onInfoBtnClick, this));
@@ -588,12 +636,12 @@ S32 LLConversationViewParticipant::arrange(S32* width, S32* height)
S32 arranged = LLFolderViewItem::arrange(width, height);
//Adjusts the avatar icon based upon the indentation
- LLRect avatarRect(getIndentation(),
- mAvatarIcon->getRect().mTop,
- getIndentation() + mAvatarIcon->getRect().getWidth(),
- mAvatarIcon->getRect().mBottom);
- mAvatarIcon->setShape(avatarRect);
-
+ LLRect avatarRect(getIndentation(),
+ mAvatarIcon->getRect().mTop,
+ getIndentation() + mAvatarIcon->getRect().getWidth(),
+ mAvatarIcon->getRect().mBottom);
+ mAvatarIcon->setShape(avatarRect);
+
//Since dimensions changed, adjust the children (info button, speaker indicator)
updateChildren();
@@ -665,7 +713,7 @@ void LLConversationViewParticipant::onMouseLeave(S32 x, S32 y, MASK mask)
S32 LLConversationViewParticipant::getLabelXPos()
{
- return getIndentation() + mAvatarIcon->getRect().getWidth() + mIconPad;
+ return getIndentation() + (mAvatarIcon->getVisible() ? mAvatarIcon->getRect().getWidth() : 0) + mIconPad;
}
// static
@@ -744,5 +792,18 @@ void LLConversationViewParticipant::hideSpeakingIndicator()
mSpeakingIndicator->setVisible(false);
}
+void LLConversationViewParticipant::setAvatarIconVisible(bool visible)
+{
+ // Already done? Then do nothing.
+ if (mAvatarIcon->getVisible() == (BOOL)visible)
+ {
+ return;
+ }
+
+ // Show/hide avatar icon.
+ mAvatarIcon->setVisible(visible);
+ updateChildren();
+}
+
// EOF
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index 5a74974302..6aaba9b59c 100644
--- a/indra/newview/llconversationview.h
+++ b/indra/newview/llconversationview.h
@@ -83,7 +83,7 @@ public:
LLConversationViewParticipant* findParticipant(const LLUUID& participant_id);
void showVoiceIndicator(bool visible);
-
+ void setIconsVisible(bool visible);
virtual void refresh();
/*virtual*/ void setFlashState(bool flash_state);
@@ -110,6 +110,8 @@ private:
bool mIsInActiveVoiceChannel;
+ bool mShowIcons;
+
LLVoiceClientStatusObserver* mVoiceClientObserver;
boost::signals2::connection mActiveVoiceChannelConnection;
@@ -145,6 +147,7 @@ public:
/*virtual*/ S32 getLabelXPos();
/*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask );
void hideSpeakingIndicator();
+ void setAvatarIconVisible(bool visible);
protected:
friend class LLUICtrlFactory;
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 33f7bc305c..7b9fd5c6c6 100755
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -864,6 +864,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
{
LLDrawInfo& params = **i;
+ gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff);
LLDrawPoolBump::bindBumpMap(params, bump_channel);
pushBatch(params, mask, TRUE);
}
diff --git a/indra/newview/llexperienceassociationresponder.cpp b/indra/newview/llexperienceassociationresponder.cpp
index b50c81eedc..7f2363aadc 100644
--- a/indra/newview/llexperienceassociationresponder.cpp
+++ b/indra/newview/llexperienceassociationresponder.cpp
@@ -29,6 +29,7 @@
#include "llviewerprecompiledheaders.h"
#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
+#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llagent.h"
@@ -47,7 +48,13 @@ void ExperienceAssociationResponder::fetchAssociatedExperience( const LLUUID& ob
void ExperienceAssociationResponder::fetchAssociatedExperience(LLSD& request, callback_t callback)
{
- LLViewerRegion* region = gAgent.getRegion();
+ LLViewerObject* object = gObjectList.findObject(request["object-id"]);
+ if (!object)
+ {
+ LL_WARNS() << "Failed to find object with ID " << request["object-id"] << " in fetchAssociatedExperience" << LL_ENDL;
+ return;
+ }
+ LLViewerRegion* region = object->getRegion();
if (region)
{
std::string lookup_url=region->getCapability("GetMetadata");
diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp
index ec6134a4b3..ee5d561927 100644
--- a/indra/newview/llexperiencelog.cpp
+++ b/indra/newview/llexperiencelog.cpp
@@ -112,6 +112,7 @@ void LLExperienceLog::handleExperienceMessage(LLSD& message)
}
message["Time"] = time_of_day;
mEvents[day].append(message);
+ mEventsToSave[day].append(message);
mSignals(message);
}
@@ -180,9 +181,8 @@ void LLExperienceLog::notify( LLSD& message )
void LLExperienceLog::saveEvents()
{
- eraseExpired();
std::string filename = getFilename();
- LLSD settings = LLSD::emptyMap().with("Events", mEvents);
+ LLSD settings = LLSD::emptyMap().with("Events", mEventsToSave);
settings["MaxDays"] = (int)mMaxDays;
settings["Notify"] = mNotifyNewEvent;
@@ -217,9 +217,8 @@ void LLExperienceLog::loadEvents()
if(mMaxDays > 0 && settings.has("Events"))
{
mEvents = settings["Events"];
+ mEventsToSave = mEvents;
}
-
- eraseExpired();
}
LLExperienceLog::~LLExperienceLog()
@@ -235,6 +234,26 @@ void LLExperienceLog::eraseExpired()
}
}
+bool LLExperienceLog::isNotExpired(std::string& date)
+{
+ LLDate event_date;
+ S32 month, day, year;
+ S32 matched = sscanf(date.c_str(), "%d-%d-%d", &year, &month, &day);
+ if (matched != 3) return false;
+ event_date.fromYMDHMS(year, month, day);
+ const U32 seconds_in_day = 24 * 60 * 60;
+ S32 curr_year = 0, curr_month = 0, curr_day = 0;
+
+
+ LLDate curr_date = LLDate::now();
+ curr_date.split(&curr_year, &curr_month, &curr_day);
+ curr_date.fromYMDHMS(curr_year, curr_month, curr_day); // Set hour, min, and sec to 0
+
+ LLDate boundary_date = LLDate(curr_date.secondsSinceEpoch() - seconds_in_day*getMaxDays());
+ return event_date >= boundary_date;
+
+}
+
const LLSD& LLExperienceLog::getEvents() const
{
return mEvents;
@@ -248,10 +267,6 @@ void LLExperienceLog::clear()
void LLExperienceLog::setMaxDays( U32 val )
{
mMaxDays = val;
- if(mMaxDays > 0)
- {
- eraseExpired();
- }
}
LLExperienceLog::callback_connection_t LLExperienceLog::addUpdateSignal( const callback_slot_t& cb )
diff --git a/indra/newview/llexperiencelog.h b/indra/newview/llexperiencelog.h
index 1e473e27d5..ac227db336 100644
--- a/indra/newview/llexperiencelog.h
+++ b/indra/newview/llexperiencelog.h
@@ -59,6 +59,8 @@ public:
static void notify(LLSD& message);
static std::string getFilename();
static std::string getPermissionString(const LLSD& message, const std::string& base);
+ void setEventsToSave(LLSD new_events){mEventsToSave = new_events; }
+ bool isNotExpired(std::string& date);
protected:
LLExperienceLog();
void handleExperienceMessage(LLSD& message);
@@ -68,7 +70,10 @@ protected:
void saveEvents();
void eraseExpired();
+
+
LLSD mEvents;
+ LLSD mEventsToSave;
callback_signal_t mSignals;
callback_connection_t mNotifyConnection;
U32 mMaxDays;
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index f2b369a9ad..8f3eaaa207 100755
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -380,9 +380,11 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
mShowDragMarker(FALSE),
mLandingTab(NULL),
mLastTab(NULL),
- mTabsHighlightEnabled(TRUE)
- , mUpdateDropDownItems(true)
-, mRestoreOverflowMenu(false)
+ mTabsHighlightEnabled(TRUE),
+ mUpdateDropDownItems(true),
+ mRestoreOverflowMenu(false),
+ mGetPrevItems(true),
+ mItemsChangedTimer()
{
// Register callback for menus with current registrar (will be parent panel's registrar)
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
@@ -659,6 +661,15 @@ void LLFavoritesBarCtrl::changed(U32 mask)
LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID());
}
updateButtons();
+ if (!mItemsChangedTimer.getStarted())
+ {
+ mItemsChangedTimer.start();
+ }
+ else
+ {
+ mItemsChangedTimer.reset();
+ }
+
}
}
@@ -693,6 +704,21 @@ void LLFavoritesBarCtrl::draw()
// Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again)
mShowDragMarker = FALSE;
}
+ if (mItemsChangedTimer.getStarted())
+ {
+ if (mItemsChangedTimer.getElapsedTimeF32() > 1.f)
+ {
+ LLFavoritesOrderStorage::instance().saveFavoritesRecord();
+ mItemsChangedTimer.stop();
+ }
+ }
+
+ if(!mItemsChangedTimer.getStarted() && LLFavoritesOrderStorage::instance().mUpdateRequired)
+ {
+ LLFavoritesOrderStorage::instance().mUpdateRequired = false;
+ mItemsChangedTimer.start();
+ }
+
}
const LLButton::Params& LLFavoritesBarCtrl::getButtonParams()
@@ -723,6 +749,12 @@ void LLFavoritesBarCtrl::updateButtons()
return;
}
+ if(mGetPrevItems)
+ {
+ LLFavoritesOrderStorage::instance().mPrevFavorites = mItems;
+ mGetPrevItems = false;
+ }
+
const LLButton::Params& button_params = getButtonParams();
if(mItems.empty())
@@ -844,6 +876,7 @@ void LLFavoritesBarCtrl::updateButtons()
{
mUpdateDropDownItems = false;
}
+
}
LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, const LLButton::Params& button_params, S32 x_offset)
@@ -912,9 +945,11 @@ BOOL LLFavoritesBarCtrl::postBuild()
BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)
{
+
if (mFavoriteFolderId.isNull())
return FALSE;
+
LLInventoryModel::cat_array_t cats;
LLIsType is_type(LLAssetType::AT_LANDMARK);
@@ -1411,6 +1446,7 @@ void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const
const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml";
const S32 LLFavoritesOrderStorage::NO_INDEX = -1;
+bool LLFavoritesOrderStorage::mSaveOnExit = false;
void LLFavoritesOrderStorage::setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index)
{
@@ -1447,6 +1483,7 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id)
LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " already loaded" << LL_ENDL;
onLandmarkLoaded(asset_id, lm);
}
+ return;
}
// static
@@ -1482,13 +1519,16 @@ void LLFavoritesOrderStorage::destroyClass()
LLFile::remove(old_filename);
}
- if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"))
- {
- LLFavoritesOrderStorage::instance().saveFavoritesSLURLs();
- }
- else
+ std::string filename = getSavedOrderFileName();
+ file.open(filename.c_str());
+ if (file.is_open())
{
- LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser();
+ file.close();
+ LLFile::remove(filename);
+ if(mSaveOnExit)
+ {
+ LLFavoritesOrderStorage::instance().saveFavoritesRecord(true);
+ }
}
}
@@ -1503,108 +1543,57 @@ std::string LLFavoritesOrderStorage::getSavedOrderFileName()
void LLFavoritesOrderStorage::load()
{
- // load per-resident sorting information
std::string filename = getSavedOrderFileName();
-
LLSD settings_llsd;
llifstream file;
file.open(filename.c_str());
if (file.is_open())
{
LLSDSerialize::fromXML(settings_llsd, file);
- LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' "
- << (settings_llsd.isMap() ? "" : "un") << "successfully"
- << LL_ENDL;
- file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites order file at '" << filename << "'" << LL_ENDL;
- }
-
- for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
- iter != settings_llsd.endMap(); ++iter)
- {
- mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger()));
+ LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' "
+ << (settings_llsd.isMap() ? "" : "un") << "successfully"
+ << LL_ENDL;
+ file.close();
+ mSaveOnExit = true;
+
+ for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
+ iter != settings_llsd.endMap(); ++iter)
+ {
+ mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger()));
+ }
}
-}
-
-void LLFavoritesOrderStorage::saveFavoritesSLURLs()
-{
- // Do not change the file if we are not logged in yet.
- if (!LLLoginInstance::getInstance()->authSuccess())
+ else
{
- LL_WARNS("FavoritesBar") << "Cannot save favorites: not logged in" << LL_ENDL;
- return;
+ filename = getStoredFavoritesFilename();
+ if (!filename.empty())
+ {
+ llifstream in_file;
+ in_file.open(filename.c_str());
+ LLSD fav_llsd;
+ LLSD user_llsd;
+ if (in_file.is_open())
+ {
+ LLSDSerialize::fromXML(fav_llsd, in_file);
+ LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' "
+ << (fav_llsd.isMap() ? "" : "un") << "successfully"
+ << LL_ENDL;
+ in_file.close();
+ user_llsd = fav_llsd[gAgentUsername];
+
+ S32 index = 0;
+ for (LLSD::array_iterator iter = user_llsd.beginArray();
+ iter != user_llsd.endArray(); ++iter)
+ {
+ mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index));
+ index++;
+ }
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
+ }
+ }
}
-
- std::string filename = getStoredFavoritesFilename();
- if (!filename.empty())
- {
- llifstream in_file;
- in_file.open(filename.c_str());
- LLSD fav_llsd;
- if (in_file.is_open())
- {
- LLSDSerialize::fromXML(fav_llsd, in_file);
- LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' "
- << (fav_llsd.isMap() ? "" : "un") << "successfully"
- << LL_ENDL;
- in_file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
- }
-
- const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
-
- LLSD user_llsd;
- for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++)
- {
- LLSD value;
- value["name"] = (*it)->getName();
- value["asset_id"] = (*it)->getAssetUUID();
-
- slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]);
- if (slurl_iter != mSLURLs.end())
- {
- LL_DEBUGS("FavoritesBar") << "Saving favorite: idx=" << LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID()) << ", SLURL=" << slurl_iter->second << ", value=" << value << LL_ENDL;
- value["slurl"] = slurl_iter->second;
- user_llsd[LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID())] = value;
- }
- else
- {
- LL_WARNS("FavoritesBar") << "Not saving favorite " << value["name"] << ": no matching SLURL" << LL_ENDL;
- }
- }
-
- LLAvatarName av_name;
- LLAvatarNameCache::get( gAgentID, &av_name );
- // Note : use the "John Doe" and not the "john.doe" version of the name
- // as we'll compare it with the stored credentials in the login panel.
- fav_llsd[av_name.getUserName()] = user_llsd;
-
- llofstream file;
- file.open(filename.c_str());
- if ( file.is_open() )
- {
- LLSDSerialize::toPrettyXML(fav_llsd, file);
- LL_INFOS("FavoritesBar") << "saved favorites for '" << av_name.getUserName()
- << "' to '" << filename << "' "
- << LL_ENDL;
- file.close();
- }
- else
- {
- LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName()
- << "' at '" << filename << "' "
- << LL_ENDL;
- }
- }
}
void LLFavoritesOrderStorage::removeFavoritesRecordOfUser()
@@ -1626,8 +1615,30 @@ void LLFavoritesOrderStorage::removeFavoritesRecordOfUser()
// See saveFavoritesSLURLs() here above for the reason why.
if (fav_llsd.has(av_name.getUserName()))
{
- LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL;
- fav_llsd.erase(av_name.getUserName());
+ LLSD user_llsd = fav_llsd[av_name.getUserName()];
+
+ if (user_llsd.beginArray()->has("id"))
+ {
+ for (LLSD::array_iterator iter = user_llsd.beginArray();iter != user_llsd.endArray(); ++iter)
+ {
+ LLSD value;
+ value["id"]= iter->get("id").asUUID();
+ iter->assign(value);
+ }
+ fav_llsd[av_name.getUserName()] = user_llsd;
+ llofstream file;
+ file.open(filename.c_str());
+ if ( file.is_open() )
+ {
+ LLSDSerialize::toPrettyXML(fav_llsd, file);
+ file.close();
+ }
+ }
+ else
+ {
+ LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL;
+ fav_llsd.erase(av_name.getUserName());
+ }
}
llofstream out_file;
@@ -1648,20 +1659,20 @@ void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmar
if (landmark)
{
LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " loaded" << LL_ENDL;
- LLVector3d pos_global;
- if (!landmark->getGlobalPos(pos_global))
- {
- // If global position was unknown on first getGlobalPos() call
- // it should be set for the subsequent calls.
- landmark->getGlobalPos(pos_global);
- }
+ LLVector3d pos_global;
+ if (!landmark->getGlobalPos(pos_global))
+ {
+ // If global position was unknown on first getGlobalPos() call
+ // it should be set for the subsequent calls.
+ landmark->getGlobalPos(pos_global);
+ }
- if (!pos_global.isExactlyZero())
- {
- LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL;
- LLLandmarkActions::getSLURLfromPosGlobal(pos_global,
+ if (!pos_global.isExactlyZero())
+ {
+ LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL;
+ LLLandmarkActions::getSLURLfromPosGlobal(pos_global,
boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1));
- }
+ }
}
}
@@ -1671,41 +1682,6 @@ void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::st
mSLURLs[asset_id] = slurl;
}
-void LLFavoritesOrderStorage::save()
-{
- if (mIsDirty)
- {
- // something changed, so save it
- std::string filename = LLFavoritesOrderStorage::getInstance()->getSavedOrderFileName();
- if (!filename.empty())
- {
- LLSD settings_llsd;
-
- for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter)
- {
- settings_llsd[iter->first.asString()] = iter->second;
- }
-
- llofstream file;
- file.open(filename.c_str());
- if ( file.is_open() )
- {
- LLSDSerialize::toPrettyXML(settings_llsd, file);
- LL_INFOS("FavoritesBar") << "saved favorites order to '" << filename << "' " << LL_ENDL;
- }
- else
- {
- LL_WARNS("FavoritesBar") << "failed to open favorites order file '" << filename << "' " << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("FavoritesBar") << "no user directory available to store favorites order file" << LL_ENDL;
- }
- }
-}
-
-
void LLFavoritesOrderStorage::cleanup()
{
// nothing to clean
@@ -1720,7 +1696,7 @@ void LLFavoritesOrderStorage::cleanup()
sort_index_map_t aTempMap;
//copy unremoved values from mSortIndexes to aTempMap
- std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(),
+ std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(),
inserter(aTempMap, aTempMap.begin()),
is_not_in_fav);
@@ -1752,8 +1728,8 @@ void LLFavoritesOrderStorage::saveOrder()
void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array_t& items )
{
- int sortField = 0;
+ int sortField = 0;
// current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i)
{
@@ -1793,6 +1769,110 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it
saveItemsOrder(items);
}
+BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed)
+{
+
+ LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ if (favorite_folder.isNull())
+ return FALSE;
+
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::cat_array_t cats;
+
+ LLIsType is_type(LLAssetType::AT_LANDMARK);
+ gInventory.collectDescendentsIf(favorite_folder, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
+
+ std::sort(items.begin(), items.end(), LLFavoritesSort());
+
+ if((items != mPrevFavorites) || pref_changed)
+ {
+ std::string filename = getStoredFavoritesFilename();
+ if (!filename.empty())
+ {
+ llifstream in_file;
+ in_file.open(filename.c_str());
+ LLSD fav_llsd;
+ if (in_file.is_open())
+ {
+ LLSDSerialize::fromXML(fav_llsd, in_file);
+ in_file.close();
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL;
+ }
+
+ LLSD user_llsd;
+ S32 fav_iter = 0;
+ for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++)
+ {
+ LLSD value;
+ if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"))
+ {
+ value["name"] = (*it)->getName();
+ value["asset_id"] = (*it)->getAssetUUID();
+ value["id"] = (*it)->getUUID();
+ slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]);
+ if (slurl_iter != mSLURLs.end())
+ {
+ value["slurl"] = slurl_iter->second;
+ user_llsd[fav_iter] = value;
+ }
+ else
+ {
+ getSLURL((*it)->getAssetUUID());
+ mUpdateRequired = true;
+ return FALSE;
+ }
+ }
+ else
+ {
+ value["id"] = (*it)->getUUID();
+ user_llsd[fav_iter] = value;
+ }
+
+ fav_iter ++;
+ }
+
+ LLAvatarName av_name;
+ LLAvatarNameCache::get( gAgentID, &av_name );
+ // Note : use the "John Doe" and not the "john.doe" version of the name
+ // as we'll compare it with the stored credentials in the login panel.
+ fav_llsd[av_name.getUserName()] = user_llsd;
+ llofstream file;
+ file.open(filename.c_str());
+ if ( file.is_open() )
+ {
+ LLSDSerialize::toPrettyXML(fav_llsd, file);
+ file.close();
+ mSaveOnExit = false;
+ }
+ else
+ {
+ LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName()
+ << "' at '" << filename << "' " << LL_ENDL;
+ }
+ }
+
+ mPrevFavorites = items;
+ }
+
+ return TRUE;
+
+}
+
+void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(BOOL show)
+{
+ if (show)
+ {
+ saveFavoritesRecord(true);
+ }
+ else
+ {
+ removeFavoritesRecordOfUser();
+ }
+}
+
void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id)
{
if (mTargetLandmarkId.isNull()) return;
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index a370724947..66fc8b2ae7 100755
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -105,8 +105,10 @@ protected:
bool mUpdateDropDownItems;
bool mRestoreOverflowMenu;
- LLUUID mSelectedItemID;
+ bool mGetPrevItems;
+ LLUUID mSelectedItemID;
+ LLFrameTimer mItemsChangedTimer;
LLUIImage* mImageDragIndication;
private:
@@ -204,12 +206,23 @@ public:
* @see cleanup()
*/
static void destroyClass();
+ static std::string getStoredFavoritesFilename();
+ static std::string getSavedOrderFileName();
+
+ BOOL saveFavoritesRecord(bool pref_changed = false);
+ void showFavoritesOnLoginChanged(BOOL show);
+
+ LLInventoryModel::item_array_t mPrevFavorites;
+
const static S32 NO_INDEX;
+ static bool mSaveOnExit;
+ bool mUpdateRequired;
+
private:
friend class LLSingleton<LLFavoritesOrderStorage>;
- LLFavoritesOrderStorage() : mIsDirty(false) { load(); }
- ~LLFavoritesOrderStorage() { save(); }
+ LLFavoritesOrderStorage() : mIsDirty(false), mUpdateRequired(false){ load(); }
+ ~LLFavoritesOrderStorage() {}
/**
* Removes sort indexes for items which are not in Favorites bar for now.
@@ -217,13 +230,8 @@ private:
void cleanup();
const static std::string SORTING_DATA_FILE_NAME;
- std::string getSavedOrderFileName();
- static std::string getStoredFavoritesFilename();
-
- void load();
- void save();
- void saveFavoritesSLURLs();
+ void load();
// Remove record of current user's favorites from file on disk.
void removeFavoritesRecordOfUser();
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index e71daa6067..c5d637d1fc 100755
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -34,10 +34,12 @@
// Viewer includes
#include "llagent.h"
#include "llagentui.h"
-#include "llappviewer.h"
+#include "llappviewer.h"
+#include "llnotificationsutil.h"
#include "llslurl.h"
#include "llvoiceclient.h"
#include "lluictrlfactory.h"
+#include "llupdaterservice.h"
#include "llviewertexteditor.h"
#include "llviewercontrol.h"
#include "llviewerstats.h"
@@ -99,9 +101,23 @@ public:
/// separated so that we can programmatically access the same info.
static LLSD getInfo();
void onClickCopyToClipboard();
+ void onClickUpdateCheck();
+
+ // checks state of updater service and starts a check outside of schedule.
+ // subscribes callback for closest state update
+ static void setUpdateListener();
private:
void setSupportText(const std::string& server_release_notes_url);
+
+ // notifications for user requested checks
+ static void showCheckUpdateNotification(S32 state);
+
+ // callback method for manual checks
+ static bool callbackCheckUpdate(LLSD const & event);
+
+ // listener name for update checks
+ static const std::string sCheckUpdateListenerName;
};
@@ -132,6 +148,9 @@ BOOL LLFloaterAbout::postBuild()
getChild<LLUICtrl>("copy_btn")->setCommitCallback(
boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this));
+ getChild<LLUICtrl>("update_btn")->setCommitCallback(
+ boost::bind(&LLFloaterAbout::onClickUpdateCheck, this));
+
static const LLUIColor about_color = LLUIColorTable::instance().getColor("TextFgReadOnlyColor");
if (gAgent.getRegion())
@@ -235,6 +254,11 @@ void LLFloaterAbout::onClickCopyToClipboard()
support_widget->deselect();
}
+void LLFloaterAbout::onClickUpdateCheck()
+{
+ setUpdateListener();
+}
+
void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)
{
#if LL_WINDOWS
@@ -256,6 +280,68 @@ void LLFloaterAbout::setSupportText(const std::string& server_release_notes_url)
}
///----------------------------------------------------------------------------
+/// Floater About Update-check related functions
+///----------------------------------------------------------------------------
+
+const std::string LLFloaterAbout::sCheckUpdateListenerName = "LLUpdateNotificationListener";
+
+void LLFloaterAbout::showCheckUpdateNotification(S32 state)
+{
+ switch (state)
+ {
+ case LLUpdaterService::UP_TO_DATE:
+ LLNotificationsUtil::add("UpdateViewerUpToDate");
+ break;
+ case LLUpdaterService::DOWNLOADING:
+ case LLUpdaterService::INSTALLING:
+ LLNotificationsUtil::add("UpdateDownloadInProgress");
+ break;
+ case LLUpdaterService::TERMINAL:
+ // download complete, user triggered check after download pop-up appeared
+ LLNotificationsUtil::add("UpdateDownloadComplete");
+ break;
+ default:
+ LLNotificationsUtil::add("UpdateCheckError");
+ break;
+ }
+}
+
+bool LLFloaterAbout::callbackCheckUpdate(LLSD const & event)
+{
+ if (!event.has("payload"))
+ {
+ return false;
+ }
+
+ LLSD payload = event["payload"];
+ if (payload.has("type") && payload["type"].asInteger() == LLUpdaterService::STATE_CHANGE)
+ {
+ LLEventPumps::instance().obtain("mainlooprepeater").stopListening(sCheckUpdateListenerName);
+ showCheckUpdateNotification(payload["state"].asInteger());
+ }
+ return false;
+}
+
+void LLFloaterAbout::setUpdateListener()
+{
+ LLUpdaterService update_service;
+ S32 service_state = update_service.getState();
+ // Note: Do not set state listener before forceCheck() since it set's new state
+ if (update_service.forceCheck() || service_state == LLUpdaterService::CHECKING_FOR_UPDATE)
+ {
+ LLEventPump& mainloop(LLEventPumps::instance().obtain("mainlooprepeater"));
+ if (mainloop.getListener(sCheckUpdateListenerName) == LLBoundListener()) // dummy listener
+ {
+ mainloop.listen(sCheckUpdateListenerName, boost::bind(&callbackCheckUpdate, _1));
+ }
+ }
+ else
+ {
+ showCheckUpdateNotification(service_state);
+ }
+}
+
+///----------------------------------------------------------------------------
/// LLFloaterAboutUtil
///----------------------------------------------------------------------------
void LLFloaterAboutUtil::registerFloater()
@@ -265,6 +351,11 @@ void LLFloaterAboutUtil::registerFloater()
}
+void LLFloaterAboutUtil::checkUpdatesAndNotify()
+{
+ LLFloaterAbout::setUpdateListener();
+}
+
///----------------------------------------------------------------------------
/// Class LLServerReleaseNotesURLFetcher implementation
///----------------------------------------------------------------------------
diff --git a/indra/newview/llfloaterabout.h b/indra/newview/llfloaterabout.h
index 8fc1aa4f29..be34b631cc 100755
--- a/indra/newview/llfloaterabout.h
+++ b/indra/newview/llfloaterabout.h
@@ -30,6 +30,9 @@
namespace LLFloaterAboutUtil
{
void registerFloater();
+
+ // Support for user initialized update/state checks
+ void checkUpdatesAndNotify();
}
#endif // LL_LLFLOATERABOUT_H
diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp
index 34904cf7ed..957c91b226 100755
--- a/indra/newview/llfloaterbump.cpp
+++ b/indra/newview/llfloaterbump.cpp
@@ -32,6 +32,7 @@
#include "llavataractions.h"
#include "llfloaterbump.h"
+#include "llfloaterreg.h"
#include "llfloaterreporter.h"
#include "llmutelist.h"
#include "llpanelblockedlist.h"
@@ -87,11 +88,11 @@ BOOL LLFloaterBump::postBuild()
// virtual
void LLFloaterBump::onOpen(const LLSD& key)
{
- mNames.clear();
- mList->deleteAllItems();
-
if (gMeanCollisionList.empty())
{
+ mNames.clear();
+ mList->deleteAllItems();
+
std::string none_detected = getString("none_detected");
LLSD row;
row["columns"][0]["value"] = none_detected;
@@ -100,12 +101,20 @@ void LLFloaterBump::onOpen(const LLSD& key)
}
else
{
- for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
- iter != gMeanCollisionList.end(); ++iter)
- {
- LLMeanCollisionData *mcd = *iter;
- add(mList, mcd);
- }
+ populateCollisionList();
+ }
+}
+
+void LLFloaterBump::populateCollisionList()
+{
+ mNames.clear();
+ mList->deleteAllItems();
+
+ for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
+ iter != gMeanCollisionList.end(); ++iter)
+ {
+ LLMeanCollisionData *mcd = *iter;
+ add(mList, mcd);
}
}
@@ -247,3 +256,8 @@ void LLFloaterBump::inviteToGroup()
{
LLAvatarActions::inviteToGroup(mItemUUID);
}
+
+LLFloaterBump* LLFloaterBump::getInstance()
+{
+ return LLFloaterReg::getTypedInstance<LLFloaterBump>("bumps");
+}
diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h
index 11b7db9fee..ce52c75255 100755
--- a/indra/newview/llfloaterbump.h
+++ b/indra/newview/llfloaterbump.h
@@ -46,6 +46,10 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
+ static LLFloaterBump* getInstance();
+
+ void populateCollisionList();
+
void startIM();
void startCall();
void reportAbuse();
diff --git a/indra/newview/llfloaterfacebook.cpp b/indra/newview/llfloaterfacebook.cpp
index 3a2047cfef..da85d378b2 100644
--- a/indra/newview/llfloaterfacebook.cpp
+++ b/indra/newview/llfloaterfacebook.cpp
@@ -64,9 +64,9 @@ const std::string DEFAULT_CHECKIN_ICON_URL = "http://map.secondlife.com.s3.amazo
const std::string DEFAULT_CHECKIN_QUERY_PARAMETERS = "?sourceid=slshare_checkin&utm_source=facebook&utm_medium=checkin&utm_campaign=slshare";
const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=facebook&utm_medium=photo&utm_campaign=slshare";
-const S32 MAX_QUALITY = 100; // Max quality value for jpeg images
-const S32 MIN_QUALITY = 0; // Min quality value for jpeg images
-const S32 TARGET_DATA_SIZE = 95000; // Size of the image (compressed) we're trying to send to Facebook
+const S32 MAX_QUALITY = 100; // Max quality value for jpeg images
+const S32 MIN_QUALITY = 0; // Min quality value for jpeg images
+const S32 TARGET_DATA_SIZE = 950000; // Size of the image (compressed) we're trying to send to Facebook
std::string get_map_url()
{
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index ab57e8c170..0a5a6e8e13 100755
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -261,6 +261,8 @@ BOOL LLFloaterIMContainer::postBuild()
mInitialized = true;
+ mIsFirstOpen = true;
+
// Add callbacks:
// We'll take care of view updates on idle
gIdleCallbacks.addFunction(idle, this);
@@ -636,14 +638,16 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
{
// Make sure we have the Nearby Chat present when showing the conversation container
nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
- if (nearby_chat == NULL)
+ if ((nearby_chat == NULL) || mIsFirstOpen)
{
+ mIsFirstOpen = false;
// If not found, force the creation of the nearby chat conversation panel
// *TODO: find a way to move this to XML as a default panel or something like that
LLSD name("nearby_chat");
LLFloaterReg::toggleInstanceOrBringToFront(name);
selectConversationPair(LLUUID(NULL), false, false);
}
+
flashConversationItemWidget(mSelectedSession,false);
LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(mSelectedSession);
@@ -920,6 +924,11 @@ void LLFloaterIMContainer::onCustomAction(const LLSD& userdata)
{
setSortOrderParticipants(LLConversationFilter::SO_DISTANCE);
}
+ if ("view_icons" == command)
+ {
+ gSavedSettings.setBOOL("ChatShowIcons", !(gSavedSettings.getBOOL("ChatShowIcons") && !gSavedSettings.getBOOL("GlobalShowIconsOverride")));
+ gSavedSettings.setBOOL("GlobalShowIconsOverride", (!gSavedSettings.getBOOL("ChatShowIcons") && gSavedSettings.getBOOL("GlobalShowIconsOverride")));
+ }
if ("chat_preferences" == command)
{
LLFloaterPreference * floater_prefp = LLFloaterReg::showTypedInstance<LLFloaterPreference>("preferences");
@@ -970,6 +979,10 @@ BOOL LLFloaterIMContainer::isActionChecked(const LLSD& userdata)
{
return (order.getSortOrderParticipants() == LLConversationFilter::SO_DISTANCE);
}
+ if ("view_icons" == command)
+ {
+ return gSavedSettings.getBOOL("ChatShowIcons") && !gSavedSettings.getBOOL("GlobalShowIconsOverride");
+ }
if ("Translating.Enabled" == command)
{
return gSavedPerAccountSettings.getBOOL("TranslatingEnabled");
@@ -1216,7 +1229,22 @@ void LLFloaterIMContainer::doToSelectedConversation(const std::string& command,
{
if (selectedIDS.size() > 0)
{
- LLAvatarActions::viewChatHistory(selectedIDS.front());
+ if(conversationItem->getType() == LLConversationItem::CONV_SESSION_GROUP)
+ {
+ LLFloaterReg::showInstance("preview_conversation", conversationItem->getUUID(), true);
+ }
+ else if(conversationItem->getType() == LLConversationItem::CONV_SESSION_AD_HOC)
+ {
+ LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(conversationItem->getUUID()));
+ if(conv)
+ {
+ LLFloaterReg::showInstance("preview_conversation", conv->getSessionID(), true);
+ }
+ }
+ else
+ {
+ LLAvatarActions::viewChatHistory(selectedIDS.front());
+ }
}
}
else
@@ -1316,6 +1344,15 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
{
return LLLogChat::isNearbyTranscriptExist();
}
+ else if (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_AD_HOC)
+ {
+ const LLConversation* conv = LLConversationLog::instance().findConversation(LLIMModel::getInstance()->findIMSession(uuids.front()));
+ if(conv)
+ {
+ return LLLogChat::isAdHocTranscriptExist(conv->getHistoryFileName());
+ }
+ return false;
+ }
else
{
bool is_group = (getCurSelectedViewModelItem()->getType() == LLConversationItem::CONV_SESSION_GROUP);
@@ -1881,22 +1918,28 @@ bool LLFloaterIMContainer::canBanSelectedMember(const LLUUID& participant_uuid)
return false;
}
- if (!gdatap->mMembers.size())
+ if (gdatap->mPendingBanRequest)
{
return false;
}
- LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid));
- if (mi == gdatap->mMembers.end())
+ if (gdatap->isRoleMemberDataComplete())
{
- return false;
- }
+ if (!gdatap->mMembers.size())
+ {
+ return false;
+ }
- LLGroupMemberData* member_data = (*mi).second;
- // Is the member an owner?
- if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
- {
- return false;
+ LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid));
+ if (mi != gdatap->mMembers.end())
+ {
+ LLGroupMemberData* member_data = (*mi).second;
+ // Is the member an owner?
+ if (member_data && member_data->isInRole(gdatap->mOwnerRole))
+ {
+ return false;
+ }
+ }
}
if( gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) &&
@@ -1924,20 +1967,8 @@ void LLFloaterIMContainer::banSelectedMember(const LLUUID& participant_uuid)
LL_WARNS("Groups") << "Unable to get group data for group " << group_uuid << LL_ENDL;
return;
}
- std::vector<LLUUID> ids;
- ids.push_back(participant_uuid);
-
- LLGroupBanData ban_data;
- gdatap->createBanEntry(participant_uuid, ban_data);
- LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, group_uuid, LLGroupMgr::BAN_CREATE, ids);
- LLGroupMgr::getInstance()->sendGroupMemberEjects(group_uuid, ids);
- LLGroupMgr::getInstance()->sendGroupMembersRequest(group_uuid);
- LLSD args;
- std::string name;
- gCacheName->getFullName(participant_uuid, name);
- args["AVATAR_NAME"] = name;
- args["GROUP_NAME"] = gdatap->mName;
- LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
+
+ gdatap->banMemberById(participant_uuid);
}
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index f21c0b9947..60cef83d9a 100755
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -193,6 +193,8 @@ private:
bool mInitialized;
bool mIsFirstLaunch;
+ bool mIsFirstOpen;
+
LLUUID mSelectedSession;
std::string mGeneralTitle;
diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp
index b7fff6cae3..ee3d633dd0 100755
--- a/indra/newview/llfloaterjoystick.cpp
+++ b/indra/newview/llfloaterjoystick.cpp
@@ -326,7 +326,21 @@ void LLFloaterJoystick::onClickOK(void *joy_panel)
}
}
+void LLFloaterJoystick::onClickCloseBtn(bool app_quitting)
+{
+ cancel();
+ closeFloater(app_quitting);
+}
+
void LLFloaterJoystick::setSNDefaults()
{
LLViewerJoystick::getInstance()->setSNDefaults();
}
+
+void LLFloaterJoystick::onClose(bool app_quitting)
+{
+ if (app_quitting)
+ {
+ cancel();
+ }
+}
diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h
index 9c3752540d..a1b5951389 100755
--- a/indra/newview/llfloaterjoystick.h
+++ b/indra/newview/llfloaterjoystick.h
@@ -45,6 +45,11 @@ public:
virtual void draw();
static void setSNDefaults();
+protected:
+
+ void onClose(bool app_quitting);
+ void onClickCloseBtn(bool app_quitting);
+
private:
LLFloaterJoystick(const LLSD& data);
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index ce32aeda94..f9fd5069af 100755
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -2439,6 +2439,8 @@ void LLPanelLandAccess::refresh()
mListAccess->clearSortOrder();
mListAccess->deleteAllItems();
S32 count = parcel->mAccessList.size();
+ getChild<LLUICtrl>("AllowedText")->setTextArg("[COUNT]", llformat("%d",count));
+
getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));
getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
@@ -2484,6 +2486,7 @@ void LLPanelLandAccess::refresh()
mListBanned->clearSortOrder();
mListBanned->deleteAllItems();
S32 count = parcel->mBanList.size();
+ getChild<LLUICtrl>("BanCheck")->setTextArg("[COUNT]", llformat("%d",count));
getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));
getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index a2a1dfbdb8..fea4e57d13 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -26,8 +26,35 @@
#include "llviewerprecompiledheaders.h"
-#include "llmodelloader.h"
-#include "lldaeloader.h"
+#if LL_MSVC
+#pragma warning (disable : 4263)
+#pragma warning (disable : 4264)
+#endif
+#include "dae.h"
+//#include "dom.h"
+#include "dom/domAsset.h"
+#include "dom/domBind_material.h"
+#include "dom/domCOLLADA.h"
+#include "dom/domConstants.h"
+#include "dom/domController.h"
+#include "dom/domEffect.h"
+#include "dom/domGeometry.h"
+#include "dom/domInstance_geometry.h"
+#include "dom/domInstance_material.h"
+#include "dom/domInstance_node.h"
+#include "dom/domInstance_effect.h"
+#include "dom/domMaterial.h"
+#include "dom/domMatrix.h"
+#include "dom/domNode.h"
+#include "dom/domProfile_COMMON.h"
+#include "dom/domRotate.h"
+#include "dom/domScale.h"
+#include "dom/domTranslate.h"
+#include "dom/domVisual_scene.h"
+#if LL_MSVC
+#pragma warning (default : 4263)
+#pragma warning (default : 4264)
+#endif
#include "llfloatermodelpreview.h"
@@ -85,15 +112,14 @@
#include "llanimationstates.h"
#include "llviewernetwork.h"
#include "llviewershadermgr.h"
-
#include "glod/glod.h"
-#include <boost/algorithm/string.hpp>
+
+const S32 SLM_SUPPORTED_VERSION = 3;
//static
S32 LLFloaterModelPreview::sUploadAmount = 10;
LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL;
-
-bool LLModelPreview::sIgnoreLoadedCallback = false;
+std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
// "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01
// But according to the UI spec for upload model floater, this parameter
@@ -173,37 +199,190 @@ std::string lod_label_name[NUM_LOD+1] =
"I went off the end of the lod_label_name array. Me so smart."
};
-BOOL stop_gloderror()
+std::string colladaVersion[VERSIONTYPE_COUNT+1] =
{
- GLuint error = glodGetError();
+ "1.4.0",
+ "1.4.1",
+ "Unsupported"
+};
- if (error != GLOD_NO_ERROR)
+
+#define LL_DEGENERACY_TOLERANCE 1e-7f
+
+inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
+{
+ volatile F32 p0 = a[0] * b[0];
+ volatile F32 p1 = a[1] * b[1];
+ volatile F32 p2 = a[2] * b[2];
+ return p0 + p1 + p2;
+}
+
+bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE)
+{
+ // small area check
+ {
+ LLVector4a edge1; edge1.setSub( a, b );
+ LLVector4a edge2; edge2.setSub( a, c );
+ //////////////////////////////////////////////////////////////////////////
+ /// Linden Modified
+ //////////////////////////////////////////////////////////////////////////
+
+ // If no one edge is more than 10x longer than any other edge, we weaken
+ // the tolerance by a factor of 1e-4f.
+
+ LLVector4a edge3; edge3.setSub( c, b );
+ const F32 len1sq = edge1.dot3(edge1).getF32();
+ const F32 len2sq = edge2.dot3(edge2).getF32();
+ const F32 len3sq = edge3.dot3(edge3).getF32();
+ bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq);
+ bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq);
+ bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq);
+ if ( abOK && acOK && cbOK )
+ {
+ tolerance *= 1e-4f;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ /// End Modified
+ //////////////////////////////////////////////////////////////////////////
+
+ LLVector4a cross; cross.setCross3( edge1, edge2 );
+
+ LLVector4a edge1b; edge1b.setSub( b, a );
+ LLVector4a edge2b; edge2b.setSub( b, c );
+ LLVector4a crossb; crossb.setCross3( edge1b, edge2b );
+
+ if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance ))
+ {
+ return true;
+ }
+ }
+
+ // point triangle distance check
+ {
+ LLVector4a Q; Q.setSub(a, b);
+ LLVector4a R; R.setSub(c, b);
+
+ const F32 QQ = dot3fpu(Q, Q);
+ const F32 RR = dot3fpu(R, R);
+ const F32 QR = dot3fpu(R, Q);
+
+ volatile F32 QQRR = QQ * RR;
+ volatile F32 QRQR = QR * QR;
+ F32 Det = (QQRR - QRQR);
+
+ if( Det == 0.0f )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool validate_face(const LLVolumeFace& face)
+{
+
+ for (U32 v = 0; v < face.mNumVertices; v++)
{
- LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
- return TRUE;
+ if(face.mPositions && !face.mPositions[v].isFinite3())
+ {
+ LL_WARNS() << "NaN position data in face found!" << LL_ENDL;
+ return false;
+ }
+
+ if(face.mNormals && !face.mNormals[v].isFinite3())
+ {
+ LL_WARNS() << "NaN normal data in face found!" << LL_ENDL;
+ return false;
+ }
}
- return FALSE;
+ for (U32 i = 0; i < face.mNumIndices; ++i)
+ {
+ if (face.mIndices[i] >= face.mNumVertices)
+ {
+ LL_WARNS() << "Face has invalid index." << LL_ENDL;
+ return false;
+ }
+ }
+
+ if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
+ {
+ LL_WARNS() << "Face has invalid number of indices." << LL_ENDL;
+ return false;
+ }
+
+
+ /*const LLVector4a scale(0.5f);
+
+
+ for (U32 i = 0; i < face.mNumIndices; i+=3)
+ {
+ U16 idx1 = face.mIndices[i];
+ U16 idx2 = face.mIndices[i+1];
+ U16 idx3 = face.mIndices[i+2];
+
+ LLVector4a v1; v1.setMul(face.mPositions[idx1], scale);
+ LLVector4a v2; v2.setMul(face.mPositions[idx2], scale);
+ LLVector4a v3; v3.setMul(face.mPositions[idx3], scale);
+
+ if (ll_is_degenerate(v1,v2,v3))
+ {
+ LL_WARNS() << "Degenerate face found!" << LL_ENDL;
+ return false;
+ }
+ }*/
+ return true;
}
-LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material)
+bool validate_model(const LLModel* mdl)
{
- LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW);
+ if (mdl->getNumVolumeFaces() == 0)
+ {
+ LL_WARNS() << "Model has no faces!" << LL_ENDL;
+ return false;
+ }
- if (texture)
+ for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
{
- if (texture->getDiscardLevel() > -1)
+ if (mdl->getVolumeFace(i).mNumVertices == 0)
+ {
+ LL_WARNS() << "Face has no vertices." << LL_ENDL;
+ return false;
+ }
+
+ if (mdl->getVolumeFace(i).mNumIndices == 0)
{
- gGL.getTexUnit(0)->bind(texture, true);
- return texture;
+ LL_WARNS() << "Face has no indices." << LL_ENDL;
+ return false;
+ }
+
+ if (!validate_face(mdl->getVolumeFace(i)))
+ {
+ return false;
}
}
- return NULL;
+ return true;
}
+BOOL stop_gloderror()
+{
+ GLuint error = glodGetError();
+
+ if (error != GLOD_NO_ERROR)
+ {
+ LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod)
-: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
+ : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
{
mMP = mp;
mLOD = lod;
@@ -214,29 +393,6 @@ void LLMeshFilePicker::notify(const std::string& filename)
mMP->loadModel(mFile, mLOD);
}
-void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut)
-{
- LLModelLoader::scene::iterator base_iter = scene.begin();
- bool found = false;
- while (!found && (base_iter != scene.end()))
- {
- matOut = base_iter->first;
-
- LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin();
- while (!found && (base_instance_iter != base_iter->second.end()))
- {
- LLModelInstance& base_instance = *base_instance_iter++;
- LLModel* base_model = base_instance.mModel;
-
- if (base_model && (base_model->mLabel == name_to_match))
- {
- baseModelOut = base_model;
- return;
- }
- }
- base_iter++;
- }
-}
//-----------------------------------------------------------------------------
// LLFloaterModelPreview()
@@ -457,11 +613,6 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option)
void LLFloaterModelPreview::loadModel(S32 lod)
{
mModelPreview->mLoading = true;
- if (lod == LLModel::LOD_PHYSICS)
- {
- // loading physics from file
- mModelPreview->mPhysicsSearchLOD = lod;
- }
(new LLMeshFilePicker(mModelPreview, lod))->getFile();
}
@@ -600,6 +751,8 @@ void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata)
void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
{
LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+ if (fp->mModelPreview->mHasBrokenModel)
+ return;
fp->mModelPreview->genLODs();
}
@@ -640,9 +793,9 @@ void LLFloaterModelPreview::draw()
childSetTextArg("status", "[STATUS]", getString("status_material_mismatch"));
}
else
- if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_MODEL )
- {
- childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_MODEL)));
+ if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING )
+ {
+ childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING)));
}
else
if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING )
@@ -794,16 +947,9 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
/*virtual*/
void LLFloaterModelPreview::onOpen(const LLSD& key)
{
- LLModelPreview::sIgnoreLoadedCallback = false;
requestAgentUploadPermissions();
}
-/*virtual*/
-void LLFloaterModelPreview::onClose(bool app_quitting)
-{
- LLModelPreview::sIgnoreLoadedCallback = true;
-}
-
//static
void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)
{
@@ -1164,6 +1310,1830 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl
}
//-----------------------------------------------------------------------------
+// LLModelLoader
+//-----------------------------------------------------------------------------
+LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
+ std::deque<std::string>& jointsFromNodes )
+: mJointList( jointMap )
+, mJointsFromNode( jointsFromNodes )
+, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mNumOfFetchingTextures(0)
+{
+ mJointMap["mPelvis"] = "mPelvis";
+ mJointMap["mTorso"] = "mTorso";
+ mJointMap["mChest"] = "mChest";
+ mJointMap["mNeck"] = "mNeck";
+ mJointMap["mHead"] = "mHead";
+ mJointMap["mSkull"] = "mSkull";
+ mJointMap["mEyeRight"] = "mEyeRight";
+ mJointMap["mEyeLeft"] = "mEyeLeft";
+ mJointMap["mCollarLeft"] = "mCollarLeft";
+ mJointMap["mShoulderLeft"] = "mShoulderLeft";
+ mJointMap["mElbowLeft"] = "mElbowLeft";
+ mJointMap["mWristLeft"] = "mWristLeft";
+ mJointMap["mCollarRight"] = "mCollarRight";
+ mJointMap["mShoulderRight"] = "mShoulderRight";
+ mJointMap["mElbowRight"] = "mElbowRight";
+ mJointMap["mWristRight"] = "mWristRight";
+ mJointMap["mHipRight"] = "mHipRight";
+ mJointMap["mKneeRight"] = "mKneeRight";
+ mJointMap["mAnkleRight"] = "mAnkleRight";
+ mJointMap["mFootRight"] = "mFootRight";
+ mJointMap["mToeRight"] = "mToeRight";
+ mJointMap["mHipLeft"] = "mHipLeft";
+ mJointMap["mKneeLeft"] = "mKneeLeft";
+ mJointMap["mAnkleLeft"] = "mAnkleLeft";
+ mJointMap["mFootLeft"] = "mFootLeft";
+ mJointMap["mToeLeft"] = "mToeLeft";
+
+ mJointMap["avatar_mPelvis"] = "mPelvis";
+ mJointMap["avatar_mTorso"] = "mTorso";
+ mJointMap["avatar_mChest"] = "mChest";
+ mJointMap["avatar_mNeck"] = "mNeck";
+ mJointMap["avatar_mHead"] = "mHead";
+ mJointMap["avatar_mSkull"] = "mSkull";
+ mJointMap["avatar_mEyeRight"] = "mEyeRight";
+ mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
+ mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
+ mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
+ mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
+ mJointMap["avatar_mWristLeft"] = "mWristLeft";
+ mJointMap["avatar_mCollarRight"] = "mCollarRight";
+ mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
+ mJointMap["avatar_mElbowRight"] = "mElbowRight";
+ mJointMap["avatar_mWristRight"] = "mWristRight";
+ mJointMap["avatar_mHipRight"] = "mHipRight";
+ mJointMap["avatar_mKneeRight"] = "mKneeRight";
+ mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
+ mJointMap["avatar_mFootRight"] = "mFootRight";
+ mJointMap["avatar_mToeRight"] = "mToeRight";
+ mJointMap["avatar_mHipLeft"] = "mHipLeft";
+ mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
+ mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
+ mJointMap["avatar_mFootLeft"] = "mFootLeft";
+ mJointMap["avatar_mToeLeft"] = "mToeLeft";
+
+
+ mJointMap["hip"] = "mPelvis";
+ mJointMap["abdomen"] = "mTorso";
+ mJointMap["chest"] = "mChest";
+ mJointMap["neck"] = "mNeck";
+ mJointMap["head"] = "mHead";
+ mJointMap["figureHair"] = "mSkull";
+ mJointMap["lCollar"] = "mCollarLeft";
+ mJointMap["lShldr"] = "mShoulderLeft";
+ mJointMap["lForeArm"] = "mElbowLeft";
+ mJointMap["lHand"] = "mWristLeft";
+ mJointMap["rCollar"] = "mCollarRight";
+ mJointMap["rShldr"] = "mShoulderRight";
+ mJointMap["rForeArm"] = "mElbowRight";
+ mJointMap["rHand"] = "mWristRight";
+ mJointMap["rThigh"] = "mHipRight";
+ mJointMap["rShin"] = "mKneeRight";
+ mJointMap["rFoot"] = "mFootRight";
+ mJointMap["lThigh"] = "mHipLeft";
+ mJointMap["lShin"] = "mKneeLeft";
+ mJointMap["lFoot"] = "mFootLeft";
+
+ if (mPreview)
+ {
+ //only try to load from slm if viewer is configured to do so and this is the
+ //initial model load (not an LoD or physics shape)
+ mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty();
+ mPreview->setLoadState(STARTING);
+ }
+ else
+ {
+ mTrySLM = false;
+ }
+
+ assert_main_thread();
+ sActiveLoaderList.push_back(this) ;
+}
+
+LLModelLoader::~LLModelLoader()
+{
+ assert_main_thread();
+ sActiveLoaderList.remove(this);
+}
+
+void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
+{
+ LLVector4a box[] =
+ {
+ LLVector4a(-1, 1,-1),
+ LLVector4a(-1, 1, 1),
+ LLVector4a(-1,-1,-1),
+ LLVector4a(-1,-1, 1),
+ LLVector4a( 1, 1,-1),
+ LLVector4a( 1, 1, 1),
+ LLVector4a( 1,-1,-1),
+ LLVector4a( 1,-1, 1),
+ };
+
+ for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
+ {
+ const LLVolumeFace& face = model->getVolumeFace(j);
+
+ LLVector4a center;
+ center.setAdd(face.mExtents[0], face.mExtents[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(face.mExtents[1],face.mExtents[0]);
+ size.mul(0.5f);
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLVector4a t;
+ t.setMul(size, box[i]);
+ t.add(center);
+
+ LLVector4a v;
+
+ mat.affineTransform(t, v);
+
+ if (first_transform)
+ {
+ first_transform = FALSE;
+ min = max = v;
+ }
+ else
+ {
+ update_min_max(min, max, v);
+ }
+ }
+ }
+}
+
+void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform)
+{
+ LLVector4a mina, maxa;
+ LLMatrix4a mata;
+
+ mata.loadu(mat);
+ mina.load3(min.mV);
+ maxa.load3(max.mV);
+
+ stretch_extents(model, mata, mina, maxa, first_transform);
+
+ min.set(mina.getF32ptr());
+ max.set(maxa.getF32ptr());
+}
+
+void LLModelLoader::run()
+{
+ doLoadModel();
+ doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
+}
+
+bool LLModelLoader::doLoadModel()
+{
+ //first, look for a .slm file of the same name that was modified later
+ //than the .dae
+
+ if (mTrySLM)
+ {
+ std::string filename = mFilename;
+
+ std::string::size_type i = filename.rfind(".");
+ if (i != std::string::npos)
+ {
+ filename.replace(i, filename.size()-1, ".slm");
+ llstat slm_status;
+ if (LLFile::stat(filename, &slm_status) == 0)
+ { //slm file exists
+ llstat dae_status;
+ if (LLFile::stat(mFilename, &dae_status) != 0 ||
+ dae_status.st_mtime < slm_status.st_mtime)
+ {
+ if (loadFromSLM(filename))
+ { //slm successfully loaded, if this fails, fall through and
+ //try loading from dae
+
+ mLod = -1; //successfully loading from an slm implicitly sets all
+ //LoDs
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ //no suitable slm exists, load from the .dae file
+ DAE dae;
+ domCOLLADA* dom = dae.open(mFilename);
+
+ if (!dom)
+ {
+ LL_INFOS()<<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL;
+ setLoadState( ERROR_PARSING );
+ return false;
+ }
+ //Dom version
+ daeString domVersion = dae.getDomVersion();
+ std::string sldom(domVersion);
+ LL_INFOS()<<"Collada Importer Version: "<<sldom<<LL_ENDL;
+ //Dae version
+ domVersionType docVersion = dom->getVersion();
+ //0=1.4
+ //1=1.4.1
+ //2=Currently unsupported, however may work
+ if (docVersion > 1 )
+ {
+ docVersion = VERSIONTYPE_COUNT;
+ }
+ LL_INFOS()<<"Dae version "<<colladaVersion[docVersion]<<LL_ENDL;
+
+
+ daeDatabase* db = dae.getDatabase();
+
+ daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
+
+ daeDocument* doc = dae.getDoc(mFilename);
+ if (!doc)
+ {
+ LL_WARNS() << "can't find internal doc" << LL_ENDL;
+ return false;
+ }
+
+ daeElement* root = doc->getDomRoot();
+ if (!root)
+ {
+ LL_WARNS() << "document has no root" << LL_ENDL;
+ return false;
+ }
+
+ //Verify some basic properties of the dae
+ //1. Basic validity check on controller
+ U32 controllerCount = (int) db->getElementCount( NULL, "controller" );
+ bool result = false;
+ for ( int i=0; i<controllerCount; ++i )
+ {
+ domController* pController = NULL;
+ db->getElement( (daeElement**) &pController, i , NULL, "controller" );
+ result = mPreview->verifyController( pController );
+ if (!result)
+ {
+ setLoadState( ERROR_PARSING );
+ return true;
+ }
+ }
+
+
+ //get unit scale
+ mTransform.setIdentity();
+
+ domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
+
+ if (unit)
+ {
+ F32 meter = unit->getMeter();
+ mTransform.mMatrix[0][0] = meter;
+ mTransform.mMatrix[1][1] = meter;
+ mTransform.mMatrix[2][2] = meter;
+ }
+
+ //get up axis rotation
+ LLMatrix4 rotation;
+
+ domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP
+ domAsset::domUp_axis* up_axis =
+ daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID())));
+
+ if (up_axis)
+ {
+ up = up_axis->getValue();
+ }
+
+ if (up == UPAXISTYPE_X_UP)
+ {
+ rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f);
+ }
+ else if (up == UPAXISTYPE_Y_UP)
+ {
+ rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
+ }
+
+ rotation *= mTransform;
+ mTransform = rotation;
+
+
+ for (daeInt idx = 0; idx < count; ++idx)
+ { //build map of domEntities to LLModel
+ domMesh* mesh = NULL;
+ db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
+
+ if (mesh)
+ {
+ LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh);
+
+ if(model->getStatus() != LLModel::NO_ERRORS)
+ {
+ setLoadState(ERROR_PARSING + model->getStatus()) ;
+ return false; //abort
+ }
+
+ if (model.notNull() && validate_model(model))
+ {
+ mModelList.push_back(model);
+ mModel[mesh] = model;
+ }
+ else
+ {
+ mPreview->mHasBrokenModel = true;
+ }
+ }
+ }
+
+ count = db->getElementCount(NULL, COLLADA_TYPE_SKIN);
+ for (daeInt idx = 0; idx < count; ++idx)
+ { //add skinned meshes as instances
+ domSkin* skin = NULL;
+ db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN);
+
+ if (skin)
+ {
+ domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
+
+ if (geom)
+ {
+ domMesh* mesh = geom->getMesh();
+ if (mesh)
+ {
+ LLModel* model = mModel[mesh];
+ if (model)
+ {
+ LLVector3 mesh_scale_vector;
+ LLVector3 mesh_translation_vector;
+ model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
+
+ LLMatrix4 normalized_transformation;
+ normalized_transformation.setTranslation(mesh_translation_vector);
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= normalized_transformation;
+ normalized_transformation = mesh_scale;
+
+ glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
+ inv_mat = inv_mat.inverse();
+ LLMatrix4 inverse_normalized_transformation(inv_mat.m);
+
+ domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
+
+ if (bind_mat)
+ { //get bind shape matrix
+ domFloat4x4& dom_value = bind_mat->getValue();
+
+ LLMeshSkinInfo& skin_info = model->mSkinInfo;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
+ }
+ }
+
+ LLMatrix4 trans = normalized_transformation;
+ trans *= skin_info.mBindShapeMatrix;
+ skin_info.mBindShapeMatrix = trans;
+ }
+
+
+ //Some collada setup for accessing the skeleton
+ daeElement* pElement = 0;
+ dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" );
+
+ //Try to get at the skeletal instance controller
+ domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
+ bool missingSkeletonOrScene = false;
+
+ //If no skeleton, do a breadth-first search to get at specific joints
+ bool rootNode = false;
+
+ //Need to test for a skeleton that does not have a root node
+ //This occurs when your instance controller does not have an associated scene
+ if ( pSkeleton )
+ {
+ daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
+ if ( pSkeletonRootNode )
+ {
+ rootNode = true;
+ }
+
+ }
+ if ( !pSkeleton || !rootNode )
+ {
+ daeElement* pScene = root->getDescendant("visual_scene");
+ if ( !pScene )
+ {
+ LL_WARNS()<<"No visual scene - unable to parse bone offsets "<<LL_ENDL;
+ missingSkeletonOrScene = true;
+ }
+ else
+ {
+ //Get the children at this level
+ daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
+ S32 childCount = children.getCount();
+
+ //Process any children that are joints
+ //Not all children are joints, some code be ambient lights, cameras, geometry etc..
+ for (S32 i = 0; i < childCount; ++i)
+ {
+ domNode* pNode = daeSafeCast<domNode>(children[i]);
+ if ( isNodeAJoint( pNode ) )
+ {
+ processJointNode( pNode, mJointList );
+ }
+ }
+ }
+ }
+ else
+ //Has Skeleton
+ {
+ //Get the root node of the skeleton
+ daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement();
+ if ( pSkeletonRootNode )
+ {
+ //Once we have the root node - start acccessing it's joint components
+ const int jointCnt = mJointMap.size();
+ std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin();
+
+ //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor.
+ for ( int i=0; i<jointCnt; ++i, ++jointIt )
+ {
+ //Build a joint for the resolver to work with
+ char str[64]={0};
+ sprintf(str,"./%s",(*jointIt).first.c_str() );
+ //LL_WARNS()<<"Joint "<< str <<LL_ENDL;
+
+ //Setup the resolver
+ daeSIDResolver resolver( pSkeletonRootNode, str );
+
+ //Look for the joint
+ domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
+ if ( pJoint )
+ {
+ //Pull out the translate id and store it in the jointTranslations map
+ daeSIDResolver jointResolverA( pJoint, "./translate" );
+ domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
+ daeSIDResolver jointResolverB( pJoint, "./location" );
+ domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
+
+ LLMatrix4 workingTransform;
+
+ //Translation via SID
+ if ( pTranslateA )
+ {
+ extractTranslation( pTranslateA, workingTransform );
+ }
+ else
+ if ( pTranslateB )
+ {
+ extractTranslation( pTranslateB, workingTransform );
+ }
+ else
+ {
+ //Translation via child from element
+ daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" );
+ if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() )
+ {
+ LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
+ missingSkeletonOrScene = true;
+ }
+ else
+ if ( pTranslateElement )
+ {
+ extractTranslationViaElement( pTranslateElement, workingTransform );
+ }
+ else
+ {
+ extractTranslationViaSID( pJoint, workingTransform );
+ }
+
+ }
+
+ //Store the joint transform w/respect to it's name.
+ mJointList[(*jointIt).second.c_str()] = workingTransform;
+ }
+ }
+
+ //If anything failed in regards to extracting the skeleton, joints or translation id,
+ //mention it
+ if ( missingSkeletonOrScene )
+ {
+ LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL;
+ }
+ }//got skeleton?
+ }
+
+
+ domSkin::domJoints* joints = skin->getJoints();
+
+ domInputLocal_Array& joint_input = joints->getInput_array();
+
+ for (size_t i = 0; i < joint_input.getCount(); ++i)
+ {
+ domInputLocal* input = joint_input.get(i);
+ xsNMTOKEN semantic = input->getSemantic();
+
+ if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
+ { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames
+ daeElement* elem = input->getSource().getElement();
+
+ domSource* source = daeSafeCast<domSource>(elem);
+ if (source)
+ {
+
+
+ domName_array* names_source = source->getName_array();
+
+ if (names_source)
+ {
+ domListOfNames &names = names_source->getValue();
+
+ for (size_t j = 0; j < names.getCount(); ++j)
+ {
+ std::string name(names.get(j));
+ if (mJointMap.find(name) != mJointMap.end())
+ {
+ name = mJointMap[name];
+ }
+ model->mSkinInfo.mJointNames.push_back(name);
+ model->mSkinInfo.mJointMap[name] = j;
+ }
+ }
+ else
+ {
+ domIDREF_array* names_source = source->getIDREF_array();
+ if (names_source)
+ {
+ xsIDREFS& names = names_source->getValue();
+
+ for (size_t j = 0; j < names.getCount(); ++j)
+ {
+ std::string name(names.get(j).getID());
+ if (mJointMap.find(name) != mJointMap.end())
+ {
+ name = mJointMap[name];
+ }
+ model->mSkinInfo.mJointNames.push_back(name);
+ model->mSkinInfo.mJointMap[name] = j;
+ }
+ }
+ }
+ }
+ }
+ else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0)
+ { //found inv_bind_matrix array, fill model->mInvBindMatrix
+ domSource* source = daeSafeCast<domSource>(input->getSource().getElement());
+ if (source)
+ {
+ domFloat_array* t = source->getFloat_array();
+ if (t)
+ {
+ domListOfFloats& transform = t->getValue();
+ S32 count = transform.getCount()/16;
+
+ for (S32 k = 0; k < count; ++k)
+ {
+ LLMatrix4 mat;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ mat.mMatrix[i][j] = transform[k*16 + i + j*4];
+ }
+ }
+
+ model->mSkinInfo.mInvBindMatrix.push_back(mat);
+ }
+ }
+ }
+ }
+ }
+
+ //Now that we've parsed the joint array, let's determine if we have a full rig
+ //(which means we have all the joint sthat are required for an avatar versus
+ //a skinned asset attached to a node in a file that contains an entire skeleton,
+ //but does not use the skeleton).
+ buildJointToNodeMappingFromScene( root );
+ mPreview->critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames );
+
+ if ( !missingSkeletonOrScene )
+ {
+ //Set the joint translations on the avatar - if it's a full mapping
+ //The joints are reset in the dtor
+ if ( mPreview->getRigWithSceneParity() )
+ {
+ std::map<std::string, std::string> :: const_iterator masterJointIt = mJointMap.begin();
+ std::map<std::string, std::string> :: const_iterator masterJointItEnd = mJointMap.end();
+ for (;masterJointIt!=masterJointItEnd;++masterJointIt )
+ {
+ std::string lookingForJoint = (*masterJointIt).first.c_str();
+
+ if ( mJointList.find( lookingForJoint ) != mJointList.end() )
+ {
+ //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL;
+ LLMatrix4 jointTransform = mJointList[lookingForJoint];
+ LLJoint* pJoint = mPreview->getPreviewAvatar()->getJoint( lookingForJoint );
+ if ( pJoint )
+ {
+ LLUUID fake_mesh_id;
+ fake_mesh_id.generate();
+ pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, gAgentAvatarp->avString());
+ }
+ else
+ {
+ //Most likely an error in the asset.
+ LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL;
+ }
+ }
+ }
+ }
+ } //missingSkeletonOrScene
+
+
+ //We need to construct the alternate bind matrix (which contains the new joint positions)
+ //in the same order as they were stored in the joint buffer. The joints associated
+ //with the skeleton are not stored in the same order as they are in the exported joint buffer.
+ //This remaps the skeletal joints to be in the same order as the joints stored in the model.
+ std::vector<std::string> :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin();
+ const int jointCnt = model->mSkinInfo.mJointNames.size();
+ for ( int i=0; i<jointCnt; ++i, ++jointIt )
+ {
+ std::string lookingForJoint = (*jointIt).c_str();
+ //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key
+ //and store it in the alternate bind matrix
+ if ( mJointList.find( lookingForJoint ) != mJointList.end() )
+ {
+ LLMatrix4 jointTransform = mJointList[lookingForJoint];
+ LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
+ newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() );
+ model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
+ }
+ else
+ {
+ LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL;
+ }
+ }
+
+ //grab raw position array
+
+ domVertices* verts = mesh->getVertices();
+ if (verts)
+ {
+ domInputLocal_Array& inputs = verts->getInput_array();
+ for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i)
+ {
+ if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0)
+ {
+ domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
+ if (pos_source)
+ {
+ domFloat_array* pos_array = pos_source->getFloat_array();
+ if (pos_array)
+ {
+ domListOfFloats& pos = pos_array->getValue();
+
+ for (size_t j = 0; j < pos.getCount(); j += 3)
+ {
+ if (pos.getCount() <= j+2)
+ {
+ LL_ERRS() << "Invalid position array size." << LL_ENDL;
+ }
+
+ LLVector3 v(pos[j], pos[j+1], pos[j+2]);
+
+ //transform from COLLADA space to volume space
+ v = v * inverse_normalized_transformation;
+
+ model->mPosition.push_back(v);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //grab skin weights array
+ domSkin::domVertex_weights* weights = skin->getVertex_weights();
+ if (weights)
+ {
+ domInputLocalOffset_Array& inputs = weights->getInput_array();
+ domFloat_array* vertex_weights = NULL;
+ for (size_t i = 0; i < inputs.getCount(); ++i)
+ {
+ if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0)
+ {
+ domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement());
+ if (weight_source)
+ {
+ vertex_weights = weight_source->getFloat_array();
+ }
+ }
+ }
+
+ if (vertex_weights)
+ {
+ domListOfFloats& w = vertex_weights->getValue();
+ domListOfUInts& vcount = weights->getVcount()->getValue();
+ domListOfInts& v = weights->getV()->getValue();
+
+ U32 c_idx = 0;
+ for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx)
+ { //for each vertex
+ daeUInt count = vcount[vc_idx];
+
+ //create list of weights that influence this vertex
+ LLModel::weight_list weight_list;
+
+ for (daeUInt i = 0; i < count; ++i)
+ { //for each weight
+ daeInt joint_idx = v[c_idx++];
+ daeInt weight_idx = v[c_idx++];
+
+ if (joint_idx == -1)
+ {
+ //ignore bindings to bind_shape_matrix
+ continue;
+ }
+
+ F32 weight_value = w[weight_idx];
+
+ weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value));
+ }
+
+ //sort by joint weight
+ std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
+
+ std::vector<LLModel::JointWeight> wght;
+
+ F32 total = 0.f;
+
+ for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i)
+ { //take up to 4 most significant weights
+ if (weight_list[i].mWeight > 0.f)
+ {
+ wght.push_back( weight_list[i] );
+ total += weight_list[i].mWeight;
+ }
+ }
+
+ F32 scale = 1.f/total;
+ if (scale != 1.f)
+ { //normalize weights
+ for (U32 i = 0; i < wght.size(); ++i)
+ {
+ wght[i].mWeight *= scale;
+ }
+ }
+
+ model->mSkinWeights[model->mPosition[vc_idx]] = wght;
+ }
+
+ //add instance to scene for this model
+
+ LLMatrix4 transformation = mTransform;
+ // adjust the transformation to compensate for mesh normalization
+
+ LLMatrix4 mesh_translation;
+ mesh_translation.setTranslation(mesh_translation_vector);
+ mesh_translation *= transformation;
+ transformation = mesh_translation;
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= transformation;
+ transformation = mesh_scale;
+
+ std::map<std::string, LLImportMaterial> materials;
+ for (U32 i = 0; i < model->mMaterialList.size(); ++i)
+ {
+ materials[model->mMaterialList[i]] = LLImportMaterial();
+ }
+ mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
+ stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ daeElement* scene = root->getDescendant("visual_scene");
+
+ if (!scene)
+ {
+ LL_WARNS() << "document has no visual_scene" << LL_ENDL;
+ setLoadState( ERROR_PARSING );
+ return true;
+ }
+
+ setLoadState( DONE );
+
+ bool badElement = false;
+
+ processElement( scene, badElement );
+
+ if ( badElement )
+ {
+ setLoadState( ERROR_PARSING );
+ }
+
+ return true;
+}
+
+void LLModelLoader::setLoadState(U32 state)
+{
+ if (mPreview)
+ {
+ mPreview->setLoadState(state);
+ }
+}
+
+bool LLModelLoader::loadFromSLM(const std::string& filename)
+{
+ //only need to populate mScene with data from slm
+ llstat stat;
+
+ if (LLFile::stat(filename, &stat))
+ { //file does not exist
+ return false;
+ }
+
+ S32 file_size = (S32) stat.st_size;
+
+ llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary);
+ LLSD data;
+ LLSDSerialize::fromBinary(data, ifstream, file_size);
+ ifstream.close();
+
+ //build model list for each LoD
+ model_list model[LLModel::NUM_LODS];
+
+ if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
+ { //unsupported version
+ return false;
+ }
+
+ LLSD& mesh = data["mesh"];
+
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+
+ for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ for (U32 i = 0; i < mesh.size(); ++i)
+ {
+ std::stringstream str(mesh[i].asString());
+ LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
+ if (loaded_model->loadModel(str))
+ {
+ loaded_model->mLocalID = i;
+ model[lod].push_back(loaded_model);
+
+ if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty())
+ {
+ //check to see if rig is valid
+ mPreview->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
+ }
+ }
+ }
+ }
+
+ if (model[LLModel::LOD_HIGH].empty())
+ { //failed to load high lod
+ return false;
+ }
+
+ // Set name.
+ std::string name = data["name"];
+ if (!name.empty())
+ {
+ model[LLModel::LOD_HIGH][0]->mLabel = name;
+ }
+
+
+ //load instance list
+ model_instance_list instance_list;
+
+ LLSD& instance = data["instance"];
+
+ for (U32 i = 0; i < instance.size(); ++i)
+ {
+ //deserialize instance list
+ instance_list.push_back(LLModelInstance(instance[i]));
+
+ //match up model instance pointers
+ S32 idx = instance_list[i].mLocalMeshID;
+
+ for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ if (model[lod].size() > idx)
+ {
+ instance_list[i].mLOD[lod] = model[lod][idx];
+ }
+ else if (!model[lod].empty())
+ {
+ // slm load failed - indexes are corrupted
+ return false;
+ }
+ }
+
+ instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
+ }
+
+
+ //convert instance_list to mScene
+ mFirstTransform = TRUE;
+ for (U32 i = 0; i < instance_list.size(); ++i)
+ {
+ LLModelInstance& cur_instance = instance_list[i];
+ mScene[cur_instance.mTransform].push_back(cur_instance);
+ stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
+ }
+
+ setLoadState( DONE );
+
+ return true;
+}
+
+//static
+bool LLModelLoader::isAlive(LLModelLoader* loader)
+{
+ if(!loader)
+ {
+ return false ;
+ }
+
+ std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
+ for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
+
+ return *iter == loader ;
+}
+
+void LLModelLoader::loadModelCallback()
+{
+ assert_main_thread();
+
+ if (mPreview)
+ {
+ mPreview->loadModelCallback(mLod);
+ }
+
+ while (!isStopped())
+ { //wait until this thread is stopped before deleting self
+ apr_sleep(100);
+ }
+
+ //doubel check if "this" is valid before deleting it, in case it is aborted during running.
+ if(!isAlive(this))
+ {
+ return ;
+ }
+
+ //generate BBox here if non-valide model in scene was detected
+ if (mPreview->mHasBrokenModel)
+ {
+ mPreview->genModelBBox();
+ }
+
+ //cleanup model loader
+ if (mPreview)
+ {
+ mPreview->mModelLoader = NULL;
+ }
+
+ delete this;
+}
+//-----------------------------------------------------------------------------
+// buildJointToNodeMappingFromScene()
+//-----------------------------------------------------------------------------
+void LLModelLoader::buildJointToNodeMappingFromScene( daeElement* pRoot )
+{
+ daeElement* pScene = pRoot->getDescendant("visual_scene");
+ if ( pScene )
+ {
+ daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren();
+ S32 childCount = children.getCount();
+ for (S32 i = 0; i < childCount; ++i)
+ {
+ domNode* pNode = daeSafeCast<domNode>(children[i]);
+ processJointToNodeMapping( pNode );
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// processJointToNodeMapping()
+//-----------------------------------------------------------------------------
+void LLModelLoader::processJointToNodeMapping( domNode* pNode )
+{
+ if ( isNodeAJoint( pNode ) )
+ {
+ //1.Store the parent
+ std::string nodeName = pNode->getName();
+ if ( !nodeName.empty() )
+ {
+ mJointsFromNode.push_front( pNode->getName() );
+ }
+ //2. Handle the kiddo's
+ processChildJoints( pNode );
+ }
+ else
+ {
+ //Determine if the're any children wrt to this failed node.
+ //This occurs when an armature is exported and ends up being what essentially amounts to
+ //as the root for the visual_scene
+ if ( pNode )
+ {
+ processChildJoints( pNode );
+ }
+ else
+ {
+ LL_INFOS()<<"Node is NULL"<<LL_ENDL;
+ }
+
+ }
+}
+//-----------------------------------------------------------------------------
+// processChildJoint()
+//-----------------------------------------------------------------------------
+void LLModelLoader::processChildJoints( domNode* pParentNode )
+{
+ daeTArray< daeSmartRef<daeElement> > childOfChild = pParentNode->getChildren();
+ S32 childOfChildCount = childOfChild.getCount();
+ for (S32 i = 0; i < childOfChildCount; ++i)
+ {
+ domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
+ if ( pChildNode )
+ {
+ processJointToNodeMapping( pChildNode );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// critiqueRigForUploadApplicability()
+//-----------------------------------------------------------------------------
+void LLModelPreview::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
+{
+ critiqueJointToNodeMappingFromScene();
+
+ //Determines the following use cases for a rig:
+ //1. It is suitable for upload with skin weights & joint positions, or
+ //2. It is suitable for upload as standard av with just skin weights
+
+ bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
+ bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
+
+ //It's OK that both could end up being true, both default to false
+ if ( isJointPositionUploadOK )
+ {
+ setRigValidForJointPositionUpload( true );
+ }
+
+ if ( isRigLegacyOK)
+ {
+ setLegacyRigValid( true );
+ }
+
+}
+//-----------------------------------------------------------------------------
+// critiqueJointToNodeMappingFromScene()
+//-----------------------------------------------------------------------------
+void LLModelPreview::critiqueJointToNodeMappingFromScene( void )
+{
+ //Do the actual nodes back the joint listing from the dae?
+ //if yes then this is a fully rigged asset, otherwise it's just a partial rig
+
+ std::deque<std::string>::iterator jointsFromNodeIt = mJointsFromNode.begin();
+ std::deque<std::string>::iterator jointsFromNodeEndIt = mJointsFromNode.end();
+ bool result = true;
+
+ if ( !mJointsFromNode.empty() )
+ {
+ for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt )
+ {
+ std::string name = *jointsFromNodeIt;
+ if ( mJointTransformMap.find( name ) != mJointTransformMap.end() )
+ {
+ continue;
+ }
+ else
+ {
+ LL_INFOS()<<"critiqueJointToNodeMappingFromScene is missing a: "<<name<<LL_ENDL;
+ result = false;
+ }
+ }
+ }
+ else
+ {
+ result = false;
+ }
+
+ //Determines the following use cases for a rig:
+ //1. Full av rig w/1-1 mapping from the scene and joint array
+ //2. Partial rig but w/o parity between the scene and joint array
+ if ( result )
+ {
+ setRigWithSceneParity( true );
+ }
+}
+//-----------------------------------------------------------------------------
+// isRigLegacy()
+//-----------------------------------------------------------------------------
+bool LLModelPreview::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
+{
+ //No joints in asset
+ if ( jointListFromAsset.size() == 0 )
+ {
+ return false;
+ }
+
+ bool result = false;
+
+ std::deque<std::string> :: const_iterator masterJointIt = mMasterLegacyJointList.begin();
+ std::deque<std::string> :: const_iterator masterJointEndIt = mMasterLegacyJointList.end();
+
+ std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
+ std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
+
+ for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
+ {
+ result = false;
+ modelJointIt = jointListFromAsset.begin();
+
+ for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
+ {
+ if ( *masterJointIt == *modelJointIt )
+ {
+ result = true;
+ break;
+ }
+ }
+ if ( !result )
+ {
+ LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
+ break;
+ }
+ }
+ return result;
+}
+//-----------------------------------------------------------------------------
+// isRigSuitableForJointPositionUpload()
+//-----------------------------------------------------------------------------
+bool LLModelPreview::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
+{
+ bool result = false;
+
+ std::deque<std::string> :: const_iterator masterJointIt = mMasterJointList.begin();
+ std::deque<std::string> :: const_iterator masterJointEndIt = mMasterJointList.end();
+
+ std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
+ std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
+
+ for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
+ {
+ result = false;
+ modelJointIt = jointListFromAsset.begin();
+
+ for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
+ {
+ if ( *masterJointIt == *modelJointIt )
+ {
+ result = true;
+ break;
+ }
+ }
+ if ( !result )
+ {
+ LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
+ break;
+ }
+ }
+ return result;
+}
+
+
+//called in the main thread
+void LLModelLoader::loadTextures()
+{
+ BOOL is_paused = isPaused() ;
+ pause() ; //pause the loader
+
+ for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
+ {
+ for(U32 i = 0 ; i < iter->second.size(); i++)
+ {
+ for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
+ j != iter->second[i].mMaterial.end(); ++j)
+ {
+ LLImportMaterial& material = j->second;
+
+ if(!material.mDiffuseMapFilename.empty())
+ {
+ material.mDiffuseMap =
+ LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW);
+ material.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE);
+ material.mDiffuseMap->forceToSaveRawImage(0, F32_MAX);
+ mNumOfFetchingTextures++ ;
+ }
+ }
+ }
+ }
+
+ if(!is_paused)
+ {
+ unpause() ;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// isNodeAJoint()
+//-----------------------------------------------------------------------------
+bool LLModelLoader::isNodeAJoint( domNode* pNode )
+{
+ if ( !pNode )
+ {
+ LL_INFOS()<<"Created node is NULL"<<LL_ENDL;
+ return false;
+ }
+
+ if ( pNode->getName() == NULL )
+ {
+ LL_INFOS()<<"Parsed node has no name "<<LL_ENDL;
+ //Attempt to write the node id, if possible (aids in debugging the visual scene)
+ if ( pNode->getId() )
+ {
+ LL_INFOS()<<"Parsed node ID: "<<pNode->getId()<<LL_ENDL;
+ }
+ return false;
+ }
+
+ if ( mJointMap.find( pNode->getName() ) != mJointMap.end() )
+ {
+ return true;
+ }
+
+ return false;
+}
+//-----------------------------------------------------------------------------
+// verifyCount
+//-----------------------------------------------------------------------------
+bool LLModelPreview::verifyCount( int expected, int result )
+{
+ if ( expected != result )
+ {
+ LL_INFOS()<< "Error: (expected/got)"<<expected<<"/"<<result<<"verts"<<LL_ENDL;
+ return false;
+ }
+ return true;
+}
+//-----------------------------------------------------------------------------
+// verifyController
+//-----------------------------------------------------------------------------
+bool LLModelPreview::verifyController( domController* pController )
+{
+
+ bool result = true;
+
+ domSkin* pSkin = pController->getSkin();
+
+ if ( pSkin )
+ {
+ xsAnyURI & uri = pSkin->getSource();
+ domElement* pElement = uri.getElement();
+
+ if ( !pElement )
+ {
+ LL_INFOS()<<"Can't resolve skin source"<<LL_ENDL;
+ return false;
+ }
+
+ daeString type_str = pElement->getTypeName();
+ if ( stricmp(type_str, "geometry") == 0 )
+ {
+ //Skin is reference directly by geometry and get the vertex count from skin
+ domSkin::domVertex_weights* pVertexWeights = pSkin->getVertex_weights();
+ U32 vertexWeightsCount = pVertexWeights->getCount();
+ domGeometry* pGeometry = (domGeometry*) (domElement*) uri.getElement();
+ domMesh* pMesh = pGeometry->getMesh();
+
+ if ( pMesh )
+ {
+ //Get vertex count from geometry
+ domVertices* pVertices = pMesh->getVertices();
+ if ( !pVertices )
+ {
+ LL_INFOS()<<"No vertices!"<<LL_ENDL;
+ return false;
+ }
+
+ if ( pVertices )
+ {
+ xsAnyURI src = pVertices->getInput_array()[0]->getSource();
+ domSource* pSource = (domSource*) (domElement*) src.getElement();
+ U32 verticesCount = pSource->getTechnique_common()->getAccessor()->getCount();
+ result = verifyCount( verticesCount, vertexWeightsCount );
+ if ( !result )
+ {
+ return result;
+ }
+ }
+ }
+
+ U32 vcountCount = (U32) pVertexWeights->getVcount()->getValue().getCount();
+ result = verifyCount( vcountCount, vertexWeightsCount );
+ if ( !result )
+ {
+ return result;
+ }
+
+ domInputLocalOffset_Array& inputs = pVertexWeights->getInput_array();
+ U32 sum = 0;
+ for (size_t i=0; i<vcountCount; i++)
+ {
+ sum += pVertexWeights->getVcount()->getValue()[i];
+ }
+ result = verifyCount( sum * inputs.getCount(), (domInt) pVertexWeights->getV()->getValue().getCount() );
+ }
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// extractTranslation()
+//-----------------------------------------------------------------------------
+void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform )
+{
+ domFloat3 jointTrans = pTranslate->getValue();
+ LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] );
+ transform.setTranslation( singleJointTranslation );
+}
+//-----------------------------------------------------------------------------
+// extractTranslationViaElement()
+//-----------------------------------------------------------------------------
+void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform )
+{
+ if ( pTranslateElement )
+ {
+ domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement );
+ domFloat3 translateChild = pTranslateChild->getValue();
+ LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] );
+ transform.setTranslation( singleJointTranslation );
+ }
+}
+//-----------------------------------------------------------------------------
+// extractTranslationViaSID()
+//-----------------------------------------------------------------------------
+void LLModelLoader::extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform )
+{
+ if ( pElement )
+ {
+ daeSIDResolver resolver( pElement, "./transform" );
+ domMatrix* pMatrix = daeSafeCast<domMatrix>( resolver.getElement() );
+ //We are only extracting out the translational component atm
+ LLMatrix4 workingTransform;
+ if ( pMatrix )
+ {
+ domFloat4x4 domArray = pMatrix->getValue();
+ for ( int i = 0; i < 4; i++ )
+ {
+ for( int j = 0; j < 4; j++ )
+ {
+ workingTransform.mMatrix[i][j] = domArray[i + j*4];
+ }
+ }
+ LLVector3 trans = workingTransform.getTranslation();
+ transform.setTranslation( trans );
+ }
+ }
+ else
+ {
+ LL_WARNS()<<"Element is nonexistent - empty/unsupported node."<<LL_ENDL;
+ }
+}
+//-----------------------------------------------------------------------------
+// processJointNode()
+//-----------------------------------------------------------------------------
+void LLModelLoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms )
+{
+ if (pNode->getName() == NULL)
+ {
+ LL_WARNS() << "nameless node, can't process" << LL_ENDL;
+ return;
+ }
+
+ //LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL;
+
+ //1. handle the incoming node - extract out translation via SID or element
+
+ LLMatrix4 workingTransform;
+
+ //Pull out the translate id and store it in the jointTranslations map
+ daeSIDResolver jointResolverA( pNode, "./translate" );
+ domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
+ daeSIDResolver jointResolverB( pNode, "./location" );
+ domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
+
+ //Translation via SID was successful
+ if ( pTranslateA )
+ {
+ extractTranslation( pTranslateA, workingTransform );
+ }
+ else
+ if ( pTranslateB )
+ {
+ extractTranslation( pTranslateB, workingTransform );
+ }
+ else
+ {
+ //Translation via child from element
+ daeElement* pTranslateElement = getChildFromElement( pNode, "translate" );
+ if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() )
+ {
+ //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
+ daeSIDResolver jointResolver( pNode, "./matrix" );
+ domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() );
+ if ( pMatrix )
+ {
+ //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL;
+ domFloat4x4 domArray = pMatrix->getValue();
+ for ( int i = 0; i < 4; i++ )
+ {
+ for( int j = 0; j < 4; j++ )
+ {
+ workingTransform.mMatrix[i][j] = domArray[i + j*4];
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL;
+ }
+ }
+ else
+ {
+ extractTranslationViaElement( pTranslateElement, workingTransform );
+ }
+ }
+
+ //Store the working transform relative to the nodes name.
+ jointTransforms[ pNode->getName() ] = workingTransform;
+
+ //2. handle the nodes children
+
+ //Gather and handle the incoming nodes children
+ daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren();
+ S32 childOfChildCount = childOfChild.getCount();
+
+ for (S32 i = 0; i < childOfChildCount; ++i)
+ {
+ domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] );
+ if ( pChildNode )
+ {
+ processJointNode( pChildNode, jointTransforms );
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// getChildFromElement()
+//-----------------------------------------------------------------------------
+daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name )
+{
+ daeElement* pChildOfElement = pElement->getChild( name.c_str() );
+ if ( pChildOfElement )
+ {
+ return pChildOfElement;
+ }
+ LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL;
+ return NULL;
+}
+
+void LLModelLoader::processElement( daeElement* element, bool& badElement )
+{
+ LLMatrix4 saved_transform = mTransform;
+
+ domTranslate* translate = daeSafeCast<domTranslate>(element);
+ if (translate)
+ {
+ domFloat3 dom_value = translate->getValue();
+
+ LLMatrix4 translation;
+ translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2]));
+
+ translation *= mTransform;
+ mTransform = translation;
+ }
+
+ domRotate* rotate = daeSafeCast<domRotate>(element);
+ if (rotate)
+ {
+ domFloat4 dom_value = rotate->getValue();
+
+ LLMatrix4 rotation;
+ rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0));
+
+ rotation *= mTransform;
+ mTransform = rotation;
+ }
+
+ domScale* scale = daeSafeCast<domScale>(element);
+ if (scale)
+ {
+ domFloat3 dom_value = scale->getValue();
+
+
+ LLVector3 scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]);
+ scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes
+ LLMatrix4 scaling;
+ scaling.initScale(scale_vector);
+
+ scaling *= mTransform;
+ mTransform = scaling;
+ }
+
+ domMatrix* matrix = daeSafeCast<domMatrix>(element);
+ if (matrix)
+ {
+ domFloat4x4 dom_value = matrix->getValue();
+
+ LLMatrix4 matrix_transform;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for(int j = 0; j < 4; j++)
+ {
+ matrix_transform.mMatrix[i][j] = dom_value[i + j*4];
+ }
+ }
+
+ matrix_transform *= mTransform;
+ mTransform = matrix_transform;
+ }
+
+ domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element);
+ if (instance_geo)
+ {
+ domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement());
+ if (geo)
+ {
+ domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID())));
+ if (mesh)
+ {
+ LLModel* model = mModel[mesh];
+ if (model)
+ {
+ LLMatrix4 transformation = mTransform;
+
+ if (mTransform.determinant() < 0)
+ { //negative scales are not supported
+ LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << LLModel::getElementLabel(instance_geo) << LL_ENDL;
+ badElement = true;
+ }
+
+ std::map<std::string, LLImportMaterial> materials = getMaterials(model, instance_geo);
+
+ // adjust the transformation to compensate for mesh normalization
+ LLVector3 mesh_scale_vector;
+ LLVector3 mesh_translation_vector;
+ model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
+
+ LLMatrix4 mesh_translation;
+ mesh_translation.setTranslation(mesh_translation_vector);
+ mesh_translation *= transformation;
+ transformation = mesh_translation;
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= transformation;
+ transformation = mesh_scale;
+
+ std::string label = getElementLabel(instance_geo);
+ mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials));
+
+ stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
+ }
+ }
+ }
+ else
+ {
+ LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL;
+ badElement = true;
+ }
+
+ }
+
+ domInstance_node* instance_node = daeSafeCast<domInstance_node>(element);
+ if (instance_node)
+ {
+ daeElement* instance = instance_node->getUrl().getElement();
+ if (instance)
+ {
+ processElement(instance,badElement);
+ }
+ }
+
+ //process children
+ daeTArray< daeSmartRef<daeElement> > children = element->getChildren();
+ int childCount = children.getCount();
+ for (S32 i = 0; i < childCount; i++)
+ {
+ processElement(children[i],badElement);
+ }
+
+ domNode* node = daeSafeCast<domNode>(element);
+ if (node)
+ { //this element was a node, restore transform before processiing siblings
+ mTransform = saved_transform;
+ }
+}
+
+std::map<std::string, LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo)
+{
+ std::map<std::string, LLImportMaterial> materials;
+ for (int i = 0; i < model->mMaterialList.size(); i++)
+ {
+ LLImportMaterial import_material;
+
+ domInstance_material* instance_mat = NULL;
+
+ domBind_material::domTechnique_common* technique =
+ daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID())));
+
+ if (technique)
+ {
+ daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>();
+ for (int j = 0; j < inst_materials.getCount(); j++)
+ {
+ std::string symbol(inst_materials[j]->getSymbol());
+
+ if (symbol == model->mMaterialList[i]) // found the binding
+ {
+ instance_mat = inst_materials[j];
+ }
+ }
+ }
+
+ if (instance_mat)
+ {
+ domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement());
+ if (material)
+ {
+ domInstance_effect* instance_effect =
+ daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID())));
+ if (instance_effect)
+ {
+ domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement());
+ if (effect)
+ {
+ domProfile_COMMON* profile =
+ daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID())));
+ if (profile)
+ {
+ import_material = profileToMaterial(profile);
+ }
+ }
+ }
+ }
+ }
+
+ import_material.mBinding = model->mMaterialList[i];
+ materials[model->mMaterialList[i]] = import_material;
+ }
+
+ return materials;
+}
+
+LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material)
+{
+ LLImportMaterial mat;
+ mat.mFullbright = FALSE;
+
+ daeElement* diffuse = material->getDescendant("diffuse");
+ if (diffuse)
+ {
+ domCommon_color_or_texture_type_complexType::domTexture* texture =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture"));
+ if (texture)
+ {
+ domCommon_newparam_type_Array newparams = material->getNewparam_array();
+ for (S32 i = 0; i < newparams.getCount(); i++)
+ {
+ domFx_surface_common* surface = newparams[i]->getSurface();
+ if (surface)
+ {
+ domFx_surface_init_common* init = surface->getFx_surface_init_common();
+ if (init)
+ {
+ domFx_surface_init_from_common_Array init_from = init->getInit_from_array();
+
+ if (init_from.getCount() > i)
+ {
+ domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement());
+ if (image)
+ {
+ // we only support init_from now - embedded data will come later
+ domImage::domInit_from* init = image->getInit_from();
+ if (init)
+ {
+ mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str());
+ mat.mDiffuseMapLabel = getElementLabel(material);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ domCommon_color_or_texture_type_complexType::domColor* color =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color"));
+ if (color)
+ {
+ domFx_color_common domfx_color = color->getValue();
+ LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
+ mat.mDiffuseColor = value;
+ }
+ }
+
+ daeElement* emission = material->getDescendant("emission");
+ if (emission)
+ {
+ LLColor4 emission_color = getDaeColor(emission);
+ if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25)
+ {
+ mat.mFullbright = TRUE;
+ }
+ }
+
+ return mat;
+}
+
+// try to get a decent label for this element
+std::string LLModelLoader::getElementLabel(daeElement *element)
+{
+ // if we have a name attribute, use it
+ std::string name = element->getAttribute("name");
+ if (name.length())
+ {
+ return name;
+ }
+
+ // if we have an ID attribute, use it
+ if (element->getID())
+ {
+ return std::string(element->getID());
+ }
+
+ // if we have a parent, use it
+ daeElement* parent = element->getParent();
+ if (parent)
+ {
+ // if parent has a name, use it
+ std::string name = parent->getAttribute("name");
+ if (name.length())
+ {
+ return name;
+ }
+
+ // if parent has an ID, use it
+ if (parent->getID())
+ {
+ return std::string(parent->getID());
+ }
+ }
+
+ // try to use our type
+ daeString element_name = element->getElementName();
+ if (element_name)
+ {
+ return std::string(element_name);
+ }
+
+ // if all else fails, use "object"
+ return std::string("object");
+}
+
+LLColor4 LLModelLoader::getDaeColor(daeElement* element)
+{
+ LLColor4 value;
+ domCommon_color_or_texture_type_complexType::domColor* color =
+ daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color"));
+ if (color)
+ {
+ domFx_color_common domfx_color = color->getValue();
+ value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]);
+ }
+
+ return value;
+}
+
+//-----------------------------------------------------------------------------
// LLModelPreview
//-----------------------------------------------------------------------------
@@ -1172,11 +3142,10 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
, mPelvisZOffset( 0.0f )
, mLegacyRigValid( false )
, mRigValidJointUpload( false )
-, mPhysicsSearchLOD( LLModel::LOD_PHYSICS )
, mResetJoints( false )
-, mModelNoErrors( true )
, mRigParityWithScene( false )
, mLastJointUpdate( false )
+, mHasBrokenModel( false )
{
mNeedsUpdate = TRUE;
mCameraDistance = 0.f;
@@ -1219,20 +3188,51 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
glodInit();
+ //move into joint mapper class
+ //1. joints for joint offset verification
+ mMasterJointList.push_front("mPelvis");
+ mMasterJointList.push_front("mTorso");
+ mMasterJointList.push_front("mChest");
+ mMasterJointList.push_front("mNeck");
+ mMasterJointList.push_front("mHead");
+ mMasterJointList.push_front("mCollarLeft");
+ mMasterJointList.push_front("mShoulderLeft");
+ mMasterJointList.push_front("mElbowLeft");
+ mMasterJointList.push_front("mWristLeft");
+ mMasterJointList.push_front("mCollarRight");
+ mMasterJointList.push_front("mShoulderRight");
+ mMasterJointList.push_front("mElbowRight");
+ mMasterJointList.push_front("mWristRight");
+ mMasterJointList.push_front("mHipRight");
+ mMasterJointList.push_front("mKneeRight");
+ mMasterJointList.push_front("mFootRight");
+ mMasterJointList.push_front("mHipLeft");
+ mMasterJointList.push_front("mKneeLeft");
+ mMasterJointList.push_front("mFootLeft");
+ //2. legacy joint list - used to verify rigs that will not be using joint offsets
+ mMasterLegacyJointList.push_front("mPelvis");
+ mMasterLegacyJointList.push_front("mTorso");
+ mMasterLegacyJointList.push_front("mChest");
+ mMasterLegacyJointList.push_front("mNeck");
+ mMasterLegacyJointList.push_front("mHead");
+ mMasterLegacyJointList.push_front("mHipRight");
+ mMasterLegacyJointList.push_front("mKneeRight");
+ mMasterLegacyJointList.push_front("mFootRight");
+ mMasterLegacyJointList.push_front("mHipLeft");
+ mMasterLegacyJointList.push_front("mKneeLeft");
+ mMasterLegacyJointList.push_front("mFootLeft");
+
createPreviewAvatar();
}
LLModelPreview::~LLModelPreview()
{
- // glod apparently has internal mem alignment issues that are angering
- // the heap-check code in windows, these should be hunted down in that
- // TP code, if possible
- //
- // kernel32.dll!HeapFree() + 0x14 bytes
- // msvcr100.dll!free(void * pBlock) Line 51 C
- // glod.dll!glodGetGroupParameteriv() + 0x119 bytes
- // glod.dll!glodShutdown() + 0x77 bytes
- //
+ if (mModelLoader)
+ {
+ mModelLoader->mPreview = NULL;
+ mModelLoader = NULL;
+ }
+ //*HACK : *TODO : turn this back on when we understand why this crashes
//glodShutdown();
}
@@ -1302,9 +3302,7 @@ U32 LLModelPreview::calcResourceCost()
decomp,
mFMP->childGetValue("upload_skin").asBoolean(),
mFMP->childGetValue("upload_joints").asBoolean(),
- TRUE,
- FALSE,
- instance.mModel->mSubmodelID);
+ TRUE);
num_hulls += decomp.mHull.size();
for (U32 i = 0; i < decomp.mHull.size(); ++i)
@@ -1371,12 +3369,29 @@ void LLModelPreview::rebuildUploadData()
F32 max_scale = 0.f;
- BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");
- BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching");
+ //reorder materials to match mBaseModel
+ for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ {
+ if (mBaseModel.size() == mModel[i].size())
+ {
+ for (U32 j = 0; j < mBaseModel.size(); ++j)
+ {
+
+ int refFaceCnt = 0;
+ int modelFaceCnt = 0;
+
+ if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) )
+ {
+ setLoadState( LLModelLoader::ERROR_MATERIALS );
+ mFMP->childDisable( "calculate_btn" );
+ }
+ }
+ }
+ }
for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)
{ //for each transform in scene
- LLMatrix4 mat = iter->first;
+ LLMatrix4 mat = iter->first;
// compute position
LLVector3 position = LLVector3(0, 0, 0) * mat;
@@ -1393,171 +3408,38 @@ void LLModelPreview::rebuildUploadData()
mat *= scale_mat;
- for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();)
- { //for each instance with said transform applied
- LLModelInstance instance = *model_iter++;
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
+ { //for each instance with said transform applied
+ LLModelInstance instance = *model_iter;
LLModel* base_model = instance.mModel;
- if (base_model && !requested_name.empty())
+ if (base_model)
{
base_model->mRequestedLabel = requested_name;
base_model->mMetric = metric;
}
- for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--)
- {
- LLModel* lod_model = NULL;
- if (!legacyMatching)
+ S32 idx = 0;
+ for (idx = 0; idx < mBaseModel.size(); ++idx)
+ { //find reference instance for this model
+ if (mBaseModel[idx] == base_model)
{
- // Fill LOD slots by finding matching meshes by label with name extensions
- // in the appropriate scene for each LOD. This fixes all kinds of issues
- // where the indexed method below fails in spectacular fashion.
- // If you don't take the time to name your LOD and PHYS meshes
- // with the name of their corresponding mesh in the HIGH LOD,
- // then the indexed method will be attempted below.
-
- LLMatrix4 transform;
-
- std::string name_to_match = instance.mLabel;
- llassert(!name_to_match.empty());
-
- int extensionLOD;
- if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty())
- {
- extensionLOD = i;
- }
- else
- {
- //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for
- extensionLOD = mPhysicsSearchLOD;
- }
-
- std::string toAdd;
- switch (extensionLOD)
- {
- case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break;
- case LLModel::LOD_LOW: toAdd = "_LOD1"; break;
- case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break;
- case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break;
- case LLModel::LOD_HIGH: break;
- }
-
- if (name_to_match.find(toAdd) == -1)
- {
- name_to_match += toAdd;
- }
-
- FindModel(mScene[i], name_to_match, lod_model, transform);
-
- if (!lod_model && i != LLModel::LOD_PHYSICS)
- {
- if (importerDebug)
- {
- LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL;
- }
-
- int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i;
- while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model)
- {
- std::string name_to_match = instance.mLabel;
- llassert(!name_to_match.empty());
-
- std::string toAdd;
- switch (searchLOD)
- {
- case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break;
- case LLModel::LOD_LOW: toAdd = "_LOD1"; break;
- case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break;
- case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break;
- case LLModel::LOD_HIGH: break;
- }
-
- if (name_to_match.find(toAdd) == -1)
- {
- name_to_match += toAdd;
- }
-
- // See if we can find an appropriately named model in LOD 'searchLOD'
- //
- FindModel(mScene[searchLOD], name_to_match, lod_model, transform);
- searchLOD++;
- }
- }
+ break;
}
- else
- {
- // Use old method of index-based association
- U32 idx = 0;
- for (idx = 0; idx < mBaseModel.size(); ++idx)
- {
- // find reference instance for this model
- if (mBaseModel[idx] == base_model)
- {
- if (importerDebug)
- {
- LL_INFOS() << "Attempting to use model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL;
- }
- break;
- }
- }
+ }
- // If the model list for the current LOD includes that index...
- //
+ if(idx < mBaseModel.size())
+ {
+ for (U32 i = 0; i < LLModel::NUM_LODS; i++)
+ { //fill LOD slots based on reference model index
if (mModel[i].size() > idx)
{
- // Assign that index from the model list for our LOD as the LOD model for this instance
- //
- lod_model = mModel[i][idx];
- if (importerDebug)
- {
- LL_INFOS() << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel << LL_ENDL;
- }
- }
- else if (importerDebug)
- {
- LL_INFOS() << "List of models does not include index " << idx << LL_ENDL;
+ instance.mLOD[i] = mModel[i][idx];
}
- }
-
- if (lod_model)
- {
- if (importerDebug)
- {
- if (i == LLModel::LOD_PHYSICS)
- {
- LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL;
- }
- }
- instance.mLOD[i] = lod_model;
- }
- else if (importerDebug)
- {
- LL_INFOS() << "List of models does not include " << instance.mLabel << LL_ENDL;
- }
- }
-
- LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH];
- if (!high_lod_model)
- {
- setLoadState( LLModelLoader::ERROR_MATERIALS );
- mFMP->childDisable( "calculate_btn" );
- }
- else
- {
- for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
- {
- int refFaceCnt = 0;
- int modelFaceCnt = 0;
- llassert(instance.mLOD[i]);
- if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) )
+ else
{
- setLoadState( LLModelLoader::ERROR_MATERIALS );
- mFMP->childDisable( "calculate_btn" );
+ instance.mLOD[i] = NULL;
}
}
}
@@ -1566,34 +3448,6 @@ void LLModelPreview::rebuildUploadData()
}
}
- for (U32 lod = 0; lod < LLModel::NUM_LODS-1; lod++)
- {
- // Search for models that are not included into upload data
- // If we found any, that means something we loaded is not a sub-model.
- for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind)
- {
- bool found_model = false;
- for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
- {
- LLModelInstance& instance = *iter;
- if (instance.mLOD[lod] == mModel[lod][model_ind])
- {
- found_model = true;
- break;
- }
- }
- if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID)
- {
- if (importerDebug)
- {
- LL_INFOS() << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models." << LL_ENDL;
- }
- setLoadState( LLModelLoader::ERROR_MATERIALS );
- mFMP->childDisable( "calculate_btn" );
- }
- }
- }
-
F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale;
F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]);
@@ -1660,6 +3514,7 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
meshes.insert(instance.mModel);
std::stringstream str;
+
LLModel::Decomposition& decomp =
instance.mLOD[LLModel::LOD_PHYSICS].notNull() ?
instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
@@ -1672,8 +3527,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
instance.mLOD[LLModel::LOD_LOW],
instance.mLOD[LLModel::LOD_IMPOSTOR],
decomp,
- save_skinweights, save_joint_positions,
- FALSE, TRUE, instance.mModel->mSubmodelID);
+ save_skinweights, save_joint_positions, FALSE, TRUE);
+
data["mesh"][instance.mModel->mLocalID] = str.str();
}
@@ -1741,28 +3596,13 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
clearGLODGroup();
}
- mModelLoader = new LLDAELoader(
- filename,
- lod,
- &LLModelPreview::loadedCallback,
- &LLModelPreview::lookupJointByName,
- &LLModelPreview::loadTextures,
- &LLModelPreview::stateChangedCallback,
- this,
- mJointTransformMap,
- mJointsFromNode,
- gSavedSettings.getU32("ImporterModelLimit"));
+ mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode );
if (force_disable_slm)
{
mModelLoader->mTrySLM = false;
}
- else
- {
- //only try to load from slm if viewer is configured to do so and this is the
- //initial model load (not an LoD or physics shape)
- mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty();
- }
+
mModelLoader->start();
mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file"));
@@ -1793,7 +3633,6 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod)
if (lod >= 0 && lod <= 3)
{
- mPhysicsSearchLOD = lod;
mModel[LLModel::LOD_PHYSICS] = mModel[lod];
mScene[LLModel::LOD_PHYSICS] = mScene[lod];
mLODFile[LLModel::LOD_PHYSICS].clear();
@@ -1813,14 +3652,11 @@ void LLModelPreview::clearIncompatible(S32 lod)
return;
}
- // at this point we don't care about sub-models,
- // different amount of sub-models means face count mismatch, not incompatibility
- U32 lod_size = countRootModels(mModel[lod]);
for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
{ //clear out any entries that aren't compatible with this model
if (i != lod)
{
- if (countRootModels(mModel[i]) != lod_size)
+ if (mModel[i].size() != mModel[lod].size())
{
mModel[i].clear();
mScene[i].clear();
@@ -1855,7 +3691,7 @@ void LLModelPreview::clearGLODGroup()
}
}
-void LLModelPreview::loadModelCallback(S32 loaded_lod)
+void LLModelPreview::loadModelCallback(S32 lod)
{
assert_main_thread();
@@ -1868,18 +3704,12 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
if(getLoadState() >= LLModelLoader::ERROR_PARSING)
{
mLoading = false ;
- mModelLoader = NULL;
return ;
}
- // Copy determinations about rig so UI will reflect them
- //
- setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload());
- setLegacyRigValid(mModelLoader->isLegacyRigValid());
-
mModelLoader->loadTextures() ;
- if (loaded_lod == -1)
+ if (lod == -1)
{ //populate all LoDs from model loader scene
mBaseModel.clear();
mBaseScene.clear();
@@ -1911,11 +3741,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
//override displayed model with current LoD
list_iter->mModel = list_iter->mLOD[lod];
- if (!list_iter->mModel)
- {
- continue;
- }
-
//add current model to current LoD's model list (LLModel::mLocalID makes a good vector index)
S32 idx = list_iter->mModel->mLocalID;
@@ -1924,7 +3749,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
mModel[lod].resize(idx+1);
}
- mModel[lod][idx] = list_iter->mModel;
+ mModel[lod][idx] = list_iter->mModel;
if (!list_iter->mModel->mSkinWeights.empty())
{
skin_weights = true;
@@ -1967,31 +3792,31 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
}
else
{ //only replace given LoD
- mModel[loaded_lod] = mModelLoader->mModelList;
- mScene[loaded_lod] = mModelLoader->mScene;
- mVertexBuffer[loaded_lod].clear();
+ mModel[lod] = mModelLoader->mModelList;
+ mScene[lod] = mModelLoader->mScene;
+ mVertexBuffer[lod].clear();
- setPreviewLOD(loaded_lod);
+ setPreviewLOD(lod);
- if (loaded_lod == LLModel::LOD_HIGH)
+ if (lod == LLModel::LOD_HIGH)
{ //save a copy of the highest LOD for automatic LOD manipulation
if (mBaseModel.empty())
{ //first time we've loaded a model, auto-gen LoD
mGenLOD = true;
}
- mBaseModel = mModel[loaded_lod];
+ mBaseModel = mModel[lod];
clearGLODGroup();
- mBaseScene = mScene[loaded_lod];
+ mBaseScene = mScene[lod];
mVertexBuffer[5].clear();
}
- clearIncompatible(loaded_lod);
+ clearIncompatible(lod);
mDirty = true;
- if (loaded_lod == LLModel::LOD_HIGH)
+ if (lod == LLModel::LOD_HIGH)
{
resetPreviewTarget();
}
@@ -2010,8 +3835,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
refresh();
mModelLoadedSignal();
-
- mModelLoader = NULL;
}
void LLModelPreview::resetPreviewTarget()
@@ -2360,20 +4183,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
- std::string name = base->mLabel;
-
- switch (lod)
- {
- case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
- case LLModel::LOD_LOW: name += "_LOD1"; break;
- case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
- case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
- case LLModel::LOD_HIGH: break;
- }
-
- mModel[lod][mdl_idx]->mLabel = name;
- mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
-
GLint* sizes = new GLint[patch_count*2];
glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);
stop_gloderror();
@@ -2486,6 +4295,125 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
{
shader->bind();
}
+
+ /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty())
+ { //build physics scene
+ mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW];
+ mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW];
+
+ for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
+ {
+ mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]);
+ }
+ }*/
+}
+
+void LLModelPreview::genModelBBox()
+{
+ LLVector3 min, max;
+ min = this->mModelLoader->mExtents[0];
+ max = this->mModelLoader->mExtents[1];
+
+ std::vector<LLVector3> v_list;
+ v_list.resize(4);
+ std::map<U8, std::vector<LLVector3> > face_list;
+
+ // Face 0
+ v_list[0] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]);
+ v_list[1] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]);
+ v_list[2] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]);
+ v_list[3] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]);
+ face_list.insert(std::pair<U8, std::vector<LLVector3> >(0, v_list));
+
+ // Face 1
+ v_list[0] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]);
+ v_list[1] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]);
+ v_list[2] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]);
+ v_list[3] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]);
+ face_list.insert(std::pair<U8, std::vector<LLVector3> >(1, v_list));
+
+ // Face 2
+ v_list[0] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]);
+ v_list[1] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]);
+ v_list[2] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]);
+ v_list[3] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]);
+ face_list.insert(std::pair<U8, std::vector<LLVector3> >(2, v_list));
+
+ // Face 3
+ v_list[0] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]);
+ v_list[1] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]);
+ v_list[2] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]);
+ v_list[3] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]);
+ face_list.insert(std::pair<U8, std::vector<LLVector3> >(3, v_list));
+
+ // Face 4
+ v_list[0] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]);
+ v_list[1] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]);
+ v_list[2] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]);
+ v_list[3] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]);
+ face_list.insert(std::pair<U8, std::vector<LLVector3> >(4, v_list));
+
+ // Face 5
+ v_list[0] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]);
+ v_list[1] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]);
+ v_list[2] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]);
+ v_list[3] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]);
+ face_list.insert(std::pair<U8, std::vector<LLVector3> >(5, v_list));
+
+ U16 Idx[] = { 0, 1, 2, 3, 0, 2, };
+
+ U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
+ LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0);
+ buff->allocateBuffer(4, 6, true);
+
+ LLStrider<LLVector3> pos;
+ LLStrider<U16> idx;
+ LLStrider<LLVector3> norm;
+ LLStrider<LLVector2> tc;
+
+ buff->getVertexStrider(pos);
+ buff->getIndexStrider(idx);
+
+ buff->getNormalStrider(norm);
+ buff->getTexCoord0Strider(tc);
+
+ for (U32 i = 0; i < 6; ++i)
+ {
+ idx[i] = Idx[i];
+ }
+
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+ LLModel* mdl = new LLModel(volume_params, 0.f);
+ mdl->mLabel = "BBOX";
+
+ mdl->setNumVolumeFaces(6);
+ for (U8 i = 0; i < 6; ++i)
+ {
+ for (U8 j = 0; j < 4; ++j)
+ {
+ pos[j] = face_list[i][j];
+ }
+
+ mdl->setVolumeFaceData(i, pos, norm, tc, idx, buff->getNumVerts(), buff->getNumIndices());
+ }
+
+ if (validate_model(mdl))
+ {
+ LLMatrix4 mat;
+ std::map<std::string, LLImportMaterial> materials;
+ std::vector<LLModelInstance> instance_list;
+ instance_list.push_back(LLModelInstance(mdl, mdl->mLabel, mat, materials));
+
+ for (S32 i = LLModel::LOD_HIGH - 1; i >= 0; i--)
+ {
+ mModel[i].clear();
+ mModel[i].push_back(mdl);
+
+ mScene[i].clear();
+ mScene[i].insert(std::pair<LLMatrix4, std::vector<LLModelInstance> >(mat, instance_list));
+ }
+ }
}
void LLModelPreview::updateStatusMessages()
@@ -2502,89 +4430,43 @@ void LLModelPreview::updateStatusMessages()
S32 total_verts[LLModel::NUM_LODS];
S32 total_submeshes[LLModel::NUM_LODS];
- for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
- {
- total_tris[i] = 0;
- total_verts[i] = 0;
- total_submeshes[i] = 0;
- }
-
- for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
+ for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
{
- LLModelInstance& instance = *iter;
-
- LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH];
- if (!model_high_lod)
- {
- setLoadState( LLModelLoader::ERROR_MATERIALS );
- mFMP->childDisable( "calculate_btn" );
- continue;
- }
+ //initialize total for this lod to 0
+ total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0;
- for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ for (LLModelLoader::scene::iterator iter = mScene[lod].begin(), endIter = mScene[lod].end(); iter != endIter; ++iter)
{
- LLModel* lod_model = instance.mLOD[i];
- if (!lod_model)
- {
- setLoadState( LLModelLoader::ERROR_MATERIALS );
- mFMP->childDisable( "calculate_btn" );
- }
-
- int refFaceCnt = 0;
- int modelFaceCnt = 0;
-
- if (!lod_model->matchMaterialOrder(model_high_lod, refFaceCnt, modelFaceCnt ) )
+ for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
{
- setLoadState( LLModelLoader::ERROR_MATERIALS );
- mFMP->childDisable( "calculate_btn" );
- }
-
- if (lod_model)
- {
- //for each model in the lod
- S32 cur_tris = 0;
- S32 cur_verts = 0;
- S32 cur_submeshes = lod_model->getNumVolumeFaces();
-
- for (S32 j = 0; j < cur_submeshes; ++j)
- { //for each submesh (face), add triangles and vertices to current total
- const LLVolumeFace& face = lod_model->getVolumeFace(j);
- cur_tris += face.mNumIndices/3;
- cur_verts += face.mNumVertices;
- }
-
- std::string instance_name = instance.mLabel;
+ LLModel* model = instance->mModel;
+ if (model)
+ {
+ //for each model in the lod
+ S32 cur_tris = 0;
+ S32 cur_verts = 0;
+ S32 cur_submeshes = model->getNumVolumeFaces();
- BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");
- if (importerDebug)
- {
- // Useful for debugging generalized complaints below about total submeshes which don't have enough
- // context to address exactly what needs to be fixed to move towards compliance with the rules.
- //
- LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: " << cur_verts << LL_ENDL;
- LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Tris: " << cur_tris << LL_ENDL;
- LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: " << cur_submeshes << LL_ENDL;
-
- LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin();
- while (mat_iter != lod_model->mMaterialList.end())
- {
- LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter) << LL_ENDL;
- mat_iter++;
- }
- }
+ for (S32 j = 0; j < cur_submeshes; ++j)
+ { //for each submesh (face), add triangles and vertices to current total
+ const LLVolumeFace& face = model->getVolumeFace(j);
+ cur_tris += face.mNumIndices/3;
+ cur_verts += face.mNumVertices;
+ }
- //add this model to the lod total
- total_tris[i] += cur_tris;
- total_verts[i] += cur_verts;
- total_submeshes[i] += cur_submeshes;
+ //add this model to the lod total
+ total_tris[lod] += cur_tris;
+ total_verts[lod] += cur_verts;
+ total_submeshes[lod] += cur_submeshes;
- //store this model's counts to asset data
- tris[i].push_back(cur_tris);
- verts[i].push_back(cur_verts);
- submeshes[i].push_back(cur_submeshes);
+ //store this model's counts to asset data
+ tris[lod].push_back(cur_tris);
+ verts[lod].push_back(cur_verts);
+ submeshes[lod].push_back(cur_submeshes);
+ }
}
}
- }
+ }
if (mMaxTriangleLimit == 0)
{
@@ -2598,48 +4480,37 @@ void LLModelPreview::updateStatusMessages()
const LLVector4a scale(0.5f);
for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i)
{ //for each model in the lod
- if (mModel[lod][i] && mModel[lod][i]->mPhysics.mHull.empty())
+ if (mModel[lod][i]->mPhysics.mHull.empty())
{ //no decomp exists
S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j)
{ //for each submesh (face), add triangles and vertices to current total
- LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
- for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; )
+ const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
+ for (S32 k = 0; k < face.mNumIndices && !has_degenerate; )
{
- U16 index_a = face.mIndices[k+0];
- U16 index_b = face.mIndices[k+1];
- U16 index_c = face.mIndices[k+2];
-
- LLVector4a v1; v1.setMul(face.mPositions[index_a], scale);
- LLVector4a v2; v2.setMul(face.mPositions[index_b], scale);
- LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);
+ LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale);
+ LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale);
+ LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale);
if (ll_is_degenerate(v1,v2,v3))
{
has_degenerate = true;
}
- else
- {
- k += 3;
- }
}
}
}
}
}
-
+
mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
std::string mesh_status_na = mFMP->getString("mesh_status_na");
S32 upload_status[LLModel::LOD_HIGH+1];
- mModelNoErrors = true;
+ bool upload_ok = true;
- const U32 lod_high = LLModel::LOD_HIGH;
- U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]);
-
- for (S32 lod = 0; lod <= lod_high; ++lod)
+ for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)
{
upload_status[lod] = 0;
@@ -2652,7 +4523,7 @@ void LLModelPreview::updateStatusMessages()
}
else
{
- if (lod == lod_high)
+ if (lod == LLModel::LOD_HIGH)
{
upload_status[lod] = 2;
message = "mesh_status_missing_lod";
@@ -2673,6 +4544,8 @@ void LLModelPreview::updateStatusMessages()
mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na);
}
+ const U32 lod_high = LLModel::LOD_HIGH;
+
if (lod != lod_high)
{
if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high])
@@ -2680,13 +4553,6 @@ void LLModelPreview::updateStatusMessages()
message = "mesh_status_submesh_mismatch";
upload_status[lod] = 2;
}
- else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count)
- {//number of submodels is different, not all faces are matched correctly.
- message = "mesh_status_submesh_mismatch";
- upload_status[lod] = 2;
- // Note: Submodels in instance were loaded from higher LOD and as result face count
- // returns same value and total_submeshes[lod] is identical to high_lod one.
- }
else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size())
{ //number of meshes is different
message = "mesh_status_mesh_mismatch";
@@ -2707,7 +4573,7 @@ void LLModelPreview::updateStatusMessages()
{
//too many vertices in this lod
message = "mesh_status_too_many_vertices";
- upload_status[lod] = 1;
+ upload_status[lod] = 2;
}
}
}
@@ -2719,7 +4585,7 @@ void LLModelPreview::updateStatusMessages()
if (upload_status[lod] >= 2)
{
- mModelNoErrors = false;
+ upload_ok = false;
}
if (lod == mPreviewLOD)
@@ -2733,41 +4599,23 @@ void LLModelPreview::updateStatusMessages()
}
- //warn if hulls have more than 256 points in them
- BOOL physExceededVertexLimit = FALSE;
- for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
+ //make sure no hulls have more than 256 points in them
+ for (U32 i = 0; upload_ok && i < mModel[LLModel::LOD_PHYSICS].size(); ++i)
{
LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i];
- if (mdl)
+ for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j)
{
- for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j)
+ if (mdl->mPhysics.mHull[j].size() > 256)
{
- if (mdl->mPhysics.mHull[j].size() > 256)
- {
- physExceededVertexLimit = TRUE;
- LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL;
- break;
- }
+ upload_ok = false;
}
}
}
- mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit);
- LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
- physStatusIcon->setVisible(physExceededVertexLimit);
- if (physExceededVertexLimit)
- {
- mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded"));
- LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning");
- physStatusIcon->setImage(img);
- }
- if (getLoadState() >= LLModelLoader::ERROR_PARSING)
- {
- mModelNoErrors = false;
- LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL;
- }
+ bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false;
+ bool skinAndRigOk = true;
bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean();
bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean();
@@ -2775,23 +4623,19 @@ void LLModelPreview::updateStatusMessages()
{
if ( uploadingJointPositions && !isRigValidForJointPositionUpload() )
{
- mModelNoErrors = false;
- LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL;
- }
+ skinAndRigOk = false;
+ }
}
-
- if(mModelNoErrors && mModelLoader)
+
+ if(upload_ok && mModelLoader)
{
if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean())
{
- // Some textures are still loading, prevent upload until they are done
- mModelNoErrors = false;
+ upload_ok = false ;
}
}
- // Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics
- // current use of has_degenerate won't block upload permanently - later checks will restore the button
- if (!mModelNoErrors || has_degenerate)
+ if (!upload_ok || errorStateFromLoader || !skinAndRigOk || has_degenerate)
{
mFMP->childDisable("ok_btn");
}
@@ -3133,8 +4977,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
LLModel* base_mdl = *base_iter;
base_iter++;
- S32 num_faces = mdl->getNumVolumeFaces();
- for (S32 i = 0; i < num_faces; ++i)
+ for (S32 i = 0, e = mdl->getNumVolumeFaces(); i < e; ++i)
{
const LLVolumeFace &vf = mdl->getVolumeFace(i);
U32 num_vertices = vf.mNumVertices;
@@ -3229,14 +5072,6 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
void LLModelPreview::update()
{
- if (mGenLOD)
- {
- mGenLOD = false;
- genLODs();
- refresh();
- updateStatusMessages();
- }
-
if (mDirty)
{
mDirty = false;
@@ -3244,8 +5079,18 @@ void LLModelPreview::update()
refresh();
updateStatusMessages();
}
-}
+ if (mGenLOD)
+ {
+ if (!this->mHasBrokenModel)
+ {
+ mGenLOD = false;
+ genLODs();
+ refresh();
+ updateStatusMessages();
+ }
+ }
+}
//-----------------------------------------------------------------------------
// getTranslationForJointOffset()
//-----------------------------------------------------------------------------
@@ -3279,79 +5124,10 @@ void LLModelPreview::createPreviewAvatar( void )
}
else
{
- LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL;
+ LL_INFOS()<<"Failed to create preview avatar for upload model window"<<LL_ENDL;
}
}
-//static
-U32 LLModelPreview::countRootModels(LLModelLoader::model_list models)
-{
- U32 root_models = 0;
- model_list::iterator model_iter = models.begin();
- while (model_iter != models.end())
- {
- LLModel* mdl = *model_iter;
- if (mdl && mdl->mSubmodelID == 0)
- {
- root_models++;
- }
- model_iter++;
- }
- return root_models;
-}
-
-void LLModelPreview::loadedCallback(
- LLModelLoader::scene& scene,
- LLModelLoader::model_list& model_list,
- S32 lod,
- void* opaque)
-{
- LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
- if (pPreview && !LLModelPreview::sIgnoreLoadedCallback)
- {
- pPreview->loadModelCallback(lod);
- }
-}
-
-void LLModelPreview::stateChangedCallback(U32 state,void* opaque)
-{
- LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
- if (pPreview)
- {
- pPreview->setLoadState(state);
- }
-}
-
-LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque)
-{
- LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
- if (pPreview)
- {
- return pPreview->getPreviewAvatar()->getJoint(str);
- }
- return NULL;
-}
-
-U32 LLModelPreview::loadTextures(LLImportMaterial& material,void* opaque)
-{
- (void)opaque;
-
- if (material.mDiffuseMapFilename.size())
- {
- material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >;
- LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData));
-
- tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW);
- tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE);
- tex->forceToSaveRawImage(0, F32_MAX);
- material.setDiffuseMap(tex->getID()); // record tex ID
- return 1;
- }
-
- material.mOpaqueData = NULL;
- return 0;
-}
-
void LLModelPreview::addEmptyFace( LLModel* pTarget )
{
U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
@@ -3597,7 +5373,7 @@ BOOL LLModelPreview::render()
}
else
{
- LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL;
+ LL_INFOS(" ") << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL;
regen = TRUE;
}
}
@@ -3607,6 +5383,24 @@ BOOL LLModelPreview::render()
genBuffers(mPreviewLOD, skin_weight);
}
+ //make sure material lists all match
+ for (U32 i = 0; i < LLModel::NUM_LODS-1; i++)
+ {
+ if (mBaseModel.size() == mModel[i].size())
+ {
+ for (U32 j = 0; j < mBaseModel.size(); ++j)
+ {
+ int refFaceCnt = 0;
+ int modelFaceCnt = 0;
+
+ if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) )
+ {
+ mFMP->childDisable( "calculate_btn" );
+ }
+ }
+ }
+ }
+
if (!skin_weight)
{
for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
@@ -3615,63 +5409,66 @@ BOOL LLModelPreview::render()
LLModel* model = instance.mLOD[mPreviewLOD];
- if (!model)
- {
- continue;
- }
-
- gGL.pushMatrix();
- LLMatrix4 mat = instance.mTransform;
+ if (!model)
+ {
+ continue;
+ }
- gGL.multMatrix((GLfloat*) mat.mMatrix);
+ gGL.pushMatrix();
+ LLMatrix4 mat;
+ if (model->getName() != "BBOX")
+ {
+ mat = instance.mTransform;
+ }
+ gGL.multMatrix((GLfloat*) mat.mMatrix);
- U32 num_models = mVertexBuffer[mPreviewLOD][model].size();
- for (U32 i = 0; i < num_models; ++i)
- {
- LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
+ for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i)
+ {
+ LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
- buffer->setBuffer(type_mask & buffer->getTypeMask());
+ buffer->setBuffer(type_mask & buffer->getTypeMask());
- if (textures)
+ if (textures)
+ {
+ int materialCnt = instance.mModel->mMaterialList.size();
+ if ( i < materialCnt )
{
- int materialCnt = instance.mModel->mMaterialList.size();
- if ( i < materialCnt )
- {
- const std::string& binding = instance.mModel->mMaterialList[i];
- const LLImportMaterial& material = instance.mMaterial[binding];
+ const std::string& binding = instance.mModel->mMaterialList[i];
+ const LLImportMaterial& material = instance.mMaterial[binding];
- gGL.diffuseColor4fv(material.mDiffuseColor.mV);
+ gGL.diffuseColor4fv(material.mDiffuseColor.mV);
- // Find the tex for this material, bind it, and add it to our set
- //
- LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material);
- if (tex)
+ if (material.mDiffuseMap.notNull())
+ {
+ if (material.mDiffuseMap->getDiscardLevel() > -1)
{
- mTextureSet.insert(tex);
+ gGL.getTexUnit(0)->bind(material.mDiffuseMap, true);
+ mTextureSet.insert(material.mDiffuseMap.get());
}
}
}
- else
- {
- gGL.diffuseColor4f(1,1,1,1);
- }
+ }
+ else
+ {
+ gGL.diffuseColor4f(1,1,1,1);
+ }
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
- if (edges)
- {
- glLineWidth(3.f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glLineWidth(1.f);
- }
+ if (edges)
+ {
+ glLineWidth(3.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
}
- gGL.popMatrix();
}
+ gGL.popMatrix();
+ }
if (physics)
{
@@ -3699,100 +5496,98 @@ BOOL LLModelPreview::render()
LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
- if (!model)
- {
- continue;
- }
+ if (!model)
+ {
+ continue;
+ }
- gGL.pushMatrix();
- LLMatrix4 mat = instance.mTransform;
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
gGL.multMatrix((GLfloat*) mat.mMatrix);
- bool render_mesh = true;
+ bool render_mesh = true;
- LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
- if (decomp)
- {
- LLMutexLock(decomp->mMutex);
+ LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
+ if (decomp)
+ {
+ LLMutexLock(decomp->mMutex);
- LLModel::Decomposition& physics = model->mPhysics;
+ LLModel::Decomposition& physics = model->mPhysics;
- if (!physics.mHull.empty())
- {
- render_mesh = false;
+ if (!physics.mHull.empty())
+ {
+ render_mesh = false;
- if (physics.mMesh.empty())
- { //build vertex buffer for physics mesh
- gMeshRepo.buildPhysicsMesh(physics);
- }
+ if (physics.mMesh.empty())
+ { //build vertex buffer for physics mesh
+ gMeshRepo.buildPhysicsMesh(physics);
+ }
- if (!physics.mMesh.empty())
- { //render hull instead of mesh
- for (U32 i = 0; i < physics.mMesh.size(); ++i)
+ if (!physics.mMesh.empty())
+ { //render hull instead of mesh
+ for (U32 i = 0; i < physics.mMesh.size(); ++i)
+ {
+ if (explode > 0.f)
{
- if (explode > 0.f)
- {
- gGL.pushMatrix();
+ gGL.pushMatrix();
- LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
- offset *= explode;
+ LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
+ offset *= explode;
- gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
- }
+ gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
+ }
- static std::vector<LLColor4U> hull_colors;
+ static std::vector<LLColor4U> hull_colors;
- if (i+1 >= hull_colors.size())
- {
- hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128));
- }
+ if (i+1 >= hull_colors.size())
+ {
+ hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128));
+ }
- gGL.diffuseColor4ubv(hull_colors[i].mV);
- LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+ gGL.diffuseColor4ubv(hull_colors[i].mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
- if (explode > 0.f)
- {
- gGL.popMatrix();
- }
+ if (explode > 0.f)
+ {
+ gGL.popMatrix();
}
}
}
}
-
- if (render_mesh)
- {
- if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
- {
- genBuffers(LLModel::LOD_PHYSICS, false);
- }
+ }
- U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
- for (U32 i = 0; i < num_models; ++i)
- {
- LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
+ if (render_mesh)
+ {
+ if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
+ {
+ genBuffers(LLModel::LOD_PHYSICS, false);
+ }
+ for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i)
+ {
+ LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f);
- buffer->setBuffer(type_mask & buffer->getTypeMask());
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ buffer->setBuffer(type_mask & buffer->getTypeMask());
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- gGL.diffuseColor3f(1.f, 1.f, 0.f);
+ gGL.diffuseColor3f(1.f, 1.f, 0.f);
- glLineWidth(2.f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ glLineWidth(2.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glLineWidth(1.f);
- }
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glLineWidth(1.f);
}
-
- gGL.popMatrix();
}
+ gGL.popMatrix();
+ }
+
glLineWidth(3.f);
glPointSize(8.f);
gPipeline.enableLightsFullbright(LLColor4::white);
@@ -3972,20 +5767,20 @@ BOOL LLModelPreview::render()
position[j] = v;
}
- llassert(model->mMaterialList.size() > i);
+ llassert(model->mMaterialList.size() > i);
const std::string& binding = instance.mModel->mMaterialList[i];
const LLImportMaterial& material = instance.mMaterial[binding];
buffer->setBuffer(type_mask & buffer->getTypeMask());
gGL.diffuseColor4fv(material.mDiffuseColor.mV);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- // Find the tex for this material, bind it, and add it to our set
- //
- LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material);
- if (tex)
+ if (material.mDiffuseMap.notNull())
{
- mTextureSet.insert(tex);
+ if (material.mDiffuseMap->getDiscardLevel() > -1)
+ {
+ gGL.getTexUnit(0)->bind(material.mDiffuseMap, true);
+ mTextureSet.insert(material.mDiffuseMap.get());
+ }
}
buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
@@ -4100,14 +5895,14 @@ void LLFloaterModelPreview::onReset(void* user_data)
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;
fmp->childDisable("reset_btn");
LLModelPreview* mp = fmp->mModelPreview;
- std::string filename = mp->mLODFile[LLModel::LOD_HIGH];
+ std::string filename = mp->mLODFile[3];
fmp->resetDisplayOptions();
//reset model preview
fmp->initModelPreview();
mp = fmp->mModelPreview;
- mp->loadModel(filename,LLModel::LOD_HIGH,true);
+ mp->loadModel(filename,3,true);
}
//static
@@ -4157,6 +5952,16 @@ void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
{
if (!mLODFrozen)
{
+ S32 lod_mode = 0;
+ LLCtrlSelectionInterface* iface = this->mFMP->childGetSelectionInterface("lod_mode_" + lod_name[lod]);
+ if (iface)
+ {
+ lod_mode = iface->getFirstSelectedIndex();
+ }
+
+ if (lod_mode == 0 && this->mHasBrokenModel)
+ return;
+
genLODs(lod, 3, enforce_tri_limit);
refresh();
}
@@ -4201,7 +6006,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)
}
mUploadBtn->setVisible(!visible);
- mUploadBtn->setEnabled(isModelUploadAllowed());
+ mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
if (visible)
{
@@ -4267,7 +6072,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()
childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger()));
childSetVisible("upload_fee", true);
childSetVisible("price_breakdown", true);
- mUploadBtn->setEnabled(isModelUploadAllowed());
+ mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
}
void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason)
@@ -4291,16 +6096,6 @@ void LLFloaterModelPreview::onModelUploadFailure()
mUploadBtn->setEnabled(true);
}
-bool LLFloaterModelPreview::isModelUploadAllowed()
-{
- bool allow_upload = mHasUploadPerm && !mUploadModelUrl.empty();
- if (mModelPreview)
- {
- allow_upload &= mModelPreview->mModelNoErrors;
- }
- return allow_upload;
-}
-
S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)
{
if (mContinue)
@@ -4350,8 +6145,8 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)
// BAP HACK: handle "" for case that MeshUploadFlag cap is broken.
mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status));
- // isModelUploadAllowed() includes mHasUploadPerm
- mUploadBtn->setEnabled(isModelUploadAllowed());
+ //mUploadBtn->setEnabled(mHasUploadPerm);
+ mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
getChild<LLTextBox>("warning_title")->setVisible(!mHasUploadPerm);
getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);
}
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 7a518c798b..813e49305b 100755
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -37,8 +37,6 @@
#include "llviewermenufile.h"
#include "llfloatermodeluploadbase.h"
-#include "lldaeloader.h"
-
class LLComboBox;
class LLJoint;
class LLViewerJointMesh;
@@ -47,18 +45,103 @@ class LLTextBox;
class LLVertexBuffer;
class LLModelPreview;
class LLFloaterModelPreview;
-class DAE;
class daeElement;
class domProfile_COMMON;
class domInstance_geometry;
class domNode;
class domTranslate;
class domController;
-class domSkin;
-class domMesh;
class LLMenuButton;
class LLToggleableMenu;
+typedef std::map<std::string, LLMatrix4> JointTransformMap;
+typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
+
+const S32 NUM_LOD = 4;
+
+class LLModelLoader : public LLThread
+{
+public:
+ typedef enum
+ {
+ STARTING = 0,
+ READING_FILE,
+ CREATING_FACES,
+ GENERATING_VERTEX_BUFFERS,
+ GENERATING_LOD,
+ DONE,
+ ERROR_PARSING, //basically loading failed
+ ERROR_MATERIALS,
+ } eLoadState;
+
+ U32 mState;
+ std::string mFilename;
+ S32 mLod;
+ LLModelPreview* mPreview;
+ LLMatrix4 mTransform;
+ BOOL mFirstTransform;
+ LLVector3 mExtents[2];
+ bool mTrySLM;
+
+ std::map<daeElement*, LLPointer<LLModel> > mModel;
+
+ typedef std::vector<LLPointer<LLModel> > model_list;
+ model_list mModelList;
+
+ typedef std::vector<LLModelInstance> model_instance_list;
+
+ typedef std::map<LLMatrix4, model_instance_list > scene;
+
+ scene mScene;
+
+ typedef std::queue<LLPointer<LLModel> > model_queue;
+
+ //queue of models that need a physics rep
+ model_queue mPhysicsQ;
+
+ LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
+ std::deque<std::string>& jointsFromNodes );
+ ~LLModelLoader() ;
+
+ virtual void run();
+ bool doLoadModel();
+ bool loadFromSLM(const std::string& filename);
+ void loadModelCallback();
+
+ void loadTextures() ; //called in the main thread.
+ void processElement(daeElement* element, bool& badElement);
+ std::map<std::string, LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo);
+ LLImportMaterial profileToMaterial(domProfile_COMMON* material);
+ std::string getElementLabel(daeElement *element);
+ LLColor4 getDaeColor(daeElement* element);
+
+ daeElement* getChildFromElement( daeElement* pElement, std::string const & name );
+
+ bool isNodeAJoint( domNode* pNode );
+ void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms );
+ void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform );
+ void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform );
+ void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform );
+
+ void setLoadState(U32 state);
+
+ void buildJointToNodeMappingFromScene( daeElement* pRoot );
+ void processJointToNodeMapping( domNode* pNode );
+ void processChildJoints( domNode* pParentNode );
+
+ //map of avatar joints as named in COLLADA assets to internal joint names
+ std::map<std::string, std::string> mJointMap;
+ JointTransformMap& mJointList;
+ std::deque<std::string>& mJointsFromNode;
+
+ S32 mNumOfFetchingTextures ; //updated in the main thread
+ bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
+
+private:
+ static std::list<LLModelLoader*> sActiveLoaderList;
+ static bool isAlive(LLModelLoader* loader) ;
+};
+
class LLFloaterModelPreview : public LLFloaterModelUploadBase
{
public:
@@ -89,7 +172,6 @@ public:
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ void onOpen(const LLSD& key);
- /*virtual*/ void onClose(bool app_quitting);
static void onMouseCaptureLostModelPreview(LLMouseHandler*);
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
@@ -128,8 +210,6 @@ public:
/*virtual*/ void onModelUploadFailure();
- bool isModelUploadAllowed();
-
protected:
friend class LLModelPreview;
friend class LLMeshFilePicker;
@@ -262,6 +342,7 @@ public:
void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);
void loadModelCallback(S32 lod);
void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
+ void genModelBBox(); // Generate just a model BBox if we can't generate proper LOD
void generateNormals();
void restoreNormals();
U32 calcResourceCost();
@@ -279,14 +360,21 @@ public:
void setHasPivot( bool val ) { mHasPivot = val; }
void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; }
+ //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
+ void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
+ void critiqueJointToNodeMappingFromScene( void );
//Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions
//Accessors for joint position upload friendly rigs
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
-
+ bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
+ //Determines if a rig is a legacy from the joint list
+ bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
//Accessors for the legacy rigs
const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
- void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
+ void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
+ //Verify that a controller matches vertex counts
+ bool verifyController( domController* pController );
static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
@@ -301,16 +389,6 @@ public:
LLVector3 getTranslationForJointOffset( std::string joint );
- static bool sIgnoreLoadedCallback;
-
-protected:
-
- static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque);
- static void stateChangedCallback(U32 state, void* opaque);
-
- static LLJoint* lookupJointByName(const std::string&, void* opaque);
- static U32 loadTextures(LLImportMaterial& material, void* opaque);
-
private:
//Utility function for controller vertex compare
bool verifyCount( int expected, int result );
@@ -318,8 +396,6 @@ private:
void createPreviewAvatar( void );
//Accessor for the dummy avatar
LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; }
- // Count amount of original models, excluding sub-models
- static U32 countRootModels(LLModelLoader::model_list models);
protected:
friend class LLModelLoader;
@@ -341,15 +417,14 @@ private:
LLVector3 mPreviewTarget;
LLVector3 mPreviewScale;
S32 mPreviewLOD;
- S32 mPhysicsSearchLOD;
U32 mResourceCost;
std::string mLODFile[LLModel::NUM_LODS];
bool mLoading;
U32 mLoadState;
bool mResetJoints;
bool mRigParityWithScene;
- bool mModelNoErrors;
-
+ bool mHasBrokenModel;
+
std::map<std::string, bool> mViewOption;
//GLOD object parameters (must rebuild object if these change)
@@ -386,7 +461,7 @@ private:
U32 mMaxTriangleLimit;
LLMeshUploadThread::instance_list mUploadData;
- std::set<LLViewerFetchedTexture * > mTextureSet;
+ std::set<LLViewerFetchedTexture* > mTextureSet;
//map of vertex buffers to models (one vertex buffer in vector per face in model
std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1];
@@ -405,9 +480,10 @@ private:
bool mLastJointUpdate;
- JointSet mJointsFromNode;
- JointTransformMap mJointTransformMap;
-
+ std::deque<std::string> mMasterJointList;
+ std::deque<std::string> mMasterLegacyJointList;
+ std::deque<std::string> mJointsFromNode;
+ JointTransformMap mJointTransformMap;
LLPointer<LLVOAvatar> mPreviewAvatar;
};
diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp
index 042cf47070..04a818c2c0 100755
--- a/indra/newview/llfloaterperms.cpp
+++ b/indra/newview/llfloaterperms.cpp
@@ -166,15 +166,59 @@ void LLFloaterPermsDefault::onCommitCopy(const LLSD& user_data)
xfer->setEnabled(copyable);
}
-class LLFloaterPermsResponder : public LLHTTPClient::Responder
+const int MAX_HTTP_RETRIES = 5;
+LLFloaterPermsRequester* LLFloaterPermsRequester::sPermsRequester = NULL;
+
+LLFloaterPermsRequester::LLFloaterPermsRequester(const std::string url, const LLSD report,
+ int maxRetries)
+ : mRetriesCount(0), mMaxRetries(maxRetries), mUrl(url), mReport(report)
+{}
+
+//static
+void LLFloaterPermsRequester::init(const std::string url, const LLSD report, int maxRetries)
+{
+ if (sPermsRequester == NULL) {
+ sPermsRequester = new LLFloaterPermsRequester(url, report, maxRetries);
+ }
+}
+
+//static
+void LLFloaterPermsRequester::finalize()
+{
+ if (sPermsRequester != NULL)
+ {
+ delete sPermsRequester;
+ sPermsRequester = NULL;
+ }
+}
+
+//static
+LLFloaterPermsRequester* LLFloaterPermsRequester::instance()
+{
+ return sPermsRequester;
+}
+
+void LLFloaterPermsRequester::start()
{
-public:
- LLFloaterPermsResponder(): LLHTTPClient::Responder() {}
-private:
- static std::string sPreviousReason;
+ ++mRetriesCount;
+ LLHTTPClient::post(mUrl, mReport, new LLFloaterPermsResponder());
+}
+
+bool LLFloaterPermsRequester::retry()
+{
+ if (++mRetriesCount < mMaxRetries)
+ {
+ LLHTTPClient::post(mUrl, mReport, new LLFloaterPermsResponder());
+ return true;
+ }
+ return false;
+}
- void httpFailure()
+void LLFloaterPermsResponder::httpFailure()
+{
+ if (!LLFloaterPermsRequester::instance() || !LLFloaterPermsRequester::instance()->retry())
{
+ LLFloaterPermsRequester::finalize();
const std::string& reason = getReason();
// Do not display the same error more than once in a row
if (reason != sPreviousReason)
@@ -185,27 +229,27 @@ private:
LLNotificationsUtil::add("DefaultObjectPermissions", args);
}
}
+}
- void httpSuccess()
- {
- //const LLSD& content = getContent();
- //dump_sequential_xml("perms_responder_result.xml", content);
-
- // Since we have had a successful POST call be sure to display the next error message
- // even if it is the same as a previous one.
- sPreviousReason = "";
- LLFloaterPermsDefault::setCapSent(true);
- LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL;
- }
-};
+void LLFloaterPermsResponder::httpSuccess()
+{
+ //const LLSD& content = getContent();
+ //dump_sequential_xml("perms_responder_result.xml", content);
- std::string LLFloaterPermsResponder::sPreviousReason;
+ // Since we have had a successful POST call be sure to display the next error message
+ // even if it is the same as a previous one.
+ sPreviousReason = "";
+ LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL;
+}
+
+std::string LLFloaterPermsResponder::sPreviousReason;
void LLFloaterPermsDefault::sendInitialPerms()
{
if(!mCapSent)
{
updateCap();
+ setCapSent(true);
}
}
@@ -230,8 +274,8 @@ void LLFloaterPermsDefault::updateCap()
LLSDSerialize::toPrettyXML(report, sent_perms_log);
LL_CONT << sent_perms_log.str() << LL_ENDL;
}
-
- LLHTTPClient::post(object_url, report, new LLFloaterPermsResponder());
+ LLFloaterPermsRequester::init(object_url, report, MAX_HTTP_RETRIES);
+ LLFloaterPermsRequester::instance()->start();
}
else
{
diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h
index 2bb0a19dc1..d3b52c1fe5 100755
--- a/indra/newview/llfloaterperms.h
+++ b/indra/newview/llfloaterperms.h
@@ -29,6 +29,7 @@
#define LL_LLFLOATERPERMPREFS_H
#include "llfloater.h"
+#include "llhttpclient.h"
class LLFloaterPerms : public LLFloater
{
@@ -89,4 +90,36 @@ private:
bool mNextOwnerTransfer[CAT_LAST];
};
+class LLFloaterPermsRequester
+{
+public:
+ LLFloaterPermsRequester(const std::string url, const LLSD report, int maxRetries);
+
+ static void init(const std::string url, const LLSD report, int maxRetries);
+ static void finalize();
+ static LLFloaterPermsRequester* instance();
+
+ void start();
+ bool retry();
+
+private:
+ int mRetriesCount;
+ int mMaxRetries;
+ const std::string mUrl;
+ const LLSD mReport;
+public:
+ static LLFloaterPermsRequester* sPermsRequester;
+};
+
+class LLFloaterPermsResponder : public LLHTTPClient::Responder
+{
+public:
+ LLFloaterPermsResponder() : LLHTTPClient::Responder() {}
+private:
+ static std::string sPreviousReason;
+
+ void httpFailure();
+ void httpSuccess();
+};
+
#endif
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ee4396758e..dac610eda1 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -49,6 +49,7 @@
//#include "llfirstuse.h"
#include "llfloaterreg.h"
#include "llfloaterabout.h"
+#include "llfavoritesbar.h"
#include "llfloaterhardwaresettings.h"
#include "llfloatersidepanelcontainer.h"
#include "llfloaterimsession.h"
@@ -1919,7 +1920,7 @@ BOOL LLPanelPreference::postBuild()
}
if (hasChild("favorites_on_login_check", TRUE))
{
- getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&showFavoritesOnLoginWarning, _1, _2));
+ getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setCommitCallback(boost::bind(&handleFavoritesOnLoginChanged, _1, _2));
bool show_favorites_at_login = LLPanelLogin::getShowFavorites();
getChild<LLCheckBoxCtrl>("favorites_on_login_check")->setValue(show_favorites_at_login);
}
@@ -2004,11 +2005,15 @@ void LLPanelPreference::showFriendsOnlyWarning(LLUICtrl* checkbox, const LLSD& v
}
}
-void LLPanelPreference::showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value)
+void LLPanelPreference::handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value)
{
- if (checkbox && checkbox->getValue())
+ if (checkbox)
{
- LLNotificationsUtil::add("FavoritesOnLogin");
+ LLFavoritesOrderStorage::instance().showFavoritesOnLoginChanged(checkbox->getValue().asBoolean());
+ if(checkbox->getValue())
+ {
+ LLNotificationsUtil::add("FavoritesOnLogin");
+ }
}
}
@@ -2235,6 +2240,11 @@ void LLFloaterPreferenceProxy::onOpen(const LLSD& key)
void LLFloaterPreferenceProxy::onClose(bool app_quitting)
{
+ if(app_quitting)
+ {
+ cancel();
+ }
+
if (mSocksSettingsDirty)
{
@@ -2334,6 +2344,11 @@ void LLFloaterPreferenceProxy::onBtnCancel()
cancel();
}
+void LLFloaterPreferenceProxy::onClickCloseBtn(bool app_quitting)
+{
+ cancel();
+}
+
void LLFloaterPreferenceProxy::cancel()
{
@@ -2344,7 +2359,7 @@ void LLFloaterPreferenceProxy::cancel()
LLSD ctrl_value = iter->second;
control->set(ctrl_value);
}
-
+ mSocksSettingsDirty = false;
closeFloater();
}
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 7bf6ae7d79..04e5e37731 100755
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -229,7 +229,7 @@ private:
//for "Only friends and groups can call or IM me"
static void showFriendsOnlyWarning(LLUICtrl*, const LLSD&);
//for "Show my Favorite Landmarks at Login"
- static void showFavoritesOnLoginWarning(LLUICtrl* checkbox, const LLSD& value);
+ static void handleFavoritesOnLoginChanged(LLUICtrl* checkbox, const LLSD& value);
typedef std::map<std::string, LLColor4> string_color_map_t;
string_color_map_t mSavedColors;
@@ -269,6 +269,7 @@ protected:
void saveSettings();
void onBtnOk();
void onBtnCancel();
+ void onClickCloseBtn(bool app_quitting = false);
void onChangeSocksSettings();
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 2f4d2a93b2..99a5cf8002 100755
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -35,6 +35,7 @@
#include "llassetstorage.h"
#include "llavatarnamecache.h"
#include "llcachename.h"
+#include "llcheckboxctrl.h"
#include "llfontgl.h"
#include "llimagej2c.h"
#include "llinventory.h"
@@ -137,6 +138,7 @@ BOOL LLFloaterReporter::postBuild()
mOwnerName = LLStringUtil::null;
getChild<LLUICtrl>("summary_edit")->setFocus(TRUE);
+ getChild<LLCheckBoxCtrl>("screen_check")->set(TRUE);
mDefaultSummary = getChild<LLUICtrl>("details_edit")->getValue().asString();
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index 16fa4684ab..afec981d56 100755
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -663,14 +663,20 @@ void LLFloaterSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* data)
{
LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
+ LLSnapshotLivePreview* previewp = getPreviewView(view);
- if (!view || !check_box)
+ if (!view || !check_box || !previewp)
{
return;
}
gSavedSettings.setBOOL("UseFreezeFrame", check_box->get());
+ if (check_box->get())
+ {
+ previewp->prepareFreezeFrame();
+ }
+
updateLayout(view);
}
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index c1c21c593e..ae33acb842 100755
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -141,6 +141,12 @@ BOOL LLFloaterTOS::postBuild()
// Don't use the start_url parameter for this browser instance -- it may finish loading before we get to add our observer.
// Store the URL separately and navigate here instead.
web_browser->navigateTo( getString( "loading_url" ) );
+ LLPluginClassMedia* media_plugin = web_browser->getMediaPlugin();
+ if (media_plugin)
+ {
+ // All links from tos_html should be opened in external browser
+ media_plugin->setOverrideClickTarget("_external");
+ }
}
return TRUE;
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 1b1c24b19a..ece3e10faa 100755
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -284,12 +284,12 @@ BOOL LLFloaterWorldMap::postBuild()
LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
avatar_combo->selectFirstItem();
avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) );
- avatar_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
+ avatar_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
mListFriendCombo = dynamic_cast<LLCtrlListInterface *>(avatar_combo);
LLSearchEditor *location_editor = getChild<LLSearchEditor>("location");
location_editor->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1));
- location_editor->setKeystrokeCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
+ location_editor->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this));
getChild<LLScrollListCtrl>("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
mListSearchResults = childGetListInterface("search_results");
@@ -297,7 +297,7 @@ BOOL LLFloaterWorldMap::postBuild()
LLComboBox *landmark_combo = getChild<LLComboBox>( "landmark combo");
landmark_combo->selectFirstItem();
landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) );
- landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
+ landmark_combo->setTextChangedCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
mListLandmarkCombo = dynamic_cast<LLCtrlListInterface *>(landmark_combo);
mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f);
diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp
index 44eda4d6c0..e9f80b795a 100755
--- a/indra/newview/llfolderviewmodelinventory.cpp
+++ b/indra/newview/llfolderviewmodelinventory.cpp
@@ -109,6 +109,29 @@ bool LLFolderViewModelInventory::contentsReady()
return !LLInventoryModelBackgroundFetch::instance().folderFetchActive();
}
+bool LLFolderViewModelInventory::isFolderComplete(LLFolderViewFolder* folder)
+{
+ LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem());
+ LLUUID cat_id = modelp->getUUID();
+ if (cat_id.isNull())
+ {
+ return false;
+ }
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ // don't need to check version - descendents_server == -1 if we have no data
+ S32 descendents_server = cat->getDescendentCount();
+ S32 descendents_actual = cat->getViewerDescendentCount();
+ if (descendents_server == descendents_actual
+ || (descendents_actual > 0 && descendents_server == -1)) // content was loaded in previous session
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
void LLFolderViewModelItemInventory::requestSort()
{
LLFolderViewModelItemCommon::requestSort();
diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h
index 0516fc3b4b..dea54cbe57 100755
--- a/indra/newview/llfolderviewmodelinventory.h
+++ b/indra/newview/llfolderviewmodelinventory.h
@@ -115,6 +115,7 @@ public:
void sort(LLFolderViewFolder* folder);
bool contentsReady();
+ bool isFolderComplete(LLFolderViewFolder* folder);
bool startDrag(std::vector<LLFolderViewModelItem*>& items);
private:
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 86f9da6318..4d92fee04f 100755
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -239,7 +239,8 @@ LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) :
mRoleMemberDataComplete(false),
mGroupPropertiesDataComplete(false),
mPendingRoleMemberRequest(false),
- mAccessTime(0.0f)
+ mAccessTime(0.0f),
+ mPendingBanRequest(false)
{
mMemberVersion.generate();
}
@@ -761,8 +762,69 @@ void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id)
mBanList.erase(ban_id);
}
+void LLGroupMgrGroupData::banMemberById(const LLUUID& participant_uuid)
+{
+ if (!mMemberDataComplete ||
+ !mRoleDataComplete ||
+ !(mRoleMemberDataComplete && mMembers.size()))
+ {
+ LL_WARNS() << "No Role-Member data yet, setting ban request to pending." << LL_ENDL;
+ mPendingBanRequest = true;
+ mPendingBanMemberID = participant_uuid;
+
+ if (!mMemberDataComplete)
+ {
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID);
+ }
+
+ if (!mRoleDataComplete)
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mID);
+ }
+
+ return;
+ }
+
+ LLGroupMgrGroupData::member_list_t::iterator mi = mMembers.find((participant_uuid));
+ if (mi == mMembers.end())
+ {
+ if (!mPendingBanRequest)
+ {
+ mPendingBanRequest = true;
+ mPendingBanMemberID = participant_uuid;
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); // member isn't in members list, request reloading
+ }
+ else
+ {
+ mPendingBanRequest = false;
+ }
+ return;
+ }
+ mPendingBanRequest = false;
+
+ LLGroupMemberData* member_data = (*mi).second;
+ if (member_data && member_data->isInRole(mOwnerRole))
+ {
+ return; // can't ban group owner
+ }
+
+ std::vector<LLUUID> ids;
+ ids.push_back(participant_uuid);
+
+ LLGroupBanData ban_data;
+ createBanEntry(participant_uuid, ban_data);
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mID, LLGroupMgr::BAN_CREATE, ids);
+ LLGroupMgr::getInstance()->sendGroupMemberEjects(mID, ids);
+ LLGroupMgr::getInstance()->sendGroupMembersRequest(mID);
+ LLSD args;
+ std::string name;
+ gCacheName->getFullName(participant_uuid, name);
+ args["AVATAR_NAME"] = name;
+ args["GROUP_NAME"] = mName;
+ LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
+}
//
// LLGroupMgr
@@ -1245,6 +1307,11 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
group_datap->mChanged = TRUE;
LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA);
+
+ if (group_datap->mPendingBanRequest)
+ {
+ group_datap->banMemberById(group_datap->mPendingBanMemberID);
+ }
}
// static
@@ -1993,8 +2060,6 @@ void LLGroupMgr::processGroupBanRequest(const LLSD& content)
LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST);
}
-
-
// Responder class for capability group management
class GroupMemberDataResponder : public LLHTTPClient::Responder
{
@@ -2083,11 +2148,6 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
return;
}
- // If we have no members, there's no reason to do anything else
- S32 num_members = content["member_count"];
- if(num_members < 1)
- return;
-
LLUUID group_id = content["group_id"].asUUID();
LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
@@ -2097,6 +2157,18 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
return;
}
+ // If we have no members, there's no reason to do anything else
+ S32 num_members = content["member_count"];
+ if (num_members < 1)
+ {
+ LL_INFOS("GrpMgr") << "Received empty group members list for group id: " << group_id.asString() << LL_ENDL;
+ // Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237
+ group_datap->mMemberDataComplete = true;
+ group_datap->mChanged = TRUE;
+ LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
+ return;
+ }
+
group_datap->mMemberCount = num_members;
LLSD member_list = content["members"];
diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h
index 2e94e8d9a0..5307c4de92 100755
--- a/indra/newview/llgroupmgr.h
+++ b/indra/newview/llgroupmgr.h
@@ -149,7 +149,7 @@ public:
const uuid_vec_t& getRoleMembers() const { return mMemberIDs; }
S32 getMembersInRole(uuid_vec_t members, BOOL needs_sort = TRUE);
- S32 getTotalMembersInRole() { return mMemberIDs.size(); }
+ S32 getTotalMembersInRole() { return mMemberCount ? mMemberCount : mMemberIDs.size(); } //FIXME: Returns 0 for Everyone role when Member list isn't yet loaded, see MAINT-5225
LLRoleData getRoleData() const { return mRoleData; }
void setRoleData(LLRoleData data) { mRoleData = data; }
@@ -269,8 +269,8 @@ public:
void createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data = LLGroupBanData());
void removeBanEntry(const LLUUID& ban_id);
+ void banMemberById(const LLUUID& participant_uuid);
-
public:
typedef std::map<LLUUID,LLGroupMemberData*> member_list_t;
typedef std::map<LLUUID,LLGroupRoleData*> role_list_t;
@@ -302,6 +302,9 @@ public:
S32 mMemberCount;
S32 mRoleCount;
+ bool mPendingBanRequest;
+ LLUUID mPendingBanMemberID;
+
protected:
void sendRoleChanges();
void cancelRoleChanges();
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 605f71f412..a20540306b 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -121,7 +121,7 @@ bool isAddAction(const std::string& action)
bool isRemoveAction(const std::string& action)
{
- return ("take_off" == action || "detach" == action || "deactivate" == action);
+ return ("take_off" == action || "detach" == action);
}
bool isMarketplaceCopyAction(const std::string& action)
@@ -295,7 +295,11 @@ BOOL LLInvFVBridge::callback_cutToClipboard(const LLSD& notification, const LLSD
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0) // YES
{
- return perform_cutToClipboard();
+ const LLInventoryObject* obj = gInventory.getObject(mUUID);
+ LLUUID parent_uuid = obj->getParentUUID();
+ BOOL result = perform_cutToClipboard();
+ gInventory.addChangedMask(LLInventoryObserver::STRUCTURE, parent_uuid);
+ return result;
}
return FALSE;
}
@@ -915,15 +919,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
return;
}
- // "Remove link" and "Delete" are the same operation.
- if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID))
- {
- items.push_back(std::string("Remove Link"));
- }
- else
- {
- items.push_back(std::string("Delete"));
- }
+ items.push_back(std::string("Delete"));
if (!isItemRemovable())
{
@@ -1810,7 +1806,9 @@ void LLItemBridge::restoreItem()
if(item)
{
LLInventoryModel* model = getInventoryModel();
- const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType()));
+ bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
+
+ const LLUUID new_parent = model->findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
// do not restamp on restore.
LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
}
@@ -2437,7 +2435,8 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const
BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
BOOL drop,
std::string& tooltip_msg,
- BOOL user_confirm)
+ BOOL is_link,
+ BOOL user_confirm)
{
LLInventoryModel* model = getInventoryModel();
@@ -2483,6 +2482,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const BOOL move_is_into_current_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT);
const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
//--------------------------------------------------------------------------------
@@ -2520,8 +2520,18 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
if (is_movable && move_is_into_outfit)
{
+ if((mUUID == my_outifts_id) || (getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_NONE))
+ {
+ is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT));
+ }
+ else
+ {
+ is_movable = false;
+ }
+ }
+ if(is_movable && move_is_into_current_outfit && is_link)
+ {
is_movable = FALSE;
- // tooltip?
}
if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))
{
@@ -2705,9 +2715,11 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
}
+
// if target is current outfit folder we use link
if (move_is_into_current_outfit &&
- inv_cat->getPreferredType() == LLFolderType::FT_NONE)
+ (inv_cat->getPreferredType() == LLFolderType::FT_NONE ||
+ inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT))
{
// traverse category and add all contents to currently worn.
BOOL append = true;
@@ -4141,7 +4153,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());
if (linked_category)
{
- accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg);
+ accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, TRUE);
}
}
else
@@ -4561,7 +4573,7 @@ void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, c
if (option == 0) // YES
{
std::string tooltip_msg;
- dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE);
+ dragCategoryIntoFolder(inv_category, TRUE, tooltip_msg, FALSE, FALSE);
}
}
@@ -5760,7 +5772,7 @@ void LLGestureBridge::performAction(LLInventoryModel* model, std::string action)
gInventory.updateItem(item);
gInventory.notifyObservers();
}
- else if (isRemoveAction(action))
+ else if ("deactivate" == action || isRemoveAction(action))
{
LLGestureMgr::instance().deactivateGesture(mUUID);
@@ -6382,12 +6394,8 @@ void LLWearableBridge::performAction(LLInventoryModel* model, std::string action
void LLWearableBridge::openItem()
{
- LLViewerInventoryItem* item = getItem();
-
- if (item)
- {
- LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
- }
+ performAction(getInventoryModel(),
+ get_is_item_worn(mUUID) ? "take_off" : "wear");
}
void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 7e7cf9c7dd..03e19cc4da 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -274,7 +274,7 @@ public:
{}
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE);
- BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE);
+ BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE);
void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);
void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category);
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 990343c205..6aaf45c35d 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -2473,7 +2473,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
LLSD args;
args["QUESTION"] = LLTrans::getString(root->getSelectedCount() > 1 ? "DeleteItems" : "DeleteItem");
- LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&onItemsRemovalConfirmation, _1, _2, root->getHandle()));
+ LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle()));
// Note: marketplace listings will be updated in the callback if delete confirmed
return;
}
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 6ae8fd0f13..b93bf9a163 100755
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -465,9 +465,9 @@ struct LLInventoryAction
static void removeItemFromDND(LLFolderView* root);
private:
- static void buildMarketplaceFolders(LLFolderView* root);
- static void updateMarketplaceFolders();
- static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed
+ static void buildMarketplaceFolders(LLFolderView* root);
+ static void updateMarketplaceFolders();
+ static std::list<LLUUID> sMarketplaceFolders; // Marketplace folders that will need update once the action is completed
};
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 4e9947fca0..46c1ffa789 100755
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -515,7 +515,7 @@ void LLLocalBitmap::updateUserSculpts(LLUUID old_id, LLUUID new_id)
{
LLSculptParams* old_params = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLSculptParams new_params(*old_params);
- new_params.setSculptTexture(new_id);
+ new_params.setSculptTexture(new_id, (*old_params).getSculptType());
object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, new_params, TRUE);
}
}
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index cf04c5f7a5..8d21fda8f9 100755
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -862,14 +862,11 @@ void LLLocationInputCtrl::refreshParcelIcons()
bool see_avs = current_parcel->getSeeAVs();
bool pathfinding_dynamic_enabled = agent_region->dynamicPathfindingEnabled();
- bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID());
- bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify());
-
// Most icons are "block this ability"
mParcelIcon[VOICE_ICON]->setVisible( !allow_voice );
mParcelIcon[FLY_ICON]->setVisible( !allow_fly );
mParcelIcon[PUSH_ICON]->setVisible( !allow_push );
- mParcelIcon[BUILD_ICON]->setVisible( !allow_build && !is_parcel_owner && !allow_group_modify );
+ mParcelIcon[BUILD_ICON]->setVisible( !allow_build );
mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage );
mParcelIcon[PATHFINDING_DIRTY_ICON]->setVisible(mIsNavMeshDirty);
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 7ddacf3033..4116e38f11 100755
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -804,6 +804,22 @@ bool LLLogChat::isNearbyTranscriptExist()
return false;
}
+bool LLLogChat::isAdHocTranscriptExist(std::string file_name)
+{
+ std::vector<std::string> list_of_transcriptions;
+ LLLogChat::getListOfTranscriptFiles(list_of_transcriptions);
+
+ file_name = makeLogFileName(file_name);
+ BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions)
+ {
+ if (transcript_file_name == file_name)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
//*TODO mark object's names in a special way so that they will be distinguishable form avatar name
//which are more strict by its nature (only firstname and secondname)
//Example, an object's name can be written like "Object <actual_object's_name>"
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index ca597599dd..6022e539a9 100755
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -120,6 +120,7 @@ public:
static void deleteTranscripts();
static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false);
static bool isNearbyTranscriptExist();
+ static bool isAdHocTranscriptExist(std::string file_name);
static bool historyThreadsFinished(LLUUID session_id);
static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id);
diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp
index 407613d32c..85faa70552 100755
--- a/indra/newview/llmanipscale.cpp
+++ b/indra/newview/llmanipscale.cpp
@@ -1677,12 +1677,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side1)));
LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple1 + i) * smallest_subdivision1);
- F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
-
- if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
+ /*if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
F32 tick_scale = 1.f;
for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
@@ -1710,12 +1710,12 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side2)));
LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple2 + i) * smallest_subdivision2);
- F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
-
- if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
+ /*if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
F32 tick_scale = 1.f;
for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f)
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 394db71fb9..b4259a456c 100755
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -1285,12 +1285,12 @@ void LLManipTranslate::renderSnapGuides()
{
tick_start = selection_center + (translate_axis * (smallest_grid_unit_scale * (F32)i - offset_nearest_grid_unit));
- F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale());
-
- if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f)
+ //No need check this condition to prevent tick position scaling (FIX MAINT-5207/5208)
+ //F32 cur_subdivisions = getSubdivisionLevel(tick_start, translate_axis, getMinGridScale());
+ /*if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f)
{
continue;
- }
+ }*/
// add in off-axis offset
tick_start += (mSnapOffsetAxis * mSnapOffsetMeters);
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index b96bdd73ff..73faed7ef5 100755
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -95,6 +95,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
mStretchToFill( true ),
mMaintainAspectRatio ( true ),
mDecoupleTextureSize ( false ),
+ mUpdateScrolls( false ),
mTextureWidth ( 1024 ),
mTextureHeight ( 1024 ),
mClearCache(false),
@@ -682,7 +683,13 @@ bool LLMediaCtrl::ensureMediaSourceExists()
mMediaSource->addObserver( this );
mMediaSource->setBackgroundColor( getBackgroundColor() );
mMediaSource->setTrustedBrowser(mTrusted);
- mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] );
+
+ F32 scale_factor = LLUI::getScaleFactor().mV[ VX ];
+ if (scale_factor != mMediaSource->getPageZoomFactor())
+ {
+ mMediaSource->setPageZoomFactor( scale_factor );
+ mUpdateScrolls = true;
+ }
if(mClearCache)
{
@@ -720,10 +727,11 @@ void LLMediaCtrl::draw()
{
F32 alpha = getDrawContext().mAlpha;
- if ( gRestoreGL == 1 )
+ if ( gRestoreGL == 1 || mUpdateScrolls)
{
LLRect r = getRect();
reshape( r.getWidth(), r.getHeight(), FALSE );
+ mUpdateScrolls = false;
return;
}
@@ -765,7 +773,12 @@ void LLMediaCtrl::draw()
{
gGL.pushUIMatrix();
{
- mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] );
+ F32 scale_factor = LLUI::getScaleFactor().mV[ VX ];
+ if (scale_factor != mMediaSource->getPageZoomFactor())
+ {
+ mMediaSource->setPageZoomFactor( scale_factor );
+ mUpdateScrolls = true;
+ }
// scale texture to fit the space using texture coords
gGL.getTexUnit(0)->bind(media_texture);
@@ -970,11 +983,11 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
case MEDIA_EVENT_CLICK_LINK_HREF:
{
- LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;
// retrieve the event parameters
std::string url = self->getClickURL();
- std::string target = self->getClickTarget();
+ std::string target = self->isOverrideClickTarget() ? self->getOverrideClickTarget() : self->getClickTarget();
std::string uuid = self->getClickUUID();
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL;
LLNotification::Params notify_params;
notify_params.name = "PopupAttempt";
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 785c57b78a..988733b85a 100755
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -192,7 +192,8 @@ public:
mHidingInitialLoad,
mClearCache,
mHoverTextChanged,
- mDecoupleTextureSize;
+ mDecoupleTextureSize,
+ mUpdateScrolls;
std::string mHomePageUrl,
mHomePageMimeType,
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index fe562baf96..70035bcc74 100755
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -303,7 +303,15 @@ void LLFloaterMove::onFlyButtonClick()
void LLFloaterMove::setMovementMode(const EMovementMode mode)
{
mCurrentMode = mode;
- gAgent.setFlying(MM_FLY == mode);
+
+ if(MM_FLY == mode)
+ {
+ LLAgent::toggleFlying();
+ }
+ else
+ {
+ gAgent.setFlying(FALSE);
+ }
// attempts to set avatar flying can not set it real flying in some cases.
// For ex. when avatar fell down & is standing up.
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 79988a0800..5510598ae7 100755
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -130,8 +130,14 @@ BOOL LLNameListCtrl::handleDragAndDrop(
return handled;
}
-void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group)
+void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience)
{
+ if(is_experience)
+ {
+ LLFloaterReg::showInstance("experience_profile", avatar_id, true);
+ return;
+ }
+
if (is_group)
LLFloaterReg::showInstance("inspect_group", LLSD().with("group_id", avatar_id));
else
@@ -230,10 +236,11 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
// Should we show a group or an avatar inspector?
bool is_group = hit_item->isGroup();
+ bool is_experience = hit_item->isExperience();
LLToolTip::Params params;
params.background_visible( false );
- params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group) );
+ params.click_callback( boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group, is_experience) );
params.delay_time(0.0f); // spawn instantly on hover
params.image( icon );
params.message("");
@@ -295,7 +302,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
const std::string& prefix)
{
LLUUID id = name_item.value().asUUID();
- LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP);
+ LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP, name_item.target() == EXPERIENCE);
if (!item) return NULL;
@@ -353,6 +360,8 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
}
break;
}
+ case EXPERIENCE:
+ // just use supplied name
default:
break;
}
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 515962df7d..19ce3c7aed 100755
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -44,22 +44,30 @@ class LLNameListItem : public LLScrollListItem, public LLHandleProvider<LLNameLi
public:
bool isGroup() const { return mIsGroup; }
void setIsGroup(bool is_group) { mIsGroup = is_group; }
+ bool isExperience() const { return mIsExperience; }
+ void setIsExperience(bool is_experience) { mIsExperience = is_experience; }
protected:
friend class LLNameListCtrl;
LLNameListItem( const LLScrollListItem::Params& p )
- : LLScrollListItem(p), mIsGroup(false)
+ : LLScrollListItem(p), mIsGroup(false), mIsExperience(false)
{
}
LLNameListItem( const LLScrollListItem::Params& p, bool is_group )
- : LLScrollListItem(p), mIsGroup(is_group)
+ : LLScrollListItem(p), mIsGroup(is_group), mIsExperience(false)
+ {
+ }
+
+ LLNameListItem( const LLScrollListItem::Params& p, bool is_group, bool is_experience )
+ : LLScrollListItem(p), mIsGroup(is_group), mIsExperience(is_experience)
{
}
private:
bool mIsGroup;
+ bool mIsExperience;
};
@@ -73,7 +81,8 @@ public:
{
INDIVIDUAL,
GROUP,
- SPECIAL
+ SPECIAL,
+ EXPERIENCE
} ENameType;
// provide names for enums
@@ -160,7 +169,7 @@ public:
/*virtual*/ void mouseOverHighlightNthItem( S32 index );
private:
- void showInspector(const LLUUID& avatar_id, bool is_group);
+ void showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience = false);
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, LLHandle<LLNameListItem> item);
private:
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 9bd6007772..b7e1b2d3a4 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1168,6 +1168,8 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO
targetPanel->setVisible(show);
toggleTypeSpecificControls(type);
+ // Update type controls here
+ updateTypeSpecificControls(type);
if (show)
{
@@ -1179,7 +1181,6 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO
mNameEditor->setText(mWearableItem->getName());
updatePanelPickerControls(type);
- updateTypeSpecificControls(type);
// clear and rebuild visual param list
U8 num_subparts = wearable_entry->mSubparts.size();
diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp
index fc4ee9862e..7c07301762 100644
--- a/indra/newview/llpanelexperiencelisteditor.cpp
+++ b/indra/newview/llpanelexperiencelisteditor.cpp
@@ -33,6 +33,7 @@
#include "llfloaterexperiencepicker.h"
#include "llfloaterreg.h"
#include "llhandle.h"
+#include "llnamelistctrl.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
@@ -54,7 +55,7 @@ LLPanelExperienceListEditor::LLPanelExperienceListEditor()
BOOL LLPanelExperienceListEditor::postBuild()
{
- mItems = getChild<LLScrollListCtrl>("experience_list");
+ mItems = getChild<LLNameListCtrl>("experience_list");
mAdd = getChild<LLButton>("btn_add");
mRemove = getChild<LLButton>("btn_remove");
mProfile = getChild<LLButton>("btn_profile");
@@ -178,12 +179,13 @@ void LLPanelExperienceListEditor::onItems()
{
const LLUUID& experience = *it;
item["id"]=experience;
+ item["target"] = LLNameListCtrl::EXPERIENCE;
LLSD& columns = item["columns"];
columns[0]["column"] = "experience_name";
columns[0]["value"] = getString("loading");
mItems->addElement(item);
- LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
+ LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
getDerivedHandle<LLPanelExperienceListEditor>(), _1));
}
diff --git a/indra/newview/llpanelexperiencelisteditor.h b/indra/newview/llpanelexperiencelisteditor.h
index f69f0509be..bc9867752d 100644
--- a/indra/newview/llpanelexperiencelisteditor.h
+++ b/indra/newview/llpanelexperiencelisteditor.h
@@ -31,6 +31,7 @@
#include "lluuid.h"
#include <set>
+class LLNameListCtrl;
class LLScrollListCtrl;
class LLButton;
class LLFloaterExperiencePicker;
@@ -82,7 +83,7 @@ private:
uuid_list_t mExperienceIds;
- LLScrollListCtrl* mItems;
+ LLNameListCtrl* mItems;
filter_list mFilters;
LLButton* mAdd;
LLButton* mRemove;
diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp
index df03ef7526..30576a8d67 100644
--- a/indra/newview/llpanelexperiencelog.cpp
+++ b/indra/newview/llpanelexperiencelog.cpp
@@ -54,7 +54,6 @@ LLPanelExperienceLog::LLPanelExperienceLog( )
buildFromFile("panel_experience_log.xml");
}
-
BOOL LLPanelExperienceLog::postBuild( void )
{
LLExperienceLog* log = LLExperienceLog::getInstance();
@@ -112,7 +111,7 @@ void LLPanelExperienceLog::refresh()
int itemsToSkip = mPageSize*mCurrentPage;
int items = 0;
bool moreItems = false;
-
+ LLSD events_to_save = events;
if (!events.emptyMap())
{
LLSD::map_const_iterator day = events.endMap();
@@ -120,6 +119,13 @@ void LLPanelExperienceLog::refresh()
{
--day;
const LLSD& dayArray = day->second;
+
+ std::string date = day->first;
+ if(!LLExperienceLog::instance().isNotExpired(date))
+ {
+ events_to_save.erase(day->first);
+ continue;
+ }
int size = dayArray.size();
if(itemsToSkip > size)
{
@@ -164,6 +170,7 @@ void LLPanelExperienceLog::refresh()
}
} while (day != events.beginMap());
}
+ LLExperienceLog::getInstance()->setEventsToSave(events_to_save);
if(waiting)
{
mEventList->deleteAllItems();
@@ -237,12 +244,8 @@ void LLPanelExperienceLog::notifyChanged()
void LLPanelExperienceLog::logSizeChanged()
{
int value = (int)(getChild<LLSpinCtrl>("logsizespinner")->get());
- bool dirty = value > 0 && value < LLExperienceLog::instance().getMaxDays();
LLExperienceLog::instance().setMaxDays(value);
- if(dirty)
- {
- refresh();
- }
+ refresh();
}
void LLPanelExperienceLog::onSelectionChanged()
diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp
index 70d826a407..43dc7569a4 100644
--- a/indra/newview/llpanelexperiencepicker.cpp
+++ b/indra/newview/llpanelexperiencepicker.cpp
@@ -42,6 +42,7 @@
#include "llviewercontrol.h"
#include "llfloater.h"
#include "lltrans.h"
+#include <boost/regex.hpp>
#define BTN_FIND "find"
#define BTN_OK "ok_btn"
@@ -147,6 +148,46 @@ void LLPanelExperiencePicker::editKeystroke( class LLLineEditor* caller, void* u
void LLPanelExperiencePicker::onBtnFind()
{
mCurrentPage=1;
+ boost::cmatch what;
+ std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
+ const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile");
+ if (boost::regex_match(text.c_str(), what, expression))
+ {
+ LLURI uri(text);
+ LLSD path_array = uri.pathArray();
+ if (path_array.size() == 4)
+ {
+ std::string exp_id = path_array.get(2).asString();
+ LLUUID experience_id(exp_id);
+ if (!experience_id.isNull())
+ {
+ const LLSD& experience_details = LLExperienceCache::get(experience_id);
+ if(!experience_details.isUndefined())
+ {
+ std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
+ if(!experience_name_string.empty())
+ {
+ getChild<LLUICtrl>(TEXT_EDIT)->setValue(experience_name_string);
+ }
+ }
+ else
+ {
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
+
+ getChildView(BTN_OK)->setEnabled(FALSE);
+ getChildView(BTN_PROFILE)->setEnabled(FALSE);
+
+ getChildView(BTN_RIGHT)->setEnabled(FALSE);
+ getChildView(BTN_LEFT)->setEnabled(FALSE);
+ LLExperienceCache::get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
+ return;
+ }
+ }
+ }
+ }
+
+
find();
}
@@ -183,7 +224,6 @@ void LLPanelExperiencePicker::find()
getChildView(BTN_LEFT)->setEnabled(FALSE);
}
-
bool LLPanelExperiencePicker::isSelectButtonEnabled()
{
LLScrollListCtrl* list=getChild<LLScrollListCtrl>(LIST_RESULTS);
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 9823e84cd9..d7e89b4832 100755
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -307,7 +307,7 @@ private:
LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
}
- object->setTEMaterialParams(face, new_material);
+ object->setTEMaterialParams(face, new_material, TRUE);
return new_material;
}
return NULL;
diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index f67a90fd01..342b57ba4a 100755
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -338,7 +338,7 @@ void LLPanelGroup::update(LLGroupChange gc)
group_name_ctrl->setToolTip(group_name);
LLGroupData agent_gdatap;
- bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike();
+ bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery();
bool join_btn_visible = !is_member && gdatap->mOpenEnrollment;
mButtonJoin->setVisible(join_btn_visible);
@@ -470,7 +470,7 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
}
LLGroupData agent_gdatap;
- bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlike();
+ bool is_member = gAgent.getGroupData(mID,agent_gdatap) || gAgent.isGodlikeWithoutAdminMenuFakery();
tab_roles->setVisible(is_member);
tab_notices->setVisible(is_member);
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 7ffaa05919..b2164c1f21 100755
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -287,11 +287,6 @@ void LLPanelGroupGeneral::activate()
{
LLGroupMgr::getInstance()->sendGroupTitlesRequest(mGroupID);
LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID);
-
- if (!gdatap || !gdatap->isMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
mFirstUse = FALSE;
}
diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp
index e662a05dfc..866cb8dbef 100755
--- a/indra/newview/llpanelgroupinvite.cpp
+++ b/indra/newview/llpanelgroupinvite.cpp
@@ -243,56 +243,59 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
LLGroupMgrGroupData::member_list_t::iterator agent_iter =
gdatap->mMembers.find(gAgent.getID());
+ //loop over the agent's roles in the group
+ //then add those roles to the list of roles that the agent
+ //can invite people to be.
+ //if the user is the owner then we add
+ //all of the roles in the group,
+ //else if they have the add to roles power
+ //we add every role but owner,
+ //else if they have the limited add to roles power
+ //we add every role the user is in,
+ //else we just add to everyone
+ bool is_owner = FALSE;
+ bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
+ GP_ROLE_ASSIGN_MEMBER);
+ bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
+ GP_ROLE_ASSIGN_MEMBER_LIMITED);
+ LLGroupMemberData* member_data = NULL;
//get the member data for the agent if it exists
- if ( agent_iter != gdatap->mMembers.end() )
+ if (agent_iter != gdatap->mMembers.end())
{
- LLGroupMemberData* member_data = (*agent_iter).second;
-
- //loop over the agent's roles in the group
- //then add those roles to the list of roles that the agent
- //can invite people to be
- if ( member_data && mRoleNames)
+ member_data = (*agent_iter).second;
+ if (member_data && mRoleNames)
{
- //if the user is the owner then we add
- //all of the roles in the group
- //else if they have the add to roles power
- //we add every role but owner,
- //else if they have the limited add to roles power
- //we add every role the user is in
- //else we just add to everyone
- bool is_owner = member_data->isOwner();
- bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER);
- bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER_LIMITED);
+ is_owner = member_data->isOwner();
+ }//end if member data is not null
+ }//end if agent is in the group
+
- LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
- LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
- //populate the role list
- for ( ; rit != end; ++rit)
+ LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
+ LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
+
+ //populate the role list:
+ for ( ; rit != end; ++rit)
+ {
+ LLUUID role_id = (*rit).first;
+ LLRoleData rd;
+ if ( gdatap->getRoleData(role_id,rd) )
+ {
+ // Owners can add any role.
+ if ( is_owner
+ // Even 'can_assign_any' can't add owner role.
+ || (can_assign_any && role_id != gdatap->mOwnerRole)
+ // Add all roles user is in
+ || (can_assign_limited && member_data && member_data->isInRole(role_id))
+ // Everyone role.
+ || role_id == LLUUID::null )
{
- LLUUID role_id = (*rit).first;
- LLRoleData rd;
- if ( gdatap->getRoleData(role_id,rd) )
- {
- // Owners can add any role.
- if ( is_owner
- // Even 'can_assign_any' can't add owner role.
- || (can_assign_any && role_id != gdatap->mOwnerRole)
- // Add all roles user is in
- || (can_assign_limited && member_data->isInRole(role_id))
- // Everyone role.
- || role_id == LLUUID::null )
- {
- mRoleNames->add(rd.mRoleName,
- role_id,
- ADD_BOTTOM);
- }
- }
+ mRoleNames->add(rd.mRoleName,
+ role_id,
+ ADD_BOTTOM);
}
- }//end if member data is not null
- }//end if agent is in the group
+ }
+ }
}
//static
@@ -579,7 +582,8 @@ void LLPanelGroupInvite::updateLists()
{
waiting = true;
}
- if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete())
+ if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete()
+ && (gdatap->isRoleMemberDataComplete() || !gdatap->mMembers.size())) // MAINT-5270: large groups receives an empty members list without some powers, so RoleMemberData wouldn't be complete for them
{
if ( mImplementation->mRoleNames )
{
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index c3a10b3fa0..00c204e702 100755
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -350,12 +350,10 @@ void LLPanelGroupRoles::update(LLGroupChange gc)
void LLPanelGroupRoles::activate()
{
+ if (!gAgent.isInGroup(mGroupID)) return;
+
// Start requesting member and role data if needed.
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
- if (!gdatap || !gdatap->isMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
if (!gdatap || !gdatap->isRoleDataComplete() )
{
@@ -364,13 +362,7 @@ void LLPanelGroupRoles::activate()
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
}
-
- // Check role-member mapping data.
- if (!gdatap || !gdatap->isRoleMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
- }
-
+
// Need this to get base group member powers
if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )
{
@@ -1163,7 +1155,37 @@ void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata)
if ( selfp )
{
- selfp->handleEjectMembers();
+ selfp->confirmEjectMembers();
+ }
+}
+
+void LLPanelGroupMembersSubTab::confirmEjectMembers()
+{
+ std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
+ if (selection.empty()) return;
+
+ S32 selection_count = selection.size();
+ if (selection_count == 1)
+ {
+ LLSD args;
+ std::string fullname;
+ gCacheName->getFullName(mMembersList->getValue(), fullname);
+ args["AVATAR_NAME"] = fullname;
+ LLSD payload;
+ LLNotificationsUtil::add("EjectGroupMemberWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));
+ }
+ else
+ {
+ LLSD args;
+ args["COUNT"] = llformat("%d", selection_count);
+ LLSD payload;
+ LLNotificationsUtil::add("EjectGroupMembersWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));
}
}
@@ -1190,6 +1212,16 @@ void LLPanelGroupMembersSubTab::handleEjectMembers()
LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members);
}
+bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option) // Eject button
+ {
+ handleEjectMembers();
+ }
+ return false;
+}
+
void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members)
{
LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id);
@@ -1327,15 +1359,26 @@ void LLPanelGroupMembersSubTab::handleMemberDoubleClick()
void LLPanelGroupMembersSubTab::activate()
{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+
LLPanelGroupSubTab::activate();
if(!mActivated)
{
+ if (!gdatap || !gdatap->isMemberDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
+ }
+
+ if (!gdatap || !gdatap->isRoleMemberDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
+ }
+
update(GC_ALL);
mActivated = true;
}
else
{
- LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
// Members can be removed outside of this tab, checking changes
if (!gdatap || (gdatap->isMemberDataComplete() && gdatap->mMembers.size() != mMembersList->getItemCount()))
{
@@ -1636,7 +1679,13 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
{
// Build a string with info on retrieval progress.
std::ostringstream retrieved;
- if ( !gdatap->isMemberDataComplete() )
+
+ if ( gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && !gdatap->mMembers.size() )
+ {
+ // MAINT-5237
+ retrieved << "Member list not available.";
+ }
+ else if ( !gdatap->isMemberDataComplete() )
{
// Still busy retreiving member list.
retrieved << "Retrieving member list (" << gdatap->mMembers.size()
@@ -1783,7 +1832,7 @@ void LLPanelGroupMembersSubTab::updateMembers()
{
mMembersList->setEnabled(TRUE);
}
- else
+ else if (gdatap->mMembers.size())
{
mMembersList->setEnabled(FALSE);
mMembersList->setCommentText(std::string("No match."));
@@ -1801,7 +1850,47 @@ void LLPanelGroupMembersSubTab::updateMembers()
void LLPanelGroupMembersSubTab::onBanMember(void* user_data)
{
LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
- self->handleBanMember();
+ self->confirmBanMembers();
+}
+
+void LLPanelGroupMembersSubTab::confirmBanMembers()
+{
+ std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
+ if (selection.empty()) return;
+
+ S32 selection_count = selection.size();
+ if (selection_count == 1)
+ {
+ LLSD args;
+ std::string fullname;
+ gCacheName->getFullName(mMembersList->getValue(), fullname);
+ args["AVATAR_NAME"] = fullname;
+ LLSD payload;
+ LLNotificationsUtil::add("BanGroupMemberWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2));
+ }
+ else
+ {
+ LLSD args;
+ args["COUNT"] = llformat("%d", selection_count);
+ LLSD payload;
+ LLNotificationsUtil::add("BanGroupMembersWarning",
+ args,
+ payload,
+ boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2));
+ }
+}
+
+bool LLPanelGroupMembersSubTab::handleBanCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option) // Eject button
+ {
+ handleBanMember();
+ }
+ return false;
}
void LLPanelGroupMembersSubTab::handleBanMember()
@@ -2111,20 +2200,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
mDeleteRoleButton->setEnabled(FALSE);
}
}
-
- if(!mFirstOpen)
- {
- if (!gdatap || !gdatap->isMemberDataComplete())
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
-
- if (!gdatap || !gdatap->isRoleMemberDataComplete())
- {
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
- }
- }
-
+
if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc)
&& gdatap
&& gdatap->isMemberDataComplete()
diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h
index 540b24ada6..9a696124a8 100755
--- a/indra/newview/llpanelgrouproles.h
+++ b/indra/newview/llpanelgrouproles.h
@@ -171,6 +171,7 @@ public:
void handleEjectMembers();
void sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members);
bool handleEjectCallback(const LLSD& notification, const LLSD& response);
+ void confirmEjectMembers();
static void onRoleCheck(LLUICtrl* check, void* user_data);
void handleRoleCheck(const LLUUID& role_id,
@@ -178,6 +179,8 @@ public:
static void onBanMember(void* user_data);
void handleBanMember();
+ bool handleBanCallback(const LLSD& notification, const LLSD& response);
+ void confirmBanMembers();
void applyMemberChanges();
diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp
index d4894d4a42..06bb886ae8 100755
--- a/indra/newview/llpanellandmarkinfo.cpp
+++ b/indra/newview/llpanellandmarkinfo.cpp
@@ -147,6 +147,7 @@ void LLPanelLandmarkInfo::setInfoType(EInfoType type)
}
else
{
+ LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_NORMAL, agent_pos);
region_name = desc;
}
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 7aaf9510eb..4229419fce 100755
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -604,7 +604,7 @@ void LLPanelMainInventory::updateItemcountText()
}
else
{
- text = getString("ItemcountUnknown");
+ text = getString("ItemcountUnknown", string_args);
}
mCounterCtrl->setValue(text);
diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp
index 2856ea9db1..d7c43c224c 100755
--- a/indra/newview/llpanelmediasettingsgeneral.cpp
+++ b/indra/newview/llpanelmediasettingsgeneral.cpp
@@ -319,6 +319,10 @@ void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& _media
// Helper to set media control to media URL as required
void LLPanelMediaSettingsGeneral::updateMediaPreview()
{
+ if(LLTrans::getString("Multiple Media") == mHomeURL->getValue().asString())
+ {
+ return;
+ }
if ( mHomeURL->getValue().asString().length() > 0 )
{
if(mPreviewMedia->getCurrentNavUrl() != mHomeURL->getValue().asString())
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index dcd0aab3ab..5dd44b4444 100755
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -1739,9 +1739,10 @@ void LLPanelObject::sendSculpt()
return;
LLSculptParams sculpt_params;
+ LLUUID sculpt_id = LLUUID::null;
if (mCtrlSculptTexture)
- sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID());
+ sculpt_id = mCtrlSculptTexture->getImageAssetID();
U8 sculpt_type = 0;
@@ -1765,7 +1766,7 @@ void LLPanelObject::sendSculpt()
if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get()))
sculpt_type |= LL_SCULPT_FLAG_INVERT;
- sculpt_params.setSculptType(sculpt_type);
+ sculpt_params.setSculptTexture(sculpt_id, sculpt_type);
mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
}
@@ -2000,7 +2001,11 @@ void LLPanelObject::onCancelSculpt(const LLSD& data)
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
if(!mTextureCtrl)
return;
-
+
+ if(mSculptTextureRevert == LLUUID::null)
+ {
+ mSculptTextureRevert = LLUUID(SCULPT_DEFAULT_TEXTURE);
+ }
mTextureCtrl->setImageAssetID(mSculptTextureRevert);
sendSculpt();
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 496168229d..01a22df9e1 100755
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -1059,6 +1059,9 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
case LLAssetType::AT_BODYPART:
applyListViewFilter(LVIT_BODYPART);
break;
+ case LLAssetType::AT_GESTURE:
+ applyListViewFilter(LVIT_GESTURES);
+ break;
case LLAssetType::AT_CLOTHING:
default:
applyListViewFilter(LVIT_CLOTHING);
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 30870daf40..841bb4337a 100755
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -80,6 +80,7 @@ public:
{
LVIT_ALL = 0,
LVIT_CLOTHING,
+ LVIT_GESTURES,
LVIT_BODYPART,
LVIT_ATTACHMENT,
LVIT_SHAPE,
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 5977d558d3..6b86459d8f 100755
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -85,6 +85,8 @@ static const std::string RECENT_TAB_NAME = "recent_panel";
static const std::string BLOCKED_TAB_NAME = "blocked_panel"; // blocked avatars
static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
+const S32 BASE_MAX_AGENT_GROUPS = 42;
+const S32 PREMIUM_MAX_AGENT_GROUPS = 60;
extern S32 gMaxAgentGroups;
@@ -585,6 +587,7 @@ BOOL LLPanelPeople::postBuild()
getChild<LLFilterEditor>("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
getChild<LLFilterEditor>("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
getChild<LLFilterEditor>("fbc_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
+ getChild<LLTextBox>("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this));
mTabContainer = getChild<LLTabContainer>("tabs");
mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2));
@@ -902,8 +905,11 @@ void LLPanelPeople::updateButtons()
LLPanel* groups_panel = mTabContainer->getCurrentPanel();
groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); // a real group selected
- groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.size()));
- groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d",(gMaxAgentGroups-gAgent.mGroups.size())));
+
+ U32 groups_count = gAgent.mGroups.size();
+ U32 groups_ramaining = gMaxAgentGroups > groups_count ? gMaxAgentGroups - groups_count : 0;
+ groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[COUNT]", llformat("%d", groups_count));
+ groups_panel->getChild<LLUICtrl>("groupcount")->setTextArg("[REMAINING]", llformat("%d", groups_ramaining));
}
else
{
@@ -1114,6 +1120,14 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)
}
}
+void LLPanelPeople::onGroupLimitInfo()
+{
+ LLSD args;
+ args["MAX_BASIC"] = BASE_MAX_AGENT_GROUPS;
+ args["MAX_PREMIUM"] = PREMIUM_MAX_AGENT_GROUPS;
+ LLNotificationsUtil::add("GroupLimitInfo", args);
+}
+
void LLPanelPeople::onTabSelected(const LLSD& param)
{
std::string tab_name = getChild<LLPanel>(param.asString())->getName();
@@ -1312,8 +1326,12 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)
}
else if (chosen_item == "view_icons")
{
- mAllFriendList->toggleIcons();
- mOnlineFriendList->toggleIcons();
+ std::string param = mAllFriendList->getIconParamName();
+ gSavedSettings.setBOOL(param, !(gSavedSettings.getBOOL(param) && !gSavedSettings.getBOOL("GlobalShowIconsOverride")));
+ gSavedSettings.setBOOL("GlobalShowIconsOverride", (!gSavedSettings.getBOOL(param) && gSavedSettings.getBOOL("GlobalShowIconsOverride")));
+ gSavedSettings.setBOOL(mOnlineFriendList->getIconParamName(), gSavedSettings.getBOOL(param));
+ mAllFriendList->setIconsVisible(gSavedSettings.getBOOL(param));
+ mOnlineFriendList->setIconsVisible(gSavedSettings.getBOOL(param));
}
else if (chosen_item == "view_permissions")
{
@@ -1349,7 +1367,10 @@ void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata)
}
else if (chosen_item == "view_icons")
{
- mNearbyList->toggleIcons();
+ std::string param = mNearbyList->getIconParamName();
+ gSavedSettings.setBOOL(param, !(gSavedSettings.getBOOL(param) && !gSavedSettings.getBOOL("GlobalShowIconsOverride")));
+ gSavedSettings.setBOOL("GlobalShowIconsOverride", (!gSavedSettings.getBOOL(param) && gSavedSettings.getBOOL("GlobalShowIconsOverride")));
+ mNearbyList->setIconsVisible(gSavedSettings.getBOOL(param));
}
else if (chosen_item == "sort_distance")
{
@@ -1368,6 +1389,8 @@ bool LLPanelPeople::onNearbyViewSortMenuItemCheck(const LLSD& userdata)
return sort_order == E_SORT_BY_NAME;
if (item == "sort_distance")
return sort_order == E_SORT_BY_DISTANCE;
+ if (item == "view_icons")
+ return gSavedSettings.getBOOL(mNearbyList->getIconParamName()) && !gSavedSettings.getBOOL("GlobalShowIconsOverride");
return false;
}
@@ -1386,7 +1409,10 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata)
}
else if (chosen_item == "view_icons")
{
- mRecentList->toggleIcons();
+ std::string param = mRecentList->getIconParamName();
+ gSavedSettings.setBOOL(param, !(gSavedSettings.getBOOL(param) && !gSavedSettings.getBOOL("GlobalShowIconsOverride")));
+ gSavedSettings.setBOOL("GlobalShowIconsOverride", (!gSavedSettings.getBOOL(param) && gSavedSettings.getBOOL("GlobalShowIconsOverride")));
+ mRecentList->setIconsVisible(gSavedSettings.getBOOL(param));
}
}
@@ -1399,6 +1425,8 @@ bool LLPanelPeople::onFriendsViewSortMenuItemCheck(const LLSD& userdata)
return sort_order == E_SORT_BY_NAME;
if (item == "sort_status")
return sort_order == E_SORT_BY_STATUS;
+ if (item == "view_icons")
+ return gSavedSettings.getBOOL(mAllFriendList->getIconParamName()) && !gSavedSettings.getBOOL("GlobalShowIconsOverride");
return false;
}
@@ -1412,6 +1440,8 @@ bool LLPanelPeople::onRecentViewSortMenuItemCheck(const LLSD& userdata)
return sort_order == E_SORT_BY_MOST_RECENT;
if (item == "sort_name")
return sort_order == E_SORT_BY_NAME;
+ if (item == "view_icons")
+ return gSavedSettings.getBOOL(mRecentList->getIconParamName()) && !gSavedSettings.getBOOL("GlobalShowIconsOverride");
return false;
}
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index c1d7a134fa..eb7e76a772 100755
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -93,6 +93,7 @@ private:
// UI callbacks
void onFilterEdit(const std::string& search_string);
+ void onGroupLimitInfo();
void onTabSelected(const LLSD& param);
void onAddFriendButtonClicked();
void onAddFriendWizButtonClicked();
diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp
index d73a5b402e..55c09d85ea 100755
--- a/indra/newview/llpanelpicks.cpp
+++ b/indra/newview/llpanelpicks.cpp
@@ -432,7 +432,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)
mNoPicks = !mPicksList->size();
}
- else if(APT_CLASSIFIEDS == type)
+ else if((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type))
{
LLAvatarClassifieds* c_info = static_cast<LLAvatarClassifieds*>(data);
if(c_info && getAvatarId() == c_info->target_id)
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 4bcd932d4b..a9a0c30e26 100755
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -921,7 +921,12 @@ void LLPanelPlaces::onBackButtonClicked()
void LLPanelPlaces::togglePickPanel(BOOL visible)
{
if (mPickPanel)
+ {
mPickPanel->setVisible(visible);
+ mPlaceProfile->setVisible(!visible);
+ updateVerbs();
+ }
+
}
void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible)
@@ -1141,16 +1146,21 @@ void LLPanelPlaces::updateVerbs()
bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE;
bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE;
+ bool is_pick_panel_visible = false;
+ if(mPickPanel)
+ {
+ is_pick_panel_visible = mPickPanel->isInVisibleChain();
+ }
bool have_3d_pos = ! mPosGlobal.isExactlyZero();
- mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn);
- mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn);
+ mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
+ mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
mOverflowBtn->setVisible(is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);
mEditBtn->setVisible(mPlaceInfoType == LANDMARK_INFO_TYPE && !isLandmarkEditModeOn);
mSaveBtn->setVisible(isLandmarkEditModeOn);
mCancelBtn->setVisible(isLandmarkEditModeOn);
mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn);
- mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn);
+ mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible);
mPlaceInfoBtn->setEnabled(!is_create_landmark_visible && !isLandmarkEditModeOn && have_3d_pos);
diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
index ac9a31ce4e..109013498e 100755
--- a/indra/newview/llpaneltopinfobar.cpp
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -313,14 +313,11 @@ void LLPanelTopInfoBar::updateParcelIcons()
bool allow_damage = vpm->allowAgentDamage(agent_region, current_parcel);
bool see_avs = current_parcel->getSeeAVs();
- bool is_parcel_owner = (gAgent.getID() == current_parcel->getOwnerID());
- bool allow_group_modify = (gAgent.isInGroup(current_parcel->getGroupID()) && current_parcel->getAllowGroupModify());
-
// Most icons are "block this ability"
mParcelIcon[VOICE_ICON]->setVisible( !allow_voice );
mParcelIcon[FLY_ICON]->setVisible( !allow_fly );
mParcelIcon[PUSH_ICON]->setVisible( !allow_push );
- mParcelIcon[BUILD_ICON]->setVisible( !allow_build && !is_parcel_owner && !allow_group_modify );
+ mParcelIcon[BUILD_ICON]->setVisible( !allow_build );
mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage );
mDamageText->setVisible(allow_damage);
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index 75e0ed3741..d86a8b4480 100755
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -131,7 +131,7 @@ protected:
{
bp_selected = true;
}
- else if (type == LLAssetType::AT_OBJECT)
+ else if (type == LLAssetType::AT_OBJECT || type == LLAssetType::AT_GESTURE)
{
attachments_selected = true;
}
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 1bbb22416d..67832c5994 100755
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -1391,6 +1391,8 @@ void LLLiveLSLEditor::buildExperienceList()
else
{
mExperiences->setEnabled(TRUE);
+ mExperiences->sortByName(TRUE);
+ mExperiences->setCurrentByIndex(mExperiences->getCurrentIndex());
getChild<LLButton>("view_profile")->setVisible(TRUE);
}
}
@@ -2621,8 +2623,12 @@ void LLLiveLSLEditor::onLoad(void* userdata)
void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
{
LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
- self->mCloseAfterSave = close_after_save;
- self->saveIfNeeded();
+ if(self)
+ {
+ self->mCloseAfterSave = close_after_save;
+ self->mScriptEd->mErrorList->setCommentText("");
+ self->saveIfNeeded();
+ }
}
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index f91a18d8d3..c8cf0faa15 100755
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -618,4 +618,5 @@ void LLPreviewTexture::setObjectID(const LLUUID& object_id)
mAssetStatus = PREVIEW_ASSET_UNLOADED;
loadAsset();
}
+ refreshFromItem();
}
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 4fafbf917b..55bcb3dc65 100755
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2127,7 +2127,7 @@ void LLSelectMgr::selectionRemoveMaterial()
{
LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
LLMaterialMgr::getInstance()->remove(object->getID(),face);
- object->setTEMaterialParams(face, NULL);
+ object->setTEMaterialParams(face, NULL, FALSE);
}
return true;
}
@@ -4950,6 +4950,7 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
ESendType send_type)
{
LLSelectNode* node;
+ LLSelectNode* linkset_root = NULL;
LLViewerRegion* last_region;
LLViewerRegion* current_region;
@@ -4957,6 +4958,8 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
S32 packets_sent = 0;
S32 objects_in_this_packet = 0;
+ bool link_operation = message_name == "ObjectLink";
+
//clear update override data (allow next update through)
struct f : public LLSelectedNodeFunctor
{
@@ -5065,6 +5068,12 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
&& (! gMessageSystem->isSendFull(NULL))
&& (objects_in_this_packet < MAX_OBJECTS_PER_PACKET))
{
+ if (link_operation && linkset_root == NULL)
+ {
+ // linksets over 254 will be split into multiple messages,
+ // but we need to provide same root for all messages or we will get separate linksets
+ linkset_root = node;
+ }
// add another instance of the body of the data
(*pack_body)(node, user_data);
// do any related logging
@@ -5093,6 +5102,22 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name,
gMessageSystem->newMessage(message_name.c_str());
(*pack_header)(user_data);
+ if (linkset_root != NULL)
+ {
+ if (current_region != last_region)
+ {
+ // root should be in one region with the child, reset it
+ linkset_root = NULL;
+ }
+ else
+ {
+ // add root instance into new message
+ (*pack_body)(linkset_root, user_data);
+ ++objects_sent;
+ ++objects_in_this_packet;
+ }
+ }
+
// don't move to the next object, we still need to add the
// body data.
}
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 17ecfab4fb..2548d730f0 100755
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -370,18 +370,25 @@ void LLSidepanelTaskInfo::refresh()
// Update creator text field
getChildView("Creator:")->setEnabled(TRUE);
+
std::string creator_name;
- LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name);
+ LLUUID creator_id;
+ LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name);
- getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
- getChildView("Creator Name")->setEnabled(TRUE);
+ if(creator_id != mCreatorID )
+ {
+ mDACreatorName->setValue(creator_name);
+ mCreatorID = creator_id;
+ }
+ mDACreatorName->setEnabled(TRUE);
// Update owner text field
getChildView("Owner:")->setEnabled(TRUE);
std::string owner_name;
- const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_name);
- if (mOwnerID.isNull())
+ LLUUID owner_id;
+ const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
+ if (owner_id.isNull())
{
if (LLSelectMgr::getInstance()->selectIsGroupOwned())
{
@@ -402,7 +409,12 @@ void LLSidepanelTaskInfo::refresh()
}
}
}
- getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
+
+ if(owner_id.isNull() || (owner_id != mOwnerID))
+ {
+ mDAOwnerName->setValue(owner_name);
+ mOwnerID = owner_id;
+ }
getChildView("Owner Name")->setEnabled(TRUE);
// update group text field
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index 728fc69723..a8e012bfa1 100755
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -271,7 +271,14 @@ LLSLURL::LLSLURL(const std::string& slurl)
// at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z
// are collectively optional
// are optional
+
mRegion = LLURI::unescape(path_array[0].asString());
+
+ if(LLStringUtil::containsNonprintable(mRegion))
+ {
+ LLStringUtil::stripNonprintable(mRegion);
+ }
+
path_array.erase(0);
// parse the x, y, and optionally z
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 0ae8a338e0..8561a89ae5 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -195,7 +195,8 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail
// Stop shining animation.
mShineAnimTimer.stop();
mSnapshotDelayTimer.start();
- mSnapshotDelayTimer.setTimerExpirySec(delay);
+ mSnapshotDelayTimer.resetWithExpiry(delay);
+
mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
@@ -462,7 +463,10 @@ void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_pare
if (old_rect.getWidth() != width || old_rect.getHeight() != height)
{
LL_DEBUGS() << "window reshaped, updating thumbnail" << LL_ENDL;
- updateSnapshot(TRUE);
+ if (mViewContainer && mViewContainer->isInVisibleChain())
+ {
+ updateSnapshot(TRUE);
+ }
}
}
@@ -670,10 +674,27 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
return FALSE;
}
- // If we're in freeze-frame mode and camera has moved, update snapshot.
+ if (previewp->mSnapshotDelayTimer.getStarted()) // Wait for a snapshot delay timer
+ {
+ if (!previewp->mSnapshotDelayTimer.hasExpired())
+ {
+ return FALSE;
+ }
+ previewp->mSnapshotDelayTimer.stop();
+ }
+
+ if (LLToolCamera::getInstance()->hasMouseCapture()) // Hide full-screen preview while camming, either don't take snapshots while ALT-zoom active
+ {
+ previewp->setVisible(FALSE);
+ return FALSE;
+ }
+
+ // If we're in freeze-frame and/or auto update mode and camera has moved, update snapshot.
LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin();
LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion();
- if (previewp->mForceUpdateSnapshot || (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview &&
+ if (previewp->mForceUpdateSnapshot ||
+ (((gSavedSettings.getBOOL("AutoSnapshot") && LLView::isAvailable(previewp->mViewContainer)) ||
+ (gSavedSettings.getBOOL("FreezeTime") && previewp->mAllowFullScreenPreview)) &&
(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f)))
{
previewp->mCameraPos = new_camera_pos;
@@ -688,11 +709,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
previewp->mForceUpdateSnapshot = FALSE;
}
- // see if it's time yet to snap the shot and bomb out otherwise.
- previewp->mSnapshotActive =
- (previewp->mSnapshotDelayTimer.getStarted() && previewp->mSnapshotDelayTimer.hasExpired())
- && !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active
- if (!previewp->mSnapshotActive && previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate())
+ if (previewp->getSnapshotUpToDate() && previewp->getThumbnailUpToDate())
{
return FALSE;
}
@@ -706,6 +723,8 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
previewp->mPreviewImage = new LLImageRaw;
}
+ previewp->mSnapshotActive = TRUE;
+
previewp->setVisible(FALSE);
previewp->setEnabled(FALSE);
@@ -734,40 +753,9 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
// Full size preview is set: get the decoded image result and save it for animation
if (gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview)
{
- // Get the decoded version of the formatted image
- previewp->getEncodedImage();
-
- // We need to scale that a bit for display...
- LLPointer<LLImageRaw> scaled = new LLImageRaw(
- previewp->mPreviewImageEncoded->getData(),
- previewp->mPreviewImageEncoded->getWidth(),
- previewp->mPreviewImageEncoded->getHeight(),
- previewp->mPreviewImageEncoded->getComponents());
-
- if (!scaled->isBufferInvalid())
- {
- // leave original image dimensions, just scale up texture buffer
- if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
- {
- // go ahead and shrink image to appropriate power of 2 for display
- scaled->biasedScaleToPowerOfTwo(1024);
- previewp->setImageScaled(TRUE);
- }
- else
- {
- // expand image but keep original image data intact
- scaled->expandToPowerOfTwo(1024, FALSE);
- }
-
- previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
- LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
- gGL.getTexUnit(0)->bind(curr_preview_image);
- curr_preview_image->setFilteringOption(previewp->getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
- curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
-
- previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
- }
+ previewp->prepareFreezeFrame();
}
+
// The snapshot is updated now...
previewp->mSnapshotUpToDate = TRUE;
@@ -777,7 +765,6 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
}
previewp->getWindow()->decBusyCount();
previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame") && previewp->mAllowFullScreenPreview); // only show fullscreen preview when in freeze frame mode
- previewp->mSnapshotDelayTimer.stop();
previewp->mSnapshotActive = FALSE;
LL_DEBUGS() << "done creating snapshot" << LL_ENDL;
}
@@ -796,6 +783,47 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
return TRUE;
}
+void LLSnapshotLivePreview::prepareFreezeFrame()
+{
+ // Get the decoded version of the formatted image
+ getEncodedImage();
+
+ // We need to scale that a bit for display...
+ LLPointer<LLImageRaw> scaled = new LLImageRaw(
+ mPreviewImageEncoded->getData(),
+ mPreviewImageEncoded->getWidth(),
+ mPreviewImageEncoded->getHeight(),
+ mPreviewImageEncoded->getComponents());
+
+ if (!scaled->isBufferInvalid())
+ {
+ // leave original image dimensions, just scale up texture buffer
+ if (mPreviewImageEncoded->getWidth() > 1024 || mPreviewImageEncoded->getHeight() > 1024)
+ {
+ // go ahead and shrink image to appropriate power of 2 for display
+ scaled->biasedScaleToPowerOfTwo(1024);
+ setImageScaled(TRUE);
+ }
+ else
+ {
+ // expand image but keep original image data intact
+ scaled->expandToPowerOfTwo(1024, FALSE);
+ }
+
+ mViewerImage[mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
+ LLPointer<LLViewerTexture> curr_preview_image = mViewerImage[mCurImageIndex];
+ gGL.getTexUnit(0)->bind(curr_preview_image);
+ curr_preview_image->setFilteringOption(getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
+ curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+
+ if (gSavedSettings.getBOOL("UseFreezeFrame") && mAllowFullScreenPreview)
+ {
+ mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
+ }
+ }
+}
+
S32 LLSnapshotLivePreview::getEncodedImageWidth() const
{
S32 width = getWidth();
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index fed33bf37c..57e5d83f8e 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -119,7 +119,7 @@ public:
void generateThumbnailImage(BOOL force_update = FALSE) ;
void resetThumbnailImage() { mThumbnailImage = NULL ; }
void drawPreviewRect(S32 offset_x, S32 offset_y) ;
-
+ void prepareFreezeFrame();
LLViewerTexture* getBigThumbnailImage();
S32 getBigThumbnailWidth() const { return mBigThumbnailWidth ; }
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 7867e1573c..44c980c96f 100755
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -547,21 +547,8 @@ void LLSpeakerMgr::updateSpeakerList()
// For groups, we need to hit the group manager.
// Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail.
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id);
- F32 large_group_delay = 0.f;
- if (gdatap)
- {
- //This is a viewer-side bandaid for maint-4414 it does not fix the core issue.
- large_group_delay = (F32)(gdatap->mMemberCount / 5000);
- }
-
- const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout") + large_group_delay;
-
- if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout))
- {
- // Request the data the first time around
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id);
- }
- else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())
+
+ if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())
{
// Add group members when we get the complete list (note: can take a while before we get that list)
LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin();
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index d2050aec3e..965aad517d 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -421,9 +421,7 @@ bool idle_startup()
gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
gSavedSettings.setString("LastGPUString", thisGPU);
- // load dynamic GPU/feature tables from website (S3)
- LLFeatureManager::getInstance()->fetchHTTPTables();
-
+
std::string xml_file = LLUI::locateSkin("xui_version.xml");
LLXMLNodePtr root;
bool xml_ok = false;
@@ -3238,6 +3236,23 @@ bool process_login_success_response()
LLStringUtil::trim(gDisplayName);
}
}
+ std::string first_name;
+ if(response.has("first_name"))
+ {
+ first_name = response["first_name"].asString();
+ LLStringUtil::replaceChar(first_name, '"', ' ');
+ LLStringUtil::trim(first_name);
+ gAgentUsername = first_name;
+ }
+
+ if(response.has("last_name") && !gAgentUsername.empty() && (gAgentUsername != "Resident"))
+ {
+ std::string last_name = response["last_name"].asString();
+ LLStringUtil::replaceChar(last_name, '"', ' ');
+ LLStringUtil::trim(last_name);
+ gAgentUsername = gAgentUsername + " " + last_name;
+ }
+
if(gDisplayName.empty())
{
if(response.has("first_name"))
@@ -3258,6 +3273,7 @@ bool process_login_success_response()
gDisplayName += text;
}
}
+
if(gDisplayName.empty())
{
gDisplayName.assign(gUserCredential->asString());
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index ef852bc905..bcdf8360ed 100755
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1544,17 +1544,20 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
{
std::string dirname = mTexturesDirName + delem + subdirs[i];
LL_INFOS() << "Deleting files in directory: " << dirname << LL_ENDL;
- gDirUtilp->deleteFilesInDir(dirname, mask);
if (purge_directories)
{
- LLFile::rmdir(dirname);
+ gDirUtilp->deleteDirAndContents(dirname);
+ }
+ else
+ {
+ gDirUtilp->deleteFilesInDir(dirname, mask);
}
}
if (purge_directories)
{
gDirUtilp->deleteFilesInDir(mTexturesDirName, mask);
LLFile::rmdir(mTexturesDirName);
- }
+ }
}
mHeaderIDMap.clear();
mTexturesSizeMap.clear();
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 81fbc471b3..ff71028a9b 100755
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1013,13 +1013,10 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
// causing a dirty inventory) and we can do an update, stall the user
// while fetching the inventory.
//
- // Note: fetch only if inventory is both dirty and not present since previously checked faces
- // could have requested new fetch for same item (removed inventory and marked as dirty=false).
- // Objects without listeners (dirty==true and inventory!=NULL. In this specific case - before
- // first fetch) shouldn't be updated either since we won't receive any changes.
- if (hit_obj->isInventoryDirty() && hit_obj->getInventoryRoot() == NULL)
+ // Fetch if inventory is dirty and listener is present (otherwise we will not receive update)
+ if (hit_obj->isInventoryDirty() && hit_obj->hasInventoryListeners())
{
- hit_obj->fetchInventoryFromServer();
+ hit_obj->requestInventory();
LLSD args;
args["ERROR_MESSAGE"] = "Unable to add texture.\nPlease wait a few seconds and try again.";
LLNotificationsUtil::add("ErrorMessage", args);
@@ -1099,10 +1096,12 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
{
hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
}
- // Force the object to update its refetch its inventory so it has this texture.
- hit_obj->fetchInventoryFromServer();
- // TODO: Check to see if adding the item was successful; if not, then
- // we should return false here.
+ // Force the object to update and refetch its inventory so it has this texture.
+ hit_obj->dirtyInventory();
+ hit_obj->requestInventory();
+ // TODO: Check to see if adding the item was successful; if not, then
+ // we should return false here. This will requre a separate listener
+ // since without listener, we have no way to receive update
}
return TRUE;
}
@@ -1155,8 +1154,7 @@ void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,
}
LLSculptParams sculpt_params;
- sculpt_params.setSculptTexture(asset_id);
- sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH);
+ sculpt_params.setSculptTexture(asset_id, LL_SCULPT_TYPE_MESH);
hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
dialog_refresh_all();
diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp
index cad5769042..8a61114852 100755
--- a/indra/newview/llurllineeditorctrl.cpp
+++ b/indra/newview/llurllineeditorctrl.cpp
@@ -84,7 +84,7 @@ void LLURLLineEditor::copyEscapedURLToClipboard()
const std::string unescaped_text = wstring_to_utf8str(mText.getWString().substr(left_pos, length));
LLWString text_to_copy;
// *HACK: Because LLSLURL is currently broken we cannot use it to check if unescaped_text is a valid SLURL (see EXT-8335).
- if (LLStringUtil::startsWith(unescaped_text, "http://")) // SLURL
+ if (LLStringUtil::startsWith(unescaped_text, "http://") || LLStringUtil::startsWith(unescaped_text, "secondlife://")) // SLURL
text_to_copy = utf8str_to_wstring(LLWeb::escapeURL(unescaped_text));
else // human-readable location
text_to_copy = utf8str_to_wstring(unescaped_text);
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 6803adfaa2..1ce42e97b8 100755
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -248,6 +248,7 @@ public:
void setHomeURL(const std::string& home_url, const std::string& mime_type = LLStringUtil::null) { mHomeURL = home_url; mHomeMimeType = mime_type;};
void clearCache();
void setPageZoomFactor( double factor );
+ double getPageZoomFactor() {return mZoomFactor;}
std::string getMimeType() { return mMimeType; }
void scaleMouse(S32 *mouse_x, S32 *mouse_y);
void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 2505ae6a9c..38d62dee5e 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -57,6 +57,7 @@
#include "llfacebookconnect.h"
#include "llfilepicker.h"
#include "llfirstuse.h"
+#include "llfloaterabout.h"
#include "llfloaterbuy.h"
#include "llfloaterbuycontents.h"
#include "llbuycurrencyhtml.h"
@@ -2139,6 +2140,22 @@ class LLAdvancedCheckShowObjectUpdates : public view_listener_t
+///////////////////////
+// CHECK FOR UPDATES //
+///////////////////////
+
+
+
+class LLAdvancedCheckViewerUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterAboutUtil::checkUpdatesAndNotify();
+ return true;
+ }
+};
+
+
////////////////////
// COMPRESS IMAGE //
////////////////////
@@ -7140,11 +7157,10 @@ void handle_selected_texture_info(void*)
{
msg.append( llformat("%d ", (S32)(it->second[i])));
}
-
- LLSD args;
- args["MESSAGE"] = msg;
- LLNotificationsUtil::add("SystemMessage", args);
}
+ LLSD args;
+ args["MESSAGE"] = msg;
+ LLNotificationsUtil::add("SystemMessage", args);
}
}
@@ -8920,6 +8936,7 @@ void initialize_menus()
// Advanced (toplevel)
view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates");
view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates");
+ view_listener_t::addMenu(new LLAdvancedCheckViewerUpdates(), "Advanced.CheckViewerUpdates");
view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");
view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");
view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 886725be79..e570657cf9 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -57,6 +57,7 @@
#include "llcallingcard.h"
#include "llbuycurrencyhtml.h"
#include "llfirstuse.h"
+#include "llfloaterbump.h"
#include "llfloaterbuyland.h"
#include "llfloaterland.h"
#include "llfloaterregioninfo.h"
@@ -2349,7 +2350,8 @@ static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::s
LLNotificationsUtil::add("GodMessage", args);
// Treat like a system message and put in chat history.
- chat.mText = av_name.getCompleteName() + ": " + message;
+ chat.mSourceType = CHAT_SOURCE_SYSTEM;
+ chat.mText = message;
LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
if (nearby_chat)
@@ -2860,6 +2862,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
case IM_FROM_TASK:
{
+
if (is_do_not_disturb && !is_owned_by_me)
{
return;
@@ -2943,17 +2946,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
payload["from_id"] = from_id;
payload["slurl"] = location;
payload["name"] = name;
- std::string session_name;
+
if (from_group)
{
payload["group_owned"] = "true";
}
- LLNotification::Params params("ServerObjectMessage");
- params.substitutions = substitutions;
- params.payload = payload;
-
- LLPostponedNotification::add<LLPostponedServerObjectNotification>(params, from_id, from_group);
+ LLNotificationsUtil::add("ServerObjectMessage", substitutions, payload);
}
break;
@@ -3789,11 +3788,15 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
}
}
- LLSD msg_notify = LLSD(LLSD::emptyMap());
- msg_notify["session_id"] = LLUUID();
- msg_notify["from_id"] = chat.mFromID;
- msg_notify["source_type"] = chat.mSourceType;
- on_new_message(msg_notify);
+ if (mesg != "")
+ {
+ LLSD msg_notify = LLSD(LLSD::emptyMap());
+ msg_notify["session_id"] = LLUUID();
+ msg_notify["from_id"] = chat.mFromID;
+ msg_notify["source_type"] = chat.mSourceType;
+ on_new_message(msg_notify);
+ }
+
}
}
@@ -6263,6 +6266,11 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use
gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3));
}
}
+ LLFloaterBump* bumps_floater = LLFloaterBump::getInstance();
+ if(bumps_floater && bumps_floater->isInVisibleChain())
+ {
+ bumps_floater->populateCollisionList();
+ }
}
void process_frozen_message(LLMessageSystem *msgsystem, void **user_data)
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index ac3f07fcd8..c4d3829ee9 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2840,6 +2840,11 @@ void LLViewerObject::clearInventoryListeners()
mInventoryCallbacks.clear();
}
+bool LLViewerObject::hasInventoryListeners()
+{
+ return !mInventoryCallbacks.empty();
+}
+
void LLViewerObject::requestInventory()
{
if(mInventoryDirty && mInventory && !mInventoryCallbacks.empty())
@@ -2847,15 +2852,20 @@ void LLViewerObject::requestInventory()
mInventory->clear(); // will deref and delete entries
delete mInventory;
mInventory = NULL;
- mInventoryDirty = FALSE; //since we are going to request it now
}
+
if(mInventory)
{
+ // inventory is either up to date or doesn't has a listener
+ // if it is dirty, leave it this way in case we gain a listener
doInventoryCallback();
}
- // throw away duplicate requests
else
{
+ // since we are going to request it now
+ mInventoryDirty = FALSE;
+
+ // Note: throws away duplicate requests
fetchInventoryFromServer();
}
}
@@ -2865,8 +2875,6 @@ void LLViewerObject::fetchInventoryFromServer()
if (!mInventoryPending)
{
delete mInventory;
- mInventory = NULL;
- mInventoryDirty = FALSE;
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_RequestTaskInventory);
msg->nextBlockFast(_PREHASH_AgentData);
@@ -2885,6 +2893,9 @@ struct LLFilenameAndTask
{
LLUUID mTaskID;
std::string mFilename;
+
+ // for sequencing in case of multiple updates
+ S16 mSerial;
#ifdef _DEBUG
static S32 sCount;
LLFilenameAndTask()
@@ -2920,9 +2931,17 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
return;
}
- msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);
LLFilenameAndTask* ft = new LLFilenameAndTask;
ft->mTaskID = task_id;
+ // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update
+ msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial);
+
+ if (ft->mSerial < object->mInventorySerialNum)
+ {
+ // viewer did some changes to inventory that were not saved yet.
+ LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL;
+ object->mInventorySerialNum = ft->mSerial;
+ }
std::string unclean_filename;
msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);
@@ -2962,9 +2981,13 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
{
LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data;
LLViewerObject* object = NULL;
- if(ft && (0 == error_code) &&
- (object = gObjectList.findObject(ft->mTaskID)))
+
+ if (ft
+ && (0 == error_code)
+ && (object = gObjectList.findObject(ft->mTaskID))
+ && ft->mSerial >= object->mInventorySerialNum)
{
+ object->mInventorySerialNum = ft->mSerial;
if (object->loadTaskInvFile(ft->mFilename))
{
@@ -2995,7 +3018,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
}
else
{
- // This Occurs When to requests were made, and the first one
+ // This Occurs When two requests were made, and the first one
// has already handled it.
LL_DEBUGS() << "Problem loading task inventory. Return code: "
<< error_code << LL_ENDL;
@@ -4637,7 +4660,7 @@ S32 LLViewerObject::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID
return retval;
}
-S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
+S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
S32 retval = 0;
const LLTextureEntry *tep = getTE(te);
@@ -4647,13 +4670,14 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri
return 0;
}
- retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams);
+ setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null);
+ setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null);
+
+ retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams, isInitFromServer);
LL_DEBUGS("Material") << "Changing material params for te " << (S32)te
<< ", object " << mID
<< " (" << retval << ")"
<< LL_ENDL;
- setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null);
- setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null);
refreshMaterials();
return retval;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 05c87c153b..65d6f8225f 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -330,7 +330,7 @@ public:
/*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags );
/*virtual*/ S32 setTEGlow(const U8 te, const F32 glow);
/*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
- /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
+ /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
// Used by Materials update functions to properly kick off rebuilds
// of VBs etc when materials updates require changes.
@@ -436,8 +436,8 @@ public:
void removeInventoryListener(LLVOInventoryListener* listener);
BOOL isInventoryPending() { return mInventoryPending; }
void clearInventoryListeners();
+ bool hasInventoryListeners();
void requestInventory();
- void fetchInventoryFromServer();
static void processTaskInv(LLMessageSystem* msg, void** user_data);
void removeInventory(const LLUUID& item_id);
@@ -593,6 +593,9 @@ private:
static void initObjectDataMap();
+ // forms task inventory request if none are pending
+ void fetchInventoryFromServer();
+
public:
//
// Viewer-side only types - use the LL_PCODE_APP mask.
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index f60829e9e8..24a6758312 100755
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -60,6 +60,7 @@
#include "llfeaturemanager.h"
#include "llviewernetwork.h"
#include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived
+#include "llsdserialize.h"
namespace LLStatViewer
{
@@ -616,8 +617,10 @@ void send_stats()
body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames");
body["MinimalSkin"] = false;
-
+
LLViewerStats::getInstance()->addToMessage(body);
+
+ LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL;
LLHTTPClient::post(url, body, new ViewerStatsResponder());
LLViewerStats::instance().getRecording().resume();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f753448770..b97a1bde99 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -160,6 +160,9 @@ const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f;
const S32 MORPH_MASK_REQUESTED_DISCARD = 0;
+const F32 MAX_STANDOFF_FROM_ORIGIN = 3;
+const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32;
+
// Discard level at which to switch to baked textures
// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB
const S32 SWITCH_TO_BAKED_DISCARD = 5;
@@ -2132,7 +2135,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
// animate the character
// store off last frame's root position to be consistent with camera position
- LLVector3 root_pos_last = mRoot->getWorldPosition();
+ mLastRootPos = mRoot->getWorldPosition();
BOOL detailed_update = updateCharacter(agent);
static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
@@ -2150,7 +2153,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
idleUpdateWindEffect();
}
- idleUpdateNameTag( root_pos_last );
+ idleUpdateNameTag( mLastRootPos );
idleUpdateRenderCost();
}
@@ -6080,10 +6083,10 @@ void LLVOAvatar::getOffObject()
{
return;
}
-
+
LLViewerObject* sit_object = (LLViewerObject*)getParent();
- if (sit_object)
+ if (sit_object)
{
stopMotionFromSource(sit_object->getID());
LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE);
@@ -6100,9 +6103,19 @@ void LLVOAvatar::getOffObject()
}
// assumes that transform will not be updated with drawable still having a parent
+ // or that drawable had no parent from the start
LLVector3 cur_position_world = mDrawable->getWorldPosition();
LLQuaternion cur_rotation_world = mDrawable->getWorldRotation();
+ if (mLastRootPos.length() >= MAX_STANDOFF_FROM_ORIGIN
+ && (cur_position_world.length() < MAX_STANDOFF_FROM_ORIGIN
+ || dist_vec(cur_position_world, mLastRootPos) > MAX_STANDOFF_DISTANCE_CHANGE))
+ {
+ // Most likely drawable got updated too early or some updates were missed - we got relative position to non-existing parent
+ // restore coordinates from cache
+ cur_position_world = mLastRootPos;
+ }
+
// set *local* position based on last *world* position, since we're unparenting the avatar
mDrawable->mXform.setPosition(cur_position_world);
mDrawable->mXform.setRotation(cur_rotation_world);
@@ -6278,6 +6291,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
BOOL LLVOAvatar::isVisible() const
{
return mDrawable.notNull()
+ && (!mOrphaned || isSelf())
&& (mDrawable->isVisible() || mIsDummy);
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 1c3f4f2aa7..5b4379165a 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -869,6 +869,8 @@ public:
private:
// set this property only with LLVOAvatar::sitDown method
BOOL mIsSitting;
+ // position backup in case of missing data
+ LLVector3 mLastRootPos;
/** Hierarchy
** **
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 267061b83d..68713280c0 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1624,6 +1624,66 @@ static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies");
static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives");
static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
+bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
+{
+ bool regen_faces = false;
+
+ LLVolume *old_volumep, *new_volumep;
+ F32 old_lod, new_lod;
+ S32 old_num_faces, new_num_faces;
+
+ old_volumep = getVolume();
+ old_lod = old_volumep->getDetail();
+ old_num_faces = old_volumep->getNumFaces();
+ old_volumep = NULL;
+
+ {
+ LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
+ const LLVolumeParams &volume_params = getVolume()->getParams();
+ setVolume(volume_params, 0);
+ }
+
+ new_volumep = getVolume();
+ new_lod = new_volumep->getDetail();
+ new_num_faces = new_volumep->getNumFaces();
+ new_volumep = NULL;
+
+ if ((new_lod != old_lod) || mSculptChanged)
+ {
+ compiled = TRUE;
+ sNumLODChanges += new_num_faces;
+
+ if ((S32)getNumTEs() != getVolume()->getNumFaces())
+ {
+ setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
+ }
+
+ drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
+
+ {
+ LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
+ regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs();
+ if (regen_faces)
+ {
+ regenFaces();
+ }
+
+ if (mSculptChanged)
+ { //changes in sculpt maps can thrash an object bounding box without
+ //triggering a spatial group bounding box update -- force spatial group
+ //to update bounding boxes
+ LLSpatialGroup* group = mDrawable->getSpatialGroup();
+ if (group)
+ {
+ group->unbound();
+ }
+ }
+ }
+ }
+
+ return regen_faces;
+}
+
BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES);
@@ -1664,83 +1724,35 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
return TRUE; // No update to complete
}
- if (mVolumeChanged || mFaceMappingChanged )
+ if (mVolumeChanged || mFaceMappingChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
- compiled = TRUE;
+ bool was_regen_faces = false;
if (mVolumeChanged)
{
- LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
- LLVolumeParams volume_params = getVolume()->getParams();
- setVolume(volume_params, 0);
+ was_regen_faces = lodOrSculptChanged(drawable, compiled);
drawable->setState(LLDrawable::REBUILD_VOLUME);
}
-
+ else if (mSculptChanged || mLODChanged)
{
+ compiled = TRUE;
+ was_regen_faces = lodOrSculptChanged(drawable, compiled);
+ }
+
+ if (!was_regen_faces) {
LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
regenFaces();
- genBBoxes(FALSE);
}
+
+ genBBoxes(FALSE);
}
- else if ((mLODChanged) || (mSculptChanged))
+ else if (mLODChanged || mSculptChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
-
- LLVolume *old_volumep, *new_volumep;
- F32 old_lod, new_lod;
- S32 old_num_faces, new_num_faces ;
-
- old_volumep = getVolume();
- old_lod = old_volumep->getDetail();
- old_num_faces = old_volumep->getNumFaces() ;
- old_volumep = NULL ;
-
- {
- LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME);
- LLVolumeParams volume_params = getVolume()->getParams();
- setVolume(volume_params, 0);
- }
-
- new_volumep = getVolume();
- new_lod = new_volumep->getDetail();
- new_num_faces = new_volumep->getNumFaces() ;
- new_volumep = NULL ;
-
- if ((new_lod != old_lod) || mSculptChanged)
- {
- compiled = TRUE;
- sNumLODChanges += new_num_faces ;
-
- if((S32)getNumTEs() != getVolume()->getNumFaces())
- {
- setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
- }
-
- drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
-
- {
- LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES);
- if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs())
- {
- regenFaces();
- }
- genBBoxes(FALSE);
-
- if (mSculptChanged)
- { //changes in sculpt maps can thrash an object bounding box without
- //triggering a spatial group bounding box update -- force spatial group
- //to update bounding boxes
- LLSpatialGroup* group = mDrawable->getSpatialGroup();
- if (group)
- {
- group->unbound();
- }
- }
- }
- }
-
+ compiled = TRUE;
+ lodOrSculptChanged(drawable, compiled);
genBBoxes(FALSE);
}
// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
@@ -2010,7 +2022,7 @@ void LLVOVolume::setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLM
LLTextureEntry* texture_entry = pVol->getTE(te);
if (texture_entry && (texture_entry->getMaterialID() == pMaterialID))
{
- pVol->setTEMaterialParams(te, pMaterialParams);
+ pVol->setTEMaterialParams(te, pMaterialParams, FALSE);
}
}
}
@@ -2081,7 +2093,7 @@ bool LLVOVolume::notifyAboutCreatingTexture(LLViewerTexture *texture)
for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)
{
LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second);
- LLViewerObject::setTEMaterialParams(it->first, it->second);
+ LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE);
}
//clear wait-list
@@ -2158,7 +2170,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)
for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)
{
LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second);
- LLViewerObject::setTEMaterialParams(it->first, it->second);
+ LLViewerObject::setTEMaterialParams(it->first, it->second, FALSE);
}
//clear wait-list
@@ -2167,7 +2179,7 @@ bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)
return 0 != new_material.size();
}
-S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
+S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer)
{
LLMaterialPtr pMaterial = const_cast<LLMaterialPtr&>(pMaterialParams);
@@ -2264,7 +2276,7 @@ S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialPa
}
}
- S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial);
+ S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial, isInitFromServer);
LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterial) ? pMaterial->asLLSD() : LLSD("null")) << " res " << res
<< ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" )
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index bbaca316b0..ff7438ac09 100755
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -192,7 +192,7 @@ public:
static void setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID& pMaterialID, const LLMaterialPtr pMaterialParams, U32 te);
- /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
+ /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams, bool isInitFromServer);
/*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t);
/*virtual*/ S32 setTEScaleS(const U8 te, const F32 s);
/*virtual*/ S32 setTEScaleT(const U8 te, const F32 t);
@@ -339,6 +339,10 @@ protected:
void cleanUpMediaImpls();
void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;
void removeMediaImpl(S32 texture_index) ;
+
+private:
+ bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled);
+
public:
static S32 getRenderComplexityMax() {return mRenderComplexity_last;}
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index 1c3808ce68..f8981d0c51 100755
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -35,6 +35,7 @@
#include "llappearancemgr.h"
#include "llinventoryfunctions.h"
#include "llinventoryicon.h"
+#include "llgesturemgr.h"
#include "lltransutil.h"
#include "llviewerattachmenu.h"
#include "llvoavatarself.h"
@@ -55,7 +56,8 @@ bool LLFindOutfitItems::operator()(LLInventoryCategory* cat,
{
if((item->getType() == LLAssetType::AT_CLOTHING)
|| (item->getType() == LLAssetType::AT_BODYPART)
- || (item->getType() == LLAssetType::AT_OBJECT))
+ || (item->getType() == LLAssetType::AT_OBJECT)
+ || (item->getType() == LLAssetType::AT_GESTURE))
{
return TRUE;
}
@@ -491,6 +493,7 @@ LLWearableItemTypeNameComparator::LLWearableItemTypeNameComparator()
mWearableOrder[LLAssetType::AT_CLOTHING] = LLWearableTypeOrder(ORDER_RANK_1, false, false);
mWearableOrder[LLAssetType::AT_OBJECT] = LLWearableTypeOrder(ORDER_RANK_2, true, true);
mWearableOrder[LLAssetType::AT_BODYPART] = LLWearableTypeOrder(ORDER_RANK_3, false, true);
+ mWearableOrder[LLAssetType::AT_GESTURE] = LLWearableTypeOrder(ORDER_RANK_4, true, false);
}
void LLWearableItemTypeNameComparator::setOrder(LLAssetType::EType items_of_type, LLWearableItemTypeNameComparator::ETypeListOrder order_priority, bool sort_asset_items_by_name, bool sort_wearable_items_by_name)
@@ -989,6 +992,10 @@ void LLWearableItemsList::ContextMenu::updateMask(U32& mask, LLAssetType::EType
{
mask |= MASK_ATTACHMENT;
}
+ else if (at == LLAssetType::AT_GESTURE)
+ {
+ mask |= MASK_GESTURE;
+ }
else
{
mask |= MASK_UNKNOWN;
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
index e6788ab249..df4b1a8a50 100755
--- a/indra/newview/llwearableitemslist.h
+++ b/indra/newview/llwearableitemslist.h
@@ -310,6 +310,7 @@ public:
ORDER_RANK_1 = 1,
ORDER_RANK_2,
ORDER_RANK_3,
+ ORDER_RANK_4,
ORDER_RANK_UNKNOWN
};
@@ -419,7 +420,8 @@ public:
MASK_CLOTHING = 0x01,
MASK_BODYPART = 0x02,
MASK_ATTACHMENT = 0x04,
- MASK_UNKNOWN = 0x08,
+ MASK_GESTURE = 0x08,
+ MASK_UNKNOWN = 0x16,
};
/* virtual */ LLContextMenu* createMenu();
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index bfae142812..837b30586b 100755
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -383,6 +383,7 @@ void LLWorldMap::reloadItems(bool force)
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_MATURE_EVENT);
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_ADULT_EVENT);
LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE);
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE_ADULT);
}
}
diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml
index aa6bc53672..299322001b 100755
--- a/indra/newview/skins/default/xui/da/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/da/menu_viewer.xml
@@ -37,7 +37,7 @@
<menu_item_separator/>
<menu_item_call label="Profil for sted" name="Place Profile"/>
<menu_item_call label="Om land" name="About Land"/>
- <menu_item_call label="Region/Estate" name="Region/Estate"/>
+ <menu_item_call label="Region/Estate" name="RegionEstate"/>
<menu_item_call label="Køb dette land" name="Buy Land"/>
<menu_item_call label="Mit land" name="My Land"/>
<menu label="Vis" name="LandShow">
diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml
index 33b876bdb9..aad3b9d062 100755
--- a/indra/newview/skins/default/xui/da/notifications.xml
+++ b/indra/newview/skins/default/xui/da/notifications.xml
@@ -1311,9 +1311,6 @@ Prøv igen om lidt.
<notification name="NoValidCircuit">
Ingen gyldig kode for kredsløb.
</notification>
- <notification name="NoValidTimestamp">
- Ikke et gyldigt klokkeslæt.
- </notification>
<notification name="NoPendingConnection">
Kunne ikke skabe fast forbindelse.
</notification>
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index 1924ff4ec3..956530c990 100755
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Fliegen" name="Fly"/>
<menu_item_check label="Immer rennen" name="Always Run"/>
<menu_item_call label="Animation meines Avatars stoppen" name="Stop Animating My Avatar"/>
- <menu_item_call label="Gehen/Rennen/Fliegen..." name="Walk / run / fly"/>
+ <menu_item_call label="Gehen/Rennen/Fliegen..." name="WalkRunFly"/>
</menu>
<menu label="Status" name="Status">
<menu_item_check label="Abwesend" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Ortsprofil" name="Place Profile"/>
<menu_item_call label="Landinformationen" name="About Land"/>
- <menu_item_call label="Region/Grundbesitz" name="Region/Estate"/>
+ <menu_item_call label="Region/Grundbesitz" name="RegionEstate"/>
<menu_item_call label="Mein Landbesitz..." name="My Land"/>
<menu_item_call label="Dieses Land kaufen" name="Buy Land"/>
<menu label="Anzeigen" name="LandShow">
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 0b1c18cd51..fa7db0a8a3 100755
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -2802,9 +2802,6 @@ Versuchen Sie es in einigen Minuten erneut.
<notification name="NoValidCircuit">
Kein gültiger Verbindungscode.
</notification>
- <notification name="NoValidTimestamp">
- Kein gültiger Zeitstempel.
- </notification>
<notification name="NoPendingConnection">
Verbindung kann nicht hergestellt werden.
</notification>
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index 60f36770bb..ec87b3684e 100755
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -43,6 +43,14 @@
top_pad="5"
height="25"
width="180" />
+ <button
+ follows="left|top"
+ label="Check for updates"
+ name="update_btn"
+ left_pad="70"
+ top_delta="0"
+ height="25"
+ width="180" />
</panel>
<panel
border="true"
diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml
index 90d45d5ebc..edf028bf60 100755
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -2013,7 +2013,7 @@ Only large parcels can be listed in search.
name="AllowedText"
top="0"
width="230">
- Allowed Residents
+ Allowed Residents ([COUNT])
</text>
<name_list
column_padding="0"
@@ -2062,7 +2062,7 @@ Only large parcels can be listed in search.
name="BanCheck"
top="0"
width="200">
- Banned Residents
+ Banned Residents ([COUNT])
</text>
<name_list
column_padding="0"
diff --git a/indra/newview/skins/default/xui/en/floater_bumps.xml b/indra/newview/skins/default/xui/en/floater_bumps.xml
index 1f2fe62b3c..126e3aac48 100755
--- a/indra/newview/skins/default/xui/en/floater_bumps.xml
+++ b/indra/newview/skins/default/xui/en/floater_bumps.xml
@@ -7,7 +7,7 @@
help_topic="floater_bumps"
save_rect="true"
title="BUMPS, PUSHES &amp; HITS"
- width="400">
+ width="420">
<floater.string
name="none_detected">
None detected
@@ -34,7 +34,7 @@
</floater.string>
<floater.string
name="timeStr">
- [[hour,datetime,slt]:[min,datetime,slt]]
+ [[hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt]]
</floater.string>
<scroll_list
draw_border="false"
@@ -45,5 +45,5 @@
multi_select="true"
name="bump_list"
top="20"
- width="388" />
+ width="408" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_experiences.xml b/indra/newview/skins/default/xui/en/floater_experiences.xml
index 70e7507907..442da887c5 100644
--- a/indra/newview/skins/default/xui/en/floater_experiences.xml
+++ b/indra/newview/skins/default/xui/en/floater_experiences.xml
@@ -12,7 +12,7 @@
name="floater_experiences"
save_rect="true"
single_instance="true"
- reuse_instance="false"
+
bg_opaque_color="0 0.5 0 0.3"
title="EXPERIENCES">
<tab_container
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 91adec0789..033a10c9ec 100755
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -565,14 +565,6 @@
<menu_item_call
label="Delete"
layout="topleft"
- name="Remove Link">
- <menu_item_call.on_click
- function="Inventory.DoToSelected"
- parameter="delete" />
- </menu_item_call>
- <menu_item_call
- label="Delete"
- layout="topleft"
name="Delete">
<menu_item_call.on_click
function="Inventory.DoToSelected"
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index e91eea04d1..73ca7c529d 100755
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -108,6 +108,12 @@
function="Floater.Show"
parameter="sl_about" />
</menu_item_call>
+ <menu_item_call
+ label="Check for Updates"
+ name="Check for Updates">
+ <menu_item_call.on_click
+ function="Advanced.CheckViewerUpdates"/>
+ </menu_item_call>
</menu>
<menu_item_check
label="Show Debug Menu"
diff --git a/indra/newview/skins/default/xui/en/menu_participant_view.xml b/indra/newview/skins/default/xui/en/menu_participant_view.xml
index 7ea87ee05c..658238bf41 100755
--- a/indra/newview/skins/default/xui/en/menu_participant_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_participant_view.xml
@@ -59,6 +59,19 @@
function="IMFloaterContainer.Check"
parameter="sort_participants_by_recent" />
</menu_item_check>
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_check
+ label="View people icons"
+ layout="topleft"
+ name="view_icons">
+ <on_click
+ function="IMFloaterContainer.Action"
+ parameter="view_icons" />
+ <on_check
+ function="IMFloaterContainer.Check"
+ parameter="view_icons" />
+ </menu_item_check>
<menu_item_separator
layout="topleft" />
<menu_item_call
diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view.xml
index 8790fde7c5..02c6cfc006 100755
--- a/indra/newview/skins/default/xui/en/menu_people_friends_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_friends_view.xml
@@ -29,8 +29,8 @@
function="People.Friends.ViewSort.Action"
parameter="view_icons" />
<menu_item_check.on_check
- function="CheckControl"
- parameter="FriendsListShowIcons" />
+ function="People.Friends.ViewSort.CheckItem"
+ parameter="view_icons" />
</menu_item_check>
<menu_item_check name="view_permissions" label="View Permissions Granted">
<menu_item_check.on_click
diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml
index da88ca9f4d..44b3d14e10 100755
--- a/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view.xml
@@ -39,8 +39,8 @@
function="People.Nearby.ViewSort.Action"
parameter="view_icons" />
<menu_item_check.on_check
- function="CheckControl"
- parameter="NearbyListShowIcons" />
+ function="People.Nearby.ViewSort.CheckItem"
+ parameter="view_icons"/>
</menu_item_check>
<menu_item_check name ="view_map" label="View Map">
<menu_item_check.on_check
diff --git a/indra/newview/skins/default/xui/en/menu_people_recent_view.xml b/indra/newview/skins/default/xui/en/menu_people_recent_view.xml
index 1dbc90dd2b..cd2260d0c4 100755
--- a/indra/newview/skins/default/xui/en/menu_people_recent_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_recent_view.xml
@@ -29,7 +29,7 @@
function="People.Recent.ViewSort.Action"
parameter="view_icons" />
<menu_item_check.on_check
- function="CheckControl"
- parameter="RecentListShowIcons" />
+ function="People.Recent.ViewSort.CheckItem"
+ parameter="view_icons" />
</menu_item_check>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_url_email.xml b/indra/newview/skins/default/xui/en/menu_url_email.xml
new file mode 100644
index 0000000000..6467fe5c90
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_url_email.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Email Popup">
+ <menu_item_call
+ label="Compose Email in an External client"
+ layout="topleft"
+ name="email_open_external">
+ <menu_item_call.on_click
+ function="Url.OpenExternal" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_call
+ label="Copy Email to clipboard"
+ layout="topleft"
+ name="email_copy">
+ <menu_item_call.on_click
+ function="Url.CopyLabel" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 2463c5f43b..3f557d0d0f 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -134,7 +134,7 @@
</menu_item_call>
<menu_item_call
label="Walk / run / fly..."
- name="Walk / run / fly">
+ name="WalkRunFly">
<menu_item_call.on_click
function="Floater.ToggleOrBringToFront"
parameter="moveview" />
@@ -509,7 +509,7 @@
</menu_item_call>
<menu_item_call
label="Region / Estate"
- name="Region/Estate">
+ name="RegionEstate">
<menu_item_call.on_click
function="Floater.Show"
parameter="region_info" />
@@ -1438,7 +1438,7 @@
function="Floater.Show"
parameter="bumps" />
</menu_item_call>
- <menu_item_separator/>
+ <menu_item_separator/>
<menu_item_call
label="About [APP_NAME]"
name="About Second Life">
@@ -1446,6 +1446,12 @@
function="Floater.Show"
parameter="sl_about" />
</menu_item_call>
+ <menu_item_call
+ label="Check for Updates"
+ name="Check for Updates">
+ <menu_item_call.on_click
+ function="Advanced.CheckViewerUpdates"/>
+ </menu_item_call>
</menu>
<menu
create_jump_keys="true"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f847c73287..70ba4d5077 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -819,6 +819,33 @@ If you no longer wish to have these abilities granted to this role, disable them
notext="Cancel"
yestext="Eject"/>
</notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="BanGroupMemberWarning"
+ type="alertmodal">
+ You are about to ban [AVATAR_NAME] from the group.
+ <tag>group</tag>
+ <tag>confirm</tag>
+ <usetemplate
+ ignoretext="Confirm banning a participant from group"
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="Ban"/>
+ </notification>
+ <notification
+ icon="alertmodal.tga"
+ name="BanGroupMembersWarning"
+ type="alertmodal">
+ You are about to ban [COUNT] members from group.
+ <tag>group</tag>
+ <tag>confirm</tag>
+ <usetemplate
+ ignoretext="Confirm banning multiple members from group"
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="Ban"/>
+ </notification>
<notification
icon="alertmodal.tga"
@@ -3892,6 +3919,53 @@ see [[INFO_URL] Information about this update]
name="okbutton"
yestext="OK"/>
</notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateDownloadInProgress"
+ type="alertmodal">
+An update is available!
+It's downloading in the background and we will prompt you to restart your viewer to finish installing it as soon as it's ready.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateDownloadComplete"
+ type="alertmodal">
+An update was downloaded. It will be installed during restart.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateCheckError"
+ type="alertmodal">
+An error occured while checking for update.
+Please try again later.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="UpdateViewerUpToDate"
+ type="alertmodal">
+Your viewer is up to date!
+If you can't wait to try out the latest features and fixes, check out the Alternate Viewers page. http://wiki.secondlife.com/wiki/Linden_Lab_Official:Alternate_Viewers.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
<notification
icon="alertmodal.tga"
@@ -4217,6 +4291,21 @@ You have reached your maximum number of groups. Please leave some group before j
<notification
icon="alert.tga"
+ name="GroupLimitInfo"
+ type="alert">
+The group limit for base accounts is [MAX_BASIC], and for [https://secondlife.com/premium/ premium]
+accounts is [MAX_PREMIUM].
+If you downgraded your account, you will need to get below [MAX_BASIC] group limit before you can join more.
+
+[https://secondlife.com/my/account/membership.php Upgrade today!]
+ <tag>group</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="Close"/>
+ </notification>
+
+ <notification
+ icon="alert.tga"
name="KickUser"
type="alert">
<tag>win</tag>
@@ -7029,15 +7118,6 @@ No valid circuit code.
<notification
icon="notify.tga"
- name="NoValidTimestamp"
- persist="true"
- type="notify">
- <tag>fail</tag>
-No valid timestamp.
- </notification>
-
- <notification
- icon="notify.tga"
name="NoPendingConnection"
persist="true"
type="notify">
diff --git a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
index c76b958eda..c357f9e7d5 100644
--- a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
+++ b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
@@ -47,19 +47,19 @@
height="12"
follows="top|left">
</text>
- <scroll_list
+ <name_list
draw_heading="false"
left="3"
width="225"
height="75"
follows="all"
name="experience_list">
- <columns
+ <name_list.columns
width="225"
user_resize="false"
name="experience_name"
label="Name"/>
- </scroll_list>
+ </name_list>
<button
layout="topleft"
follows="top|right"
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 0518688f45..0a85477bf4 100755
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -21,7 +21,7 @@
</panel.string>
<panel.string
name="ItemcountUnknown">
-
+ Fetched [ITEM_COUNT] Items [FILTER]
</panel.string>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 2d4665c128..4fb8b9a67f 100755
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -506,7 +506,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
left="3"
use_ellipses="true"
name="groupcount">
- You belong to [COUNT] groups, and can join [REMAINING] more.
+ You belong to [COUNT] groups, and can join [REMAINING] more. [secondlife:/// Want more?]
</text>
<group_list
allow_select="true"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
index 2e778014c5..3e96160834 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -216,7 +216,7 @@
control_name="QAMode"
follows="top|left"
height="15"
- label="Show Developer Menu"
+ label="Show Develop Menu"
layout="topleft"
left="30"
name="show_develop_menu_check"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 1e9a1aa27c..a8be517f3c 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -270,7 +270,7 @@
value="1" />
-->
<combo_box.item
- label="Download and install updates manually"
+ label="I will download and install updates manually"
name="Install_manual"
value="0" />
</combo_box>
@@ -313,4 +313,30 @@
<button.commit_callback
function="Pref.Proxy" />
</button>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="30"
+ name="People Icons:"
+ mouse_opaque="false"
+ top_pad="5"
+ width="300">
+ People Icons:
+ </text>
+ <check_box
+ top_delta="4"
+ enabled="true"
+ follows="left|top"
+ height="14"
+ initial_value="false"
+ control_name="GlobalShowIconsOverride"
+ label="Hide people icons (global override)"
+ left_delta="50"
+ mouse_opaque="true"
+ name="global_show_icons_override"
+ width="400"
+ top_pad="10"/>
</panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index b7e0cff146..4eb6e2462d 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -238,6 +238,7 @@ Please try logging in again in a minute.</string>
<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>
<string name="TooltipTooManyWearables">You can't wear a folder containing more than [AMOUNT] items. You can change this limit in Advanced > Show Debug Settings > WearFolderLimit.</string>
<string name="TooltipPrice" value="L$[AMOUNT]: "/>
+ <string name="TooltipSLIcon">This links to a page on the official SecondLife.com or LindenLab.com domain.</string>
<string name="TooltipOutboxDragToWorld">You can't rez items from the Marketplace Listings folder</string>
<string name="TooltipOutboxWorn">You can't put items you are wearing in the Marketplace Listings folder</string>
@@ -277,6 +278,7 @@ Please try logging in again in a minute.</string>
<string name="TooltipMapUrl">Click to view this location on a map</string>
<string name="TooltipSLAPP">Click to run the secondlife:// command</string>
<string name="CurrentURL" value=" CurrentURL: [CurrentURL]" />
+ <string name="TooltipEmail">Click to compose an email</string>
<!-- text for SLURL labels -->
<string name="SLurlLabelTeleport">Teleport to</string>
diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml
index 5118171d80..f6ebb498ec 100755
--- a/indra/newview/skins/default/xui/es/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/es/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Volar" name="Fly"/>
<menu_item_check label="Correr siempre" name="Always Run"/>
<menu_item_call label="Parar mis animaciones" name="Stop Animating My Avatar"/>
- <menu_item_call label="Caminar / Correr / Volar..." name="Walk / run / fly"/>
+ <menu_item_call label="Caminar / Correr / Volar..." name="WalkRunFly"/>
</menu>
<menu label="Estado" name="Status">
<menu_item_check label="Ausente" name="Away"/>
@@ -63,7 +63,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Perfil del lugar" name="Place Profile"/>
<menu_item_call label="Acerca del terreno" name="About Land"/>
- <menu_item_call label="Región/Estado" name="Region/Estate"/>
+ <menu_item_call label="Región/Estado" name="RegionEstate"/>
<menu_item_call label="Mis terrenos..." name="My Land"/>
<menu_item_call label="Comprar este terreno" name="Buy Land"/>
<menu label="Mostrar" name="LandShow">
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 9578e1b863..1e367b33fc 100755
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -2796,9 +2796,6 @@ Por favor, vuelve a intentarlo en unos momentos.
<notification name="NoValidCircuit">
Circuito de código inválido.
</notification>
- <notification name="NoValidTimestamp">
- Fecha inválida.
- </notification>
<notification name="NoPendingConnection">
No se puede crear la conexión.
</notification>
diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml
index 33b2ba6982..788cdbf856 100755
--- a/indra/newview/skins/default/xui/fr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Voler" name="Fly"/>
<menu_item_check label="Toujours courir" name="Always Run"/>
<menu_item_call label="Arrêter mon animation" name="Stop Animating My Avatar"/>
- <menu_item_call label="Marcher / Courir / Voler..." name="Walk / run / fly"/>
+ <menu_item_call label="Marcher / Courir / Voler..." name="WalkRunFly"/>
</menu>
<menu label="Statut" name="Status">
<menu_item_check label="Absent" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Photo" name="Take Snapshot"/>
<menu_item_call label="Profil du lieu" name="Place Profile"/>
<menu_item_call label="À propos du terrain" name="About Land"/>
- <menu_item_call label="Région/Domaine" name="Region/Estate"/>
+ <menu_item_call label="Région/Domaine" name="RegionEstate"/>
<menu_item_call label="Mes terrains..." name="My Land"/>
<menu_item_call label="Acheter ce terrain" name="Buy Land"/>
<menu label="Afficher" name="LandShow">
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index f13a80fe61..29e6fe1979 100755
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -2788,9 +2788,6 @@ Veuillez réessayer dans quelques minutes.
<notification name="NoValidCircuit">
Aucun code de circuit valide.
</notification>
- <notification name="NoValidTimestamp">
- Timestamp non valide.
- </notification>
<notification name="NoPendingConnection">
Impossible de créer la connexion en attente.
</notification>
diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml
index 40082cb265..2b8249c8a9 100755
--- a/indra/newview/skins/default/xui/fr/panel_login.xml
+++ b/indra/newview/skins/default/xui/fr/panel_login.xml
@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<panel name="panel_login">
<panel.string name="forgot_password_url">http://secondlife.com/account/request.php?lang=fr</panel.string>
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=fr
- </panel.string>
<layout_stack name="ui_stack">
<layout_panel name="ui_container">
<combo_box label="Nom d&apos;utilisateur" name="username_combo" tool_tip="Nom d&apos;utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/>
diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml
index 3f4c370ccd..18ddad5ee8 100755
--- a/indra/newview/skins/default/xui/it/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/it/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Vola" name="Fly"/>
<menu_item_check label="Corri sempre" name="Always Run"/>
<menu_item_call label="Ferma animazione" name="Stop Animating My Avatar"/>
- <menu_item_call label="Cammina / corri / vola..." name="Walk / run / fly"/>
+ <menu_item_call label="Cammina / corri / vola..." name="WalkRunFly"/>
</menu>
<menu label="Stato" name="Status">
<menu_item_check label="Assente" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Istantanea" name="Take Snapshot"/>
<menu_item_call label="Profilo del luogo" name="Place Profile"/>
<menu_item_call label="Informazioni sul terreno" name="About Land"/>
- <menu_item_call label="Regione/proprietà immobiliare" name="Region/Estate"/>
+ <menu_item_call label="Regione/proprietà immobiliare" name="RegionEstate"/>
<menu_item_call label="Terreni posseduti..." name="My Land"/>
<menu_item_call label="Acquista questo terreno" name="Buy Land"/>
<menu label="Mostra" name="LandShow">
diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml
index 06f2b70dcf..61131b09c3 100755
--- a/indra/newview/skins/default/xui/it/notifications.xml
+++ b/indra/newview/skins/default/xui/it/notifications.xml
@@ -2793,9 +2793,6 @@ Riprova tra qualche istante.
<notification name="NoValidCircuit">
Nessun codice circuito valido.
</notification>
- <notification name="NoValidTimestamp">
- Nessuna data/timestamp valido.
- </notification>
<notification name="NoPendingConnection">
Impossibile creare la connessione in sospeso.
</notification>
diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml
index 3f756c5f94..0384dc1efc 100755
--- a/indra/newview/skins/default/xui/ja/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="飛ぶ" name="Fly"/>
<menu_item_check label="常に走る" name="Always Run"/>
<menu_item_call label="私のアニメーションを停止する" name="Stop Animating My Avatar"/>
- <menu_item_call label="歩行/走行/飛行..." name="Walk / run / fly"/>
+ <menu_item_call label="歩行/走行/飛行..." name="WalkRunFly"/>
</menu>
<menu label="ログイン" name="Status">
<menu_item_check label="一時退席中" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="スナップショット" name="Take Snapshot"/>
<menu_item_call label="場所のプロフィール" name="Place Profile"/>
<menu_item_call label="土地情報" name="About Land"/>
- <menu_item_call label="地域 / 不動産" name="Region/Estate"/>
+ <menu_item_call label="地域 / 不動産" name="RegionEstate"/>
<menu_item_call label="保有地..." name="My Land"/>
<menu_item_call label="この土地を購入" name="Buy Land"/>
<menu label="表示" name="LandShow">
diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml
index 694f38467e..5f0ce7a73b 100755
--- a/indra/newview/skins/default/xui/ja/notifications.xml
+++ b/indra/newview/skins/default/xui/ja/notifications.xml
@@ -2836,9 +2836,6 @@ Web ページにリンクすると、他人がこの場所に簡単にアクセ
<notification name="NoValidCircuit">
回路コードが無効です。
</notification>
- <notification name="NoValidTimestamp">
- タイムスタンプが無効です。
- </notification>
<notification name="NoPendingConnection">
接続を生成できません。
</notification>
diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml
index ef3fe71945..6fd498eea8 100755
--- a/indra/newview/skins/default/xui/pl/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml
@@ -33,7 +33,7 @@
<menu_item_call label="Zrób zdjęcie" name="Take Snapshot"/>
<menu_item_call label="Profil miejsca" name="Place Profile"/>
<menu_item_call label="O posiadłości" name="About Land"/>
- <menu_item_call label="Region/Majątek" name="Region/Estate"/>
+ <menu_item_call label="Region/Majątek" name="RegionEstate"/>
<menu_item_call label="Moje posiadłości" name="My Land"/>
<menu_item_call label="Kup posiadłość" name="Buy Land"/>
<menu label="Pokaż" name="LandShow">
diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml
index 62fda0d601..c4a65d92b4 100755
--- a/indra/newview/skins/default/xui/pl/notifications.xml
+++ b/indra/newview/skins/default/xui/pl/notifications.xml
@@ -2368,9 +2368,6 @@ Spróbuj ponowanie za kilka minut.
<notification name="NoValidCircuit">
Nieważny obwód kodowania.
</notification>
- <notification name="NoValidTimestamp">
- Niewłaściwy czas zapisu.
- </notification>
<notification name="NoPendingConnection">
Brak możliwości wykonania połączenia.
</notification>
diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml
index 9b3b6077ed..3d5d9eccc6 100755
--- a/indra/newview/skins/default/xui/pt/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Voar" name="Fly"/>
<menu_item_check label="Correr sempre" name="Always Run"/>
<menu_item_call label="Parar minha animação" name="Stop Animating My Avatar"/>
- <menu_item_call label="Andar/correr/voar..." name="Walk / run / fly"/>
+ <menu_item_call label="Andar/correr/voar..." name="WalkRunFly"/>
</menu>
<menu label="Status" name="Status">
<menu_item_check label="Ausente" name="Away"/>
@@ -64,7 +64,7 @@
<menu_item_call label="Foto" name="Take Snapshot"/>
<menu_item_call label="Perfil da região" name="Place Profile"/>
<menu_item_call label="Sobre terrenos" name="About Land"/>
- <menu_item_call label="Região/Propriedade" name="Region/Estate"/>
+ <menu_item_call label="Região/Propriedade" name="RegionEstate"/>
<menu_item_call label="Meus terrenos..." name="My Land"/>
<menu_item_call label="Comprar este terreno" name="Buy Land"/>
<menu label="Mostrar" name="LandShow">
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index 29b85d9e97..a264495404 100755
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -2777,9 +2777,6 @@ Por favor, tente novamente em alguns instantes.
<notification name="NoValidCircuit">
Código de circuito inválido.
</notification>
- <notification name="NoValidTimestamp">
- Hora inválida.
- </notification>
<notification name="NoPendingConnection">
Impossível criar a conexão pendente.
</notification>
diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml
index 958105a70f..d22ca845f9 100755
--- a/indra/newview/skins/default/xui/ru/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Полет" name="Fly"/>
<menu_item_check label="Всегда бегать" name="Always Run"/>
<menu_item_call label="Остановить анимацию" name="Stop Animating My Avatar"/>
- <menu_item_call label="Ходьба / бег / полет..." name="Walk / run / fly"/>
+ <menu_item_call label="Ходьба / бег / полет..." name="WalkRunFly"/>
</menu>
<menu label="Статус" name="Status">
<menu_item_check label="Нет на месте" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="Снимок" name="Take Snapshot"/>
<menu_item_call label="Профиль места" name="Place Profile"/>
<menu_item_call label="О земле" name="About Land"/>
- <menu_item_call label="Регион/землевладение" name="Region/Estate"/>
+ <menu_item_call label="Регион/землевладение" name="RegionEstate"/>
<menu_item_call label="Мои владения..." name="My Land"/>
<menu_item_call label="Купить эту землю" name="Buy Land"/>
<menu label="Показать" name="LandShow">
diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml
index acf3ce608f..70b9a25590 100755
--- a/indra/newview/skins/default/xui/ru/notifications.xml
+++ b/indra/newview/skins/default/xui/ru/notifications.xml
@@ -2788,9 +2788,6 @@ http://secondlife.com/download.
<notification name="NoValidCircuit">
Нет подходящего кода канала.
</notification>
- <notification name="NoValidTimestamp">
- Нет подходящей метки времени.
- </notification>
<notification name="NoPendingConnection">
Невозможно создать отложенное соединение.
</notification>
diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml
index cc8d8c895b..cea57011dd 100755
--- a/indra/newview/skins/default/xui/tr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="Uç" name="Fly"/>
<menu_item_check label="Daima Koş" name="Always Run"/>
<menu_item_call label="Beni Anime Etmeyi Durdur" name="Stop Animating My Avatar"/>
- <menu_item_call label="Yürü / koş / uç..." name="Walk / run / fly"/>
+ <menu_item_call label="Yürü / koş / uç..." name="WalkRunFly"/>
</menu>
<menu label="Durum" name="Status">
<menu_item_check label="Uzakta" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="Anlık Görüntü" name="Take Snapshot"/>
<menu_item_call label="Profili yerleştir" name="Place Profile"/>
<menu_item_call label="Arazi hakkında" name="About Land"/>
- <menu_item_call label="Bölge / Gayrimenkul" name="Region/Estate"/>
+ <menu_item_call label="Bölge / Gayrimenkul" name="RegionEstate"/>
<menu_item_call label="Sahip olduğum arazi parçaları..." name="My Land"/>
<menu_item_call label="Bu araziyi satın al" name="Buy Land"/>
<menu label="Göster" name="LandShow">
diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml
index a6c69c7ab2..df22251b3d 100755
--- a/indra/newview/skins/default/xui/tr/notifications.xml
+++ b/indra/newview/skins/default/xui/tr/notifications.xml
@@ -2788,9 +2788,6 @@ Lütfen biraz sonra tekrar deneyin.
<notification name="NoValidCircuit">
Geçerli bir devre kodu yok.
</notification>
- <notification name="NoValidTimestamp">
- Geçerli bir zaman damgası yok.
- </notification>
<notification name="NoPendingConnection">
Beklemedeki bağlantı oluşturulamıyor.
</notification>
diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml
index e94f52a401..9572ad49d3 100755
--- a/indra/newview/skins/default/xui/zh/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml
@@ -15,7 +15,7 @@
<menu_item_check label="飛行" name="Fly"/>
<menu_item_check label="以跑代步" name="Always Run"/>
<menu_item_call label="停止我身上的動作" name="Stop Animating My Avatar"/>
- <menu_item_call label="行走 / 跑步 / 飛行…" name="Walk / run / fly"/>
+ <menu_item_call label="行走 / 跑步 / 飛行…" name="WalkRunFly"/>
</menu>
<menu label="狀態" name="Status">
<menu_item_check label="離開" name="Away"/>
@@ -62,7 +62,7 @@
<menu_item_call label="快照" name="Take Snapshot"/>
<menu_item_call label="地點小檔案" name="Place Profile"/>
<menu_item_call label="土地資料" name="About Land"/>
- <menu_item_call label="地區/領地" name="Region/Estate"/>
+ <menu_item_call label="地區/領地" name="RegionEstate"/>
<menu_item_call label="我所擁有的土地…" name="My Land"/>
<menu_item_call label="購買這塊土地" name="Buy Land"/>
<menu label="顯示" name="LandShow">
diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml
index 179f01e90d..0a98101b60 100755
--- a/indra/newview/skins/default/xui/zh/notifications.xml
+++ b/indra/newview/skins/default/xui/zh/notifications.xml
@@ -2778,9 +2778,6 @@ SHA1 指紋:[MD5_DIGEST]
<notification name="NoValidCircuit">
沒有有效的線路碼。
</notification>
- <notification name="NoValidTimestamp">
- 沒有有效的時間戳記。
- </notification>
<notification name="NoPendingConnection">
無法建立待通的連線。
</notification>
diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp
index c152493a51..788955a1b2 100755
--- a/indra/viewer_components/updater/llupdaterservice.cpp
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -132,6 +132,7 @@ public:
void startChecking(bool install_if_ready);
void stopChecking();
+ bool forceCheck();
bool isChecking();
LLUpdaterService::eUpdaterState getState();
@@ -266,6 +267,46 @@ void LLUpdaterServiceImpl::stopChecking()
setState(LLUpdaterService::TERMINAL);
}
+bool LLUpdaterServiceImpl::forceCheck()
+{
+ if (!mIsDownloading && getState() != LLUpdaterService::CHECKING_FOR_UPDATE)
+ {
+ if (mIsChecking)
+ {
+ // Service is running, just reset the timer
+ if (mTimer.getStarted())
+ {
+ mTimer.setTimerExpirySec(0);
+ setState(LLUpdaterService::CHECKING_FOR_UPDATE);
+ return true;
+ }
+ }
+ else if (!mChannel.empty() && !mVersion.empty())
+ {
+ // one time check
+ bool has_install = checkForInstall(false);
+ if (!has_install)
+ {
+ std::string query_url = LLGridManager::getInstance()->getUpdateServiceURL();
+ if (!query_url.empty())
+ {
+ setState(LLUpdaterService::CHECKING_FOR_UPDATE);
+ mUpdateChecker.checkVersion(query_url, mChannel, mVersion,
+ mPlatform, mPlatformVersion, mUniqueId,
+ mWillingToTest);
+ return true;
+ }
+ else
+ {
+ LL_WARNS("UpdaterService")
+ << "No updater service defined for grid '" << LLGridManager::getInstance()->getGrid() << LL_ENDL;
+ }
+ }
+ }
+ }
+ return false;
+}
+
bool LLUpdaterServiceImpl::isChecking()
{
return mIsChecking;
@@ -402,9 +443,9 @@ bool LLUpdaterServiceImpl::checkForResume()
void LLUpdaterServiceImpl::error(std::string const & message)
{
+ setState(LLUpdaterService::TEMPORARY_ERROR);
if(mIsChecking)
{
- setState(LLUpdaterService::TEMPORARY_ERROR);
restartTimer(mCheckPeriod);
}
}
@@ -449,8 +490,12 @@ void LLUpdaterServiceImpl::response(LLSD const & content)
else
{
LL_WARNS("UpdaterService") << "Invalid update query response ignored; retry in "
- << mCheckPeriod << " seconds" << LL_ENDL;
- restartTimer(mCheckPeriod);
+ << mCheckPeriod << " seconds" << LL_ENDL;
+ setState(LLUpdaterService::TEMPORARY_ERROR);
+ if (mIsChecking)
+ {
+ restartTimer(mCheckPeriod);
+ }
}
}
@@ -672,6 +717,11 @@ void LLUpdaterService::stopChecking()
mImpl->stopChecking();
}
+bool LLUpdaterService::forceCheck()
+{
+ return mImpl->forceCheck();
+}
+
bool LLUpdaterService::isChecking()
{
return mImpl->isChecking();
diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h
index 0ddf24935b..95bbe1695c 100755
--- a/indra/viewer_components/updater/llupdaterservice.h
+++ b/indra/viewer_components/updater/llupdaterservice.h
@@ -84,6 +84,7 @@ public:
void startChecking(bool install_if_ready = false);
void stopChecking();
+ bool forceCheck();
bool isChecking();
eUpdaterState getState();