diff --git a/.hgignore b/.hgignore
index 9566d358d4..f8b44bc6d3 100644
--- a/.hgignore
+++ b/.hgignore
@@ -77,4 +77,5 @@ glob:indra/newview/search_history.txt
glob:indra/newview/filters.xml
glob:indra/newview/avatar_icons_cache.txt
glob:indra/newview/avatar_lad.log
+glob:*.diff
glob:fmod*
diff --git a/.hgtags b/.hgtags
index 40e942d6ef..ee7cdb6cb1 100644
--- a/.hgtags
+++ b/.hgtags
@@ -1,3 +1,4 @@
+bb38ff1a763738609e1b3cada6d15fa61e5e84b9 2.1.1-release
003dd9461bfa479049afcc34545ab3431b147c7c v2start
08398e650c222336bb2b6de0cd3bba944aef11b4 2-1rn1
0962101bfa7df0643a6e625786025fe7f8a6dc97 2-1-beta-2
@@ -199,6 +200,45 @@ dbaaef19266478a20654c46395300640163e98e3 3.1.0-beta2
bc01ee26fd0f1866e266429e85f76340523e91f1 3.1.0-beta2
ae2de7b0b33c03dc5bdf3a7bfa54463b512221b2 DRTVWR-92_3.1.0-release
ae2de7b0b33c03dc5bdf3a7bfa54463b512221b2 3.1.0-release
+a8230590e28e4f30f5105549e0e43211d9d55711 3.2.0-start
+e440cd1dfbd128d7d5467019e497f7f803640ad6 DRTVWR-95_3.2.0-beta1
+e440cd1dfbd128d7d5467019e497f7f803640ad6 3.2.0-beta1
+9bcc2b7176634254e501e3fb4c5b56c1f637852e DRTVWR-97_3.2.0-beta2
+9bcc2b7176634254e501e3fb4c5b56c1f637852e 3.2.0-beta2
+2a13d30ee50ccfed50268238e36bb90d738ccc9e DRTVWR-98_3.2.0-beta3
+2a13d30ee50ccfed50268238e36bb90d738ccc9e 3.2.0-beta3
+3150219d229d628f0c15e58e8a51511cbd97e58d DRTVWR-94_3.2.0-release
+3150219d229d628f0c15e58e8a51511cbd97e58d 3.2.0-release
+c4911ec8cd81e676dfd2af438b3e065407a94a7a 3.2.1-start
+3150219d229d628f0c15e58e8a51511cbd97e58d DRTVWR-94_3.2.0-release
+3150219d229d628f0c15e58e8a51511cbd97e58d 3.2.0-release
+40b46edba007d15d0059c80864b708b99c1da368 3.2.2-start
+3150219d229d628f0c15e58e8a51511cbd97e58d DRTVWR-94_3.2.0-release
+3150219d229d628f0c15e58e8a51511cbd97e58d 3.2.0-release
+9e390d76807fa70d356b8716fb83b8ce42a629ef DRTVWR-100_3.2.1-beta1
+9e390d76807fa70d356b8716fb83b8ce42a629ef 3.2.1-beta1
+523df3e67378541498d516d52af4402176a26bac DRTVWR-102_3.2.2-beta1
+523df3e67378541498d516d52af4402176a26bac 3.2.2-beta1
+80f3e30d8aa4d8f674a48bd742aaa6d8e9eae0b5 3.2.3-start
+a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release
+a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release
+3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-start
+a9abb9633a266c8d2fe62411cfd1c86d32da72bf DRTVWR-60_2.7.1-release
+fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-60_2.7.1-release
+a9abb9633a266c8d2fe62411cfd1c86d32da72bf 2.7.1-release
+fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.1-release
+3fe994349fae64fc40874bb59db387131eb35a41 DRTVWR-104_3.2.4-beta1
+3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-beta1
+8a44ff3d2104269ce76145c2772cf1bdff2a2abe 3.2.5-start
+fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-62_2.7.2-release
+fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.2-release
+bd6bcde2584491fd9228f1fa51c4575f4e764e19 DRTVWR-103_3.2.4-release
+bd6bcde2584491fd9228f1fa51c4575f4e764e19 3.2.4-release
+3d2d5d244c6398a4214c666d5dd3965b0918709a DRTVWR-106_3.2.5-beta1
+3d2d5d244c6398a4214c666d5dd3965b0918709a 3.2.5-beta1
+65a2c1c8d855b88edfbea4e16ef2f27e7cff8b1d DRTVWR-107_3.2.5-beta2
+65a2c1c8d855b88edfbea4e16ef2f27e7cff8b1d 3.2.5-beta2
+2174ed1c7129562428a5cfe8651ed77b8d26ae18 3.2.6-start
425f96b1e81e01644bf5e951961e7d1023bffb89 RLVa-1.2.0
fc0cbb86f5bd6e7737159e35aea2c4cf9f619b62 RLVa-1.2.1
43cb7dc1804de1a25c0b2b3f0715584af1f8b470 RLVa-1.2.2
diff --git a/BuildParams b/BuildParams
index 1c76b6f935..c051397853 100644
--- a/BuildParams
+++ b/BuildParams
@@ -136,14 +136,6 @@ viewer-mesh.login_channel = "Project Viewer - Mesh"
viewer-mesh.viewer_grid = aditi
viewer-mesh.email = shining@lists.lindenlab.com
-
-# ========================================
-# CG
-# ========================================
-
-cg_viewer-development_lenny.show_changes_since = 4b140ce7839d
-cg_viewer-development_lenny.email = cg@lindenlab.com
-
# ================
# oz
# ================
@@ -151,20 +143,31 @@ cg_viewer-development_lenny.email = cg@lindenlab.com
oz_viewer-devreview.build_debug_release_separately = true
oz_viewer-devreview.codeticket_add_context = false
oz_viewer-devreview.build_enforce_coding_policy = true
+oz_viewer-devreview.email = oz@lindenlab.com
-oz_project-1.build_debug_release_separately = true
-oz_project-1.codeticket_add_context = false
-oz_project-2.build_debug_release_separately = true
-oz_project-2.codeticket_add_context = false
-oz_project-3.build_debug_release_separately = true
-oz_project-3.codeticket_add_context = false
-oz_project-4.build_debug_release_separately = true
-oz_project-4.codeticket_add_context = false
+oz_viewer-trial.build_debug_release_separately = true
+oz_viewer-trial.codeticket_add_context = false
+oz_viewer-trial.build_enforce_coding_policy = true
+oz_viewer-trial.email = oz@lindenlab.com
oz_viewer-beta-review.build_debug_release_separately = true
oz_viewer-beta-review.codeticket_add_context = false
oz_viewer-beta-review.viewer_channel = "Second Life Beta Viewer"
oz_viewer-beta-review.login_channel = "Second Life Beta Viewer"
+oz_viewer-beta-review.email = oz@lindenlab.com
+
+oz_project-1.build_debug_release_separately = true
+oz_project-1.codeticket_add_context = false
+oz_project-1.email = oz@lindenlab.com
+oz_project-2.build_debug_release_separately = true
+oz_project-2.codeticket_add_context = false
+oz_project-2.email = oz@lindenlab.com
+oz_project-3.build_debug_release_separately = true
+oz_project-3.codeticket_add_context = false
+oz_project-3.email = oz@lindenlab.com
+oz_project-4.build_debug_release_separately = true
+oz_project-4.codeticket_add_context = false
+oz_project-4.email = oz@lindenlab.com
# =================================================================
# asset delivery 2010 projects
@@ -190,4 +193,10 @@ simon_viewer-dev-private.public_build = false
simon_viewer-dev-private.email_status_this_is_os = false
+# ========================================
+# Vir
+# ========================================
+vir-project-1.viewer_channel = "Second Life Release"
+vir-project-1.login_channel = "Second Life Release"
+
# eof
diff --git a/autobuild.xml b/autobuild.xml
index a41acfb731..0516d5d099 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1206,9 +1206,9 @@
archive
name
darwin
@@ -1230,9 +1230,9 @@
archive
name
windows
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 04c82ebc9c..e56baa931a 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -171,6 +171,8 @@ Ansariel Hiller
STORM-1101
VWR-25480
VWR-26150
+ STORM-1685
+ STORM-1713
Aralara Rajal
Ardy Lay
STORM-859
@@ -483,6 +485,7 @@ Ima Mechanique
OPEN-76
STORM-959
STORM-1175
+ STORM-1708
Imnotgoing Sideways
Inma Rau
Innula Zenovka
@@ -578,9 +581,34 @@ Jonathan Yap
STORM-1572
STORM-1574
STORM-1579
+ STORM-1638
+ STORM-976
STORM-1639
+ STORM-910
+ STORM-1653
+ STORM-1642
+ STORM-591
+ STORM-1105
+ STORM-1679
+ STORM-1222
+ STORM-1659
+ STORM-1674
+ STORM-1685
+ STORM-1721
+ STORM-1727
+ STORM-1725
+ STORM-1719
+ STORM-1712
+ STORM-1728
+ STORM-1736
+ STORM-1734
+ STORM-1731
+ STORM-653
+ STORM-1737
+ STORM-1733
+ STORM-1790
Kadah Coba
- STORM-1060
+ STORM-1060
Jondan Lundquist
Josef Munster
Josette Windlow
@@ -913,6 +941,7 @@ Robin Cornelius
SNOW-599
SNOW-747
STORM-422
+ STORM-591
STORM-960
STORM-1019
STORM-1095
@@ -1107,6 +1136,9 @@ Tofu Buzzard
CTS-411
STORM-546
VWR-24509
+ STORM-1684
+ SH-2477
+ STORM-1684
Tony Kembia
Torben Trautman
TouchaHoney Perhaps
@@ -1140,6 +1172,7 @@ Vector Hastings
VWR-8726
Veritas Raymaker
Vex Streeter
+ STORM-1642
Viaticus Speculaas
Vick Forcella
Villain Baroque
@@ -1225,6 +1258,7 @@ Zi Ree
VWR-1140
VWR-24017
VWR-25588
+ STORM-1790
Zipherius Turas
VWR-76
VWR-77
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index eee5d3c925..95317f61dc 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -1,4 +1,3 @@
-
# -*- cmake -*-
# cmake_minimum_required should appear before any
@@ -70,6 +69,9 @@ if (VIEWER)
add_subdirectory(${LIBS_OPEN_PREFIX}llxuixml)
add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components)
+ # Legacy C++ tests. Build always, run if LL_TESTS is true.
+ add_subdirectory(${VIEWER_PREFIX}test)
+
# viewer media plugins
add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 27fd0e8b66..43f75b9f51 100755
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -46,7 +46,7 @@ if (WINDOWS)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP -D_SCL_SECURE_NO_WARNINGS=1"
CACHE STRING "C++ compiler debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
- "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /Ob2 /Gm -D_SECURE_STL=0"
+ "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /Ob0 -D_SECURE_STL=0"
CACHE STRING "C++ compiler release-with-debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /Ob2 /Oi /Ot /GF /Gy /arch:SSE2 -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0"
@@ -64,7 +64,7 @@ if (WINDOWS)
/D_UNICODE
/GS
/TP
- /W2
+ /W3
/c
/Zc:forScope
/nologo
diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt
index df47167154..1180460f4b 100644
--- a/indra/integration_tests/llui_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llui_libtest/CMakeLists.txt
@@ -71,6 +71,7 @@ endif (DARWIN)
# Sort by high-level to low-level
target_link_libraries(llui_libtest
llui
+ llinventory
llmessage
${LLRENDER_LIBRARIES}
${LLIMAGE_LIBRARIES}
diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp
index 7316717193..62465f9937 100644
--- a/indra/linux_crash_logger/llcrashloggerlinux.cpp
+++ b/indra/linux_crash_logger/llcrashloggerlinux.cpp
@@ -133,6 +133,12 @@ bool LLCrashLoggerLinux::mainLoop()
return true;
}
+bool LLCrashLoggerLinux::cleanup()
+{
+ commonCleanup();
+ return true;
+}
+
void LLCrashLoggerLinux::updateApplication(const std::string& message)
{
LLCrashLogger::updateApplication(message);
diff --git a/indra/linux_crash_logger/llcrashloggerlinux.h b/indra/linux_crash_logger/llcrashloggerlinux.h
index 65d5e4e653..dae6c46651 100644
--- a/indra/linux_crash_logger/llcrashloggerlinux.h
+++ b/indra/linux_crash_logger/llcrashloggerlinux.h
@@ -39,6 +39,7 @@ public:
virtual bool mainLoop();
virtual void updateApplication(const std::string& = LLStringUtil::null);
virtual void gatherPlatformSpecificFiles();
+ virtual bool cleanup();
};
#endif
diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp
index 4aff513116..a45a49c47c 100644
--- a/indra/llaudio/llaudioengine.cpp
+++ b/indra/llaudio/llaudioengine.cpp
@@ -1269,6 +1269,7 @@ LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32
mSyncSlave(false),
mQueueSounds(false),
mPlayedOnce(false),
+ mCorrupted(false),
mType(type),
mChannelp(NULL),
mCurrentDatap(NULL),
@@ -1301,16 +1302,25 @@ void LLAudioSource::setChannel(LLAudioChannel *channelp)
void LLAudioSource::update()
{
+ if(mCorrupted)
+ {
+ return ; //no need to update
+ }
+
if (!getCurrentBuffer())
{
if (getCurrentData())
{
// Hack - try and load the sound. Will do this as a callback
// on decode later.
- if (getCurrentData()->load())
+ if (getCurrentData()->load() && getCurrentData()->getBuffer())
{
play(getCurrentData()->getID());
- }
+ }
+ else
+ {
+ mCorrupted = true ;
+ }
}
}
}
@@ -1426,6 +1436,11 @@ bool LLAudioSource::play(const LLUUID &audio_uuid)
bool LLAudioSource::isDone() const
{
+ if(mCorrupted)
+ {
+ return true ;
+ }
+
const F32 MAX_AGE = 60.f;
const F32 MAX_UNPLAYED_AGE = 15.f;
const F32 MAX_MUTED_AGE = 11.f;
@@ -1741,7 +1756,7 @@ LLAudioData::LLAudioData(const LLUUID &uuid) :
}
}
-
+//return false when the audio file is corrupted.
bool LLAudioData::load()
{
// For now, just assume we're going to use one buffer per audiodata.
@@ -1757,7 +1772,7 @@ bool LLAudioData::load()
{
// No free buffers, abort.
llinfos << "Not able to allocate a new audio buffer, aborting." << llendl;
- return false;
+ return true;
}
std::string uuid_str;
diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h
index 30d2490635..a47ee7ca7c 100644
--- a/indra/llaudio/llaudioengine.h
+++ b/indra/llaudio/llaudioengine.h
@@ -334,6 +334,7 @@ protected:
bool mSyncSlave;
bool mQueueSounds;
bool mPlayedOnce;
+ bool mCorrupted;
S32 mType;
LLVector3d mPositionGlobal;
LLVector3 mVelocity;
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 145dddd543..5e566d6c7c 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -93,7 +93,8 @@ LLAssetDictionary::LLAssetDictionary()
addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true));
addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
- addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
+ addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
+ addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false));
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE));
};
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 74ccd00324..d538accbf7 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -108,9 +108,13 @@ public:
AT_LINK_FOLDER = 25,
// Inventory folder link
+
+ AT_WIDGET = 40,
+ // UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...)
+
AT_MESH = 49,
- // Mesh data in our proprietary SLM format
-
+ // Mesh data in our proprietary SLM format
+
AT_COUNT = 50,
// +*********************************************************+
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 3ee26c015e..556b6b0937 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -620,6 +620,12 @@ namespace LLError
s.defaultLevel = level;
}
+ ELevel getDefaultLevel()
+ {
+ Settings& s = Settings::get();
+ return s.defaultLevel;
+ }
+
void setFunctionLevel(const std::string& function_name, ELevel level)
{
Globals& g = Globals::get();
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index fb75d45e2c..ed9de002f5 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -75,6 +75,7 @@ namespace LLError
LL_COMMON_API void setPrintLocation(bool);
LL_COMMON_API void setDefaultLevel(LLError::ELevel);
+ LL_COMMON_API ELevel getDefaultLevel();
LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel);
LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel);
LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel);
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index 17a4287538..31d5f3d2c7 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -151,6 +151,7 @@
#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class
#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class
+#pragma warning (disable : 4018) // '<' : signed/unsigned mismatch
#endif // LL_MSVC
#if LL_WINDOWS
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 6ca0737445..e295e3c621 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -24,6 +24,9 @@
* $/LicenseInfo$
*/
+// Must turn on conditional declarations in header file so definitions end up
+// with proper linkage.
+#define LLSD_DEBUG_INFO
#include "linden_common.h"
#include "llsd.h"
@@ -31,6 +34,7 @@
#include "../llmath/llmath.h"
#include "llformat.h"
#include "llsdserialize.h"
+#include "stringize.h"
#ifndef LL_RELEASE_FOR_DOWNLOAD
#define NAME_UNNAMED_NAMESPACE
@@ -50,6 +54,18 @@ namespace
using namespace LLSDUnnamedNamespace;
#endif
+namespace llsd
+{
+
+// statics
+S32 sLLSDAllocationCount = 0;
+S32 sLLSDNetObjects = 0;
+
+} // namespace llsd
+
+#define ALLOC_LLSD_OBJECT { llsd::sLLSDNetObjects++; llsd::sLLSDAllocationCount++; }
+#define FREE_LLSD_OBJECT { llsd::sLLSDNetObjects--; }
+
class LLSD::Impl
/**< This class is the abstract base class of the implementation of LLSD
It provides the reference counting implementation, and the default
@@ -58,13 +74,10 @@ class LLSD::Impl
*/
{
-private:
- U32 mUseCount;
-
protected:
Impl();
- enum StaticAllocationMarker { STATIC };
+ enum StaticAllocationMarker { STATIC_USAGE_COUNT = 0xFFFFFFFF };
Impl(StaticAllocationMarker);
///< This constructor is used for static objects and causes the
// suppresses adjusting the debugging counters when they are
@@ -72,8 +85,10 @@ protected:
virtual ~Impl();
- bool shared() const { return mUseCount > 1; }
+ bool shared() const { return (mUseCount > 1) && (mUseCount != STATIC_USAGE_COUNT); }
+ U32 mUseCount;
+
public:
static void reset(Impl*& var, Impl* impl);
///< safely set var to refer to the new impl (possibly shared)
@@ -128,6 +143,18 @@ public:
virtual LLSD::array_const_iterator beginArray() const { return endArray(); }
virtual LLSD::array_const_iterator endArray() const { static const std::vector empty; return empty.end(); }
+ virtual void dumpStats() const;
+ virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
+ // Container subclasses contain LLSD objects, rather than directly
+ // containing Impl objects. This helper forwards through LLSD.
+ void calcStats(const LLSD& llsd, S32 type_counts[], S32 share_counts[]) const
+ {
+ safe(llsd.impl).calcStats(type_counts, share_counts);
+ }
+
+ static const Impl& getImpl(const LLSD& llsd) { return safe(llsd.impl); }
+ static Impl& getImpl(LLSD& llsd) { return safe(llsd.impl); }
+
static const LLSD& undef();
static U32 sAllocationCount;
@@ -360,6 +387,9 @@ namespace
LLSD::map_iterator endMap() { return mData.end(); }
virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); }
virtual LLSD::map_const_iterator endMap() const { return mData.end(); }
+
+ virtual void dumpStats() const;
+ virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
};
ImplMap& ImplMap::makeMap(LLSD::Impl*& var)
@@ -414,6 +444,34 @@ namespace
return i->second;
}
+ void ImplMap::dumpStats() const
+ {
+ std::cout << "Map size: " << mData.size() << std::endl;
+
+ std::cout << "LLSD Net Objects: " << llsd::sLLSDNetObjects << std::endl;
+ std::cout << "LLSD allocations: " << llsd::sLLSDAllocationCount << std::endl;
+
+ std::cout << "LLSD::Impl Net Objects: " << sOutstandingCount << std::endl;
+ std::cout << "LLSD::Impl allocations: " << sAllocationCount << std::endl;
+
+ Impl::dumpStats();
+ }
+
+ void ImplMap::calcStats(S32 type_counts[], S32 share_counts[]) const
+ {
+ LLSD::map_const_iterator iter = beginMap();
+ while (iter != endMap())
+ {
+ //std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl;
+ Impl::calcStats((*iter).second, type_counts, share_counts);
+ iter++;
+ }
+
+ // Add in the values for this map
+ Impl::calcStats(type_counts, share_counts);
+ }
+
+
class ImplArray : public LLSD::Impl
{
private:
@@ -449,6 +507,8 @@ namespace
LLSD::array_iterator endArray() { return mData.end(); }
virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); }
virtual LLSD::array_const_iterator endArray() const { return mData.end(); }
+
+ virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
};
ImplArray& ImplArray::makeArray(Impl*& var)
@@ -490,12 +550,13 @@ namespace
void ImplArray::insert(LLSD::Integer i, const LLSD& v)
{
- if (i < 0) {
+ if (i < 0)
+ {
return;
}
DataVector::size_type index = i;
- if (index >= mData.size())
+ if (index >= mData.size()) // tbd - sanity check limit for index ?
{
mData.resize(index + 1);
}
@@ -543,6 +604,19 @@ namespace
return mData[index];
}
+
+ void ImplArray::calcStats(S32 type_counts[], S32 share_counts[]) const
+ {
+ LLSD::array_const_iterator iter = beginArray();
+ while (iter != endArray())
+ { // Add values for all items held in the array
+ Impl::calcStats((*iter), type_counts, share_counts);
+ iter++;
+ }
+
+ // Add in the values for this array
+ Impl::calcStats(type_counts, share_counts);
+ }
}
LLSD::Impl::Impl()
@@ -564,8 +638,11 @@ LLSD::Impl::~Impl()
void LLSD::Impl::reset(Impl*& var, Impl* impl)
{
- if (impl) ++impl->mUseCount;
- if (var && --var->mUseCount == 0)
+ if (impl && impl->mUseCount != STATIC_USAGE_COUNT)
+ {
+ ++impl->mUseCount;
+ }
+ if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
{
delete var;
}
@@ -574,13 +651,13 @@ void LLSD::Impl::reset(Impl*& var, Impl* impl)
LLSD::Impl& LLSD::Impl::safe(Impl* impl)
{
- static Impl theUndefined(STATIC);
+ static Impl theUndefined(STATIC_USAGE_COUNT);
return impl ? *impl : theUndefined;
}
const LLSD::Impl& LLSD::Impl::safe(const Impl* impl)
{
- static Impl theUndefined(STATIC);
+ static Impl theUndefined(STATIC_USAGE_COUNT);
return impl ? *impl : theUndefined;
}
@@ -656,6 +733,43 @@ const LLSD& LLSD::Impl::undef()
return immutableUndefined;
}
+void LLSD::Impl::dumpStats() const
+{
+ S32 type_counts[LLSD::TypeLLSDNumTypes + 1];
+ memset(&type_counts, 0, sizeof(type_counts));
+
+ S32 share_counts[LLSD::TypeLLSDNumTypes + 1];
+ memset(&share_counts, 0, sizeof(share_counts));
+
+ // Add info from all the values this object has
+ calcStats(type_counts, share_counts);
+
+ S32 type_index = LLSD::TypeLLSDTypeBegin;
+ while (type_index != LLSD::TypeLLSDTypeEnd)
+ {
+ std::cout << LLSD::typeString((LLSD::Type)type_index) << " type "
+ << type_counts[type_index] << " objects, "
+ << share_counts[type_index] << " shared"
+ << std::endl;
+ type_index++;
+ }
+}
+
+
+void LLSD::Impl::calcStats(S32 type_counts[], S32 share_counts[]) const
+{
+ S32 tp = S32(type());
+ if (0 <= tp && tp < LLSD::TypeLLSDNumTypes)
+ {
+ type_counts[tp]++;
+ if (shared())
+ {
+ share_counts[tp]++;
+ }
+ }
+}
+
+
U32 LLSD::Impl::sAllocationCount = 0;
U32 LLSD::Impl::sOutstandingCount = 0;
@@ -681,10 +795,10 @@ namespace
}
-LLSD::LLSD() : impl(0) { }
-LLSD::~LLSD() { Impl::reset(impl, 0); }
+LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; }
+LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); }
-LLSD::LLSD(const LLSD& other) : impl(0) { assign(other); }
+LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); }
void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); }
@@ -692,18 +806,18 @@ void LLSD::clear() { Impl::assignUndefined(impl); }
LLSD::Type LLSD::type() const { return safe(impl).type(); }
-// Scaler Constructors
-LLSD::LLSD(Boolean v) : impl(0) { assign(v); }
-LLSD::LLSD(Integer v) : impl(0) { assign(v); }
-LLSD::LLSD(Real v) : impl(0) { assign(v); }
-LLSD::LLSD(const UUID& v) : impl(0) { assign(v); }
-LLSD::LLSD(const String& v) : impl(0) { assign(v); }
-LLSD::LLSD(const Date& v) : impl(0) { assign(v); }
-LLSD::LLSD(const URI& v) : impl(0) { assign(v); }
-LLSD::LLSD(const Binary& v) : impl(0) { assign(v); }
+// Scalar Constructors
+LLSD::LLSD(Boolean v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
+LLSD::LLSD(Integer v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
+LLSD::LLSD(Real v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
+LLSD::LLSD(const UUID& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
+LLSD::LLSD(const String& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
+LLSD::LLSD(const Date& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
+LLSD::LLSD(const URI& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
+LLSD::LLSD(const Binary& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
// Convenience Constructors
-LLSD::LLSD(F32 v) : impl(0) { assign((Real)v); }
+LLSD::LLSD(F32 v) : impl(0) { ALLOC_LLSD_OBJECT; assign((Real)v); }
// Scalar Assignment
void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); }
@@ -726,7 +840,7 @@ LLSD::URI LLSD::asURI() const { return safe(impl).asURI(); }
LLSD::Binary LLSD::asBinary() const { return safe(impl).asBinary(); }
// const char * helpers
-LLSD::LLSD(const char* v) : impl(0) { assign(v); }
+LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
void LLSD::assign(const char* v)
{
if(v) assign(std::string(v));
@@ -784,9 +898,6 @@ LLSD& LLSD::operator[](Integer i)
const LLSD& LLSD::operator[](Integer i) const
{ return safe(impl).ref(i); }
-U32 LLSD::allocationCount() { return Impl::sAllocationCount; }
-U32 LLSD::outstandingCount() { return Impl::sOutstandingCount; }
-
static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
{
// sStorage is used to hold the string representation of the llsd last
@@ -801,15 +912,9 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
{
std::ostringstream out;
if (useXMLFormat)
- {
- LLSDXMLStreamer xml_streamer(llsd);
- out << xml_streamer;
- }
+ out << LLSDXMLStreamer(llsd);
else
- {
- LLSDNotationStreamer notation_streamer(llsd);
- out << notation_streamer;
- }
+ out << LLSDNotationStreamer(llsd);
out_string = out.str();
}
int len = out_string.length();
@@ -840,3 +945,38 @@ LLSD::array_iterator LLSD::beginArray() { return makeArray(impl).beginArray();
LLSD::array_iterator LLSD::endArray() { return makeArray(impl).endArray(); }
LLSD::array_const_iterator LLSD::beginArray() const{ return safe(impl).beginArray(); }
LLSD::array_const_iterator LLSD::endArray() const { return safe(impl).endArray(); }
+
+namespace llsd
+{
+
+U32 allocationCount() { return LLSD::Impl::sAllocationCount; }
+U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; }
+
+// Diagnostic dump of contents in an LLSD object
+void dumpStats(const LLSD& llsd) { LLSD::Impl::getImpl(llsd).dumpStats(); }
+
+} // namespace llsd
+
+// static
+std::string LLSD::typeString(Type type)
+{
+ static const char * sTypeNameArray[] = {
+ "Undefined",
+ "Boolean",
+ "Integer",
+ "Real",
+ "String",
+ "UUID",
+ "Date",
+ "URI",
+ "Binary",
+ "Map",
+ "Array"
+ };
+
+ if (0 <= type && type < LL_ARRAY_SIZE(sTypeNameArray))
+ {
+ return sTypeNameArray[type];
+ }
+ return STRINGIZE("** invalid type value " << type);
+}
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 90d0f97873..5eb69059ac 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -40,10 +40,10 @@
/**
LLSD provides a flexible data system similar to the data facilities of
dynamic languages like Perl and Python. It is created to support exchange
- of structured data between loosly coupled systems. (Here, "loosly coupled"
+ of structured data between loosely coupled systems. (Here, "loosely coupled"
means not compiled together into the same module.)
- Data in such exchanges must be highly tollerant of changes on either side
+ Data in such exchanges must be highly tolerant of changes on either side
such as:
- recompilation
- implementation in a different langauge
@@ -51,19 +51,19 @@
- execution of older versions (with fewer parameters)
To this aim, the C++ API of LLSD strives to be very easy to use, and to
- default to "the right thing" whereever possible. It is extremely tollerant
+ default to "the right thing" wherever possible. It is extremely tolerant
of errors and unexpected situations.
- The fundimental class is LLSD. LLSD is a value holding object. It holds
+ The fundamental class is LLSD. LLSD is a value holding object. It holds
one value that is either undefined, one of the scalar types, or a map or an
array. LLSD objects have value semantics (copying them copies the value,
- though it can be considered efficient, due to shareing.), and mutable.
+ though it can be considered efficient, due to sharing), and mutable.
Undefined is the singular value given to LLSD objects that are not
initialized with any data. It is also used as the return value for
- operations that return an LLSD,
+ operations that return an LLSD.
- The sclar data types are:
+ The scalar data types are:
- Boolean - true or false
- Integer - a 32 bit signed integer
- Real - a 64 IEEE 754 floating point value
@@ -80,9 +80,73 @@
An array is a sequence of zero or more LLSD values.
+ Thread Safety
+
+ In general, these LLSD classes offer *less* safety than STL container
+ classes. Implementations prior to this one were unsafe even when
+ completely unrelated LLSD trees were in two threads due to reference
+ sharing of special 'undefined' values that participated in the reference
+ counting mechanism.
+
+ The dereference-before-refcount and aggressive tree sharing also make
+ it impractical to share an LLSD across threads. A strategy of passing
+ ownership or a copy to another thread is still difficult due to a lack
+ of a cloning interface but it can be done with some care.
+
+ One way of transferring ownership is as follows:
+
+ void method(const LLSD input) {
+ ...
+ LLSD * xfer_tree = new LLSD();
+ {
+ // Top-level values
+ (* xfer_tree)['label'] = "Some text";
+ (* xfer_tree)['mode'] = APP_MODE_CONSTANT;
+
+ // There will be a second-level
+ LLSD subtree(LLSD::emptyMap());
+ (* xfer_tree)['subtree'] = subtree;
+
+ // Do *not* copy from LLSD objects via LLSD
+ // intermediaries. Only use plain-old-data
+ // types as intermediaries to prevent reference
+ // sharing.
+ subtree['value1'] = input['value1'].asInteger();
+ subtree['value2'] = input['value2'].asString();
+
+ // Close scope and drop 'subtree's reference.
+ // Only xfer_tree has a reference to the second
+ // level data.
+ }
+ ...
+ // Transfer the LLSD pointer to another thread. Ownership
+ // transfers, this thread no longer has a reference to any
+ // part of the xfer_tree and there's nothing to free or
+ // release here. Receiving thread does need to delete the
+ // pointer when it is done with the LLSD. Transfer
+ // mechanism must perform correct data ordering operations
+ // as dictated by architecture.
+ other_thread.sendMessageAndPointer("Take This", xfer_tree);
+ xfer_tree = NULL;
+
+
+ Avoid this pattern which provides half of a race condition:
+
+ void method(const LLSD input) {
+ ...
+ LLSD xfer_tree(LLSD::emptyMap());
+ xfer_tree['label'] = "Some text";
+ xfer_tree['mode'] = APP_MODE_CONSTANT;
+ ...
+ other_thread.sendMessageAndPointer("Take This", xfer_tree);
+
+
@nosubgrouping
*/
+// Normally undefined, used for diagnostics
+//#define LLSD_DEBUG_INFO 1
+
class LL_COMMON_API LLSD
{
public:
@@ -202,7 +266,7 @@ public:
//@}
/** @name Character Pointer Helpers
- These are helper routines to make working with char* the same as easy as
+ These are helper routines to make working with char* as easy as
working with strings.
*/
//@{
@@ -266,7 +330,7 @@ public:
/** @name Type Testing */
//@{
enum Type {
- TypeUndefined,
+ TypeUndefined = 0,
TypeBoolean,
TypeInteger,
TypeReal,
@@ -276,7 +340,10 @@ public:
TypeURI,
TypeBinary,
TypeMap,
- TypeArray
+ TypeArray,
+ TypeLLSDTypeEnd,
+ TypeLLSDTypeBegin = TypeUndefined,
+ TypeLLSDNumTypes = (TypeLLSDTypeEnd - TypeLLSDTypeBegin)
};
Type type() const;
@@ -302,7 +369,7 @@ public:
If you get a linker error about these being missing, you have made
mistake in your code. DO NOT IMPLEMENT THESE FUNCTIONS as a fix.
- All of thse problems stem from trying to support char* in LLSD or in
+ All of these problems stem from trying to support char* in LLSD or in
std::string. There are too many automatic casts that will lead to
using an arbitrary pointer or scalar type to std::string.
*/
@@ -311,7 +378,7 @@ public:
void assign(const void*); ///< assign from arbitrary pointers
LLSD& operator=(const void*); ///< assign from arbitrary pointers
- bool has(Integer) const; ///< has only works for Maps
+ bool has(Integer) const; ///< has() only works for Maps
//@}
/** @name Implementation */
@@ -320,13 +387,7 @@ public:
class Impl;
private:
Impl* impl;
- //@}
-
- /** @name Unit Testing Interface */
- //@{
-public:
- static U32 allocationCount(); ///< how many Impls have been made
- static U32 outstandingCount(); ///< how many Impls are still alive
+ friend class LLSD::Impl;
//@}
private:
@@ -338,6 +399,10 @@ private:
/// Returns Notation version of llsd -- only to be called from debugger
static const char *dump(const LLSD &llsd);
//@}
+
+public:
+
+ static std::string typeString(Type type); // Return human-readable type as a string
};
struct llsd_select_bool : public std::unary_function
@@ -385,9 +450,32 @@ struct llsd_select_string : public std::unary_function
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
+namespace llsd
+{
+
+#ifdef LLSD_DEBUG_INFO
+/** @name Unit Testing Interface */
+//@{
+ LL_COMMON_API void dumpStats(const LLSD&); ///< Output information on object and usage
+
+ /// @warn THE FOLLOWING COUNTS WILL NOT BE ACCURATE IN A MULTI-THREADED
+ /// ENVIRONMENT.
+ ///
+ /// These counts track LLSD::Impl (hidden) objects.
+ LL_COMMON_API U32 allocationCount(); ///< how many Impls have been made
+ LL_COMMON_API U32 outstandingCount(); ///< how many Impls are still alive
+
+ /// These counts track LLSD (public) objects.
+ LL_COMMON_API extern S32 sLLSDAllocationCount; ///< Number of LLSD objects ever created
+ LL_COMMON_API extern S32 sLLSDNetObjects; ///< Number of LLSD objects that exist
+#endif
+//@}
+
+} // namespace llsd
+
/** QUESTIONS & TO DOS
- - Would Binary be more convenient as usigned char* buffer semantics?
- - Should Binary be convertable to/from String, and if so how?
+ - Would Binary be more convenient as unsigned char* buffer semantics?
+ - Should Binary be convertible to/from String, and if so how?
- as UTF8 encoded strings (making not like UUID<->String)
- as Base64 or Base96 encoded (making like UUID<->String)
- Conversions to std::string and LLUUID do not result in easy assignment
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 6fce042315..18223bd7d3 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -611,6 +611,7 @@ LLCPUInfo::LLCPUInfo()
out << " (" << mCPUMHz << " MHz)";
}
mCPUString = out.str();
+ LLStringUtil::trim(mCPUString);
}
bool LLCPUInfo::hasAltivec() const
diff --git a/indra/llcommon/llversionviewer.h.in b/indra/llcommon/llversionviewer.h.in
index 9fb0c10d6f..147a8f33c2 100644
--- a/indra/llcommon/llversionviewer.h.in
+++ b/indra/llcommon/llversionviewer.h.in
@@ -29,7 +29,7 @@
const S32 LL_VERSION_MAJOR = 3;
const S32 LL_VERSION_MINOR = 2;
-const S32 LL_VERSION_PATCH = 1;
+const S32 LL_VERSION_PATCH = 7;
const S32 LL_VERSION_BUILD = 0;
const char * const LL_CHANNEL = "Firestorm-private";
diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h
index 556eff8370..40b3364b36 100644
--- a/indra/llcommon/stdenums.h
+++ b/indra/llcommon/stdenums.h
@@ -49,8 +49,9 @@ enum EDragAndDropType
DAD_ANIMATION = 12,
DAD_GESTURE = 13,
DAD_LINK = 14,
- DAD_MESH = 15,
- DAD_COUNT = 16, // number of types in this enum
+ DAD_MESH = 15,
+ DAD_WIDGET = 16,
+ DAD_COUNT = 17, // number of types in this enum
};
// Reasons for drags to be denied.
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index 0dd178aec1..c95c99c055 100644
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -42,6 +42,7 @@
#include "llpumpio.h"
#include "llhttpclient.h"
#include "llsdserialize.h"
+#include "llproxy.h"
// [SL:KB] - Patch: Viewer-CrashLookup | Checked: 2011-03-24 (Catznip-2.6.0a) | Added: Catznip-2.6.0a
#ifdef LL_WINDOWS
@@ -596,3 +597,9 @@ bool LLCrashLogger::init()
return true;
}
+
+// For cleanup code common to all platforms.
+void LLCrashLogger::commonCleanup()
+{
+ LLProxy::cleanupClass();
+}
diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h
index 24ce201e7e..3e330780b0 100644
--- a/indra/llcrashlogger/llcrashlogger.h
+++ b/indra/llcrashlogger/llcrashlogger.h
@@ -51,7 +51,8 @@ public:
virtual void updateApplication(const std::string& message = LLStringUtil::null);
virtual bool init();
virtual bool mainLoop() = 0;
- virtual bool cleanup() { return true; }
+ virtual bool cleanup() = 0;
+ void commonCleanup();
void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; }
S32 getCrashBehavior() { return mCrashBehavior; }
bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout);
diff --git a/indra/llinventory/lleconomy.cpp b/indra/llinventory/lleconomy.cpp
index c6eaa6d3e1..d643ea6ed9 100644
--- a/indra/llinventory/lleconomy.cpp
+++ b/indra/llinventory/lleconomy.cpp
@@ -48,6 +48,31 @@ LLGlobalEconomy::LLGlobalEconomy()
LLGlobalEconomy::~LLGlobalEconomy()
{ }
+void LLGlobalEconomy::addObserver(LLEconomyObserver* observer)
+{
+ mObservers.push_back(observer);
+}
+
+void LLGlobalEconomy::removeObserver(LLEconomyObserver* observer)
+{
+ std::list::iterator it =
+ std::find(mObservers.begin(), mObservers.end(), observer);
+ if (it != mObservers.end())
+ {
+ mObservers.erase(it);
+ }
+}
+
+void LLGlobalEconomy::notifyObservers()
+{
+ for (std::list::iterator it = mObservers.begin();
+ it != mObservers.end();
+ ++it)
+ {
+ (*it)->onEconomyDataChange();
+ }
+}
+
// static
void LLGlobalEconomy::processEconomyData(LLMessageSystem *msg, LLGlobalEconomy* econ_data)
{
@@ -88,6 +113,8 @@ void LLGlobalEconomy::processEconomyData(LLMessageSystem *msg, LLGlobalEconomy*
econ_data->setTeleportPriceExponent(f);
msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceGroupCreate, i);
econ_data->setPriceGroupCreate(i);
+
+ econ_data->notifyObservers();
}
S32 LLGlobalEconomy::calculateTeleportCost(F32 distance) const
diff --git a/indra/llinventory/lleconomy.h b/indra/llinventory/lleconomy.h
index cc6643f955..eb2ecf71ba 100644
--- a/indra/llinventory/lleconomy.h
+++ b/indra/llinventory/lleconomy.h
@@ -31,6 +31,16 @@
class LLMessageSystem;
class LLVector3;
+/**
+ * Register an observer to be notified of economy data updates coming from server.
+ */
+class LLEconomyObserver
+{
+public:
+ virtual ~LLEconomyObserver() {}
+ virtual void onEconomyDataChange() = 0;
+};
+
class LLGlobalEconomy
{
public:
@@ -46,6 +56,10 @@ public:
virtual void print();
+ void addObserver(LLEconomyObserver* observer);
+ void removeObserver(LLEconomyObserver* observer);
+ void notifyObservers();
+
static void processEconomyData(LLMessageSystem *msg, LLGlobalEconomy* econ_data);
S32 calculateTeleportCost(F32 distance) const;
@@ -89,6 +103,8 @@ private:
S32 mTeleportMinPrice;
F32 mTeleportPriceExponent;
S32 mPriceGroupCreate;
+
+ std::list mObservers;
};
diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp
index d2bba21648..8282d79b67 100644
--- a/indra/llinventory/llinventorytype.cpp
+++ b/indra/llinventory/llinventorytype.cpp
@@ -84,6 +84,7 @@ LLInventoryDictionary::LLInventoryDictionary()
addEntry(LLInventoryType::IT_ANIMATION, new InventoryEntry("animation", "animation", 1, LLAssetType::AT_ANIMATION));
addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE));
addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH));
+ addEntry(LLInventoryType::IT_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET));
}
@@ -134,7 +135,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
LLInventoryType::IT_NONE, // 37 AT_NONE
LLInventoryType::IT_NONE, // 38 AT_NONE
LLInventoryType::IT_NONE, // 39 AT_NONE
- LLInventoryType::IT_NONE, // 40 AT_NONE
+ LLInventoryType::IT_WIDGET, // 40 AT_WIDGET
LLInventoryType::IT_NONE, // 41 AT_NONE
LLInventoryType::IT_NONE, // 42 AT_NONE
LLInventoryType::IT_NONE, // 43 AT_NONE
@@ -143,7 +144,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
LLInventoryType::IT_NONE, // 46 AT_NONE
LLInventoryType::IT_NONE, // 47 AT_NONE
LLInventoryType::IT_NONE, // 48 AT_NONE
- LLInventoryType::IT_MESH // 49 AT_MESH
+ LLInventoryType::IT_MESH, // 49 AT_MESH
};
// static
diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h
index 1a24e351ad..4d1e0db040 100644
--- a/indra/llinventory/llinventorytype.h
+++ b/indra/llinventory/llinventorytype.h
@@ -62,7 +62,8 @@ public:
IT_ANIMATION = 19,
IT_GESTURE = 20,
IT_MESH = 22,
- IT_COUNT = 23,
+ IT_WIDGET = 23,
+ IT_COUNT = 24,
IT_NONE = -1
};
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index cd100cdf9f..b5e59c1ca3 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -75,10 +75,6 @@ set(llmath_HEADER_FILES
llvector4a.h
llvector4a.inl
llvector4logical.h
- llv4math.h
- llv4matrix3.h
- llv4matrix4.h
- llv4vector3.h
llvolume.h
llvolumemgr.h
llvolumeoctree.h
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index ffde53cfbb..1b11e83b4a 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -685,7 +685,7 @@ public:
if (lt != 0x7)
{
- OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
+ //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
return false;
}
diff --git a/indra/llmath/llv4math.h b/indra/llmath/llv4math.h
deleted file mode 100644
index 5f403ba526..0000000000
--- a/indra/llmath/llv4math.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * @file llv4math.h
- * @brief LLV4* class header file - vector processor enabled math
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLV4MATH_H
-#define LL_LLV4MATH_H
-
-// *NOTE: We do not support SSE acceleration on Windows builds.
-// Our minimum specification for the viewer includes 1 GHz Athlon processors,
-// which covers the Athlon Thunderbird series that does not support SSE.
-//
-// Our header files include statements like this
-// const F32 HAVOK_TIMESTEP = 1.f / 45.f;
-// This creates "globals" that are included in each .obj file. If a single
-// .cpp file has SSE code generation turned on (eg, llviewerjointmesh_sse.cpp)
-// these globals will be initialized using SSE instructions. This causes SL
-// to crash before main() on processors without SSE. Untangling all these
-// headers/variables is too much work for the small performance gains of
-// vectorization.
-//
-// Therefore we only support vectorization on builds where the everything is
-// built with SSE or Altivec. See https://jira.secondlife.com/browse/VWR-1610
-// and https://jira.lindenlab.com/browse/SL-47720 for details.
-//
-// Sorry the code is such a mess. JC
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4MATH - GNUC
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#if LL_GNUC && __GNUC__ >= 4 && __SSE__
-
-#define LL_VECTORIZE 1
-
-#if LL_DARWIN
-
-#include
-#include
-typedef vFloat V4F32;
-
-#else
-
-#include
-typedef float V4F32 __attribute__((vector_size(16)));
-
-#endif
-
-#endif
-#if LL_GNUC
-
-#define LL_LLV4MATH_ALIGN_PREFIX
-#define LL_LLV4MATH_ALIGN_POSTFIX __attribute__((aligned(16)))
-
-#endif
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4MATH - MSVC
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-// Only vectorize if the entire Windows build uses SSE.
-// _M_IX86_FP is set when SSE code generation is turned on, and I have
-// confirmed this in VS2003, VS2003 SP1, and VS2005. JC
-#if LL_MSVC && _M_IX86_FP
-
-#define LL_VECTORIZE 1
-
-#include
-
-typedef __m128 V4F32;
-
-#endif
-#if LL_MSVC
-
-#define LL_LLV4MATH_ALIGN_PREFIX __declspec(align(16))
-#define LL_LLV4MATH_ALIGN_POSTFIX
-
-#endif
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4MATH - default - no vectorization
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#if !LL_VECTORIZE
-
-#define LL_VECTORIZE 0
-
-struct V4F32 { F32 __pad__[4]; };
-
-inline F32 llv4lerp(F32 a, F32 b, F32 w) { return ( b - a ) * w + a; }
-
-#endif
-
-#ifndef LL_LLV4MATH_ALIGN_PREFIX
-# define LL_LLV4MATH_ALIGN_PREFIX
-#endif
-#ifndef LL_LLV4MATH_ALIGN_POSTFIX
-# define LL_LLV4MATH_ALIGN_POSTFIX
-#endif
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4MATH
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-
-#define LLV4_NUM_AXIS 4
-
-class LLV4Vector3;
-class LLV4Matrix3;
-class LLV4Matrix4;
-
-#endif
diff --git a/indra/llmath/llv4matrix3.h b/indra/llmath/llv4matrix3.h
deleted file mode 100644
index 270f5d7dae..0000000000
--- a/indra/llmath/llv4matrix3.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/**
- * @file llviewerjointmesh.cpp
- * @brief LLV4* class header file - vector processor enabled math
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLV4MATRIX3_H
-#define LL_LLV4MATRIX3_H
-
-#include "llv4math.h"
-#include "llv4vector3.h"
-#include "m3math.h" // for operator LLMatrix3()
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Matrix3
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-LL_LLV4MATH_ALIGN_PREFIX
-
-class LLV4Matrix3
-{
-public:
- union {
- F32 mMatrix[LLV4_NUM_AXIS][LLV4_NUM_AXIS];
- V4F32 mV[LLV4_NUM_AXIS];
- };
-
- void lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w);
- void multiply(const LLVector3 &a, LLVector3& out) const;
- void multiply(const LLVector4 &a, LLV4Vector3& out) const;
- void multiply(const LLVector3 &a, LLV4Vector3& out) const;
-
- const LLV4Matrix3& transpose();
- const LLV4Matrix3& operator=(const LLMatrix3& a);
-
- operator LLMatrix3() const { return (reinterpret_cast(const_cast(&mMatrix[0][0])))->getMat3(); }
-
- friend LLVector3 operator*(const LLVector3& a, const LLV4Matrix3& b);
-}
-
-LL_LLV4MATH_ALIGN_POSTFIX;
-
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Matrix3 - SSE
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#if LL_VECTORIZE
-
-inline void LLV4Matrix3::lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w)
-{
- __m128 vw = _mm_set1_ps(w);
- mV[VX] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VX], a.mV[VX]), vw), a.mV[VX]); // ( b - a ) * w + a
- mV[VY] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VY], a.mV[VY]), vw), a.mV[VY]);
- mV[VZ] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VZ], a.mV[VZ]), vw), a.mV[VZ]);
-}
-
-inline void LLV4Matrix3::multiply(const LLVector3 &a, LLVector3& o) const
-{
- LLV4Vector3 j;
- j.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
- j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
- j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
- o.setVec(j.mV);
-}
-
-inline void LLV4Matrix3::multiply(const LLVector4 &a, LLV4Vector3& o) const
-{
- o.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
- o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
- o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
-}
-
-inline void LLV4Matrix3::multiply(const LLVector3 &a, LLV4Vector3& o) const
-{
- o.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
- o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
- o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Matrix3
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#else
-
-inline void LLV4Matrix3::lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w)
-{
- mMatrix[VX][VX] = llv4lerp(a.mMatrix[VX][VX], b.mMatrix[VX][VX], w);
- mMatrix[VX][VY] = llv4lerp(a.mMatrix[VX][VY], b.mMatrix[VX][VY], w);
- mMatrix[VX][VZ] = llv4lerp(a.mMatrix[VX][VZ], b.mMatrix[VX][VZ], w);
-
- mMatrix[VY][VX] = llv4lerp(a.mMatrix[VY][VX], b.mMatrix[VY][VX], w);
- mMatrix[VY][VY] = llv4lerp(a.mMatrix[VY][VY], b.mMatrix[VY][VY], w);
- mMatrix[VY][VZ] = llv4lerp(a.mMatrix[VY][VZ], b.mMatrix[VY][VZ], w);
-
- mMatrix[VZ][VX] = llv4lerp(a.mMatrix[VZ][VX], b.mMatrix[VZ][VX], w);
- mMatrix[VZ][VY] = llv4lerp(a.mMatrix[VZ][VY], b.mMatrix[VZ][VY], w);
- mMatrix[VZ][VZ] = llv4lerp(a.mMatrix[VZ][VZ], b.mMatrix[VZ][VZ], w);
-}
-
-inline void LLV4Matrix3::multiply(const LLVector3 &a, LLVector3& o) const
-{
- o.setVec( a.mV[VX] * mMatrix[VX][VX] +
- a.mV[VY] * mMatrix[VY][VX] +
- a.mV[VZ] * mMatrix[VZ][VX],
-
- a.mV[VX] * mMatrix[VX][VY] +
- a.mV[VY] * mMatrix[VY][VY] +
- a.mV[VZ] * mMatrix[VZ][VY],
-
- a.mV[VX] * mMatrix[VX][VZ] +
- a.mV[VY] * mMatrix[VY][VZ] +
- a.mV[VZ] * mMatrix[VZ][VZ]);
-}
-
-inline void LLV4Matrix3::multiply(const LLVector4 &a, LLV4Vector3& o) const
-{
- o.setVec( a.mV[VX] * mMatrix[VX][VX] +
- a.mV[VY] * mMatrix[VY][VX] +
- a.mV[VZ] * mMatrix[VZ][VX],
-
- a.mV[VX] * mMatrix[VX][VY] +
- a.mV[VY] * mMatrix[VY][VY] +
- a.mV[VZ] * mMatrix[VZ][VY],
-
- a.mV[VX] * mMatrix[VX][VZ] +
- a.mV[VY] * mMatrix[VY][VZ] +
- a.mV[VZ] * mMatrix[VZ][VZ]);
-}
-
-inline void LLV4Matrix3::multiply(const LLVector3 &a, LLV4Vector3& o) const
-{
- o.setVec( a.mV[VX] * mMatrix[VX][VX] +
- a.mV[VY] * mMatrix[VY][VX] +
- a.mV[VZ] * mMatrix[VZ][VX],
-
- a.mV[VX] * mMatrix[VX][VY] +
- a.mV[VY] * mMatrix[VY][VY] +
- a.mV[VZ] * mMatrix[VZ][VY],
-
- a.mV[VX] * mMatrix[VX][VZ] +
- a.mV[VY] * mMatrix[VY][VZ] +
- a.mV[VZ] * mMatrix[VZ][VZ]);
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Matrix3
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#endif
-
-inline const LLV4Matrix3& LLV4Matrix3::transpose()
-{
-#if LL_VECTORIZE && defined(_MM_TRANSPOSE4_PS)
- _MM_TRANSPOSE4_PS(mV[VX], mV[VY], mV[VZ], mV[VW]);
- return *this;
-#else
- F32 temp;
- temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
- temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
- temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
-#endif
- return *this;
-}
-
-inline const LLV4Matrix3& LLV4Matrix3::operator=(const LLMatrix3& a)
-{
- memcpy(mMatrix[VX], a.mMatrix[VX], sizeof(F32) * 3 );
- memcpy(mMatrix[VY], a.mMatrix[VY], sizeof(F32) * 3 );
- memcpy(mMatrix[VZ], a.mMatrix[VZ], sizeof(F32) * 3 );
- return *this;
-}
-
-inline LLVector3 operator*(const LLVector3& a, const LLV4Matrix3& b)
-{
- return LLVector3(
- a.mV[VX] * b.mMatrix[VX][VX] +
- a.mV[VY] * b.mMatrix[VY][VX] +
- a.mV[VZ] * b.mMatrix[VZ][VX],
-
- a.mV[VX] * b.mMatrix[VX][VY] +
- a.mV[VY] * b.mMatrix[VY][VY] +
- a.mV[VZ] * b.mMatrix[VZ][VY],
-
- a.mV[VX] * b.mMatrix[VX][VZ] +
- a.mV[VY] * b.mMatrix[VY][VZ] +
- a.mV[VZ] * b.mMatrix[VZ][VZ] );
-}
-
-#endif
diff --git a/indra/llmath/llv4matrix4.h b/indra/llmath/llv4matrix4.h
deleted file mode 100644
index 2eb49d9294..0000000000
--- a/indra/llmath/llv4matrix4.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/**
- * @file llviewerjointmesh.cpp
- * @brief LLV4* class header file - vector processor enabled math
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLV4MATRIX4_H
-#define LL_LLV4MATRIX4_H
-
-#include "llv4math.h"
-#include "llv4matrix3.h" // just for operator LLV4Matrix3()
-#include "llv4vector3.h"
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Matrix4
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-LL_LLV4MATH_ALIGN_PREFIX
-
-class LLV4Matrix4
-{
-public:
- union {
- F32 mMatrix[LLV4_NUM_AXIS][LLV4_NUM_AXIS];
- V4F32 mV[LLV4_NUM_AXIS];
- };
-
- void lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w);
- void multiply(const LLVector3 &a, LLVector3& o) const;
- void multiply(const LLVector3 &a, LLV4Vector3& o) const;
-
- const LLV4Matrix4& transpose();
- const LLV4Matrix4& translate(const LLVector3 &vec);
- const LLV4Matrix4& translate(const LLV4Vector3 &vec);
- const LLV4Matrix4& operator=(const LLMatrix4& a);
-
- operator LLMatrix4() const { return *(reinterpret_cast(const_cast(&mMatrix[0][0]))); }
- operator LLV4Matrix3() const { return *(reinterpret_cast(const_cast(&mMatrix[0][0]))); }
-
- friend LLVector3 operator*(const LLVector3 &a, const LLV4Matrix4 &b);
-}
-
-LL_LLV4MATH_ALIGN_POSTFIX;
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Matrix4 - SSE
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#if LL_VECTORIZE
-
-inline void LLV4Matrix4::lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w)
-{
- __m128 vw = _mm_set1_ps(w);
- mV[VX] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VX], a.mV[VX]), vw), a.mV[VX]); // ( b - a ) * w + a
- mV[VY] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VY], a.mV[VY]), vw), a.mV[VY]);
- mV[VZ] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VZ], a.mV[VZ]), vw), a.mV[VZ]);
- mV[VW] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VW], a.mV[VW]), vw), a.mV[VW]);
-}
-
-inline void LLV4Matrix4::multiply(const LLVector3 &a, LLVector3& o) const
-{
- LLV4Vector3 j;
- j.v = _mm_add_ps(mV[VW], _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX])); // ( ax * vx ) + vw
- j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
- j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
- o.setVec(j.mV);
-}
-
-inline void LLV4Matrix4::multiply(const LLVector3 &a, LLV4Vector3& o) const
-{
- o.v = _mm_add_ps(mV[VW], _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX])); // ( ax * vx ) + vw
- o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
- o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
-}
-
-inline const LLV4Matrix4& LLV4Matrix4::translate(const LLV4Vector3 &vec)
-{
- mV[VW] = _mm_add_ps(mV[VW], vec.v);
- return (*this);
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Matrix4
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#else
-
-inline void LLV4Matrix4::lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w)
-{
- mMatrix[VX][VX] = llv4lerp(a.mMatrix[VX][VX], b.mMatrix[VX][VX], w);
- mMatrix[VX][VY] = llv4lerp(a.mMatrix[VX][VY], b.mMatrix[VX][VY], w);
- mMatrix[VX][VZ] = llv4lerp(a.mMatrix[VX][VZ], b.mMatrix[VX][VZ], w);
-
- mMatrix[VY][VX] = llv4lerp(a.mMatrix[VY][VX], b.mMatrix[VY][VX], w);
- mMatrix[VY][VY] = llv4lerp(a.mMatrix[VY][VY], b.mMatrix[VY][VY], w);
- mMatrix[VY][VZ] = llv4lerp(a.mMatrix[VY][VZ], b.mMatrix[VY][VZ], w);
-
- mMatrix[VZ][VX] = llv4lerp(a.mMatrix[VZ][VX], b.mMatrix[VZ][VX], w);
- mMatrix[VZ][VY] = llv4lerp(a.mMatrix[VZ][VY], b.mMatrix[VZ][VY], w);
- mMatrix[VZ][VZ] = llv4lerp(a.mMatrix[VZ][VZ], b.mMatrix[VZ][VZ], w);
-
- mMatrix[VW][VX] = llv4lerp(a.mMatrix[VW][VX], b.mMatrix[VW][VX], w);
- mMatrix[VW][VY] = llv4lerp(a.mMatrix[VW][VY], b.mMatrix[VW][VY], w);
- mMatrix[VW][VZ] = llv4lerp(a.mMatrix[VW][VZ], b.mMatrix[VW][VZ], w);
-}
-
-inline void LLV4Matrix4::multiply(const LLVector3 &a, LLVector3& o) const
-{
- o.setVec( a.mV[VX] * mMatrix[VX][VX] +
- a.mV[VY] * mMatrix[VY][VX] +
- a.mV[VZ] * mMatrix[VZ][VX] +
- mMatrix[VW][VX],
-
- a.mV[VX] * mMatrix[VX][VY] +
- a.mV[VY] * mMatrix[VY][VY] +
- a.mV[VZ] * mMatrix[VZ][VY] +
- mMatrix[VW][VY],
-
- a.mV[VX] * mMatrix[VX][VZ] +
- a.mV[VY] * mMatrix[VY][VZ] +
- a.mV[VZ] * mMatrix[VZ][VZ] +
- mMatrix[VW][VZ]);
-}
-
-inline void LLV4Matrix4::multiply(const LLVector3 &a, LLV4Vector3& o) const
-{
- o.setVec( a.mV[VX] * mMatrix[VX][VX] +
- a.mV[VY] * mMatrix[VY][VX] +
- a.mV[VZ] * mMatrix[VZ][VX] +
- mMatrix[VW][VX],
-
- a.mV[VX] * mMatrix[VX][VY] +
- a.mV[VY] * mMatrix[VY][VY] +
- a.mV[VZ] * mMatrix[VZ][VY] +
- mMatrix[VW][VY],
-
- a.mV[VX] * mMatrix[VX][VZ] +
- a.mV[VY] * mMatrix[VY][VZ] +
- a.mV[VZ] * mMatrix[VZ][VZ] +
- mMatrix[VW][VZ]);
-}
-
-inline const LLV4Matrix4& LLV4Matrix4::translate(const LLV4Vector3 &vec)
-{
- mMatrix[3][0] += vec.mV[0];
- mMatrix[3][1] += vec.mV[1];
- mMatrix[3][2] += vec.mV[2];
- return (*this);
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Matrix4
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-#endif
-
-inline const LLV4Matrix4& LLV4Matrix4::operator=(const LLMatrix4& a)
-{
- memcpy(mMatrix, a.mMatrix, sizeof(F32) * 16 );
- return *this;
-}
-
-inline const LLV4Matrix4& LLV4Matrix4::transpose()
-{
-#if LL_VECTORIZE && defined(_MM_TRANSPOSE4_PS)
- _MM_TRANSPOSE4_PS(mV[VX], mV[VY], mV[VZ], mV[VW]);
-#else
- LLV4Matrix4 mat;
- mat.mMatrix[0][0] = mMatrix[0][0];
- mat.mMatrix[1][0] = mMatrix[0][1];
- mat.mMatrix[2][0] = mMatrix[0][2];
- mat.mMatrix[3][0] = mMatrix[0][3];
-
- mat.mMatrix[0][1] = mMatrix[1][0];
- mat.mMatrix[1][1] = mMatrix[1][1];
- mat.mMatrix[2][1] = mMatrix[1][2];
- mat.mMatrix[3][1] = mMatrix[1][3];
-
- mat.mMatrix[0][2] = mMatrix[2][0];
- mat.mMatrix[1][2] = mMatrix[2][1];
- mat.mMatrix[2][2] = mMatrix[2][2];
- mat.mMatrix[3][2] = mMatrix[2][3];
-
- mat.mMatrix[0][3] = mMatrix[3][0];
- mat.mMatrix[1][3] = mMatrix[3][1];
- mat.mMatrix[2][3] = mMatrix[3][2];
- mat.mMatrix[3][3] = mMatrix[3][3];
-
- *this = mat;
-#endif
- return *this;
-}
-
-inline const LLV4Matrix4& LLV4Matrix4::translate(const LLVector3 &vec)
-{
- mMatrix[3][0] += vec.mV[0];
- mMatrix[3][1] += vec.mV[1];
- mMatrix[3][2] += vec.mV[2];
- return (*this);
-}
-
-inline LLVector3 operator*(const LLVector3 &a, const LLV4Matrix4 &b)
-{
- return LLVector3(a.mV[VX] * b.mMatrix[VX][VX] +
- a.mV[VY] * b.mMatrix[VY][VX] +
- a.mV[VZ] * b.mMatrix[VZ][VX] +
- b.mMatrix[VW][VX],
-
- a.mV[VX] * b.mMatrix[VX][VY] +
- a.mV[VY] * b.mMatrix[VY][VY] +
- a.mV[VZ] * b.mMatrix[VZ][VY] +
- b.mMatrix[VW][VY],
-
- a.mV[VX] * b.mMatrix[VX][VZ] +
- a.mV[VY] * b.mMatrix[VY][VZ] +
- a.mV[VZ] * b.mMatrix[VZ][VZ] +
- b.mMatrix[VW][VZ]);
-}
-
-
-#endif
diff --git a/indra/llmath/llv4vector3.h b/indra/llmath/llv4vector3.h
deleted file mode 100644
index a340d53f5a..0000000000
--- a/indra/llmath/llv4vector3.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * @file llviewerjointmesh.cpp
- * @brief LLV4* class header file - vector processor enabled math
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLV4VECTOR3_H
-#define LL_LLV4VECTOR3_H
-
-#include "llv4math.h"
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Vector3
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-LL_LLV4MATH_ALIGN_PREFIX
-
-class LLV4Vector3
-{
-public:
- union {
- F32 mV[LLV4_NUM_AXIS];
- V4F32 v;
- };
-
- enum {
- ALIGNMENT = 16
- };
-
- void setVec(F32 x, F32 y, F32 z);
- void setVec(F32 a);
-}
-
-LL_LLV4MATH_ALIGN_POSTFIX;
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLV4Vector3
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-inline void LLV4Vector3::setVec(F32 x, F32 y, F32 z)
-{
- mV[VX] = x;
- mV[VY] = y;
- mV[VZ] = z;
-}
-
-inline void LLV4Vector3::setVec(F32 a)
-{
-#if LL_VECTORIZE
- v = _mm_set1_ps(a);
-#else
- setVec(a, a, a);
-#endif
-}
-
-#endif
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 3342dbf258..371989ab49 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -4313,15 +4313,25 @@ S32 LLVolume::getNumTriangleIndices() const
}
-S32 LLVolume::getNumTriangles() const
+S32 LLVolume::getNumTriangles(S32* vcount) const
{
U32 triangle_count = 0;
+ U32 vertex_count = 0;
for (S32 i = 0; i < getNumVolumeFaces(); ++i)
{
- triangle_count += getVolumeFace(i).mNumIndices/3;
+ const LLVolumeFace& face = getVolumeFace(i);
+ triangle_count += face.mNumIndices/3;
+
+ vertex_count += face.mNumVertices;
}
+
+ if (vcount)
+ {
+ *vcount = vertex_count;
+ }
+
return triangle_count;
}
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 15b634a555..3775aafdd9 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -993,7 +993,7 @@ public:
S32 getNumTriangleIndices() const;
static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts);
- S32 getNumTriangles() const;
+ S32 getNumTriangles(S32* vcount = NULL) const;
void generateSilhouetteVertices(std::vector &vertices,
std::vector &normals,
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 8122d3f5e1..aea51e7695 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -592,7 +592,6 @@ void LLCurl::Multi::cleanup()
{
return ; //nothing to clean.
}
-
// Clean up active
for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
iter != mEasyActiveList.end(); ++iter)
diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp
index 304a692cdf..3d8ca2ad9f 100644
--- a/indra/llmessage/llsdmessagereader.cpp
+++ b/indra/llmessage/llsdmessagereader.cpp
@@ -291,9 +291,10 @@ S32 getElementSize(const LLSD& llsd)
case LLSD::TypeMap:
case LLSD::TypeArray:
case LLSD::TypeUndefined:
+ default: // TypeLLSDTypeEnd, TypeLLSDNumTypes, etc.
return 0;
}
- return 0;
+ //return 0;
}
//virtual
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index c53857fcee..dbd96673a1 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1239,6 +1239,14 @@ void LLPluginClassMedia::focus(bool focused)
sendMessage(message);
}
+void LLPluginClassMedia::set_page_zoom_factor( double factor )
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_page_zoom_factor");
+
+ message.setValueReal("factor", factor);
+ sendMessage(message);
+}
+
void LLPluginClassMedia::clear_cache()
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 26fff7a614..5fe8254331 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -41,7 +41,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
LOG_CLASS(LLPluginClassMedia);
public:
LLPluginClassMedia(LLPluginClassMediaOwner *owner);
- ~LLPluginClassMedia();
+ virtual ~LLPluginClassMedia();
// local initialization, called by the media manager when creating a source
bool init(const std::string &launcher_filename,
@@ -202,6 +202,7 @@ public:
bool pluginSupportsMediaBrowser(void);
void focus(bool focused);
+ void set_page_zoom_factor( double factor );
void clear_cache();
void clear_cookies();
void set_cookies(const std::string &cookies);
diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h
index 3643a15d8c..e6926c3e37 100644
--- a/indra/llplugin/llplugininstance.h
+++ b/indra/llplugin/llplugininstance.h
@@ -39,7 +39,7 @@
class LLPluginInstanceMessageListener
{
public:
- ~LLPluginInstanceMessageListener();
+ virtual ~LLPluginInstanceMessageListener();
/** Plugin receives message from plugin loader shell. */
virtual void receivePluginMessage(const std::string &message) = 0;
};
diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp
index 8d13e38ad5..091e93ea4b 100644
--- a/indra/llplugin/llpluginmessagepipe.cpp
+++ b/indra/llplugin/llpluginmessagepipe.cpp
@@ -94,10 +94,10 @@ void LLPluginMessagePipeOwner::killMessagePipe(void)
LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket):
mInputMutex(gAPRPoolp),
mOutputMutex(gAPRPoolp),
+ mOutputStartIndex(0),
mOwner(owner),
mSocket(socket)
{
-
mOwner->setMessagePipe(this);
}
@@ -113,6 +113,14 @@ bool LLPluginMessagePipe::addMessage(const std::string &message)
{
// queue the message for later output
LLMutexLock lock(&mOutputMutex);
+
+ // If we're starting to use up too much memory, clear
+ if (mOutputStartIndex > 1024 * 1024)
+ {
+ mOutput = mOutput.substr(mOutputStartIndex);
+ mOutputStartIndex = 0;
+ }
+
mOutput += message;
mOutput += MESSAGE_DELIMITER; // message separator
@@ -165,35 +173,44 @@ bool LLPluginMessagePipe::pumpOutput()
if(mSocket)
{
apr_status_t status;
- apr_size_t size;
+ apr_size_t in_size, out_size;
LLMutexLock lock(&mOutputMutex);
- if(!mOutput.empty())
+
+ const char * output_data = &(mOutput.data()[mOutputStartIndex]);
+ if(*output_data != '\0')
{
// write any outgoing messages
- size = (apr_size_t)mOutput.size();
+ in_size = (apr_size_t) (mOutput.size() - mOutputStartIndex);
+ out_size = in_size;
setSocketTimeout(0);
// LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL;
- status = apr_socket_send(
- mSocket->getSocket(),
- (const char*)mOutput.data(),
- &size);
+ status = apr_socket_send(mSocket->getSocket(),
+ output_data,
+ &out_size);
// LL_INFOS("Plugin") << "after apr_socket_send, size = " << size << LL_ENDL;
- if(status == APR_SUCCESS)
+ if((status == APR_SUCCESS) || APR_STATUS_IS_EAGAIN(status))
{
- // success
- mOutput = mOutput.substr(size);
- }
- else if(APR_STATUS_IS_EAGAIN(status))
- {
- // Socket buffer is full...
- // remove the written part from the buffer and try again later.
- mOutput = mOutput.substr(size);
+ // Success or Socket buffer is full...
+
+ // If we've pumped the entire string, clear it
+ if (out_size == in_size)
+ {
+ mOutputStartIndex = 0;
+ mOutput.clear();
+ }
+ else
+ {
+ llassert(in_size > out_size);
+
+ // Remove the written part from the buffer and try again later.
+ mOutputStartIndex += out_size;
+ }
}
else if(APR_STATUS_IS_EOF(status))
{
diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h
index beb942c0fe..c3498beac0 100644
--- a/indra/llplugin/llpluginmessagepipe.h
+++ b/indra/llplugin/llpluginmessagepipe.h
@@ -40,7 +40,7 @@ class LLPluginMessagePipeOwner
LOG_CLASS(LLPluginMessagePipeOwner);
public:
LLPluginMessagePipeOwner();
- ~LLPluginMessagePipeOwner();
+ virtual ~LLPluginMessagePipeOwner();
// called with incoming messages
virtual void receiveMessageRaw(const std::string &message) = 0;
@@ -86,6 +86,7 @@ protected:
std::string mInput;
LLMutex mOutputMutex;
std::string mOutput;
+ std::string::size_type mOutputStartIndex;
LLPluginMessagePipeOwner *mOwner;
LLSocket::ptr_t mSocket;
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index 8b9c830f79..d64900ca1f 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -41,7 +41,7 @@
class LLPluginProcessParentOwner
{
public:
- ~LLPluginProcessParentOwner();
+ virtual ~LLPluginProcessParentOwner();
virtual void receivePluginMessage(const LLPluginMessage &message) = 0;
virtual bool receivePluginMessageEarly(const LLPluginMessage &message) {return false;};
// This will only be called when the plugin has died unexpectedly
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 6e4bb7ec97..cb32a510b8 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -31,11 +31,18 @@
#include "llconvexdecomposition.h"
#include "llsdserialize.h"
#include "llvector4a.h"
-
+#if LL_MSVC
+#pragma warning (disable : 4263)
+#pragma warning (disable : 4264)
+#endif
#include "dae.h"
#include "dae/daeErrorHandler.h"
#include "dom/domConstants.h"
#include "dom/domMesh.h"
+#if LL_MSVC
+#pragma warning (default : 4263)
+#pragma warning (default : 4264)
+#endif
#ifdef LL_STANDALONE
# include
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index 1b10354c22..45a3b18179 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -36,6 +36,7 @@
#include "m4math.h"
#include "llrender.h"
+#include "llglslshader.h"
#include "llglheaders.h"
@@ -195,7 +196,7 @@ void LLCubeMap::enableTexture(S32 stage)
void LLCubeMap::enableTextureCoords(S32 stage)
{
mTextureCoordStage = stage;
- if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
+ if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
{
if (stage > 0)
{
@@ -237,7 +238,7 @@ void LLCubeMap::disableTexture(void)
void LLCubeMap::disableTextureCoords(void)
{
- if (gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
+ if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
{
if (mTextureCoordStage > 0)
{
@@ -264,19 +265,19 @@ void LLCubeMap::setMatrix(S32 stage)
gGL.getTexUnit(stage)->activate();
}
- LLVector3 x(LLVector3d(gGLModelView+0));
- LLVector3 y(LLVector3d(gGLModelView+4));
- LLVector3 z(LLVector3d(gGLModelView+8));
+ LLVector3 x(gGLModelView+0);
+ LLVector3 y(gGLModelView+4);
+ LLVector3 z(gGLModelView+8);
LLMatrix3 mat3;
mat3.setRows(x,y,z);
LLMatrix4 trans(mat3);
trans.transpose();
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glLoadMatrixf((F32 *)trans.mMatrix);
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.pushMatrix();
+ gGL.loadMatrix((F32 *)trans.mMatrix);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
/*if (stage > 0)
{
@@ -292,9 +293,9 @@ void LLCubeMap::restoreMatrix()
{
gGL.getTexUnit(mMatrixStage)->activate();
}
- glMatrixMode(GL_TEXTURE);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_TEXTURE);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
/*if (mMatrixStage > 0)
{
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index 91c8a37022..66d4ad2d87 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -55,7 +55,10 @@ FT_Library gFTLibrary = NULL;
//static
void LLFontManager::initClass()
{
- gFontManagerp = new LLFontManager;
+ if (!gFontManagerp)
+ {
+ gFontManagerp = new LLFontManager;
+ }
}
//static
@@ -136,7 +139,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
FT_Done_Face(mFTFace);
mFTFace = NULL;
}
-
+
int error;
error = FT_New_Face( gFTLibrary,
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 4e3cfb9c8a..946e602fee 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -67,6 +67,36 @@ static const std::string HEADLESS_VERSION_STRING("1.0");
std::ofstream gFailLog;
+#if GL_ARB_debug_output
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+void APIENTRY gl_debug_callback(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar* message,
+ GLvoid* userParam)
+{
+ if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+ {
+ llwarns << "----- GL ERROR --------" << llendl;
+ }
+ else
+ {
+ llwarns << "----- GL WARNING -------" << llendl;
+ }
+ llwarns << "Type: " << std::hex << type << llendl;
+ llwarns << "ID: " << std::hex << id << llendl;
+ llwarns << "Severity: " << std::hex << severity << llendl;
+ llwarns << "Message: " << message << llendl;
+ llwarns << "-----------------------" << llendl;
+}
+#endif
+
void ll_init_fail_log(std::string filename)
{
gFailLog.open(filename.c_str());
@@ -110,6 +140,11 @@ std::list LLGLUpdate::sGLQ;
#if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS
// ATI prototypes
+
+#if LL_WINDOWS
+PFNGLGETSTRINGIPROC glGetStringi = NULL;
+#endif
+
// vertex blending prototypes
PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB = NULL;
PFNGLVERTEXBLENDARBPROC glVertexBlendARB = NULL;
@@ -128,6 +163,12 @@ PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL;
+//GL_ARB_vertex_array_object
+PFNGLBINDVERTEXARRAYPROC glBindVertexArray = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = NULL;
+PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = NULL;
+PFNGLISVERTEXARRAYPROC glIsVertexArray = NULL;
+
// GL_ARB_map_buffer_range
PFNGLMAPBUFFERRANGEPROC glMapBufferRange = NULL;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = NULL;
@@ -197,10 +238,16 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
//GL_ARB_texture_multisample
-PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
-PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
-PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
-PFNGLSAMPLEMASKIPROC glSampleMaski;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL;
+PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL;
+PFNGLSAMPLEMASKIPROC glSampleMaski = NULL;
+
+//GL_ARB_debug_output
+PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL;
+PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL;
+PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB = NULL;
+PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB = NULL;
// GL_EXT_blend_func_separate
PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
@@ -249,6 +296,10 @@ PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL;
PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
+#if LL_WINDOWS
+PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
+#endif
+
// vertex shader prototypes
#if LL_LINUX || LL_SOLARIS
PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL;
@@ -349,6 +400,7 @@ LLGLManager::LLGLManager() :
mHasBlendFuncSeparate(FALSE),
mHasSync(FALSE),
mHasVertexBufferObject(FALSE),
+ mHasVertexArrayObject(FALSE),
mHasMapBufferRange(FALSE),
mHasFlushBufferRange(FALSE),
mHasPBuffer(FALSE),
@@ -370,6 +422,7 @@ LLGLManager::LLGLManager() :
mHasAnisotropic(FALSE),
mHasARBEnvCombine(FALSE),
mHasCubeMap(FALSE),
+ mHasDebugOutput(FALSE),
mIsATI(FALSE),
mIsNVIDIA(FALSE),
@@ -409,6 +462,15 @@ void LLGLManager::initWGL()
LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL;
}
+ if (ExtensionExists("WGL_ARB_create_context",gGLHExts.mSysExts))
+ {
+ GLH_EXT_NAME(wglCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB");
+ }
+ else
+ {
+ LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL;
+ }
+
if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts))
{
GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT");
@@ -438,13 +500,45 @@ bool LLGLManager::initGL()
LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL;
}
- GLint alpha_bits;
- glGetIntegerv( GL_ALPHA_BITS, &alpha_bits );
- if( 8 != alpha_bits )
+ stop_glerror();
+
+#if LL_WINDOWS
+ if (!glGetStringi)
{
- LL_WARNS("RenderInit") << "Frame buffer has less than 8 bits of alpha. Avatar texture compositing will fail." << LL_ENDL;
+ glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi");
}
+ //reload extensions string (may have changed after using wglCreateContextAttrib)
+ if (glGetStringi)
+ {
+ std::stringstream str;
+
+ GLint count = 0;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &count);
+ for (GLint i = 0; i < count; ++i)
+ {
+ std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i));
+ str << ext << " ";
+ LL_DEBUGS("GLExtensions") << ext << llendl;
+ }
+
+ {
+ PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
+ wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
+ if(wglGetExtensionsStringARB)
+ {
+ str << (const char*) wglGetExtensionsStringARB(wglGetCurrentDC());
+ }
+ }
+
+ free(gGLHExts.mSysExts);
+ std::string extensions = str.str();
+ gGLHExts.mSysExts = strdup(extensions.c_str());
+ }
+#endif
+
+ stop_glerror();
+
// Extract video card strings and convert to upper case to
// work around driver-to-driver variation in capitalization.
mGLVendor = std::string((const char *)glGetString(GL_VENDOR));
@@ -459,7 +553,7 @@ bool LLGLManager::initGL()
&mDriverVersionVendorString );
mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
-
+
// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
// from being recognized as ATI.
if (mGLVendor.substr(0,4) == "ATI ")
@@ -531,8 +625,12 @@ bool LLGLManager::initGL()
mGLVendorShort = "MISC";
}
+ stop_glerror();
// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
initExtensions();
+ stop_glerror();
+
+ S32 old_vram = mVRAM;
if (mHasATIMemInfo)
{ //ask the gl how much vram is free at startup and attempt to use no more than half of that
@@ -548,7 +646,27 @@ bool LLGLManager::initGL()
mVRAM = dedicated_memory/1024;
}
- if (mHasMultitexture)
+ if (mVRAM < 256)
+ { //something likely went wrong using the above extensions, fall back to old method
+ mVRAM = old_vram;
+ }
+
+ stop_glerror();
+
+ stop_glerror();
+
+ if (mHasFragmentShader)
+ {
+ GLint num_tex_image_units;
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
+ mNumTextureImageUnits = llmin(num_tex_image_units, 32);
+ }
+
+ if (LLRender::sGLCoreProfile)
+ {
+ mNumTextureUnits = llmin(mNumTextureImageUnits, MAX_GL_TEXTURE_UNITS);
+ }
+ else if (mHasMultitexture)
{
GLint num_tex_units;
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units);
@@ -567,12 +685,7 @@ bool LLGLManager::initGL()
return false;
}
- if (mHasFragmentShader)
- {
- GLint num_tex_image_units;
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
- mNumTextureImageUnits = llmin(num_tex_image_units, 32);
- }
+ stop_glerror();
if (mHasTextureMultisample)
{
@@ -582,6 +695,21 @@ bool LLGLManager::initGL()
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
}
+ stop_glerror();
+
+#if LL_WINDOWS
+ if (mHasDebugOutput && gDebugGL)
+ { //setup debug output callback
+ //glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
+ glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ }
+#endif
+
+ stop_glerror();
+
+ //HACK always disable texture multisample, use FXAA instead
+ mHasTextureMultisample = FALSE;
#if LL_WINDOWS
if (mIsATI)
{ //using multisample textures on ATI results in black screen for some reason
@@ -593,10 +721,17 @@ bool LLGLManager::initGL()
{
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
}
+
+ stop_glerror();
setToDebugGPU();
+ stop_glerror();
+
initGLStates();
+
+ stop_glerror();
+
return true;
}
@@ -700,14 +835,6 @@ std::string LLGLManager::getRawGLString()
return gl_string;
}
-U32 LLGLManager::getNumFBOFSAASamples(U32 samples)
-{
- samples = llmin(samples, (U32) mMaxColorTextureSamples);
- samples = llmin(samples, (U32) mMaxDepthTextureSamples);
- samples = llmin(samples, (U32) 4);
- return samples;
-}
-
void LLGLManager::shutdownGL()
{
if (mInited)
@@ -774,7 +901,7 @@ void LLGLManager::initExtensions()
mHasVertexShader = FALSE;
mHasFragmentShader = FALSE;
mHasTextureRectangle = FALSE;
-#else // LL_MESA_HEADLESS
+#else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called
mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
@@ -788,6 +915,7 @@ void LLGLManager::initExtensions()
mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
+ mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts);
mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
@@ -806,13 +934,14 @@ void LLGLManager::initExtensions()
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
+ mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
#if !LL_DARWIN
mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
#endif
- mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
+ mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts)
- && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
- mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
+ && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
+ mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts));
#endif
#if LL_LINUX || LL_SOLARIS
@@ -985,6 +1114,13 @@ void LLGLManager::initExtensions()
mHasVertexBufferObject = FALSE;
}
}
+ if (mHasVertexArrayObject)
+ {
+ glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glBindVertexArray");
+ glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteVertexArrays");
+ glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenVertexArrays");
+ glIsVertexArray = (PFNGLISVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glIsVertexArray");
+ }
if (mHasSync)
{
glFenceSync = (PFNGLFENCESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glFenceSync");
@@ -1039,6 +1175,13 @@ void LLGLManager::initExtensions()
glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
}
+ if (mHasDebugOutput)
+ {
+ glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB");
+ glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageInsertARB");
+ glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageCallbackARB");
+ glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetDebugMessageLogARB");
+ }
#if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS
// This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah
glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
@@ -1193,7 +1336,7 @@ void rotate_quat(LLQuaternion& rotation)
{
F32 angle_radians, x, y, z;
rotation.getAngleAxis(&angle_radians, &x, &y, &z);
- glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
+ gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
}
void flush_glerror()
@@ -1230,10 +1373,6 @@ void log_glerror()
void do_assert_glerror()
{
- if (LL_UNLIKELY(!gGLManager.mInited))
- {
- LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL;
- }
// Create or update texture to be used with this data
GLenum error;
error = glGetError();
@@ -1326,11 +1465,6 @@ void LLGLState::initClass()
//make sure multisample defaults to disabled
sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE;
glDisable(GL_MULTISAMPLE_ARB);
-
- sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE;
- glDisable(GL_MULTISAMPLE_ARB);
-
- glEnableClientState(GL_VERTEX_ARRAY);
}
//static
@@ -1604,7 +1738,7 @@ void LLGLState::checkTextureChannels(const std::string& msg)
void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
{
- if (!gDebugGL)
+ if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
{
return;
}
@@ -1625,7 +1759,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
error = TRUE;
}
- glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
+ /*glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
if (active_texture != GL_TEXTURE0_ARB)
{
llwarns << "Active texture corrupted: " << active_texture << llendl;
@@ -1634,7 +1768,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
gFailLog << "Active texture corrupted: " << active_texture << std::endl;
}
error = TRUE;
- }
+ }*/
static const char* label[] =
{
@@ -1661,7 +1795,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
};
- for (S32 j = 0; j < 4; j++)
+ for (S32 j = 1; j < 4; j++)
{
if (glIsEnabled(value[j]))
{
@@ -1783,17 +1917,26 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) :
mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
{
if (LLGLSLShader::sNoFixedFunction)
- { //always disable state that's deprecated post GL 3.0
+ { //always ignore state that's deprecated post GL 3.0
switch (state)
{
case GL_ALPHA_TEST:
- enabled = 0;
+ case GL_NORMALIZE:
+ case GL_TEXTURE_GEN_R:
+ case GL_TEXTURE_GEN_S:
+ case GL_TEXTURE_GEN_T:
+ case GL_TEXTURE_GEN_Q:
+ case GL_LIGHTING:
+ case GL_COLOR_MATERIAL:
+ case GL_FOG:
+ case GL_LINE_STIPPLE:
+ mState = 0;
break;
}
}
stop_glerror();
- if (state)
+ if (mState)
{
mWasEnabled = sStateMap[state];
llassert(mWasEnabled == glIsEnabled(state));
@@ -1875,79 +2018,6 @@ void LLGLManager::initGLStates()
////////////////////////////////////////////////////////////////////////////////
-void enable_vertex_weighting(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glEnableVertexAttribArrayARB(index); // vertex weights
-#endif
-}
-
-void disable_vertex_weighting(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glDisableVertexAttribArrayARB(index); // vertex weights
-#endif
-}
-
-void enable_binormals(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0)
- {
- glEnableVertexAttribArrayARB(index); // binormals
- }
-#endif
-}
-
-void disable_binormals(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0)
- {
- glDisableVertexAttribArrayARB(index); // binormals
- }
-#endif
-}
-
-
-void enable_cloth_weights(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glEnableVertexAttribArrayARB(index);
-#endif
-}
-
-void disable_cloth_weights(const S32 index)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glDisableVertexAttribArrayARB(index);
-#endif
-}
-
-void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, stride, weights);
- stop_glerror();
-#endif
-}
-
-void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glVertexAttribPointerARB(index, 4, GL_FLOAT, TRUE, stride, weights);
- stop_glerror();
-#endif
-}
-
-void set_binormals(const S32 index, const U32 stride,const LLVector3 *binormals)
-{
-#if GL_ARB_vertex_program
- if (index > 0) glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, binormals);
- stop_glerror();
-#endif
-}
-
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific )
{
// GL_VERSION returns a null-terminated string with the format:
@@ -2060,20 +2130,20 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
glh::matrix4f suffix;
suffix.set_row(2, cplane);
glh::matrix4f newP = suffix * P;
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(newP.m);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadMatrix(newP.m);
gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m);
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
}
LLGLUserClipPlane::~LLGLUserClipPlane()
{
if (mApply)
{
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
}
}
@@ -2263,16 +2333,16 @@ LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P, U32 layer)
P.element(2, i) = P.element(3, i) * depth;
}
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(P.m);
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadMatrix(P.m);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
}
LLGLSquashToFarClip::~LLGLSquashToFarClip()
{
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
}
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index d736133f3f..6a147b8e19 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -88,6 +88,7 @@ public:
// ARB Extensions
BOOL mHasVertexBufferObject;
+ BOOL mHasVertexArrayObject;
BOOL mHasSync;
BOOL mHasMapBufferRange;
BOOL mHasFlushBufferRange;
@@ -112,6 +113,7 @@ public:
BOOL mHasAnisotropic;
BOOL mHasARBEnvCombine;
BOOL mHasCubeMap;
+ BOOL mHasDebugOutput;
// Vendor-specific extensions
BOOL mIsATI;
@@ -148,7 +150,6 @@ public:
void printGLInfoString();
void getGLInfo(LLSD& info);
- U32 getNumFBOFSAASamples(U32 desired_samples = 32);
// In ALL CAPS
std::string mGLVendor;
std::string mGLVendorShort;
@@ -252,7 +253,7 @@ public:
static void dumpStates();
static void checkStates(const std::string& msg = "");
static void checkTextureChannels(const std::string& msg = "");
- static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0x0001);
+ static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0);
protected:
static boost::unordered_map sStateMap;
@@ -419,15 +420,7 @@ extern LLMatrix4 gGLObliqueProjectionInverse;
#include "llglstates.h"
void init_glstates();
-void enable_vertex_weighting(const S32 index);
-void disable_vertex_weighting(const S32 index);
-void enable_binormals(const S32 index);
-void disable_binormals(const S32 index);
-void enable_cloth_weights(const S32 index);
-void disable_cloth_weights(const S32 index);
-void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights);
-void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights);
-void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals);
+
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
extern BOOL gClothRipple;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 851a75629e..10aad202e1 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -68,6 +68,12 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
+// GL_ARB_vertex_array_object
+extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
+extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
+extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
+
// GL_ARB_sync
extern PFNGLFENCESYNCPROC glFenceSync;
extern PFNGLISSYNCPROC glIsSync;
@@ -310,6 +316,12 @@ extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
#endif // LL_LINUX_NV_GL_HEADERS
+// GL_ARB_vertex_array_object
+extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
+extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
+extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
+
// GL_ARB_vertex_buffer_object
extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB;
@@ -531,6 +543,9 @@ extern PFNGLSAMPLEMASKIPROC glSampleMaski;
#include "GL/glext.h"
#include "GL/glh_extensions.h"
+// WGL_ARB_create_context
+extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
+extern PFNGLGETSTRINGIPROC glGetStringi;
// GL_ARB_vertex_buffer_object
extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
@@ -545,6 +560,12 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
+// GL_ARB_vertex_array_object
+extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
+extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
+extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
+
// GL_ARB_sync
extern PFNGLFENCESYNCPROC glFenceSync;
extern PFNGLISSYNCPROC glIsSync;
@@ -735,6 +756,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
+//GL_ARB_debug_output
+extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
+extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
+extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
+extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;
+
#elif LL_DARWIN
//----------------------------------------------------------------------------
// LL_DARWIN
@@ -899,6 +926,31 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
#endif /* GL_GLEXT_FUNCTION_POINTERS */
#endif
+#ifndef GL_ARB_texture_rg
+#define GL_RG 0x8227
+#define GL_RG_INTEGER 0x8228
+#define GL_R8 0x8229
+#define GL_R16 0x822A
+#define GL_RG8 0x822B
+#define GL_RG16 0x822C
+#define GL_R16F 0x822D
+#define GL_R32F 0x822E
+#define GL_RG16F 0x822F
+#define GL_RG32F 0x8230
+#define GL_R8I 0x8231
+#define GL_R8UI 0x8232
+#define GL_R16I 0x8233
+#define GL_R16UI 0x8234
+#define GL_R32I 0x8235
+#define GL_R32UI 0x8236
+#define GL_RG8I 0x8237
+#define GL_RG8UI 0x8238
+#define GL_RG16I 0x8239
+#define GL_RG16UI 0x823A
+#define GL_RG32I 0x823B
+#define GL_RG32UI 0x823C
+#endif
+
// May be needed for DARWIN...
// #ifndef GL_ARB_compressed_tex_image
// #define GL_ARB_compressed_tex_image 1
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 5950b3fe7b..6b2852670a 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -31,6 +31,7 @@
#include "llshadermgr.h"
#include "llfile.h"
#include "llrender.h"
+#include "llvertexbuffer.h"
#if LL_DARWIN
#include "OpenGL/OpenGL.h"
@@ -50,6 +51,7 @@ using std::string;
GLhandleARB LLGLSLShader::sCurBoundShader = 0;
LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
+S32 LLGLSLShader::sIndexedTextureChannels = 0;
bool LLGLSLShader::sNoFixedFunction = false;
//UI shader -- declared here so llui_libtest will link properly
@@ -75,6 +77,7 @@ hasAlphaMask(false)
LLGLSLShader::LLGLSLShader()
: mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE)
{
+
}
void LLGLSLShader::unload()
@@ -110,17 +113,19 @@ void LLGLSLShader::unload()
BOOL LLGLSLShader::createShader(vector * attributes,
vector * uniforms)
{
+ //reloading, reset matrix hash values
+ for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
+ {
+ mMatHash[i] = 0xFFFFFFFF;
+ }
+ mLightHash = 0xFFFFFFFF;
+
llassert_always(!mShaderFiles.empty());
BOOL success = TRUE;
// Create program
mProgramObject = glCreateProgramObjectARB();
- if (gGLManager.mGLVersion < 3.1f)
- { //force indexed texture channels to 1 if GL version is old (performance improvement for drivers with poor branching shader model support)
- mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
- }
-
//compile new source
vector< pair >::iterator fileIter = mShaderFiles.begin();
for ( ; fileIter != mShaderFiles.end(); fileIter++ )
@@ -235,6 +240,13 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
BOOL LLGLSLShader::mapAttributes(const vector * attributes)
{
+ //before linking, make sure reserved attributes always have consistent locations
+ for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
+ {
+ const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str();
+ glBindAttribLocationARB(mProgramObject, i, (const GLcharARB *) name);
+ }
+
//link the program
BOOL res = link();
@@ -308,7 +320,7 @@ void LLGLSLShader::mapUniform(GLint index, const vector * uniforms)
for (S32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedUniforms.size(); i++)
{
if ( (mUniform[i] == -1)
- && (LLShaderMgr::instance()->mReservedUniforms[i].compare(0, length, name, LLShaderMgr::instance()->mReservedUniforms[i].length()) == 0))
+ && (LLShaderMgr::instance()->mReservedUniforms[i] == name))
{
//found it
mUniform[i] = location;
@@ -322,7 +334,7 @@ void LLGLSLShader::mapUniform(GLint index, const vector * uniforms)
for (U32 i = 0; i < uniforms->size(); i++)
{
if ( (mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] == -1)
- && ((*uniforms)[i].compare(0, length, name, (*uniforms)[i].length()) == 0))
+ && ((*uniforms)[i] == name))
{
//found it
mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] = location;
@@ -386,6 +398,7 @@ void LLGLSLShader::bind()
gGL.flush();
if (gGLManager.mHasShaderObjects)
{
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(mProgramObject);
sCurBoundShader = mProgramObject;
sCurBoundShaderPtr = this;
@@ -411,6 +424,7 @@ void LLGLSLShader::unbind()
stop_glerror();
}
}
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(0);
sCurBoundShader = 0;
sCurBoundShaderPtr = NULL;
@@ -420,9 +434,13 @@ void LLGLSLShader::unbind()
void LLGLSLShader::bindNoShader(void)
{
- glUseProgramObjectARB(0);
- sCurBoundShader = 0;
- sCurBoundShaderPtr = NULL;
+ LLVertexBuffer::unbind();
+ if (gGLManager.mHasShaderObjects)
+ {
+ glUseProgramObjectARB(0);
+ sCurBoundShader = 0;
+ sCurBoundShaderPtr = NULL;
+ }
}
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
@@ -768,13 +786,17 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform)
}
}
- /*if (gDebugGL)
+ return ret;
+}
+
+GLint LLGLSLShader::getUniformLocation(U32 index)
+{
+ GLint ret = -1;
+ if (mProgramObject > 0)
{
- if (ret == -1 && ret != glGetUniformLocationARB(mProgramObject, uniform.c_str()))
- {
- llerrs << "Uniform map invalid." << llendl;
- }
- }*/
+ llassert(index < mUniform.size());
+ return mUniform[index];
+ }
return ret;
}
@@ -930,7 +952,9 @@ void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v
std::map::iterator iter = mValue.find(location);
if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
{
+ stop_glerror();
glUniform4fvARB(location, count, v);
+ stop_glerror();
mValue[location] = vec;
}
}
@@ -985,8 +1009,8 @@ void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v)
}
}
-void LLGLSLShader::setAlphaRange(F32 minimum, F32 maximum)
+void LLGLSLShader::setMinimumAlpha(F32 minimum)
{
- uniform1f("minimum_alpha", minimum);
- uniform1f("maximum_alpha", maximum);
+ gGL.flush();
+ uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum);
}
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index d7bbddfa9f..00b4b0dbd4 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -70,7 +70,7 @@ public:
static GLhandleARB sCurBoundShader;
static LLGLSLShader* sCurBoundShaderPtr;
-
+ static S32 sIndexedTextureChannels;
static bool sNoFixedFunction;
void unload();
@@ -109,16 +109,17 @@ public:
void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
- void setAlphaRange(F32 minimum, F32 maximum);
+ void setMinimumAlpha(F32 minimum);
void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void vertexAttrib4fv(U32 index, GLfloat* v);
GLint getUniformLocation(const std::string& uniform);
+ GLint getUniformLocation(U32 index);
+
GLint getAttribLocation(U32 attrib);
GLint mapUniformTextureChannel(GLint location, GLenum type);
-
//enable/disable texture channel for specified uniform
//if given texture uniform is active in the shader,
//the corresponding channel will be active upon return
@@ -133,6 +134,9 @@ public:
// Unbinds any previously bound shader by explicitly binding no shader.
static void bindNoShader(void);
+ U32 mMatHash[LLRender::NUM_MATRIX_MODES];
+ U32 mLightHash;
+
GLhandleARB mProgramObject;
std::vector mAttribute; //lookup table of attribute enum to attribute channel
std::vector mUniform; //lookup table of uniform enum to uniform location
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 7188b0fa44..78591ddd38 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -36,7 +36,9 @@
#include "llmath.h"
#include "llgl.h"
+#include "llglslshader.h"
#include "llrender.h"
+
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
@@ -725,7 +727,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
{
if (mAutoGenMips)
{
- glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
+ if (!gGLManager.mHasFramebufferObject)
+ {
+ glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
+ }
stop_glerror();
{
// LLFastTimer t2(FTM_TEMP4);
@@ -754,6 +759,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
stop_glerror();
}
}
+
+ if (gGLManager.mHasFramebufferObject)
+ {
+ glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget));
+ }
}
else
{
@@ -875,6 +885,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
{
+ //not compatible with core GL profile
+ llassert(!LLRender::sGLCoreProfile);
+
if (gGLManager.mIsDisabled)
{
llwarns << "Trying to create a texture while GL is disabled!" << llendl;
@@ -901,29 +914,29 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
{
switch (mComponents)
{
- case 1:
+ case 1:
// Use luminance alpha (for fonts)
mFormatInternal = GL_LUMINANCE8;
mFormatPrimary = GL_LUMINANCE;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 2:
+ case 2:
// Use luminance alpha (for fonts)
mFormatInternal = GL_LUMINANCE8_ALPHA8;
mFormatPrimary = GL_LUMINANCE_ALPHA;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 3:
+ case 3:
mFormatInternal = GL_RGB8;
mFormatPrimary = GL_RGB;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 4:
+ case 4:
mFormatInternal = GL_RGBA8;
mFormatPrimary = GL_RGBA;
mFormatType = GL_UNSIGNED_BYTE;
break;
- default:
+ default:
llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
}
}
@@ -1099,8 +1112,75 @@ void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
// static
void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels)
{
- glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
+ bool use_scratch = false;
+ U32* scratch = NULL;
+ if (LLRender::sGLCoreProfile)
+ {
+ if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_ALPHA is deprecated, convert to RGBA
+ use_scratch = true;
+ scratch = new U32[width*height];
+
+ U32 pixel_count = (U32) (width*height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8* pix = (U8*) &scratch[i];
+ pix[0] = pix[1] = pix[2] = 0;
+ pix[3] = ((U8*) pixels)[i];
+ }
+
+ pixformat = GL_RGBA;
+ intformat = GL_RGBA8;
+ }
+
+ if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
+ use_scratch = true;
+ scratch = new U32[width*height];
+
+ U32 pixel_count = (U32) (width*height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8 lum = ((U8*) pixels)[i*2+0];
+ U8 alpha = ((U8*) pixels)[i*2+1];
+
+ U8* pix = (U8*) &scratch[i];
+ pix[0] = pix[1] = pix[2] = lum;
+ pix[3] = alpha;
+ }
+
+ pixformat = GL_RGBA;
+ intformat = GL_RGBA8;
+ }
+
+ if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
+ { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
+ use_scratch = true;
+ scratch = new U32[width*height];
+
+ U32 pixel_count = (U32) (width*height);
+ for (U32 i = 0; i < pixel_count; i++)
+ {
+ U8 lum = ((U8*) pixels)[i];
+
+ U8* pix = (U8*) &scratch[i];
+ pix[0] = pix[1] = pix[2] = lum;
+ pix[3] = 255;
+ }
+
+ pixformat = GL_RGBA;
+ intformat = GL_RGB8;
+ }
+ }
+
stop_glerror();
+ glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
+ stop_glerror();
+
+ if (use_scratch)
+ {
+ delete [] scratch;
+ }
}
//create an empty GL texture: just create a texture name
@@ -1167,29 +1247,29 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
{
switch (mComponents)
{
- case 1:
+ case 1:
// Use luminance alpha (for fonts)
mFormatInternal = GL_LUMINANCE8;
mFormatPrimary = GL_LUMINANCE;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 2:
+ case 2:
// Use luminance alpha (for fonts)
mFormatInternal = GL_LUMINANCE8_ALPHA8;
mFormatPrimary = GL_LUMINANCE_ALPHA;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 3:
+ case 3:
mFormatInternal = GL_RGB8;
mFormatPrimary = GL_RGB;
mFormatType = GL_UNSIGNED_BYTE;
break;
- case 4:
+ case 4:
mFormatInternal = GL_RGBA8;
mFormatPrimary = GL_RGBA;
mFormatType = GL_UNSIGNED_BYTE;
break;
- default:
+ default:
llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
}
@@ -1212,6 +1292,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
{
llassert(data_in);
+ stop_glerror();
if (discard_level < 0)
{
@@ -1240,8 +1321,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
stop_glerror();
{
llverify(gGL.getTexUnit(0)->bind(this));
+ stop_glerror();
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
+ stop_glerror();
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level);
+ stop_glerror();
}
}
if (!mTexName)
@@ -1754,7 +1838,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
// this to be an intentional effect and don't treat as a mask.
U32 midrangetotal = 0;
- for (U32 i = 4; i < 11; i++)
+ for (U32 i = 2; i < 13; i++)
{
midrangetotal += sample[i];
}
@@ -1769,7 +1853,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
upperhalftotal += sample[i];
}
- if (midrangetotal > length/16 || // lots of midrange, or
+ if (midrangetotal > length/48 || // lots of midrange, or
(lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or
(upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque
{
diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp
index d76b2d9004..c0045c8044 100644
--- a/indra/llrender/llpostprocess.cpp
+++ b/indra/llrender/llpostprocess.cpp
@@ -466,21 +466,21 @@ void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadT
void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height)
{
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f );
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.ortho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f );
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
}
void LLPostProcess::viewPerspective(void)
{
- glMatrixMode( GL_PROJECTION );
- glPopMatrix();
- glMatrixMode( GL_MODELVIEW );
- glPopMatrix();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
}
void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height)
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 7931230731..9c9f8a5465 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1,4 +1,4 @@
-/**
+ /**
* @file llrender.cpp
* @brief LLRender implementation
*
@@ -34,19 +34,21 @@
#include "llimagegl.h"
#include "llrendertarget.h"
#include "lltexture.h"
+#include "llshadermgr.h"
LLRender gGL;
// Handy copies of last good GL matrices
-F64 gGLModelView[16];
-F64 gGLLastModelView[16];
-F64 gGLLastProjection[16];
-F64 gGLProjection[16];
+F32 gGLModelView[16];
+F32 gGLLastModelView[16];
+F32 gGLLastProjection[16];
+F32 gGLProjection[16];
S32 gGLViewport[4];
U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
U32 LLTexUnit::sWhiteTexture = 0;
+bool LLRender::sGLCoreProfile = false;
static const U32 LL_NUM_TEXTURE_LAYERS = 32;
static const U32 LL_NUM_LIGHT_UNITS = 8;
@@ -178,10 +180,13 @@ void LLTexUnit::enable(eTextureType type)
if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) )
{
+ stop_glerror();
activate();
+ stop_glerror();
if (mCurrTexType != TT_NONE && !gGL.mDirty)
{
disable(); // Force a disable of a previous texture type if it's enabled.
+ stop_glerror();
}
mCurrTexType = type;
@@ -190,7 +195,9 @@ void LLTexUnit::enable(eTextureType type)
type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
mIndex < gGLManager.mNumTextureUnits)
{
+ stop_glerror();
glEnable(sGLTextureType[type]);
+ stop_glerror();
}
}
}
@@ -286,26 +293,35 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
{
return bind(LLImageGL::sDefaultGLTexture) ;
}
+ stop_glerror();
return false ;
}
if ((mCurrTexture != texture->getTexName()) || forceBind)
{
gGL.flush();
+ stop_glerror();
activate();
+ stop_glerror();
enable(texture->getTarget());
+ stop_glerror();
mCurrTexture = texture->getTexName();
glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
+ stop_glerror();
texture->updateBindStats(texture->mTextureMemory);
mHasMipMaps = texture->mHasMipMaps;
if (texture->mTexOptionsDirty)
{
+ stop_glerror();
texture->mTexOptionsDirty = false;
setTextureAddressMode(texture->mAddressMode);
setTextureFilteringOption(texture->mFilterOption);
+ stop_glerror();
}
}
+ stop_glerror();
+
return true;
}
@@ -814,14 +830,16 @@ LLLightState::LLLightState(S32 index)
mAmbient.set(0,0,0,1);
mPosition.set(0,0,1,0);
mSpotDirection.set(0,0,-1);
-
}
void LLLightState::enable()
{
if (!mEnabled)
{
- glEnable(GL_LIGHT0+mIndex);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glEnable(GL_LIGHT0+mIndex);
+ }
mEnabled = true;
}
}
@@ -830,7 +848,10 @@ void LLLightState::disable()
{
if (mEnabled)
{
- glDisable(GL_LIGHT0+mIndex);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glDisable(GL_LIGHT0+mIndex);
+ }
mEnabled = false;
}
}
@@ -839,8 +860,12 @@ void LLLightState::setDiffuse(const LLColor4& diffuse)
{
if (mDiffuse != diffuse)
{
+ ++gGL.mLightHash;
mDiffuse = diffuse;
- glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV);
+ }
}
}
@@ -848,8 +873,12 @@ void LLLightState::setAmbient(const LLColor4& ambient)
{
if (mAmbient != ambient)
{
+ ++gGL.mLightHash;
mAmbient = ambient;
- glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV);
+ }
}
}
@@ -857,16 +886,34 @@ void LLLightState::setSpecular(const LLColor4& specular)
{
if (mSpecular != specular)
{
+ ++gGL.mLightHash;
mSpecular = specular;
- glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV);
+ }
}
}
void LLLightState::setPosition(const LLVector4& position)
{
//always set position because modelview matrix may have changed
+ ++gGL.mLightHash;
mPosition = position;
- glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV);
+ }
+ else
+ { //transform position by current modelview matrix
+ glh::vec4f pos(position.mV);
+
+ const glh::matrix4f& mat = gGL.getModelviewMatrix();
+ mat.mult_matrix_vec(pos);
+
+ mPosition.set(pos.v);
+ }
+
}
void LLLightState::setConstantAttenuation(const F32& atten)
@@ -874,7 +921,11 @@ void LLLightState::setConstantAttenuation(const F32& atten)
if (mConstantAtten != atten)
{
mConstantAtten = atten;
- glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten);
+ ++gGL.mLightHash;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten);
+ }
}
}
@@ -882,8 +933,12 @@ void LLLightState::setLinearAttenuation(const F32& atten)
{
if (mLinearAtten != atten)
{
+ ++gGL.mLightHash;
mLinearAtten = atten;
- glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten);
+ }
}
}
@@ -891,8 +946,12 @@ void LLLightState::setQuadraticAttenuation(const F32& atten)
{
if (mQuadraticAtten != atten)
{
+ ++gGL.mLightHash;
mQuadraticAtten = atten;
- glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten);
+ }
}
}
@@ -900,8 +959,12 @@ void LLLightState::setSpotExponent(const F32& exponent)
{
if (mSpotExponent != exponent)
{
+ ++gGL.mLightHash;
mSpotExponent = exponent;
- glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent);
+ }
}
}
@@ -909,21 +972,39 @@ void LLLightState::setSpotCutoff(const F32& cutoff)
{
if (mSpotCutoff != cutoff)
{
+ ++gGL.mLightHash;
mSpotCutoff = cutoff;
- glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff);
+ }
}
}
void LLLightState::setSpotDirection(const LLVector3& direction)
{
//always set direction because modelview matrix may have changed
+ ++gGL.mLightHash;
mSpotDirection = direction;
- glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV);
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV);
+ }
+ else
+ { //transform direction by current modelview matrix
+ glh::vec3f dir(direction.mV);
+
+ const glh::matrix4f& mat = gGL.getModelviewMatrix();
+ mat.mult_matrix_dir(dir);
+
+ mSpotDirection.set(direction);
+ }
}
LLRender::LLRender()
: mDirty(false),
mCount(0),
+ mQuadCycle(0),
mMode(LLRender::TRIANGLES),
mCurrTextureUnitIndex(0),
mMaxAnisotropy(0.f)
@@ -951,6 +1032,17 @@ LLRender::LLRender()
mCurrBlendAlphaSFactor = BF_UNDEF;
mCurrBlendColorDFactor = BF_UNDEF;
mCurrBlendAlphaDFactor = BF_UNDEF;
+
+ mMatrixMode = LLRender::MM_MODELVIEW;
+
+ for (U32 i = 0; i < NUM_MATRIX_MODES; ++i)
+ {
+ mMatIdx[i] = 0;
+ mMatHash[i] = 0;
+ mCurMatHash[i] = 0xFFFFFFFF;
+ }
+
+ mLightHash = 0;
}
LLRender::~LLRender()
@@ -961,12 +1053,13 @@ LLRender::~LLRender()
void LLRender::init()
{
llassert_always(mBuffer.isNull()) ;
-
+ stop_glerror();
mBuffer = new LLVertexBuffer(immediate_mask, 0);
mBuffer->allocateBuffer(4096, 0, TRUE);
mBuffer->getVertexStrider(mVerticesp);
mBuffer->getTexCoord0Strider(mTexcoordsp);
mBuffer->getColorStrider(mColorsp);
+ stop_glerror();
}
void LLRender::shutdown()
@@ -1007,28 +1100,353 @@ void LLRender::refreshState(void)
mDirty = false;
}
+void LLRender::syncLightState()
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (!shader)
+ {
+ return;
+ }
+
+ if (shader->mLightHash != mLightHash)
+ {
+ shader->mLightHash = mLightHash;
+
+ LLVector4 position[8];
+ LLVector3 direction[8];
+ LLVector3 attenuation[8];
+ LLVector3 diffuse[8];
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLLightState* light = mLightState[i];
+
+ position[i] = light->mPosition;
+ direction[i] = light->mSpotDirection;
+ attenuation[i].set(light->mLinearAtten, light->mQuadraticAtten, light->mSpecular.mV[3]);
+ diffuse[i].set(light->mDiffuse.mV);
+ }
+
+ shader->uniform4fv(LLShaderMgr::LIGHT_POSITION, 8, position[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_DIRECTION, 8, direction[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_ATTENUATION, 8, attenuation[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, 8, diffuse[0].mV);
+ shader->uniform4fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV);
+ //HACK -- duplicate sunlight color for compatibility with drivers that can't deal with multiple shader objects referencing the same uniform
+ shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
+ }
+}
+
+void LLRender::syncMatrices()
+{
+ stop_glerror();
+
+ U32 name[] =
+ {
+ LLShaderMgr::MODELVIEW_MATRIX,
+ LLShaderMgr::PROJECTION_MATRIX,
+ LLShaderMgr::TEXTURE_MATRIX0,
+ LLShaderMgr::TEXTURE_MATRIX1,
+ LLShaderMgr::TEXTURE_MATRIX2,
+ LLShaderMgr::TEXTURE_MATRIX3,
+ };
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ static glh::matrix4f cached_mvp;
+ static U32 cached_mvp_mdv_hash = 0xFFFFFFFF;
+ static U32 cached_mvp_proj_hash = 0xFFFFFFFF;
+
+ static glh::matrix4f cached_normal;
+ static U32 cached_normal_hash = 0xFFFFFFFF;
+
+ if (shader)
+ {
+ llassert(shader);
+
+ bool mvp_done = false;
+
+ U32 i = MM_MODELVIEW;
+ if (mMatHash[i] != shader->mMatHash[i])
+ { //update modelview, normal, and MVP
+ glh::matrix4f& mat = mMatrix[i][mMatIdx[i]];
+
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m);
+ shader->mMatHash[i] = mMatHash[i];
+
+ //update normal matrix
+ S32 loc = shader->getUniformLocation(LLShaderMgr::NORMAL_MATRIX);
+ if (loc > -1)
+ {
+ if (cached_normal_hash != mMatHash[i])
+ {
+ cached_normal = mat.inverse().transpose();
+ cached_normal_hash = mMatHash[i];
+ }
+
+ glh::matrix4f& norm = cached_normal;
+
+ F32 norm_mat[] =
+ {
+ norm.m[0], norm.m[1], norm.m[2],
+ norm.m[4], norm.m[5], norm.m[6],
+ norm.m[8], norm.m[9], norm.m[10]
+ };
+
+ shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat);
+ }
+
+ //update MVP matrix
+ mvp_done = true;
+ loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX);
+ if (loc > -1)
+ {
+ U32 proj = MM_PROJECTION;
+
+ if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION])
+ {
+ cached_mvp = mat;
+ cached_mvp.mult_left(mMatrix[proj][mMatIdx[proj]]);
+ cached_mvp_mdv_hash = mMatHash[i];
+ cached_mvp_proj_hash = mMatHash[MM_PROJECTION];
+ }
+
+ shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m);
+ }
+ }
+
+
+ i = MM_PROJECTION;
+ if (mMatHash[i] != shader->mMatHash[i])
+ { //update projection matrix, normal, and MVP
+ glh::matrix4f& mat = mMatrix[i][mMatIdx[i]];
+
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m);
+ shader->mMatHash[i] = mMatHash[i];
+
+ if (!mvp_done)
+ {
+ //update MVP matrix
+ S32 loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX);
+ if (loc > -1)
+ {
+ if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION])
+ {
+ U32 mdv = MM_MODELVIEW;
+ cached_mvp = mat;
+ cached_mvp.mult_right(mMatrix[mdv][mMatIdx[mdv]]);
+ cached_mvp_mdv_hash = mMatHash[MM_MODELVIEW];
+ cached_mvp_proj_hash = mMatHash[MM_PROJECTION];
+ }
+
+ shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m);
+ }
+ }
+ }
+
+ for (i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i)
+ {
+ if (mMatHash[i] != shader->mMatHash[i])
+ {
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].m);
+ shader->mMatHash[i] = mMatHash[i];
+ }
+ }
+
+
+ if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting)
+ { //also sync light state
+ syncLightState();
+ }
+ }
+ else if (!LLGLSLShader::sNoFixedFunction)
+ {
+ GLenum mode[] =
+ {
+ GL_MODELVIEW,
+ GL_PROJECTION,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ };
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ if (mMatHash[i] != mCurMatHash[i])
+ {
+ glMatrixMode(mode[i]);
+ glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
+ mCurMatHash[i] = mMatHash[i];
+ }
+ }
+
+ for (U32 i = 2; i < NUM_MATRIX_MODES; ++i)
+ {
+ if (mMatHash[i] != mCurMatHash[i])
+ {
+ gGL.getTexUnit(i-2)->activate();
+ glMatrixMode(mode[i]);
+ glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
+ mCurMatHash[i] = mMatHash[i];
+ }
+ }
+ }
+
+ stop_glerror();
+}
+
void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
flush();
- glTranslatef(x,y,z);
+
+ {
+ glh::matrix4f trans_mat(1,0,0,x,
+ 0,1,0,y,
+ 0,0,1,z,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(trans_mat);
+ mMatHash[mMatrixMode]++;
+ }
}
void LLRender::scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
flush();
- glScalef(x,y,z);
+
+ {
+ glh::matrix4f scale_mat(x,0,0,0,
+ 0,y,0,0,
+ 0,0,z,0,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(scale_mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar)
+{
+ flush();
+
+ {
+
+ glh::matrix4f ortho_mat(2.f/(right-left),0,0, -(right+left)/(right-left),
+ 0,2.f/(top-bottom),0, -(top+bottom)/(top-bottom),
+ 0,0,-2.f/(zFar-zNear), -(zFar+zNear)/(zFar-zNear),
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(ortho_mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z)
+{
+ flush();
+
+ {
+ F32 r = a * DEG_TO_RAD;
+
+ F32 c = cosf(r);
+ F32 s = sinf(r);
+
+ F32 ic = 1.f-c;
+
+ glh::matrix4f rot_mat(x*x*ic+c, x*y*ic-z*s, x*z*ic+y*s, 0,
+ x*y*ic+z*s, y*y*ic+c, y*z*ic-x*s, 0,
+ x*z*ic-y*s, y*z*ic+x*s, z*z*ic+c, 0,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(rot_mat);
+ mMatHash[mMatrixMode]++;
+ }
}
void LLRender::pushMatrix()
{
flush();
- glPushMatrix();
+
+ {
+ if (mMatIdx[mMatrixMode] < LL_MATRIX_STACK_DEPTH-1)
+ {
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]+1] = mMatrix[mMatrixMode][mMatIdx[mMatrixMode]];
+ ++mMatIdx[mMatrixMode];
+ }
+ else
+ {
+ llwarns << "Matrix stack overflow." << llendl;
+ }
+ }
}
void LLRender::popMatrix()
{
flush();
- glPopMatrix();
+ {
+ if (mMatIdx[mMatrixMode] > 0)
+ {
+ --mMatIdx[mMatrixMode];
+ mMatHash[mMatrixMode]++;
+ }
+ else
+ {
+ llwarns << "Matrix stack underflow." << llendl;
+ }
+ }
+}
+
+void LLRender::loadMatrix(const GLfloat* m)
+{
+ flush();
+ {
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].set_value((GLfloat*) m);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::multMatrix(const GLfloat* m)
+{
+ flush();
+ {
+ glh::matrix4f mat((GLfloat*) m);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::matrixMode(U32 mode)
+{
+ if (mode == MM_TEXTURE)
+ {
+ mode = MM_TEXTURE0 + gGL.getCurrentTexUnitIndex();
+ }
+
+ llassert(mode < NUM_MATRIX_MODES);
+ mMatrixMode = mode;
+}
+
+void LLRender::loadIdentity()
+{
+ flush();
+
+ {
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity();
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+const glh::matrix4f& LLRender::getModelviewMatrix()
+{
+ return mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]];
+}
+
+const glh::matrix4f& LLRender::getProjectionMatrix()
+{
+ return mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]];
}
void LLRender::translateUI(F32 x, F32 y, F32 z)
@@ -1284,6 +1702,19 @@ LLLightState* LLRender::getLight(U32 index)
return NULL;
}
+void LLRender::setAmbientLightColor(const LLColor4& color)
+{
+ if (color != mAmbientLightColor)
+ {
+ ++mLightHash;
+ mAmbientLightColor = color;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.mV);
+ }
+ }
+}
+
bool LLRender::verifyTexUnitActive(U32 unitToVerify)
{
if (mCurrTextureUnitIndex == unitToVerify)
@@ -1309,6 +1740,11 @@ void LLRender::begin(const GLuint& mode)
{
if (mode != mMode)
{
+ if (mode == LLRender::QUADS)
+ {
+ mQuadCycle = 1;
+ }
+
if (mMode == LLRender::QUADS ||
mMode == LLRender::LINES ||
mMode == LLRender::TRIANGLES ||
@@ -1396,7 +1832,7 @@ void LLRender::flush()
if (gDebugGL)
{
- if (mMode == LLRender::QUADS)
+ if (mMode == LLRender::QUADS && !sGLCoreProfile)
{
if (mCount%4 != 0)
{
@@ -1421,12 +1857,34 @@ void LLRender::flush()
}
}
- mBuffer->setBuffer(immediate_mask);
- mBuffer->drawArrays(mMode, 0, mCount);
+ //store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
+ U32 count = mCount;
+ mCount = 0;
+
+ if (mBuffer->useVBOs() && !mBuffer->isLocked())
+ { //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
+ mBuffer->getVertexStrider(mVerticesp, 0, count);
+ mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
+ mBuffer->getColorStrider(mColorsp, 0, count);
+ }
+
+ mBuffer->flush();
+ mBuffer->setBuffer(immediate_mask);
+
+ if (mMode == LLRender::QUADS && sGLCoreProfile)
+ {
+ mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
+ mQuadCycle = 1;
+ }
+ else
+ {
+ mBuffer->drawArrays(mMode, 0, count);
+ }
+
+ mVerticesp[0] = mVerticesp[count];
+ mTexcoordsp[0] = mTexcoordsp[count];
+ mColorsp[0] = mColorsp[count];
- mVerticesp[0] = mVerticesp[mCount];
- mTexcoordsp[0] = mTexcoordsp[mCount];
- mColorsp[0] = mColorsp[mCount];
mCount = 0;
}
}
@@ -1434,6 +1892,17 @@ void LLRender::flush()
void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
//the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095]
+ if (mCount > 2048)
+ { //break when buffer gets reasonably full to keep GL command buffers happy and avoid overflow below
+ switch (mMode)
+ {
+ case LLRender::POINTS: flush(); break;
+ case LLRender::TRIANGLES: if (mCount%3==0) flush(); break;
+ case LLRender::QUADS: if(mCount%4 == 0) flush(); break;
+ case LLRender::LINES: if (mCount%2 == 0) flush(); break;
+ }
+ }
+
if (mCount > 4094)
{
// llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl;
@@ -1450,10 +1919,29 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
mVerticesp[mCount] = vert;
}
+ if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile)
+ {
+ mQuadCycle++;
+ if (mQuadCycle == 4)
+ { //copy two vertices so fourth quad element will add a triangle
+ mQuadCycle = 0;
+
+ mCount++;
+ mVerticesp[mCount] = mVerticesp[mCount-3];
+ mColorsp[mCount] = mColorsp[mCount-3];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-3];
+
+ mCount++;
+ mVerticesp[mCount] = mVerticesp[mCount-2];
+ mColorsp[mCount] = mColorsp[mCount-2];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-2];
+ }
+ }
+
mCount++;
mVerticesp[mCount] = mVerticesp[mCount-1];
mColorsp[mCount] = mColorsp[mCount-1];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
}
void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
@@ -1464,13 +1952,50 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
return;
}
- for (S32 i = 0; i < vert_count; i++)
- {
- mVerticesp[mCount] = verts[i];
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
+
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
- mCount++;
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy two
+ mVerticesp[mCount++] = verts[i-3];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount++] = verts[i-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last one
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
+
+ mCount++;
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
}
// Often happens with LLFontGL::render(), especially in LLScrollListText::draw()
@@ -1489,13 +2014,50 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 v
return;
}
- for (S32 i = 0; i < vert_count; i++)
- {
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
- mCount++;
- mColorsp[mCount] = mColorsp[mCount-1];
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last two
+ mVerticesp[mCount] = verts[i-3];
+ mTexcoordsp[mCount++] = uvs[i-3];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i-1];
+ mTexcoordsp[mCount++] = uvs[i-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last one
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+
+ mCount++;
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
}
// Often happens with LLFontGL::render(), especially in LLScrollListText::draw()
@@ -1517,13 +2079,51 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLCol
return;
}
- for (S32 i = 0; i < vert_count; i++)
- {
- mVerticesp[mCount] = verts[i];
- mTexcoordsp[mCount] = uvs[i];
- mColorsp[mCount] = colors[i];
+
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
- mCount++;
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ //copy last two
+ mVerticesp[mCount] = verts[i-3];
+ mTexcoordsp[mCount] = uvs[i-3];
+ mColorsp[mCount++] = colors[i-3];
+
+ mVerticesp[mCount] = verts[i-1];
+ mTexcoordsp[mCount] = uvs[i-1];
+ mColorsp[mCount++] = colors[i-1];
+
+ //copy last one
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount] = colors[i];
+
+ mCount++;
+ }
}
// Often happens with LLFontGL::render(), especially in LLScrollListText::draw()
@@ -1605,6 +2205,81 @@ void LLRender::color3fv(const GLfloat* c)
color4f(c[0],c[1],c[2],1);
}
+void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f);
+ }
+ else
+ {
+ glColor3f(r,g,b);
+ }
+}
+
+void LLRender::diffuseColor3fv(const F32* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f);
+ }
+ else
+ {
+ glColor3fv(c);
+ }
+}
+
+void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a);
+ }
+ else
+ {
+ glColor4f(r,g,b,a);
+ }
+}
+
+void LLRender::diffuseColor4fv(const F32* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c);
+ }
+ else
+ {
+ glColor4fv(c);
+ }
+}
+
+void LLRender::diffuseColor4ubv(const U8* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f);
+ }
+ else
+ {
+ glColor4ubv(c);
+ }
+}
+
void LLRender::debugTexUnits(void)
{
LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL;
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 8f7ee30d87..fa5f7f311d 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -41,6 +41,8 @@
#include "llstrider.h"
#include "llpointer.h"
#include "llglheaders.h"
+#include "llmatrix4a.h"
+#include "glh/glh_linear.h"
class LLVertexBuffer;
class LLCubeMap;
@@ -48,6 +50,8 @@ class LLImageGL;
class LLRenderTarget;
class LLTexture ;
+#define LL_MATRIX_STACK_DEPTH 32
+
class LLTexUnit
{
friend class LLRender;
@@ -235,6 +239,8 @@ public:
void setSpotDirection(const LLVector3& direction);
protected:
+ friend class LLRender;
+
S32 mIndex;
bool mEnabled;
LLColor4 mDiffuse;
@@ -308,6 +314,18 @@ public:
BF_UNDEF
} eBlendFactor;
+ typedef enum
+ {
+ MM_MODELVIEW = 0,
+ MM_PROJECTION,
+ MM_TEXTURE0,
+ MM_TEXTURE1,
+ MM_TEXTURE2,
+ MM_TEXTURE3,
+ NUM_MATRIX_MODES,
+ MM_TEXTURE
+ } eMatrixMode;
+
LLRender();
~LLRender();
void init() ;
@@ -319,8 +337,21 @@ public:
void translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z);
void scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z);
+ void rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z);
+ void ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar);
+
void pushMatrix();
void popMatrix();
+ void loadMatrix(const GLfloat* m);
+ void loadIdentity();
+ void multMatrix(const GLfloat* m);
+ void matrixMode(U32 mode);
+
+ const glh::matrix4f& getModelviewMatrix();
+ const glh::matrix4f& getProjectionMatrix();
+
+ void syncMatrices();
+ void syncLightState();
void translateUI(F32 x, F32 y, F32 z);
void scaleUI(F32 x, F32 y, F32 z);
@@ -351,6 +382,12 @@ public:
void color3fv(const GLfloat* c);
void color4ubv(const GLubyte* c);
+ void diffuseColor3f(F32 r, F32 g, F32 b);
+ void diffuseColor3fv(const F32* c);
+ void diffuseColor4f(F32 r, F32 g, F32 b, F32 a);
+ void diffuseColor4fv(const F32* c);
+ void diffuseColor4ubv(const U8* c);
+
void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
@@ -368,7 +405,8 @@ public:
eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor);
LLLightState* getLight(U32 index);
-
+ void setAmbientLightColor(const LLColor4& color);
+
LLTexUnit* getTexUnit(U32 index);
U32 getCurrentTexUnitIndex(void) const { return mCurrTextureUnitIndex; }
@@ -389,9 +427,21 @@ public:
public:
static U32 sUICalls;
static U32 sUIVerts;
+ static bool sGLCoreProfile;
private:
- bool mDirty;
+ friend class LLLightState;
+
+ U32 mMatrixMode;
+ U32 mMatIdx[NUM_MATRIX_MODES];
+ U32 mMatHash[NUM_MATRIX_MODES];
+ glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
+ U32 mCurMatHash[NUM_MATRIX_MODES];
+ U32 mLightHash;
+ LLColor4 mAmbientLightColor;
+
+ bool mDirty;
+ U32 mQuadCycle;
U32 mCount;
U32 mMode;
U32 mCurrTextureUnitIndex;
@@ -419,10 +469,10 @@ private:
};
-extern F64 gGLModelView[16];
-extern F64 gGLLastModelView[16];
-extern F64 gGLLastProjection[16];
-extern F64 gGLProjection[16];
+extern F32 gGLModelView[16];
+extern F32 gGLLastModelView[16];
+extern F32 gGLLastProjection[16];
+extern F32 gGLProjection[16];
extern S32 gGLViewport[4];
extern LLRender gGL;
diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp
index a5cd70445f..26bfe036e8 100644
--- a/indra/llrender/llrendersphere.cpp
+++ b/indra/llrender/llrendersphere.cpp
@@ -35,106 +35,12 @@
#include "llglheaders.h"
-GLUquadricObj *gQuadObj2 = NULL;
LLRenderSphere gSphere;
-void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks);
-
-void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks)
-{
- if (!gQuadObj2)
- {
- gQuadObj2 = gluNewQuadric();
- if (!gQuadObj2)
- {
- llwarns << "drawSolidSphere couldn't allocate quadric" << llendl;
- return;
- }
- }
-
- gluQuadricDrawStyle(gQuadObj2, GLU_FILL);
- gluQuadricNormals(gQuadObj2, GLU_SMOOTH);
- // If we ever changed/used the texture or orientation state
- // of quadObj, we'd need to change it to the defaults here
- // with gluQuadricTexture and/or gluQuadricOrientation.
- gluQuadricTexture(gQuadObj2, GL_TRUE);
- gluSphere(gQuadObj2, radius, slices, stacks);
-}
-
-
-// A couple thoughts on sphere drawing:
-// 1) You need more slices than stacks, but little less than 2:1
-// 2) At low LOD, setting stacks to an odd number avoids a "band" around the equator, making things look smoother
-void LLRenderSphere::prerender()
-{
- // Create a series of display lists for different LODs
- mDList[0] = glGenLists(1);
- glNewList(mDList[0], GL_COMPILE);
- drawSolidSphere(1.0, 30, 20);
- glEndList();
-
- mDList[1] = glGenLists(1);
- glNewList(mDList[1], GL_COMPILE);
- drawSolidSphere(1.0, 20, 15);
- glEndList();
-
- mDList[2] = glGenLists(1);
- glNewList(mDList[2], GL_COMPILE);
- drawSolidSphere(1.0, 12, 8);
- glEndList();
-
- mDList[3] = glGenLists(1);
- glNewList(mDList[3], GL_COMPILE);
- drawSolidSphere(1.0, 8, 5);
- glEndList();
-}
-
-void LLRenderSphere::cleanupGL()
-{
- for (S32 detail = 0; detail < 4; detail++)
- {
- glDeleteLists(mDList[detail], 1);
- mDList[detail] = 0;
- }
-
- if (gQuadObj2)
- {
- gluDeleteQuadric(gQuadObj2);
- gQuadObj2 = NULL;
- }
-}
-
-// Constants here are empirically derived from my eyeballs, JNC
-//
-// The toughest adjustment is the cutoff for the lowest LOD
-// Maybe we should have more LODs at the low end?
-void LLRenderSphere::render(F32 pixel_area)
-{
- S32 level_of_detail;
-
- if (pixel_area > 10000.f)
- {
- level_of_detail = 0;
- }
- else if (pixel_area > 800.f)
- {
- level_of_detail = 1;
- }
- else if (pixel_area > 100.f)
- {
- level_of_detail = 2;
- }
- else
- {
- level_of_detail = 3;
- }
- glCallList(mDList[level_of_detail]);
-}
-
-
void LLRenderSphere::render()
{
- glCallList(mDList[0]);
+ renderGGL();
+ gGL.flush();
}
inline LLVector3 polar_to_cart(F32 latitude, F32 longitude)
diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h
index 96a6bec80c..f8e9e86e7f 100644
--- a/indra/llrender/llrendersphere.h
+++ b/indra/llrender/llrendersphere.h
@@ -40,11 +40,6 @@ void lat2xyz(LLVector3 * result, F32 lat, F32 lon); // utility routine
class LLRenderSphere
{
public:
- LLGLuint mDList[5];
-
- void prerender();
- void cleanupGL();
- void render(F32 pixel_area); // of a box of size 1.0 at that position
void render(); // render at highest LOD
void renderGGL(); // render using LLRender
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 9eacf08d2c..ef2a7395da 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -31,8 +31,7 @@
#include "llgl.h"
LLRenderTarget* LLRenderTarget::sBoundTarget = NULL;
-
-
+U32 LLRenderTarget::sBytesAllocated = 0;
void check_framebuffer_status()
{
@@ -51,7 +50,7 @@ void check_framebuffer_status()
}
}
-BOOL LLRenderTarget::sUseFBO = false;
+bool LLRenderTarget::sUseFBO = false;
LLRenderTarget::LLRenderTarget() :
mResX(0),
@@ -62,8 +61,7 @@ LLRenderTarget::LLRenderTarget() :
mStencil(0),
mUseDepth(false),
mRenderDepth(false),
- mUsage(LLTexUnit::TT_TEXTURE),
- mSamples(0)
+ mUsage(LLTexUnit::TT_TEXTURE)
{
}
@@ -84,20 +82,6 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
mStencil = stencil;
mUsage = usage;
mUseDepth = depth;
- mSamples = samples;
-
- mSamples = gGLManager.getNumFBOFSAASamples(mSamples);
-
- if (mSamples > 1 && gGLManager.mHasTextureMultisample)
- {
- mUsage = LLTexUnit::TT_MULTISAMPLE_TEXTURE;
- //no support for multisampled stencil targets yet
- mStencil = false;
- }
- else
- {
- mSamples = 0;
- }
if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
{
@@ -157,21 +141,6 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
stop_glerror();
-#ifdef GL_ARB_texture_multisample
- if (mSamples > 1)
- {
- clear_glerror();
- glTexImage2DMultisample(LLTexUnit::getInternalType(mUsage), mSamples, color_fmt, mResX, mResY, GL_TRUE);
- if (glGetError() != GL_NO_ERROR)
- {
- llwarns << "Could not allocate multisample color buffer for render target." << llendl;
- return false;
- }
- }
- else
-#else
- llassert_always(mSamples <= 1);
-#endif
{
clear_glerror();
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@@ -182,32 +151,32 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
}
}
+ sBytesAllocated += mResX*mResY*4;
+
stop_glerror();
- if (mSamples == 0)
- {
- if (offset == 0)
- { //use bilinear filtering on single texture render targets that aren't multisampled
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- stop_glerror();
- }
- else
- { //don't filter data attachments
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
- }
+
+ if (offset == 0)
+ { //use bilinear filtering on single texture render targets that aren't multisampled
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ stop_glerror();
+ }
+ else
+ { //don't filter data attachments
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ stop_glerror();
+ }
- if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
- {
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
- stop_glerror();
- }
- else
- {
- // ATI doesn't support mirrored repeat for rectangular textures.
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
- }
+ if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
+ {
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
+ stop_glerror();
+ }
+ else
+ {
+ // ATI doesn't support mirrored repeat for rectangular textures.
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
}
if (mFBO)
@@ -250,26 +219,16 @@ bool LLRenderTarget::allocateDepth()
{
LLImageGL::generateTextures(1, &mDepth);
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
- if (mSamples == 0)
- {
- U32 internal_type = LLTexUnit::getInternalType(mUsage);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
- clear_glerror();
- LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
- }
-#ifdef GL_ARB_texture_multisample
- else
- {
- stop_glerror();
- clear_glerror();
- glTexImage2DMultisample(LLTexUnit::getInternalType(mUsage), mSamples, GL_DEPTH_COMPONENT32, mResX, mResY, GL_TRUE);
- }
-#else
- llassert_always(mSamples <= 1);
-#endif
+
+ U32 internal_type = LLTexUnit::getInternalType(mUsage);
+ stop_glerror();
+ clear_glerror();
+ LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
}
+ sBytesAllocated += mResX*mResY*4;
+
if (glGetError() != GL_NO_ERROR)
{
llwarns << "Unable to allocate depth buffer for render target." << llendl;
@@ -339,14 +298,16 @@ void LLRenderTarget::release()
stop_glerror();
}
mDepth = 0;
+
+ sBytesAllocated -= mResX*mResY*4;
}
else if (mUseDepth && mFBO)
{ //detach shared depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (mStencil)
{ //attached as a renderbuffer
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
mStencil = false;
}
else
@@ -364,6 +325,7 @@ void LLRenderTarget::release()
if (mTex.size() > 0)
{
+ sBytesAllocated -= mResX*mResY*4*mTex.size();
LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
mTex.clear();
}
@@ -495,7 +457,8 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
gGL.flush();
if (!source.mFBO || !mFBO)
{
- llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+ llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+ return;
}
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index f6af03fb80..2735ab21c5 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -63,7 +63,8 @@ class LLRenderTarget
{
public:
//whether or not to use FBO implementation
- static BOOL sUseFBO;
+ static bool sUseFBO;
+ static U32 sBytesAllocated;
LLRenderTarget();
~LLRenderTarget();
@@ -143,11 +144,10 @@ protected:
std::vector mTex;
U32 mFBO;
U32 mDepth;
- BOOL mStencil;
- BOOL mUseDepth;
- BOOL mRenderDepth;
+ bool mStencil;
+ bool mUseDepth;
+ bool mRenderDepth;
LLTexUnit::eTextureType mUsage;
- U32 mSamples;
static LLRenderTarget* sBoundTarget;
};
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 2aaea6586d..bcc065d234 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -81,7 +81,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->calculatesAtmospherics)
{
- if (!shader->attachObject("windlight/atmosphericsVarsV.glsl"))
+ if (features->hasWaterFog)
+ {
+ if (!shader->attachObject("windlight/atmosphericsVarsWaterV.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else if (!shader->attachObject("windlight/atmosphericsVarsV.glsl"))
{
return FALSE;
}
@@ -167,7 +174,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
if(features->calculatesAtmospherics)
{
- if (!shader->attachObject("windlight/atmosphericsVarsF.glsl"))
+ if (features->hasWaterFog)
+ {
+ if (!shader->attachObject("windlight/atmosphericsVarsWaterF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else if (!shader->attachObject("windlight/atmosphericsVarsF.glsl"))
{
return FALSE;
}
@@ -247,7 +261,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -286,7 +300,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
@@ -310,7 +324,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
else if (features->hasWaterFog)
@@ -342,7 +356,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -361,7 +375,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -401,7 +415,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
@@ -425,7 +439,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
@@ -444,10 +458,26 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
{
return FALSE;
}
- shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
+ shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1);
}
}
}
+
+ if (features->mIndexedTextureChannels <= 1)
+ {
+ if (!shader->attachObject("objects/nonindexedTextureV.glsl"))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!shader->attachObject("objects/indexedTextureV.glsl"))
+ {
+ return FALSE;
+ }
+ }
+
return TRUE;
}
@@ -483,7 +513,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
}
else
{
- LL_DEBUGS("ShaderLoading") << log << LL_ENDL;
+ LL_INFOS("ShaderLoading") << log << LL_ENDL;
}
}
}
@@ -544,23 +574,64 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
//we can't have any lines longer than 1024 characters
- //or any shaders longer than 1024 lines... deal - DaveP
+ //or any shaders longer than 4096 lines... deal - DaveP
GLcharARB buff[1024];
- GLcharARB* text[1024];
+ GLcharARB* text[4096];
GLuint count = 0;
- if (gGLManager.mGLVersion < 2.1f)
+ F32 version = gGLManager.mGLVersion;
+
+//hack to never use GLSL > 1.20 on OSX
+#if LL_DARWIN
+ version = llmin(version, 2.9f);
+#endif
+
+ if (version < 2.1f)
{
text[count++] = strdup("#version 110\n");
+ text[count++] = strdup("#define ATTRIBUTE attribute\n");
+ text[count++] = strdup("#define VARYING varying\n");
}
- else if (gGLManager.mGLVersion < 3.f)
+ else if (version < 3.3f)
{
//set version to 1.20
text[count++] = strdup("#version 120\n");
+ text[count++] = strdup("#define FXAA_GLSL_120 1\n");
+ text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n");
+ text[count++] = strdup("#define ATTRIBUTE attribute\n");
+ text[count++] = strdup("#define VARYING varying\n");
}
else
- { //set version to 1.30
- text[count++] = strdup("#version 130\n");
+ {
+ if (version < 4.f)
+ {
+ //set version to 1.30
+ text[count++] = strdup("#version 130\n");
+ }
+ else
+ { //set version to 400
+ text[count++] = strdup("#version 400\n");
+ }
+
+ text[count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n");
+ text[count++] = strdup("#define FXAA_GLSL_130 1\n");
+
+ text[count++] = strdup("#define ATTRIBUTE in\n");
+
+ if (type == GL_VERTEX_SHADER_ARB)
+ { //"varying" state is "out" in a vertex program, "in" in a fragment program
+ // ("varying" is deprecated after version 1.20)
+ text[count++] = strdup("#define VARYING out\n");
+ }
+ else
+ {
+ text[count++] = strdup("#define VARYING in\n");
+ }
+
+ //backwards compatibility with legacy texture lookup syntax
+ text[count++] = strdup("#define textureCube texture\n");
+ text[count++] = strdup("#define texture2DLod textureLod\n");
+ text[count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n");
}
//copy preprocessor definitions into buffer
@@ -584,7 +655,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
.
uniform sampler2D texN;
- varying float vary_texture_index;
+ VARYING float vary_texture_index;
vec4 diffuseLookup(vec2 texcoord)
{
@@ -610,7 +681,11 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
text[count++] = strdup(decl.c_str());
}
- text[count++] = strdup("varying float vary_texture_index;\n");
+ if (texture_index_channels > 1)
+ {
+ text[count++] = strdup("VARYING float vary_texture_index;\n");
+ }
+
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
text[count++] = strdup("{\n");
@@ -633,7 +708,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
text[count++] = strdup("\t}\n");
- text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
+ text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
text[count++] = strdup("}\n");
}
else
@@ -656,13 +731,13 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
text[count++] = strdup(if_str.c_str());
}
- text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
+ text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
text[count++] = strdup("}\n");
}
}
//copy file into memory
- while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) )
+ while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) )
{
text[count++] = (GLcharARB *)strdup((char *)buff);
}
@@ -717,14 +792,24 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
dumpObjectLog(ret);
+#if LL_WINDOWS
std::stringstream ostr;
//dump shader source for debugging
for (GLuint i = 0; i < count; i++)
{
ostr << i << ": " << text[i];
+
+ if (i % 128 == 0)
+ { //dump every 128 lines
+
+ LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
+ ostr = std::stringstream();
+ }
+
}
LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
+#endif // LL_WINDOWS
ret = 0;
}
@@ -773,28 +858,42 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors)
LL_WARNS("ShaderLoading") << "GLSL Linker Error:" << LL_ENDL;
}
-// NOTE: Removing LL_DARWIN block as it doesn't seem to actually give the correct answer,
-// but want it for reference once I move it.
-#if 0
- // Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
- // per Apple's suggestion
- glBegin(gGL.mMode);
- glEnd();
+#if LL_DARWIN
- // Query whether the shader can or cannot run in hardware
- // http://developer.apple.com/qa/qa2007/qa1502.html
- long vertexGPUProcessing;
- CGLContextObj ctx = CGLGetCurrentContext();
- CGLGetParameter (ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
- long fragmentGPUProcessing;
- CGLGetParameter (ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
- if (!fragmentGPUProcessing || !vertexGPUProcessing)
+ // For some reason this absolutely kills the frame rate when VBO's are enabled
+ if (0)
{
- LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL;
- success = GL_FALSE;
- suppress_errors = FALSE;
+ // Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
+ // per Apple's suggestion
+ LLGLSLShader::sNoFixedFunction = false;
+
+ glUseProgramObjectARB(obj);
+
+ gGL.begin(LLRender::TRIANGLES);
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.end();
+ gGL.flush();
+
+ glUseProgramObjectARB(0);
+
+ LLGLSLShader::sNoFixedFunction = true;
+
+ // Query whether the shader can or cannot run in hardware
+ // http://developer.apple.com/qa/qa2007/qa1502.html
+ GLint vertexGPUProcessing, fragmentGPUProcessing;
+ CGLContextObj ctx = CGLGetCurrentContext();
+ CGLGetParameter(ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
+ CGLGetParameter(ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
+ if (!fragmentGPUProcessing || !vertexGPUProcessing)
+ {
+ LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL;
+ success = GL_FALSE;
+ suppress_errors = FALSE;
+ }
}
-
+
#else
std::string log = get_object_log(obj);
LLStringUtil::toLower(log);
@@ -832,3 +931,181 @@ BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj)
return success;
}
+//virtual
+void LLShaderMgr::initAttribsAndUniforms()
+{
+ //MUST match order of enum in LLVertexBuffer.h
+ mReservedAttribs.push_back("position");
+ mReservedAttribs.push_back("normal");
+ mReservedAttribs.push_back("texcoord0");
+ mReservedAttribs.push_back("texcoord1");
+ mReservedAttribs.push_back("texcoord2");
+ mReservedAttribs.push_back("texcoord3");
+ mReservedAttribs.push_back("diffuse_color");
+ mReservedAttribs.push_back("emissive");
+ mReservedAttribs.push_back("binormal");
+ mReservedAttribs.push_back("weight");
+ mReservedAttribs.push_back("weight4");
+ mReservedAttribs.push_back("clothing");
+ mReservedAttribs.push_back("texture_index");
+
+ //matrix state
+ mReservedUniforms.push_back("modelview_matrix");
+ mReservedUniforms.push_back("projection_matrix");
+ mReservedUniforms.push_back("inv_proj");
+ mReservedUniforms.push_back("modelview_projection_matrix");
+ mReservedUniforms.push_back("normal_matrix");
+ mReservedUniforms.push_back("texture_matrix0");
+ mReservedUniforms.push_back("texture_matrix1");
+ mReservedUniforms.push_back("texture_matrix2");
+ mReservedUniforms.push_back("texture_matrix3");
+ llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_MATRIX3+1);
+
+ mReservedUniforms.push_back("viewport");
+
+ mReservedUniforms.push_back("light_position");
+ mReservedUniforms.push_back("light_direction");
+ mReservedUniforms.push_back("light_attenuation");
+ mReservedUniforms.push_back("light_diffuse");
+ mReservedUniforms.push_back("light_ambient");
+ mReservedUniforms.push_back("light_count");
+ mReservedUniforms.push_back("light");
+ mReservedUniforms.push_back("light_col");
+ mReservedUniforms.push_back("far_z");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::MULTI_LIGHT_FAR_Z+1);
+
+
+ mReservedUniforms.push_back("proj_mat");
+ mReservedUniforms.push_back("proj_near");
+ mReservedUniforms.push_back("proj_p");
+ mReservedUniforms.push_back("proj_n");
+ mReservedUniforms.push_back("proj_origin");
+ mReservedUniforms.push_back("proj_range");
+ mReservedUniforms.push_back("proj_ambiance");
+ mReservedUniforms.push_back("proj_shadow_idx");
+ mReservedUniforms.push_back("shadow_fade");
+ mReservedUniforms.push_back("proj_focus");
+ mReservedUniforms.push_back("proj_lod");
+ mReservedUniforms.push_back("proj_ambient_lod");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::PROJECTOR_AMBIENT_LOD+1);
+
+ mReservedUniforms.push_back("color");
+
+ mReservedUniforms.push_back("diffuseMap");
+ mReservedUniforms.push_back("specularMap");
+ mReservedUniforms.push_back("bumpMap");
+ mReservedUniforms.push_back("environmentMap");
+ mReservedUniforms.push_back("cloude_noise_texture");
+ mReservedUniforms.push_back("fullbright");
+ mReservedUniforms.push_back("lightnorm");
+ mReservedUniforms.push_back("sunlight_color_copy");
+ mReservedUniforms.push_back("ambient");
+ mReservedUniforms.push_back("blue_horizon");
+ mReservedUniforms.push_back("blue_density");
+ mReservedUniforms.push_back("haze_horizon");
+ mReservedUniforms.push_back("haze_density");
+ mReservedUniforms.push_back("cloud_shadow");
+ mReservedUniforms.push_back("density_multiplier");
+ mReservedUniforms.push_back("distance_multiplier");
+ mReservedUniforms.push_back("max_y");
+ mReservedUniforms.push_back("glow");
+ mReservedUniforms.push_back("cloud_color");
+ mReservedUniforms.push_back("cloud_pos_density1");
+ mReservedUniforms.push_back("cloud_pos_density2");
+ mReservedUniforms.push_back("cloud_scale");
+ mReservedUniforms.push_back("gamma");
+ mReservedUniforms.push_back("scene_light_strength");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::SCENE_LIGHT_STRENGTH+1);
+
+ mReservedUniforms.push_back("center");
+ mReservedUniforms.push_back("size");
+ mReservedUniforms.push_back("falloff");
+
+
+ mReservedUniforms.push_back("minLuminance");
+ mReservedUniforms.push_back("maxExtractAlpha");
+ mReservedUniforms.push_back("lumWeights");
+ mReservedUniforms.push_back("warmthWeights");
+ mReservedUniforms.push_back("warmthAmount");
+ mReservedUniforms.push_back("glowStrength");
+ mReservedUniforms.push_back("glowDelta");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_DELTA+1);
+
+
+ mReservedUniforms.push_back("minimum_alpha");
+
+ mReservedUniforms.push_back("shadow_matrix");
+ mReservedUniforms.push_back("env_mat");
+ mReservedUniforms.push_back("shadow_clip");
+ mReservedUniforms.push_back("sun_wash");
+ mReservedUniforms.push_back("shadow_noise");
+ mReservedUniforms.push_back("blur_size");
+ mReservedUniforms.push_back("ssao_radius");
+ mReservedUniforms.push_back("ssao_max_radius");
+ mReservedUniforms.push_back("ssao_factor");
+ mReservedUniforms.push_back("ssao_factor_inv");
+ mReservedUniforms.push_back("ssao_effect_mat");
+ mReservedUniforms.push_back("screen_res");
+ mReservedUniforms.push_back("near_clip");
+ mReservedUniforms.push_back("shadow_offset");
+ mReservedUniforms.push_back("shadow_bias");
+ mReservedUniforms.push_back("spot_shadow_bias");
+ mReservedUniforms.push_back("spot_shadow_offset");
+ mReservedUniforms.push_back("sun_dir");
+ mReservedUniforms.push_back("shadow_res");
+ mReservedUniforms.push_back("proj_shadow_res");
+ mReservedUniforms.push_back("depth_cutoff");
+ mReservedUniforms.push_back("norm_cutoff");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_NORM_CUTOFF+1);
+
+ mReservedUniforms.push_back("tc_scale");
+ mReservedUniforms.push_back("rcp_screen_res");
+ mReservedUniforms.push_back("rcp_frame_opt");
+ mReservedUniforms.push_back("rcp_frame_opt2");
+
+ mReservedUniforms.push_back("focal_distance");
+ mReservedUniforms.push_back("blur_constant");
+ mReservedUniforms.push_back("tan_pixel_angle");
+ mReservedUniforms.push_back("magnification");
+ mReservedUniforms.push_back("max_cof");
+ mReservedUniforms.push_back("res_scale");
+
+ mReservedUniforms.push_back("depthMap");
+ mReservedUniforms.push_back("shadowMap0");
+ mReservedUniforms.push_back("shadowMap1");
+ mReservedUniforms.push_back("shadowMap2");
+ mReservedUniforms.push_back("shadowMap3");
+ mReservedUniforms.push_back("shadowMap4");
+ mReservedUniforms.push_back("shadowMap5");
+
+ llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1);
+
+ mReservedUniforms.push_back("normalMap");
+ mReservedUniforms.push_back("positionMap");
+ mReservedUniforms.push_back("diffuseRect");
+ mReservedUniforms.push_back("specularRect");
+ mReservedUniforms.push_back("noiseMap");
+ mReservedUniforms.push_back("lightFunc");
+ mReservedUniforms.push_back("lightMap");
+ mReservedUniforms.push_back("bloomMap");
+ mReservedUniforms.push_back("projectionMap");
+
+ llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
+
+ std::set dupe_check;
+
+ for (U32 i = 0; i < mReservedUniforms.size(); ++i)
+ {
+ if (dupe_check.find(mReservedUniforms[i]) != dupe_check.end())
+ {
+ llerrs << "Duplicate reserved uniform name found: " << mReservedUniforms[i] << llendl;
+ }
+ dupe_check.insert(mReservedUniforms[i]);
+ }
+}
+
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 2f30103811..950e6c9c2f 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -36,9 +36,137 @@ public:
LLShaderMgr();
virtual ~LLShaderMgr();
+ typedef enum
+ {
+ MODELVIEW_MATRIX = 0,
+ PROJECTION_MATRIX,
+ INVERSE_PROJECTION_MATRIX,
+ MODELVIEW_PROJECTION_MATRIX,
+ NORMAL_MATRIX,
+ TEXTURE_MATRIX0,
+ TEXTURE_MATRIX1,
+ TEXTURE_MATRIX2,
+ TEXTURE_MATRIX3,
+ VIEWPORT,
+ LIGHT_POSITION,
+ LIGHT_DIRECTION,
+ LIGHT_ATTENUATION,
+ LIGHT_DIFFUSE,
+ LIGHT_AMBIENT,
+ MULTI_LIGHT_COUNT,
+ MULTI_LIGHT,
+ MULTI_LIGHT_COL,
+ MULTI_LIGHT_FAR_Z,
+ PROJECTOR_MATRIX,
+ PROJECTOR_NEAR,
+ PROJECTOR_P,
+ PROJECTOR_N,
+ PROJECTOR_ORIGIN,
+ PROJECTOR_RANGE,
+ PROJECTOR_AMBIANCE,
+ PROJECTOR_SHADOW_INDEX,
+ PROJECTOR_SHADOW_FADE,
+ PROJECTOR_FOCUS,
+ PROJECTOR_LOD,
+ PROJECTOR_AMBIENT_LOD,
+ DIFFUSE_COLOR,
+ DIFFUSE_MAP,
+ SPECULAR_MAP,
+ BUMP_MAP,
+ ENVIRONMENT_MAP,
+ CLOUD_NOISE_MAP,
+ FULLBRIGHT,
+ LIGHTNORM,
+ SUNLIGHT_COLOR,
+ AMBIENT,
+ BLUE_HORIZON,
+ BLUE_DENSITY,
+ HAZE_HORIZON,
+ HAZE_DENSITY,
+ CLOUD_SHADOW,
+ DENSITY_MULTIPLIER,
+ DISTANCE_MULTIPLIER,
+ MAX_Y,
+ GLOW,
+ CLOUD_COLOR,
+ CLOUD_POS_DENSITY1,
+ CLOUD_POS_DENSITY2,
+ CLOUD_SCALE,
+ GAMMA,
+ SCENE_LIGHT_STRENGTH,
+ LIGHT_CENTER,
+ LIGHT_SIZE,
+ LIGHT_FALLOFF,
+
+ GLOW_MIN_LUMINANCE,
+ GLOW_MAX_EXTRACT_ALPHA,
+ GLOW_LUM_WEIGHTS,
+ GLOW_WARMTH_WEIGHTS,
+ GLOW_WARMTH_AMOUNT,
+ GLOW_STRENGTH,
+ GLOW_DELTA,
+
+ MINIMUM_ALPHA,
+
+ DEFERRED_SHADOW_MATRIX,
+ DEFERRED_ENV_MAT,
+ DEFERRED_SHADOW_CLIP,
+ DEFERRED_SUN_WASH,
+ DEFERRED_SHADOW_NOISE,
+ DEFERRED_BLUR_SIZE,
+ DEFERRED_SSAO_RADIUS,
+ DEFERRED_SSAO_MAX_RADIUS,
+ DEFERRED_SSAO_FACTOR,
+ DEFERRED_SSAO_FACTOR_INV,
+ DEFERRED_SSAO_EFFECT_MAT,
+ DEFERRED_SCREEN_RES,
+ DEFERRED_NEAR_CLIP,
+ DEFERRED_SHADOW_OFFSET,
+ DEFERRED_SHADOW_BIAS,
+ DEFERRED_SPOT_SHADOW_BIAS,
+ DEFERRED_SPOT_SHADOW_OFFSET,
+ DEFERRED_SUN_DIR,
+ DEFERRED_SHADOW_RES,
+ DEFERRED_PROJ_SHADOW_RES,
+ DEFERRED_DEPTH_CUTOFF,
+ DEFERRED_NORM_CUTOFF,
+
+ FXAA_TC_SCALE,
+ FXAA_RCP_SCREEN_RES,
+ FXAA_RCP_FRAME_OPT,
+ FXAA_RCP_FRAME_OPT2,
+
+ DOF_FOCAL_DISTANCE,
+ DOF_BLUR_CONSTANT,
+ DOF_TAN_PIXEL_ANGLE,
+ DOF_MAGNIFICATION,
+ DOF_MAX_COF,
+ DOF_RES_SCALE,
+
+ DEFERRED_DEPTH,
+ DEFERRED_SHADOW0,
+ DEFERRED_SHADOW1,
+ DEFERRED_SHADOW2,
+ DEFERRED_SHADOW3,
+ DEFERRED_SHADOW4,
+ DEFERRED_SHADOW5,
+ DEFERRED_NORMAL,
+ DEFERRED_POSITION,
+ DEFERRED_DIFFUSE,
+ DEFERRED_SPECULAR,
+ DEFERRED_NOISE,
+ DEFERRED_LIGHTFUNC,
+ DEFERRED_LIGHT,
+ DEFERRED_BLOOM,
+ DEFERRED_PROJECTION,
+ END_RESERVED_UNIFORMS
+ } eGLSLReservedUniforms;
+
// singleton pattern implementation
static LLShaderMgr * instance();
+ virtual void initAttribsAndUniforms(void);
+
BOOL attachShaderFeatures(LLGLSLShader * shader);
void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 8fd1193780..20a450fbfb 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -34,9 +34,21 @@
#include "llmemtype.h"
#include "llrender.h"
#include "llvector4a.h"
+#include "llshadermgr.h"
#include "llglslshader.h"
#include "llmemory.h"
+//Next Highest Power Of Two
+//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
+U32 nhpo2(U32 v)
+{
+ U32 r = 1;
+ while (r < v) {
+ r *= 2;
+ }
+ return r;
+}
+
//============================================================================
@@ -45,6 +57,7 @@ LLVBOPool LLVertexBuffer::sStreamVBOPool;
LLVBOPool LLVertexBuffer::sDynamicVBOPool;
LLVBOPool LLVertexBuffer::sStreamIBOPool;
LLVBOPool LLVertexBuffer::sDynamicIBOPool;
+U32 LLVBOPool::sBytesPooled = 0;
LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ;
U32 LLVertexBuffer::sBindCount = 0;
@@ -55,6 +68,7 @@ S32 LLVertexBuffer::sMappedCount = 0;
BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ;
BOOL LLVertexBuffer::sEnableVBOs = TRUE;
U32 LLVertexBuffer::sGLRenderBuffer = 0;
+U32 LLVertexBuffer::sGLRenderArray = 0;
U32 LLVertexBuffer::sGLRenderIndices = 0;
U32 LLVertexBuffer::sLastMask = 0;
BOOL LLVertexBuffer::sVBOActive = FALSE;
@@ -62,11 +76,8 @@ BOOL LLVertexBuffer::sIBOActive = FALSE;
U32 LLVertexBuffer::sAllocatedBytes = 0;
BOOL LLVertexBuffer::sMapped = FALSE;
BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
+BOOL LLVertexBuffer::sUseVAO = FALSE;
BOOL LLVertexBuffer::sPreferStreamDraw = FALSE;
-S32 LLVertexBuffer::sWeight4Loc = -1;
-
-std::vector LLVertexBuffer::sDeleteList;
-
const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms
@@ -84,7 +95,7 @@ public:
#endif
}
- ~LLGLSyncFence()
+ virtual ~LLGLSyncFence()
{
#ifdef GL_ARB_sync
if (mSync)
@@ -122,6 +133,109 @@ public:
};
+
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i)
+{
+ llassert(i > 0);
+ llassert(nhpo2(i) == i);
+
+ U32 r = 0;
+
+ while (i >>= 1) ++r;
+
+ return r;
+}
+
+U8* LLVBOPool::allocate(U32& name, U32 size)
+{
+ llassert(nhpo2(size) == size);
+
+ U32 i = wpo2(size);
+
+ if (mFreeList.size() <= i)
+ {
+ mFreeList.resize(i+1);
+ }
+
+ U8* ret = NULL;
+
+ if (mFreeList[i].empty())
+ {
+ //make a new buffer
+ glGenBuffersARB(1, &name);
+ glBindBufferARB(mType, name);
+ glBufferDataARB(mType, size, 0, mUsage);
+ LLVertexBuffer::sAllocatedBytes += size;
+
+ if (LLVertexBuffer::sDisableVBOMapping)
+ {
+ ret = (U8*) ll_aligned_malloc_16(size);
+ }
+ glBindBufferARB(mType, 0);
+ }
+ else
+ {
+ name = mFreeList[i].front().mGLName;
+ ret = mFreeList[i].front().mClientData;
+
+ sBytesPooled -= size;
+
+ mFreeList[i].pop_front();
+ }
+
+ return ret;
+}
+
+void LLVBOPool::release(U32 name, U8* buffer, U32 size)
+{
+ llassert(nhpo2(size) == size);
+
+ U32 i = wpo2(size);
+
+ llassert(mFreeList.size() > i);
+
+ Record rec;
+ rec.mGLName = name;
+ rec.mClientData = buffer;
+
+ sBytesPooled += size;
+
+ mFreeList[i].push_back(rec);
+}
+
+void LLVBOPool::cleanup()
+{
+ U32 size = 1;
+
+ for (U32 i = 0; i < mFreeList.size(); ++i)
+ {
+ record_list_t& l = mFreeList[i];
+
+ while (!l.empty())
+ {
+ Record& r = l.front();
+
+ glDeleteBuffersARB(1, &r.mGLName);
+
+ if (r.mClientData)
+ {
+ ll_aligned_free_16(r.mClientData);
+ }
+
+ l.pop_front();
+
+ LLVertexBuffer::sAllocatedBytes -= size;
+ sBytesPooled -= size;
+ }
+
+ size *= 2;
+ }
+}
+
+
+//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
{
sizeof(LLVector4), // TYPE_VERTEX,
@@ -131,10 +245,12 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
sizeof(LLVector2), // TYPE_TEXCOORD2,
sizeof(LLVector2), // TYPE_TEXCOORD3,
sizeof(LLColor4U), // TYPE_COLOR,
+ sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
sizeof(LLVector4), // TYPE_BINORMAL,
sizeof(F32), // TYPE_WEIGHT,
sizeof(LLVector4), // TYPE_WEIGHT4,
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
+ sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
};
U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
@@ -149,146 +265,147 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
GL_LINE_LOOP,
};
+
//static
void LLVertexBuffer::setupClientArrays(U32 data_mask)
{
- /*if (LLGLImmediate::sStarted)
- {
- llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl;
- }*/
-
if (sLastMask != data_mask)
{
- U32 mask[] =
- {
- MAP_VERTEX,
- MAP_NORMAL,
- MAP_TEXCOORD0,
- MAP_COLOR,
- };
-
- GLenum array[] =
- {
- GL_VERTEX_ARRAY,
- GL_NORMAL_ARRAY,
- GL_TEXTURE_COORD_ARRAY,
- GL_COLOR_ARRAY,
- };
-
BOOL error = FALSE;
- for (U32 i = 0; i < 4; ++i)
+
+ if (LLGLSLShader::sNoFixedFunction)
{
- if (sLastMask & mask[i])
- { //was enabled
- if (!(data_mask & mask[i]) && i > 0)
- { //needs to be disabled
- glDisableClientState(array[i]);
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ S32 loc = i;
+
+ U32 mask = 1 << i;
+
+ if (sLastMask & (1 << i))
+ { //was enabled
+ if (!(data_mask & mask))
+ { //needs to be disabled
+ glDisableVertexAttribArrayARB(loc);
+ }
}
- else if (gDebugGL)
- { //needs to be enabled, make sure it was (DEBUG TEMPORARY)
- if (i > 0 && !glIsEnabled(array[i]))
- {
+ else
+ { //was disabled
+ if (data_mask & mask)
+ { //needs to be enabled
+ glEnableVertexAttribArrayARB(loc);
+ }
+ }
+ }
+ }
+ else
+ {
+
+ GLenum array[] =
+ {
+ GL_VERTEX_ARRAY,
+ GL_NORMAL_ARRAY,
+ GL_TEXTURE_COORD_ARRAY,
+ GL_COLOR_ARRAY,
+ };
+
+ GLenum mask[] =
+ {
+ MAP_VERTEX,
+ MAP_NORMAL,
+ MAP_TEXCOORD0,
+ MAP_COLOR
+ };
+
+
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ if (sLastMask & mask[i])
+ { //was enabled
+ if (!(data_mask & mask[i]))
+ { //needs to be disabled
+ glDisableClientState(array[i]);
+ }
+ else if (gDebugGL)
+ { //needs to be enabled, make sure it was (DEBUG)
+ if (!glIsEnabled(array[i]))
+ {
+ if (gDebugSession)
+ {
+ error = TRUE;
+ gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
+ }
+ else
+ {
+ llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
+ }
+ }
+ }
+ }
+ else
+ { //was disabled
+ if (data_mask & mask[i])
+ { //needs to be enabled
+ glEnableClientState(array[i]);
+ }
+ else if (gDebugGL && glIsEnabled(array[i]))
+ { //needs to be disabled, make sure it was (DEBUG TEMPORARY)
if (gDebugSession)
{
error = TRUE;
- gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
+ gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
}
else
{
- llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
+ llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
}
}
}
}
- else
- { //was disabled
- if (data_mask & mask[i] && i > 0)
- { //needs to be enabled
- glEnableClientState(array[i]);
- }
- else if (gDebugGL && i > 0 && glIsEnabled(array[i]))
- { //needs to be disabled, make sure it was (DEBUG TEMPORARY)
- if (gDebugSession)
- {
- error = TRUE;
- gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
- }
- else
- {
- llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
- }
- }
- }
- }
-
- if (error)
- {
- ll_fail("LLVertexBuffer::setupClientArrays failed");
- }
-
- U32 map_tc[] =
- {
- MAP_TEXCOORD1,
- MAP_TEXCOORD2,
- MAP_TEXCOORD3
- };
-
- for (U32 i = 0; i < 3; i++)
- {
- if (sLastMask & map_tc[i])
+
+ U32 map_tc[] =
{
- if (!(data_mask & map_tc[i]))
+ MAP_TEXCOORD1,
+ MAP_TEXCOORD2,
+ MAP_TEXCOORD3
+ };
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (sLastMask & map_tc[i])
+ {
+ if (!(data_mask & map_tc[i]))
+ { //disable
+ glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+ else if (data_mask & map_tc[i])
{
glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+
+ if (sLastMask & MAP_BINORMAL)
+ {
+ if (!(data_mask & MAP_BINORMAL))
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
- else if (data_mask & map_tc[i])
+ else if (data_mask & MAP_BINORMAL)
{
- glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
-
- if (sLastMask & MAP_BINORMAL)
- {
- if (!(data_mask & MAP_BINORMAL))
- {
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
- }
- else if (data_mask & MAP_BINORMAL)
- {
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
-
- if (sLastMask & MAP_WEIGHT4)
- {
- if (sWeight4Loc < 0)
- {
- llerrs << "Weighting disabled but vertex buffer still bound!" << llendl;
- }
-
- if (!(data_mask & MAP_WEIGHT4))
- { //disable 4-component skin weight
- glDisableVertexAttribArrayARB(sWeight4Loc);
- }
- }
- else if (data_mask & MAP_WEIGHT4)
- {
- if (sWeight4Loc >= 0)
- { //enable 4-component skin weight
- glEnableVertexAttribArrayARB(sWeight4Loc);
- }
- }
-
sLastMask = data_mask;
}
}
@@ -296,6 +413,9 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
//static
void LLVertexBuffer::drawArrays(U32 mode, const std::vector& pos, const std::vector& norm)
{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ gGL.syncMatrices();
+
U32 count = pos.size();
llassert_always(norm.size() >= pos.size());
llassert_always(count > 0) ;
@@ -304,24 +424,79 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector& pos, con
setupClientArrays(MAP_VERTEX | MAP_NORMAL);
- glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
- glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader)
+ {
+ S32 loc = LLVertexBuffer::TYPE_VERTEX;
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
+ }
+ loc = LLVertexBuffer::TYPE_NORMAL;
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
+ }
+ }
+ else
+ {
+ glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
+ glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+ }
glDrawArrays(sGLMode[mode], 0, count);
}
-void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
+//static
+void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
{
- if (start >= (U32) mRequestedNumVerts ||
- end >= (U32) mRequestedNumVerts)
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ gGL.syncMatrices();
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX;
+ if (tc)
{
- llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mRequestedNumVerts << llendl;
+ mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
}
- llassert(mRequestedNumIndices >= 0);
+ unbind();
+
+ setupClientArrays(mask);
- if (indices_offset >= (U32) mRequestedNumIndices ||
- indices_offset + count > (U32) mRequestedNumIndices)
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ S32 loc = LLVertexBuffer::TYPE_VERTEX;
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
+
+ if (tc)
+ {
+ loc = LLVertexBuffer::TYPE_TEXCOORD0;
+ glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
+ }
+ }
+ else
+ {
+ glTexCoordPointer(2, GL_FLOAT, 0, tc);
+ glVertexPointer(3, GL_FLOAT, 16, pos);
+ }
+
+ glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+}
+
+void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+ if (start >= (U32) mNumVerts ||
+ end >= (U32) mNumVerts)
+ {
+ llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl;
+ }
+
+ llassert(mNumIndices >= 0);
+
+ if (indices_offset >= (U32) mNumIndices ||
+ indices_offset + count > (U32) mNumIndices)
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
@@ -336,6 +511,25 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
}
}
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader && shader->mFeatures.mIndexedTextureChannels > 1)
+ {
+ LLStrider v;
+ //hack to get non-const reference
+ LLVertexBuffer* vb = (LLVertexBuffer*) this;
+ vb->getVertexStrider(v);
+
+ for (U32 i = start; i < end; i++)
+ {
+ S32 idx = (S32) (v[i][3]+0.25f);
+ if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels)
+ {
+ llerrs << "Bad texture index found in vertex data stream." << llendl;
+ }
+ }
+ }
}
}
@@ -343,16 +537,40 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
{
validateRange(start, end, count, indices_offset);
- llassert(mRequestedNumVerts >= 0);
+ gGL.syncMatrices();
- if (mGLIndices != sGLRenderIndices)
+ llassert(mNumVerts >= 0);
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ if (mGLArray)
{
- llerrs << "Wrong index buffer bound." << llendl;
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ if (mGLIndices != sGLRenderIndices)
+ {
+ llerrs << "Wrong index buffer bound." << llendl;
+ }
+
+ if (mGLBuffer != sGLRenderBuffer)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
}
- if (mGLBuffer != sGLRenderBuffer)
+ if (gDebugGL && !mGLArray && useVBOs())
{
- llerrs << "Wrong vertex buffer bound." << llendl;
+ GLint elem = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+ if (elem != mGLIndices)
+ {
+ llerrs << "Wrong index buffer bound!" << llendl;
+ }
}
if (mode >= LLRender::NUM_MODES)
@@ -372,21 +590,35 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
- llassert(mRequestedNumIndices >= 0);
- if (indices_offset >= (U32) mRequestedNumIndices ||
- indices_offset + count > (U32) mRequestedNumIndices)
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ gGL.syncMatrices();
+
+ llassert(mNumIndices >= 0);
+ if (indices_offset >= (U32) mNumIndices ||
+ indices_offset + count > (U32) mNumIndices)
{
llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
}
- if (mGLIndices != sGLRenderIndices)
+ if (mGLArray)
{
- llerrs << "Wrong index buffer bound." << llendl;
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
}
-
- if (mGLBuffer != sGLRenderBuffer)
+ else
{
- llerrs << "Wrong vertex buffer bound." << llendl;
+ if (mGLIndices != sGLRenderIndices)
+ {
+ llerrs << "Wrong index buffer bound." << llendl;
+ }
+
+ if (mGLBuffer != sGLRenderBuffer)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
}
if (mode >= LLRender::NUM_MODES)
@@ -404,16 +636,30 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{
- llassert(mRequestedNumVerts >= 0);
- if (first >= (U32) mRequestedNumVerts ||
- first + count > (U32) mRequestedNumVerts)
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ gGL.syncMatrices();
+
+ llassert(mNumVerts >= 0);
+ if (first >= (U32) mNumVerts ||
+ first + count > (U32) mNumVerts)
{
llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
}
- if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
+ if (mGLArray)
{
- llerrs << "Wrong vertex buffer bound." << llendl;
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
}
if (mode >= LLRender::NUM_MODES)
@@ -432,28 +678,37 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
{
sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ;
- if(sEnableVBOs)
- {
- //llassert_always(glBindBufferARB) ; //double check the extention for VBO is loaded.
-
- llinfos << "VBO is enabled." << llendl ;
- }
- else
- {
- llinfos << "VBO is disabled." << llendl ;
- }
-
sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;
if(!sPrivatePoolp)
- {
+ {
sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ;
}
+
+ sStreamVBOPool.mType = GL_ARRAY_BUFFER_ARB;
+ sStreamVBOPool.mUsage= GL_STREAM_DRAW_ARB;
+ sStreamIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB;
+ sStreamIBOPool.mUsage= GL_STREAM_DRAW_ARB;
+
+ sDynamicVBOPool.mType = GL_ARRAY_BUFFER_ARB;
+ sDynamicVBOPool.mUsage= GL_DYNAMIC_DRAW_ARB;
+ sDynamicIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB;
+ sDynamicIBOPool.mUsage= GL_DYNAMIC_DRAW_ARB;
}
//static
void LLVertexBuffer::unbind()
{
+ if (sGLRenderArray)
+ {
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(0);
+#endif
+ sGLRenderArray = 0;
+ sGLRenderIndices = 0;
+ sIBOActive = FALSE;
+ }
+
if (sVBOActive)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
@@ -476,7 +731,11 @@ void LLVertexBuffer::cleanupClass()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
unbind();
- clientCopy(); // deletes GL buffers
+
+ sStreamIBOPool.cleanup();
+ sDynamicIBOPool.cleanup();
+ sStreamVBOPool.cleanup();
+ sDynamicVBOPool.cleanup();
if(sPrivatePoolp)
{
@@ -485,15 +744,6 @@ void LLVertexBuffer::cleanupClass()
}
}
-void LLVertexBuffer::clientCopy(F64 max_time)
-{
- if (!sDeleteList.empty())
- {
- glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0]));
- sDeleteList.clear();
- }
-}
-
//----------------------------------------------------------------------------
LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
@@ -501,20 +751,16 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mNumVerts(0),
mNumIndices(0),
- mRequestedNumVerts(-1),
- mRequestedNumIndices(-1),
mUsage(usage),
mGLBuffer(0),
+ mGLArray(0),
mGLIndices(0),
mMappedData(NULL),
mMappedIndexData(NULL),
mVertexLocked(FALSE),
mIndexLocked(FALSE),
mFinal(FALSE),
- mFilthy(FALSE),
mEmpty(TRUE),
- mResized(FALSE),
- mDynamicSize(FALSE),
mFence(NULL)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
@@ -534,6 +780,16 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mUsage = GL_STREAM_DRAW_ARB;
}
+ if (mUsage == 0 && LLRender::sGLCoreProfile)
+ { //MUST use VBOs for all rendering
+ mUsage = GL_STREAM_DRAW_ARB;
+ }
+
+ if (mUsage && mUsage != GL_STREAM_DRAW_ARB)
+ { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
+ mUsage = GL_DYNAMIC_DRAW_ARB;
+ }
+
//zero out offsets
for (U32 i = 0; i < TYPE_MAX; i++)
{
@@ -542,6 +798,7 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
mTypeMask = typemask;
mSize = 0;
+ mIndicesSize = 0;
mAlignedOffset = 0;
mAlignedIndexOffset = 0;
@@ -552,12 +809,12 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
{
S32 offset = 0;
- for (S32 i=0; i mSize || needed_size <= mSize/2)
{
- mNumVerts = nverts;
+ createGLBuffer(needed_size);
}
- else if (mUsage == GL_STATIC_DRAW_ARB ||
- nverts > mNumVerts ||
- nverts < mNumVerts/2)
- {
- if (mUsage != GL_STATIC_DRAW_ARB && nverts + nverts/4 <= 65535)
- {
- nverts += nverts/4;
- }
- mNumVerts = nverts;
- }
- mSize = calcOffsets(mTypeMask, mOffsets, mNumVerts);
+
+ mNumVerts = nverts;
}
void LLVertexBuffer::updateNumIndices(S32 nindices)
@@ -867,28 +1101,22 @@ void LLVertexBuffer::updateNumIndices(S32 nindices)
llassert(nindices >= 0);
- mRequestedNumIndices = nindices;
- if (!mDynamicSize)
- {
- mNumIndices = nindices;
- }
- else if (mUsage == GL_STATIC_DRAW_ARB ||
- nindices > mNumIndices ||
- nindices < mNumIndices/2)
- {
- if (mUsage != GL_STATIC_DRAW_ARB)
- {
- nindices += nindices/4;
- }
+ U32 needed_size = sizeof(U16) * nindices;
- mNumIndices = nindices;
+ if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2)
+ {
+ createGLIndices(needed_size);
}
+
+ mNumIndices = nindices;
}
void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
-
+
+ stop_glerror();
+
if (nverts < 0 || nindices < 0 ||
nverts > 65536)
{
@@ -898,17 +1126,107 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
updateNumVerts(nverts);
updateNumIndices(nindices);
- if (mMappedData)
- {
- llerrs << "LLVertexBuffer::allocateBuffer() called redundantly." << llendl;
- }
if (create && (nverts || nindices))
{
- createGLBuffer();
- createGLIndices();
+ //actually allocate space for the vertex buffer if using VBO mapping
+ flush();
+
+ if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
+ {
+#if GL_ARB_vertex_array_object
+ glGenVertexArrays(1, &mGLArray);
+#endif
+ setupVertexArray();
+ }
}
-
- sAllocatedBytes += getSize() + getIndicesSize();
+}
+
+static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO");
+
+void LLVertexBuffer::setupVertexArray()
+{
+ if (!mGLArray)
+ {
+ return;
+ }
+
+ LLFastTimer t(FTM_SETUP_VERTEX_ARRAY);
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(mGLArray);
+#endif
+ sGLRenderArray = mGLArray;
+
+ U32 attrib_size[] =
+ {
+ 3, //TYPE_VERTEX,
+ 3, //TYPE_NORMAL,
+ 2, //TYPE_TEXCOORD0,
+ 2, //TYPE_TEXCOORD1,
+ 2, //TYPE_TEXCOORD2,
+ 2, //TYPE_TEXCOORD3,
+ 4, //TYPE_COLOR,
+ 4, //TYPE_EMISSIVE,
+ 3, //TYPE_BINORMAL,
+ 1, //TYPE_WEIGHT,
+ 4, //TYPE_WEIGHT4,
+ 4, //TYPE_CLOTHWEIGHT,
+ 1, //TYPE_TEXTURE_INDEX
+ };
+
+ U32 attrib_type[] =
+ {
+ GL_FLOAT, //TYPE_VERTEX,
+ GL_FLOAT, //TYPE_NORMAL,
+ GL_FLOAT, //TYPE_TEXCOORD0,
+ GL_FLOAT, //TYPE_TEXCOORD1,
+ GL_FLOAT, //TYPE_TEXCOORD2,
+ GL_FLOAT, //TYPE_TEXCOORD3,
+ GL_UNSIGNED_BYTE, //TYPE_COLOR,
+ GL_UNSIGNED_BYTE, //TYPE_EMISSIVE,
+ GL_FLOAT, //TYPE_BINORMAL,
+ GL_FLOAT, //TYPE_WEIGHT,
+ GL_FLOAT, //TYPE_WEIGHT4,
+ GL_FLOAT, //TYPE_CLOTHWEIGHT,
+ GL_FLOAT, //TYPE_TEXTURE_INDEX
+ };
+
+ U32 attrib_normalized[] =
+ {
+ GL_FALSE, //TYPE_VERTEX,
+ GL_FALSE, //TYPE_NORMAL,
+ GL_FALSE, //TYPE_TEXCOORD0,
+ GL_FALSE, //TYPE_TEXCOORD1,
+ GL_FALSE, //TYPE_TEXCOORD2,
+ GL_FALSE, //TYPE_TEXCOORD3,
+ GL_TRUE, //TYPE_COLOR,
+ GL_TRUE, //TYPE_EMISSIVE,
+ GL_FALSE, //TYPE_BINORMAL,
+ GL_FALSE, //TYPE_WEIGHT,
+ GL_FALSE, //TYPE_WEIGHT4,
+ GL_FALSE, //TYPE_CLOTHWEIGHT,
+ GL_FALSE, //TYPE_TEXTURE_INDEX
+ };
+
+ bindGLBuffer(true);
+ bindGLIndices(true);
+
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ if (mTypeMask & (1 << i))
+ {
+ glEnableVertexAttribArrayARB(i);
+ glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]);
+ }
+ else
+ {
+ glDisableVertexAttribArrayARB(i);
+ }
+ }
+
+ //draw a dummy triangle to set index array pointer
+ //glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL);
+
+ unbind();
}
void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
@@ -916,78 +1234,19 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
llassert(newnverts >= 0);
llassert(newnindices >= 0);
- mRequestedNumVerts = newnverts;
- mRequestedNumIndices = newnindices;
-
LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
- mDynamicSize = TRUE;
- if (mUsage == GL_STATIC_DRAW_ARB)
- { //always delete/allocate static buffers on resize
- destroyGLBuffer();
- destroyGLIndices();
- allocateBuffer(newnverts, newnindices, TRUE);
- mFinal = FALSE;
- }
- else if (newnverts > mNumVerts || newnindices > mNumIndices ||
- newnverts < mNumVerts/2 || newnindices < mNumIndices/2)
+
+ updateNumVerts(newnverts);
+ updateNumIndices(newnindices);
+
+ if (useVBOs())
{
- sAllocatedBytes -= getSize() + getIndicesSize();
-
- updateNumVerts(newnverts);
- updateNumIndices(newnindices);
-
- S32 newsize = getSize();
- S32 new_index_size = getIndicesSize();
+ flush();
- sAllocatedBytes += newsize + new_index_size;
-
- if (newsize)
- {
- if (!mGLBuffer)
- { //no buffer exists, create a new one
- createGLBuffer();
- }
- else
- {
- if (!useVBOs())
- {
- FREE_MEM(sPrivatePoolp, mMappedData);
- mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, newsize);
- }
- mResized = TRUE;
- }
+ if (mGLArray)
+ { //if size changed, offsets changed
+ setupVertexArray();
}
- else if (mGLBuffer)
- {
- destroyGLBuffer();
- }
-
- if (new_index_size)
- {
- if (!mGLIndices)
- {
- createGLIndices();
- }
- else
- {
- if (!useVBOs())
- {
- FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
- mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, new_index_size);
- }
- mResized = TRUE;
- }
- }
- else if (mGLIndices)
- {
- destroyGLIndices();
- }
- }
-
- if (mResized && useVBOs())
- {
- freeClientBuffer() ;
- setBuffer(0);
}
}
@@ -1004,32 +1263,6 @@ BOOL LLVertexBuffer::useVBOs() const
}
//----------------------------------------------------------------------------
-void LLVertexBuffer::freeClientBuffer()
-{
- if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData))
- {
- FREE_MEM(sPrivatePoolp, mMappedData) ;
- FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
- mMappedData = NULL ;
- mMappedIndexData = NULL ;
- }
-}
-
-void LLVertexBuffer::allocateClientVertexBuffer()
-{
- if(!mMappedData)
- {
- mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getSize());
- }
-}
-
-void LLVertexBuffer::allocateClientIndexBuffer()
-{
- if(!mMappedIndexData)
- {
- mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getIndicesSize());
- }
-}
bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
{
@@ -1052,6 +1285,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
// Map for data access
U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
{
+ bindGLBuffer(true);
LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
if (mFinal)
{
@@ -1102,7 +1336,6 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
if (!mVertexLocked)
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
- setBuffer(0, type);
mVertexLocked = TRUE;
sMappedCount++;
stop_glerror();
@@ -1110,7 +1343,6 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
if(sDisableVBOMapping)
{
map_range = false;
- allocateClientVertexBuffer() ;
}
else
{
@@ -1132,6 +1364,18 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
else
{
#ifdef GL_ARB_map_buffer_range
+
+ if (gDebugGL)
+ {
+ GLint size = 0;
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
+
+ if (size < mSize)
+ {
+ llerrs << "Invalid buffer size." << llendl;
+ }
+ }
+
src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize,
GL_MAP_WRITE_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT);
@@ -1217,6 +1461,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
+ bindGLIndices(true);
if (mFinal)
{
llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl;
@@ -1264,15 +1509,24 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
{
LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
- setBuffer(0, TYPE_INDEX);
mIndexLocked = TRUE;
sMappedCount++;
stop_glerror();
+ if (gDebugGL && useVBOs())
+ {
+ GLint elem = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+ if (elem != mGLIndices)
+ {
+ llerrs << "Wrong index buffer bound!" << llendl;
+ }
+ }
+
if(sDisableVBOMapping)
{
map_range = false;
- allocateClientIndexBuffer() ;
}
else
{
@@ -1365,19 +1619,20 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
}
}
-void LLVertexBuffer::unmapBuffer(S32 type)
+void LLVertexBuffer::unmapBuffer()
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
- if (!useVBOs() || type == -2)
+ if (!useVBOs())
{
return ; //nothing to unmap
}
bool updated_all = false ;
- if (mMappedData && mVertexLocked && type != TYPE_INDEX)
+ if (mMappedData && mVertexLocked)
{
- updated_all = (mIndexLocked && type < 0) ; //both vertex and index buffers done updating
+ bindGLBuffer(true);
+ updated_all = mIndexLocked; //both vertex and index buffers done updating
if(sDisableVBOMapping)
{
@@ -1441,8 +1696,9 @@ void LLVertexBuffer::unmapBuffer(S32 type)
sMappedCount--;
}
- if (mMappedIndexData && mIndexLocked && (type < 0 || type == TYPE_INDEX))
+ if (mMappedIndexData && mIndexLocked)
{
+ bindGLIndices();
if(sDisableVBOMapping)
{
if (!mMappedIndexRegions.empty())
@@ -1507,21 +1763,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
if(updated_all)
{
- if(mUsage == GL_STATIC_DRAW_ARB)
- {
- //static draw buffers can only be mapped a single time
- //throw out client data (we won't be using it again)
- mEmpty = TRUE;
- mFinal = TRUE;
- if(sDisableVBOMapping)
- {
- freeClientBuffer() ;
- }
- }
- else
- {
- mEmpty = FALSE;
- }
+ mEmpty = FALSE;
}
}
@@ -1576,6 +1818,10 @@ bool LLVertexBuffer::getVertexStrider(LLStrider& strider, S32 index,
{
return VertexBufferStrider::get(*this, strider, index, count, map_range);
}
+bool LLVertexBuffer::getVertexStrider(LLStrider& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider::get(*this, strider, index, count, map_range);
+}
bool LLVertexBuffer::getIndexStrider(LLStrider& strider, S32 index, S32 count, bool map_range)
{
return VertexBufferStrider::get(*this, strider, index, count, map_range);
@@ -1601,6 +1847,10 @@ bool LLVertexBuffer::getColorStrider(LLStrider& strider, S32 index, S
{
return VertexBufferStrider::get(*this, strider, index, count, map_range);
}
+bool LLVertexBuffer::getEmissiveStrider(LLStrider& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider::get(*this, strider, index, count, map_range);
+}
bool LLVertexBuffer::getWeightStrider(LLStrider& strider, S32 index, S32 count, bool map_range)
{
return VertexBufferStrider::get(*this, strider, index, count, map_range);
@@ -1618,43 +1868,151 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider& strider, S32 in
//----------------------------------------------------------------------------
-// Set for rendering
-void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
+static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array");
+bool LLVertexBuffer::bindGLArray()
{
+ if (mGLArray && sGLRenderArray != mGLArray)
+ {
+ {
+ LLFastTimer t(FTM_BIND_GL_ARRAY);
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(mGLArray);
+#endif
+ sGLRenderArray = mGLArray;
+ }
+
+ //really shouldn't be necessary, but some drivers don't properly restore the
+ //state of GL_ELEMENT_ARRAY_BUFFER_BINDING
+ bindGLIndices();
+
+ return true;
+ }
+
+ return false;
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer");
+
+bool LLVertexBuffer::bindGLBuffer(bool force_bind)
+{
+ bindGLArray();
+
+ bool ret = false;
+
+ if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
+ {
+ LLFastTimer t(FTM_BIND_GL_BUFFER);
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
+ sGLRenderBuffer = mGLBuffer;
+ sBindCount++;
+ sVBOActive = TRUE;
+
+ if (mGLArray)
+ {
+ llassert(sGLRenderArray == mGLArray);
+ //mCachedRenderBuffer = mGLBuffer;
+ }
+
+ ret = true;
+ }
+
+ return ret;
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices");
+
+bool LLVertexBuffer::bindGLIndices(bool force_bind)
+{
+ bindGLArray();
+
+ bool ret = false;
+ if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
+ {
+ LLFastTimer t(FTM_BIND_GL_INDICES);
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
+ sGLRenderIndices = mGLIndices;
+ stop_glerror();
+ sBindCount++;
+ sIBOActive = TRUE;
+ ret = true;
+ }
+
+ return ret;
+}
+
+void LLVertexBuffer::flush()
+{
+ if (useVBOs())
+ {
+ unmapBuffer();
+ }
+}
+
+// Set for rendering
+void LLVertexBuffer::setBuffer(U32 data_mask)
+{
+ flush();
+
LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
//set up pointers if the data mask is different ...
BOOL setup = (sLastMask != data_mask);
+ if (gDebugGL && data_mask != 0)
+ { //make sure data requirements are fulfilled
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ if (shader)
+ {
+ U32 required_mask = 0;
+ for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i)
+ {
+ if (shader->getAttribLocation(i) > -1)
+ {
+ U32 required = 1 << i;
+ if ((data_mask & required) == 0)
+ {
+ llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl;
+ }
+
+ required_mask |= required;
+ }
+ }
+
+ if ((data_mask & required_mask) != required_mask)
+ {
+ llerrs << "Shader consumption mismatches data provision." << llendl;
+ }
+ }
+ }
+
if (useVBOs())
{
- if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
+ if (mGLArray)
{
- /*if (sMapped)
- {
- llerrs << "VBO bound while another VBO mapped!" << llendl;
- }*/
- stop_glerror();
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
- stop_glerror();
- sBindCount++;
- sVBOActive = TRUE;
- setup = TRUE; // ... or the bound buffer changed
+ bindGLArray();
+ setup = FALSE; //do NOT perform pointer setup if using VAO
}
- if (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))
+ else
{
- /*if (sMapped)
+ if (bindGLBuffer())
{
- llerrs << "VBO bound while another VBO mapped!" << llendl;
- }*/
- stop_glerror();
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
- stop_glerror();
- sBindCount++;
- sIBOActive = TRUE;
+ setup = TRUE;
+ }
+ if (bindGLIndices())
+ {
+ setup = TRUE;
+ }
}
-
+
BOOL error = FALSE;
- if (gDebugGL)
+ if (gDebugGL && !mGLArray)
{
GLint buff;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
@@ -1689,81 +2047,20 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
}
}
- if (mResized)
- {
- if (gDebugGL)
- {
- GLint buff;
- glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
- if ((GLuint)buff != mGLBuffer)
- {
- if (gDebugSession)
- {
- error = TRUE;
- gFailLog << "Invalid GL vertex buffer bound: " << std::endl;
- }
- else
- {
- llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
- }
- }
-
- if (mGLIndices != 0)
- {
- glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
- if ((GLuint)buff != mGLIndices)
- {
- if (gDebugSession)
- {
- error = TRUE;
- gFailLog << "Invalid GL index buffer bound: "<< std::endl;
- }
- else
- {
- llerrs << "Invalid GL index buffer bound: " << buff << llendl;
- }
- }
- }
- }
-
- if (mGLBuffer)
- {
- stop_glerror();
- glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), NULL, mUsage);
- stop_glerror();
- }
- if (mGLIndices)
- {
- stop_glerror();
- glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), NULL, mUsage);
- stop_glerror();
- }
-
- mEmpty = TRUE;
- mResized = FALSE;
-
- if (data_mask != 0)
- {
- if (gDebugSession)
- {
- error = TRUE;
- gFailLog << "Buffer set for rendering before being filled after resize." << std::endl;
- }
- else
- {
- llerrs << "Buffer set for rendering before being filled after resize." << llendl;
- }
- }
- }
-
- if (error)
- {
- ll_fail("LLVertexBuffer::mapBuffer failed");
- }
- unmapBuffer(type);
+
}
else
- {
+ {
+ if (sGLRenderArray)
+ {
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(0);
+#endif
+ sGLRenderArray = 0;
+ sGLRenderIndices = 0;
+ sIBOActive = FALSE;
+ }
+
if (mGLBuffer)
{
if (sVBOActive)
@@ -1775,30 +2072,30 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
}
if (sGLRenderBuffer != mGLBuffer)
{
+ sGLRenderBuffer = mGLBuffer;
setup = TRUE; // ... or a client memory pointer changed
}
}
- if (mGLIndices && sIBOActive)
+ if (mGLIndices)
{
- /*if (sMapped)
+ if (sIBOActive)
{
- llerrs << "VBO unbound while potentially mapped!" << llendl;
- }*/
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
- sBindCount++;
- sIBOActive = FALSE;
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ sBindCount++;
+ sIBOActive = FALSE;
+ }
+
+ sGLRenderIndices = mGLIndices;
}
}
- setupClientArrays(data_mask);
-
- if (mGLIndices)
+ if (!mGLArray)
{
- sGLRenderIndices = mGLIndices;
+ setupClientArrays(data_mask);
}
+
if (mGLBuffer)
{
- sGLRenderBuffer = mGLBuffer;
if (data_mask && setup)
{
setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
@@ -1808,80 +2105,150 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
}
// virtual (default)
-void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
+void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
{
LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
stop_glerror();
U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
- if ((data_mask & mTypeMask) != data_mask)
+ /*if ((data_mask & mTypeMask) != data_mask)
{
llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
- }
+ }*/
- if (data_mask & MAP_NORMAL)
- {
- glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
- }
- if (data_mask & MAP_TEXCOORD3)
- {
- glClientActiveTextureARB(GL_TEXTURE3_ARB);
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
- if (data_mask & MAP_TEXCOORD2)
- {
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
- if (data_mask & MAP_TEXCOORD1)
- {
- glClientActiveTextureARB(GL_TEXTURE1_ARB);
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
- if (data_mask & MAP_BINORMAL)
- {
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
- if (data_mask & MAP_TEXCOORD0)
- {
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
- }
- if (data_mask & MAP_COLOR)
- {
- glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
- }
-
- if (data_mask & MAP_WEIGHT)
- {
- glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
- }
-
- if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
- {
- glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
- }
-
- if (data_mask & MAP_CLOTHWEIGHT)
- {
- glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
- }
- if (data_mask & MAP_VERTEX)
+ if (LLGLSLShader::sNoFixedFunction)
{
+ if (data_mask & MAP_NORMAL)
+ {
+ S32 loc = TYPE_NORMAL;
+ void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ {
+ S32 loc = TYPE_TEXCOORD3;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ {
+ S32 loc = TYPE_TEXCOORD2;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD1)
+ {
+ S32 loc = TYPE_TEXCOORD1;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
+ }
+ if (data_mask & MAP_BINORMAL)
+ {
+ S32 loc = TYPE_BINORMAL;
+ void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ S32 loc = TYPE_TEXCOORD0;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ S32 loc = TYPE_COLOR;
+ void* ptr = (void*)(base + mOffsets[TYPE_COLOR]);
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
+ }
+ if (data_mask & MAP_EMISSIVE)
+ {
+ S32 loc = TYPE_EMISSIVE;
+ void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+ }
+ if (data_mask & MAP_WEIGHT)
+ {
+ S32 loc = TYPE_WEIGHT;
+ void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+ glVertexAttribPointerARB(loc, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
+ }
+ if (data_mask & MAP_WEIGHT4)
+ {
+ S32 loc = TYPE_WEIGHT4;
+ void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
+ }
+ if (data_mask & MAP_CLOTHWEIGHT)
+ {
+ S32 loc = TYPE_CLOTHWEIGHT;
+ void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+ }
if (data_mask & MAP_TEXTURE_INDEX)
{
- glVertexPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ S32 loc = TYPE_TEXTURE_INDEX;
+ void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
+ glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
}
- else
+ if (data_mask & MAP_VERTEX)
+ {
+ S32 loc = TYPE_VERTEX;
+ void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+ }
+ }
+ else
+ {
+ if (data_mask & MAP_NORMAL)
+ {
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ {
+ glClientActiveTextureARB(GL_TEXTURE3_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD1)
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_BINORMAL)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ }
+ if (data_mask & MAP_VERTEX)
{
glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
- }
+ }
}
llglassertok();
}
+LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
+: mType(type), mIndex(index), mCount(count)
+{
+ llassert(mType == LLVertexBuffer::TYPE_INDEX ||
+ mType < LLVertexBuffer::TYPE_TEXTURE_INDEX);
+}
+
+
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 578cec3885..3e6f6a959a 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -38,6 +38,8 @@
#include
#include
+#define LL_MAX_VERTEX_ATTRIB_LOCATION 64
+
//============================================================================
// NOTES
// Threading:
@@ -49,25 +51,32 @@
//============================================================================
// gl name pools for dynamic and streaming buffers
-
-class LLVBOPool : public LLGLNamePool
+class LLVBOPool
{
-protected:
- virtual GLuint allocateName()
- {
- GLuint name;
- stop_glerror();
- glGenBuffersARB(1, &name);
- stop_glerror();
- return name;
- }
+public:
+ static U32 sBytesPooled;
- virtual void releaseName(GLuint name)
+ U32 mUsage;
+ U32 mType;
+
+ //size MUST be a power of 2
+ U8* allocate(U32& name, U32 size);
+
+ //size MUST be the size provided to allocate that returned the given name
+ void release(U32 name, U8* buffer, U32 size);
+
+ //destroy all records in mFreeList
+ void cleanup();
+
+ class Record
{
- stop_glerror();
- glDeleteBuffersARB(1, &name);
- stop_glerror();
- }
+ public:
+ U32 mGLName;
+ U8* mClientData;
+ };
+
+ typedef std::list record_list_t;
+ std::vector mFreeList;
};
class LLGLFence
@@ -90,9 +99,7 @@ public:
S32 mIndex;
S32 mCount;
- MappedRegion(S32 type, S32 index, S32 count)
- : mType(type), mIndex(index), mCount(count)
- { }
+ MappedRegion(S32 type, S32 index, S32 count);
};
LLVertexBuffer(const LLVertexBuffer& rhs)
@@ -111,18 +118,17 @@ public:
static LLVBOPool sStreamIBOPool;
static LLVBOPool sDynamicIBOPool;
- static S32 sWeight4Loc;
-
static BOOL sUseStreamDraw;
+ static BOOL sUseVAO;
static BOOL sPreferStreamDraw;
static void initClass(bool use_vbo, bool no_vbo_mapping);
static void cleanupClass();
static void setupClientArrays(U32 data_mask);
static void drawArrays(U32 mode, const std::vector& pos, const std::vector& norm);
+ static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
- static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
- static void unbind(); //unbind any bound vertex buffer
+ static void unbind(); //unbind any bound vertex buffer
//get the size of a vertex with the given typemask
static S32 calcVertexSize(const U32& typemask);
@@ -133,24 +139,29 @@ public:
static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
+ //WARNING -- when updating these enums you MUST
+ // 1 - update LLVertexBuffer::sTypeSize
+ // 2 - add a strider accessor
+ // 3 - modify LLVertexBuffer::setupVertexBuffer
+ // 4 - modify LLVertexBuffer::setupClientArray
+ // 5 - modify LLViewerShaderMgr::mReservedAttribs
+ // 6 - update LLVertexBuffer::setupVertexArray
enum {
- TYPE_VERTEX,
+ TYPE_VERTEX = 0,
TYPE_NORMAL,
TYPE_TEXCOORD0,
TYPE_TEXCOORD1,
TYPE_TEXCOORD2,
TYPE_TEXCOORD3,
TYPE_COLOR,
- // These use VertexAttribPointer and should possibly be made generic
+ TYPE_EMISSIVE,
TYPE_BINORMAL,
TYPE_WEIGHT,
TYPE_WEIGHT4,
TYPE_CLOTHWEIGHT,
- TYPE_MAX,
- TYPE_INDEX,
-
- //no actual additional data, but indicates position.w is texture index
TYPE_TEXTURE_INDEX,
+ TYPE_MAX,
+ TYPE_INDEX,
};
enum {
MAP_VERTEX = (1<unmapBuffer();
bool getVertexStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getVertexStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getIndexStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getTexCoord0Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getTexCoord1Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getNormalStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getBinormalStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getColorStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getEmissiveStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getWeightStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getWeight4Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getClothWeightStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false);
+
BOOL isEmpty() const { return mEmpty; }
BOOL isLocked() const { return mVertexLocked || mIndexLocked; }
S32 getNumVerts() const { return mNumVerts; }
S32 getNumIndices() const { return mNumIndices; }
- S32 getRequestedVerts() const { return mRequestedNumVerts; }
- S32 getRequestedIndices() const { return mRequestedNumIndices; }
-
+
U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; }
U32 getTypeMask() const { return mTypeMask; }
bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); }
S32 getSize() const;
- S32 getIndicesSize() const { return mNumIndices * sizeof(U16); }
+ S32 getIndicesSize() const { return mIndicesSize; }
U8* getMappedData() const { return mMappedData; }
U8* getMappedIndices() const { return mMappedIndexData; }
S32 getOffset(S32 type) const { return mOffsets[type]; }
@@ -252,25 +267,23 @@ public:
protected:
S32 mNumVerts; // Number of vertices allocated
S32 mNumIndices; // Number of indices allocated
- S32 mRequestedNumVerts; // Number of vertices requested
- S32 mRequestedNumIndices; // Number of indices requested
-
+
ptrdiff_t mAlignedOffset;
ptrdiff_t mAlignedIndexOffset;
S32 mSize;
+ S32 mIndicesSize;
U32 mTypeMask;
S32 mUsage; // GL usage
U32 mGLBuffer; // GL VBO handle
U32 mGLIndices; // GL IBO handle
+ U32 mGLArray; // GL VAO handle
+
U8* mMappedData; // pointer to currently mapped data (NULL if unmapped)
U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped)
BOOL mVertexLocked; // if TRUE, vertex buffer is being or has been written to in client memory
BOOL mIndexLocked; // if TRUE, index buffer is being or has been written to in client memory
BOOL mFinal; // if TRUE, buffer can not be mapped again
- BOOL mFilthy; // if TRUE, entire buffer must be copied (used to prevent redundant dirty flags)
BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded.
- BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not
- BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded)
S32 mOffsets[TYPE_MAX];
std::vector mMappedVertexRegions;
@@ -290,7 +303,6 @@ public:
static S32 sGLCount;
static S32 sMappedCount;
static BOOL sMapped;
- static std::vector sDeleteList;
typedef std::list buffer_list_t;
static BOOL sDisableVBOMapping; //disable glMapBufferARB
@@ -298,6 +310,7 @@ public:
static S32 sTypeSize[TYPE_MAX];
static U32 sGLMode[LLRender::NUM_MODES];
static U32 sGLRenderBuffer;
+ static U32 sGLRenderArray;
static U32 sGLRenderIndices;
static BOOL sVBOActive;
static BOOL sIBOActive;
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 79cdc73183..18c95266c4 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -5,6 +5,7 @@ project(llui)
include(00-Common)
include(LLCommon)
include(LLImage)
+include(LLInventory)
include(LLMath)
include(LLMessage)
include(LLRender)
@@ -16,6 +17,7 @@ include(LLXUIXML)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLIMAGE_INCLUDE_DIRS}
+ ${LLINVENTORY_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
${LLMESSAGE_INCLUDE_DIRS}
${LLRENDER_INCLUDE_DIRS}
@@ -35,6 +37,7 @@ set(llui_SOURCE_FILES
llcheckboxctrl.cpp
llclipboard.cpp
llcombobox.cpp
+ llcommandmanager.cpp
llconsole.cpp
llcontainerview.cpp
llctrlselectioninterface.cpp
@@ -100,6 +103,7 @@ set(llui_SOURCE_FILES
lltimectrl.cpp
lltransutil.cpp
lltoggleablemenu.cpp
+ lltoolbar.cpp
lltooltip.cpp
llui.cpp
lluicolortable.cpp
@@ -133,6 +137,7 @@ set(llui_HEADER_FILES
llcheckboxctrl.h
llclipboard.h
llcombobox.h
+ llcommandmanager.h
llconsole.h
llcontainerview.h
llctrlselectioninterface.h
@@ -204,6 +209,7 @@ set(llui_HEADER_FILES
lltextvalidate.h
lltimectrl.h
lltoggleablemenu.h
+ lltoolbar.h
lltooltip.h
lltransutil.h
lluicolortable.h
@@ -250,6 +256,7 @@ target_link_libraries(llui
${LLRENDER_LIBRARIES}
${LLWINDOW_LIBRARIES}
${LLIMAGE_LIBRARIES}
+ ${LLINVENTORY_LIBRARIES}
${LLVFS_LIBRARIES} # ugh, just for LLDir
${LLXUIXML_LIBRARIES}
${LLXML_LIBRARIES}
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 4b0b7c561d..7a5f9f9fd6 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -973,7 +973,7 @@ void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child)
if ( root_rect.overlaps(screen_rect) && LLUI::sDirtyRect.overlaps(screen_rect))
{
- glMatrixMode(GL_MODELVIEW);
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
LLUI::pushMatrix();
{
LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom, 0.f);
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index a330b4c08b..7820163f23 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -86,10 +86,11 @@ LLButton::Params::Params()
label_color_selected("label_color_selected"), // requires is_toggle true
label_color_disabled("label_color_disabled"),
label_color_disabled_selected("label_color_disabled_selected"),
- highlight_color("highlight_color"),
image_color("image_color"),
image_color_disabled("image_color_disabled"),
- image_overlay_color("image_overlay_color", LLColor4::white),
+ image_overlay_color("image_overlay_color", LLColor4::white % 0.75f),
+ image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f),
+ image_overlay_selected_color("image_overlay_selected_color", LLColor4::white),
flash_color("flash_color"),
pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),
pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),
@@ -102,10 +103,13 @@ LLButton::Params::Params()
scale_image("scale_image", true),
hover_glow_amount("hover_glow_amount"),
commit_on_return("commit_on_return", true),
+ display_pressed_state("display_pressed_state", true),
use_draw_context_alpha("use_draw_context_alpha", true),
badge("badge"),
handle_right_mouse("handle_right_mouse"),
- held_down_delay("held_down_delay")
+ held_down_delay("held_down_delay"),
+ button_flash_count("button_flash_count"),
+ button_flash_rate("button_flash_rate")
{
addSynonym(is_toggle, "toggle");
changeDefault(initial_value, LLSD(false));
@@ -114,7 +118,7 @@ LLButton::Params::Params()
LLButton::LLButton(const LLButton::Params& p)
: LLUICtrl(p),
- LLBadgeOwner(LLView::getHandle()),
+ LLBadgeOwner(getHandle()),
mMouseDownFrame(0),
mMouseHeldDownCount(0),
mBorderEnabled( FALSE ),
@@ -139,12 +143,13 @@ LLButton::LLButton(const LLButton::Params& p)
mSelectedLabelColor(p.label_color_selected()),
mDisabledLabelColor(p.label_color_disabled()),
mDisabledSelectedLabelColor(p.label_color_disabled_selected()),
- mHighlightColor(p.highlight_color()),
mImageColor(p.image_color()),
mFlashBgColor(p.flash_color()),
mDisabledImageColor(p.image_color_disabled()),
mImageOverlay(p.image_overlay()),
mImageOverlayColor(p.image_overlay_color()),
+ mImageOverlayDisabledColor(p.image_overlay_disabled_color()),
+ mImageOverlaySelectedColor(p.image_overlay_selected_color()),
mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)),
mImageOverlayTopPad(p.image_top_pad),
mImageOverlayBottomPad(p.image_bottom_pad),
@@ -162,12 +167,15 @@ LLButton::LLButton(const LLButton::Params& p)
mCommitOnReturn(p.commit_on_return),
mFadeWhenDisabled(FALSE),
mForcePressedState(false),
+ mDisplayPressedState(p.display_pressed_state),
mLastDrawCharsCount(0),
mMouseDownSignal(NULL),
mMouseUpSignal(NULL),
mHeldDownSignal(NULL),
mUseDrawContextAlpha(p.use_draw_context_alpha),
- mHandleRightMouse(p.handle_right_mouse)
+ mHandleRightMouse(p.handle_right_mouse),
+ mButtonFlashCount(p.button_flash_count),
+ mButtonFlashRate(p.button_flash_rate)
{
static LLUICachedControl llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
static Params default_params(LLUICtrlFactory::getDefaultParams());
@@ -295,6 +303,24 @@ void LLButton::onCommit()
LLUICtrl::onCommit();
}
+boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb)
+{
+ return setClickedCallback(initCommitCallback(cb));
+}
+boost::signals2::connection LLButton::setMouseDownCallback(const CommitCallbackParam& cb)
+{
+ return setMouseDownCallback(initCommitCallback(cb));
+}
+boost::signals2::connection LLButton::setMouseUpCallback(const CommitCallbackParam& cb)
+{
+ return setMouseUpCallback(initCommitCallback(cb));
+}
+boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackParam& cb)
+{
+ return setHeldDownCallback(initCommitCallback(cb));
+}
+
+
boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )
{
if (!mCommitSignal) mCommitSignal = new commit_signal_t();
@@ -317,7 +343,7 @@ boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t
}
-// *TODO: Deprecate (for backwards compatability only)
+// *TODO: Deprecate (for backwards compatibility only)
boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
{
return setClickedCallback(boost::bind(cb, data));
@@ -514,15 +540,6 @@ BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask)
return TRUE;
}
-
-void LLButton::onMouseEnter(S32 x, S32 y, MASK mask)
-{
- LLUICtrl::onMouseEnter(x, y, mask);
-
- if (isInEnabledChain())
- mNeedsHighlight = TRUE;
-}
-
void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
{
LLUICtrl::onMouseLeave(x, y, mask);
@@ -537,6 +554,10 @@ void LLButton::setHighlight(bool b)
BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
{
+ if (isInEnabledChain()
+ && (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this))
+ mNeedsHighlight = TRUE;
+
if (!childrenHandleHover(x, y, mask))
{
if (mMouseDownTimer.getStarted())
@@ -557,21 +578,37 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
return TRUE;
}
+void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height)
+{
+ overlay_width = mImageOverlay->getWidth();
+ overlay_height = mImageOverlay->getHeight();
+
+ F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f);
+ overlay_width = llround((F32)overlay_width * scale_factor);
+ overlay_height = llround((F32)overlay_height * scale_factor);
+}
+
// virtual
void LLButton::draw()
{
+ static LLCachedControl sEnableButtonFlashing(*LLUI::sSettingGroups["config"], "EnableButtonFlashing", true);
F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
bool flash = FALSE;
- static LLUICachedControl button_flash_rate("ButtonFlashRate", 0);
- static LLUICachedControl button_flash_count("ButtonFlashCount", 0);
- if( mFlashing )
+ if( mFlashing)
{
- F32 elapsed = mFlashingTimer.getElapsedTimeF32();
- S32 flash_count = S32(elapsed * button_flash_rate * 2.f);
- // flash on or off?
- flash = (flash_count % 2 == 0) || flash_count > S32((F32)button_flash_count * 2.f);
+ if ( sEnableButtonFlashing)
+ {
+ F32 elapsed = mFlashingTimer.getElapsedTimeF32();
+ S32 flash_count = S32(elapsed * mButtonFlashRate * 2.f);
+ // flash on or off?
+ flash = (flash_count % 2 == 0) || flash_count > S32((F32)mButtonFlashCount * 2.f);
+ }
+ else
+ { // otherwise just highlight button in flash color
+ flash = true;
+ }
}
bool pressed_by_keyboard = FALSE;
@@ -600,7 +637,7 @@ void LLButton::draw()
LLColor4 glow_color = LLColor4::white;
LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
LLUIImage* imagep = NULL;
- if (pressed)
+ if (pressed && mDisplayPressedState)
{
imagep = selected ? mImagePressedSelected : mImagePressed;
}
@@ -710,16 +747,7 @@ void LLButton::draw()
}
// Unselected label assignments
- LLWString label;
-
- if( getToggleState() )
- {
- label = mSelectedLabel;
- }
- else
- {
- label = mUnselectedLabel;
- }
+ LLWString label = getCurrentLabel();
// overlay with keyboard focus border
if (hasFocus())
@@ -784,18 +812,16 @@ void LLButton::draw()
if (mImageOverlay.notNull())
{
// get max width and height (discard level 0)
- S32 overlay_width = mImageOverlay->getWidth();
- S32 overlay_height = mImageOverlay->getHeight();
+ S32 overlay_width;
+ S32 overlay_height;
- F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f);
- overlay_width = llround((F32)overlay_width * scale_factor);
- overlay_height = llround((F32)overlay_height * scale_factor);
+ getOverlayImageSize(overlay_width, overlay_height);
S32 center_x = getLocalRect().getCenterX();
S32 center_y = getLocalRect().getCenterY();
//FUGLY HACK FOR "DEPRESSED" BUTTONS
- if (pressed)
+ if (pressed && mDisplayPressedState)
{
center_y--;
center_x++;
@@ -806,7 +832,11 @@ void LLButton::draw()
LLColor4 overlay_color = mImageOverlayColor.get();
if (!enabled)
{
- overlay_color.mV[VALPHA] = 0.5f;
+ overlay_color = mImageOverlayDisabledColor.get();
+ }
+ else if (getToggleState())
+ {
+ overlay_color = mImageOverlaySelectedColor.get();
}
overlay_color.mV[VALPHA] *= alpha;
@@ -814,6 +844,7 @@ void LLButton::draw()
{
case LLFontGL::LEFT:
text_left += overlay_width + mImgOverlayLabelSpace;
+ text_width -= overlay_width + mImgOverlayLabelSpace;
mImageOverlay->draw(
mLeftHPad,
center_y - (overlay_height / 2),
@@ -831,6 +862,7 @@ void LLButton::draw()
break;
case LLFontGL::RIGHT:
text_right -= overlay_width + mImgOverlayLabelSpace;
+ text_width -= overlay_width + mImgOverlayLabelSpace;
mImageOverlay->draw(
getRect().getWidth() - mRightHPad - overlay_width,
center_y - (overlay_height / 2),
@@ -866,7 +898,7 @@ void LLButton::draw()
S32 y_offset = 2 + (getRect().getHeight() - 20)/2;
- if (pressed)
+ if (pressed && mDisplayPressedState)
{
y_offset--;
x++;
@@ -922,7 +954,7 @@ void LLButton::setToggleState(BOOL b)
void LLButton::setFlashing( BOOL b )
{
- if (b != mFlashing)
+ if ((bool)b != mFlashing)
{
mFlashing = b;
mFlashingTimer.reset();
@@ -962,6 +994,23 @@ void LLButton::setLabelSelected( const LLStringExplicit& label )
mSelectedLabel = label;
}
+bool LLButton::labelIsTruncated() const
+{
+ return getCurrentLabel().getString().size() > mLastDrawCharsCount;
+}
+
+const LLUIString& LLButton::getCurrentLabel() const
+{
+ if( getToggleState() )
+ {
+ return mSelectedLabel;
+ }
+ else
+ {
+ return mUnselectedLabel;
+ }
+}
+
void LLButton::setImageUnselected(LLPointer image)
{
mImageUnselected = image;
@@ -973,16 +1022,7 @@ void LLButton::setImageUnselected(LLPointer image)
void LLButton::autoResize()
{
- LLUIString label;
- if(getToggleState())
- {
- label = mSelectedLabel;
- }
- else
- {
- label = mUnselectedLabel;
- }
- resize(label);
+ resize(getCurrentLabel());
}
void LLButton::resize(LLUIString label)
@@ -992,11 +1032,32 @@ void LLButton::resize(LLUIString label)
// get current btn length
S32 btn_width =getRect().getWidth();
// check if it need resize
- if (mAutoResize == TRUE)
+ if (mAutoResize)
{
- if (btn_width - (mRightHPad + mLeftHPad) < label_width)
+ S32 min_width = label_width + mLeftHPad + mRightHPad;
+ if (mImageOverlay)
{
- setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mLeft + label_width + mLeftHPad + mRightHPad , getRect().mBottom));
+ S32 overlay_width = mImageOverlay->getWidth();
+ F32 scale_factor = (getRect().getHeight() - (mImageOverlayBottomPad + mImageOverlayTopPad)) / (F32)mImageOverlay->getHeight();
+ overlay_width = llround((F32)overlay_width * scale_factor);
+
+ switch(mImageOverlayAlignment)
+ {
+ case LLFontGL::LEFT:
+ case LLFontGL::RIGHT:
+ min_width += overlay_width + mImgOverlayLabelSpace;
+ break;
+ case LLFontGL::HCENTER:
+ min_width = llmax(min_width, overlay_width + mLeftHPad + mRightHPad);
+ break;
+ default:
+ // draw nothing
+ break;
+ }
+ }
+ if (btn_width < min_width)
+ {
+ reshape(min_width, getRect().getHeight());
}
}
}
@@ -1143,7 +1204,7 @@ void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)
// Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
button->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
// Set the clicked callback to toggle the floater
- button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname));
+ button->setClickedCallback(boost::bind(&LLFloaterReg::toggleInstance, sdname, LLSD()));
}
// static
@@ -1184,7 +1245,6 @@ void LLButton::resetMouseDownTimer()
mMouseDownTimer.reset();
}
-
BOOL LLButton::handleDoubleClick(S32 x, S32 y, MASK mask)
{
// just treat a double click as a second click
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 2ba20ef87b..23cd92fc15 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -94,10 +94,11 @@ public:
label_color_selected,
label_color_disabled,
label_color_disabled_selected,
- highlight_color,
image_color,
image_color_disabled,
image_overlay_color,
+ image_overlay_selected_color,
+ image_overlay_disabled_color,
flash_color;
// layout
@@ -123,7 +124,8 @@ public:
// misc
Optional is_toggle,
scale_image,
- commit_on_return;
+ commit_on_return,
+ display_pressed_state;
Optional hover_glow_amount;
Optional held_down_delay;
@@ -134,6 +136,9 @@ public:
Optional handle_right_mouse;
+ Optional button_flash_count;
+ Optional button_flash_rate;
+
Params();
};
@@ -160,7 +165,6 @@ public:
virtual void draw();
/*virtual*/ BOOL postBuild();
- virtual void onMouseEnter(S32 x, S32 y, MASK mask);
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
virtual void onMouseCaptureLost();
@@ -171,6 +175,11 @@ public:
void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; }
+ boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb);
+ boost::signals2::connection setMouseDownCallback(const CommitCallbackParam& cb);
+ boost::signals2::connection setMouseUpCallback(const CommitCallbackParam& cb);
+ boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb);
+
boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button
boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON
@@ -238,6 +247,8 @@ public:
S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; }
+ bool labelIsTruncated() const;
+ const LLUIString& getCurrentLabel() const;
void setScaleImage(BOOL scale) { mScaleImage = scale; }
BOOL getScaleImage() const { return mScaleImage; }
@@ -273,14 +284,16 @@ public:
protected:
LLPointer getImageUnselected() const { return mImageUnselected; }
LLPointer getImageSelected() const { return mImageSelected; }
+ void getOverlayImageSize(S32& overlay_width, S32& overlay_height);
LLFrameTimer mMouseDownTimer;
+ bool mNeedsHighlight;
+ S32 mButtonFlashCount;
+ F32 mButtonFlashRate;
-private:
void drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size);
void resetMouseDownTimer();
-private:
commit_signal_t* mMouseDownSignal;
commit_signal_t* mMouseUpSignal;
commit_signal_t* mHeldDownSignal;
@@ -296,6 +309,8 @@ private:
LLPointer mImageOverlay;
LLFontGL::HAlign mImageOverlayAlignment;
LLUIColor mImageOverlayColor;
+ LLUIColor mImageOverlaySelectedColor;
+ LLUIColor mImageOverlayDisabledColor;
LLPointer mImageUnselected;
LLUIString mUnselectedLabel;
@@ -324,21 +339,19 @@ private:
flash icon name is set in attributes(by default it isn't). First way is used otherwise. */
LLPointer mImageFlash;
- LLUIColor mHighlightColor;
LLUIColor mFlashBgColor;
LLUIColor mImageColor;
LLUIColor mDisabledImageColor;
- BOOL mIsToggle;
- BOOL mScaleImage;
+ bool mIsToggle;
+ bool mScaleImage;
- BOOL mDropShadowedText;
- BOOL mAutoResize;
- BOOL mUseEllipses;
- BOOL mBorderEnabled;
-
- BOOL mFlashing;
+ bool mDropShadowedText;
+ bool mAutoResize;
+ bool mUseEllipses;
+ bool mBorderEnabled;
+ bool mFlashing;
LLFontGL::HAlign mHAlign;
S32 mLeftHPad;
@@ -358,10 +371,10 @@ private:
F32 mHoverGlowStrength;
F32 mCurGlowStrength;
- BOOL mNeedsHighlight;
- BOOL mCommitOnReturn;
- BOOL mFadeWhenDisabled;
+ bool mCommitOnReturn;
+ bool mFadeWhenDisabled;
bool mForcePressedState;
+ bool mDisplayPressedState;
LLFrameTimer mFlashingTimer;
diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp
index 984c4ec5fb..6910b962a1 100644
--- a/indra/llui/llclipboard.cpp
+++ b/indra/llui/llclipboard.cpp
@@ -40,6 +40,7 @@ LLClipboard gClipboard;
LLClipboard::LLClipboard()
{
+ mSourceItem = NULL;
}
@@ -134,3 +135,8 @@ BOOL LLClipboard::canPastePrimaryString() const
{
return LLView::getWindow()->isPrimaryTextAvailable();
}
+
+void LLClipboard::setSourceObject(const LLUUID& source_id, LLAssetType::EType type)
+{
+ mSourceItem = new LLInventoryObject (source_id, LLUUID::null, type, "");
+}
diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h
index 24cb46c3f4..9371b94284 100644
--- a/indra/llui/llclipboard.h
+++ b/indra/llui/llclipboard.h
@@ -30,6 +30,8 @@
#include "llstring.h"
#include "lluuid.h"
+#include "stdenums.h"
+#include "llinventory.h"
class LLClipboard
@@ -52,9 +54,14 @@ public:
BOOL canPastePrimaryString() const;
const LLWString& getPastePrimaryWString(LLUUID* source_id = NULL);
+ // Support clipboard for object known only by their uuid and asset type
+ void setSourceObject(const LLUUID& source_id, LLAssetType::EType type);
+ const LLInventoryObject* getSourceObject() { return mSourceItem; }
+
private:
- LLUUID mSourceID;
+ LLUUID mSourceID;
LLWString mString;
+ LLInventoryObject* mSourceItem;
};
diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp
new file mode 100644
index 0000000000..0e2f3f1961
--- /dev/null
+++ b/indra/llui/llcommandmanager.cpp
@@ -0,0 +1,172 @@
+/**
+ * @file llcommandmanager.cpp
+ * @brief LLCommandManager class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+// A control that displays the name of the chosen item, which when
+// clicked shows a scrolling box of options.
+
+#include "linden_common.h"
+
+#include "llcommandmanager.h"
+#include "lldir.h"
+#include "llerror.h"
+#include "llxuiparser.h"
+
+#include
+
+
+//
+// LLCommandId class
+//
+
+const LLCommandId LLCommandId::null = LLCommandId("null command");
+
+//
+// LLCommand class
+//
+
+LLCommand::Params::Params()
+ : available_in_toybox("available_in_toybox", false)
+ , icon("icon")
+ , label_ref("label_ref")
+ , name("name")
+ , tooltip_ref("tooltip_ref")
+ , execute_function("execute_function")
+ , execute_parameters("execute_parameters")
+ , execute_stop_function("execute_stop_function")
+ , execute_stop_parameters("execute_stop_parameters")
+ , is_enabled_function("is_enabled_function")
+ , is_enabled_parameters("is_enabled_parameters")
+ , is_running_function("is_running_function")
+ , is_running_parameters("is_running_parameters")
+ , is_starting_function("is_starting_function")
+ , is_starting_parameters("is_starting_parameters")
+{
+}
+
+LLCommand::LLCommand(const LLCommand::Params& p)
+ : mIdentifier(p.name)
+ , mAvailableInToybox(p.available_in_toybox)
+ , mIcon(p.icon)
+ , mLabelRef(p.label_ref)
+ , mName(p.name)
+ , mTooltipRef(p.tooltip_ref)
+ , mExecuteFunction(p.execute_function)
+ , mExecuteParameters(p.execute_parameters)
+ , mExecuteStopFunction(p.execute_stop_function)
+ , mExecuteStopParameters(p.execute_stop_parameters)
+ , mIsEnabledFunction(p.is_enabled_function)
+ , mIsEnabledParameters(p.is_enabled_parameters)
+ , mIsRunningFunction(p.is_running_function)
+ , mIsRunningParameters(p.is_running_parameters)
+ , mIsStartingFunction(p.is_starting_function)
+ , mIsStartingParameters(p.is_starting_parameters)
+{
+}
+
+
+//
+// LLCommandManager class
+//
+
+LLCommandManager::LLCommandManager()
+{
+}
+
+LLCommandManager::~LLCommandManager()
+{
+ for (CommandVector::iterator cmdIt = mCommands.begin(); cmdIt != mCommands.end(); ++cmdIt)
+ {
+ LLCommand * command = *cmdIt;
+
+ delete command;
+ }
+}
+
+U32 LLCommandManager::commandCount() const
+{
+ return mCommands.size();
+}
+
+LLCommand * LLCommandManager::getCommand(U32 commandIndex)
+{
+ return mCommands[commandIndex];
+}
+
+LLCommand * LLCommandManager::getCommand(const LLCommandId& commandId)
+{
+ LLCommand * command_match = NULL;
+
+ CommandIndexMap::const_iterator found = mCommandIndices.find(commandId.uuid());
+
+ if (found != mCommandIndices.end())
+ {
+ command_match = mCommands[found->second];
+ }
+
+ return command_match;
+}
+
+void LLCommandManager::addCommand(LLCommand * command)
+{
+ LLCommandId command_id = command->id();
+ mCommandIndices[command_id.uuid()] = mCommands.size();
+ mCommands.push_back(command);
+
+ lldebugs << "Successfully added command: " << command->name() << llendl;
+}
+
+//static
+bool LLCommandManager::load()
+{
+ LLCommandManager& mgr = LLCommandManager::instance();
+
+ std::string commands_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "commands.xml");
+
+ LLCommandManager::Params commandsParams;
+
+ LLSimpleXUIParser parser;
+
+ if (!parser.readXUI(commands_file, commandsParams))
+ {
+ llerrs << "Unable to load xml file: " << commands_file << llendl;
+ return false;
+ }
+
+ if (!commandsParams.validateBlock())
+ {
+ llerrs << "Invalid commands file: " << commands_file << llendl;
+ return false;
+ }
+
+ BOOST_FOREACH(LLCommand::Params& commandParams, commandsParams.commands)
+ {
+ LLCommand * command = new LLCommand(commandParams);
+
+ mgr.addCommand(command);
+ }
+
+ return true;
+}
diff --git a/indra/llui/llcommandmanager.h b/indra/llui/llcommandmanager.h
new file mode 100644
index 0000000000..a7276a48aa
--- /dev/null
+++ b/indra/llui/llcommandmanager.h
@@ -0,0 +1,202 @@
+/**
+ * @file llcommandmanager.h
+ * @brief LLCommandManager class to hold commands
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLCOMMANDMANAGER_H
+#define LL_LLCOMMANDMANAGER_H
+
+#include "llinitparam.h"
+#include "llsingleton.h"
+
+
+class LLCommand;
+class LLCommandManager;
+
+
+class LLCommandId
+{
+public:
+ friend class LLCommand;
+ friend class LLCommandManager;
+
+ struct Params : public LLInitParam::Block
+ {
+ Mandatory name;
+
+ Params()
+ : name("name")
+ {}
+ };
+
+ LLCommandId(const std::string& name)
+ {
+ mUUID = LLUUID::generateNewID(name);
+ }
+
+ LLCommandId(const Params& p)
+ {
+ mUUID = LLUUID::generateNewID(p.name);
+ }
+
+ LLCommandId(const LLUUID& uuid)
+ : mUUID(uuid)
+ {}
+
+ const LLUUID& uuid() const { return mUUID; }
+
+ bool operator!=(const LLCommandId& command) const
+ {
+ return (mUUID != command.mUUID);
+ }
+
+ bool operator==(const LLCommandId& command) const
+ {
+ return (mUUID == command.mUUID);
+ }
+
+ static const LLCommandId null;
+
+private:
+ LLUUID mUUID;
+};
+
+typedef std::list command_id_list_t;
+
+
+class LLCommand
+{
+public:
+ struct Params : public LLInitParam::Block
+ {
+ Mandatory available_in_toybox;
+ Mandatory icon;
+ Mandatory label_ref;
+ Mandatory name;
+ Mandatory tooltip_ref;
+
+ Mandatory execute_function;
+ Optional execute_parameters;
+
+ Optional execute_stop_function;
+ Optional execute_stop_parameters;
+
+ Optional is_enabled_function;
+ Optional is_enabled_parameters;
+
+ Optional is_running_function;
+ Optional is_running_parameters;
+
+ Optional is_starting_function;
+ Optional is_starting_parameters;
+
+ Params();
+ };
+
+ LLCommand(const LLCommand::Params& p);
+
+ const bool availableInToybox() const { return mAvailableInToybox; }
+ const std::string& icon() const { return mIcon; }
+ const LLCommandId& id() const { return mIdentifier; }
+ const std::string& labelRef() const { return mLabelRef; }
+ const std::string& name() const { return mName; }
+ const std::string& tooltipRef() const { return mTooltipRef; }
+
+ const std::string& executeFunctionName() const { return mExecuteFunction; }
+ const LLSD& executeParameters() const { return mExecuteParameters; }
+
+ const std::string& executeStopFunctionName() const { return mExecuteStopFunction; }
+ const LLSD& executeStopParameters() const { return mExecuteStopParameters; }
+
+ const std::string& isEnabledFunctionName() const { return mIsEnabledFunction; }
+ const LLSD& isEnabledParameters() const { return mIsEnabledParameters; }
+
+ const std::string& isRunningFunctionName() const { return mIsRunningFunction; }
+ const LLSD& isRunningParameters() const { return mIsRunningParameters; }
+
+ const std::string& isStartingFunctionName() const { return mIsStartingFunction; }
+ const LLSD& isStartingParameters() const { return mIsStartingParameters; }
+
+private:
+ LLCommandId mIdentifier;
+
+ bool mAvailableInToybox;
+ std::string mIcon;
+ std::string mLabelRef;
+ std::string mName;
+ std::string mTooltipRef;
+
+ std::string mExecuteFunction;
+ LLSD mExecuteParameters;
+
+ std::string mExecuteStopFunction;
+ LLSD mExecuteStopParameters;
+
+ std::string mIsEnabledFunction;
+ LLSD mIsEnabledParameters;
+
+ std::string mIsRunningFunction;
+ LLSD mIsRunningParameters;
+
+ std::string mIsStartingFunction;
+ LLSD mIsStartingParameters;
+};
+
+
+class LLCommandManager
+: public LLSingleton
+{
+public:
+ struct Params : public LLInitParam::Block
+ {
+ Multiple< LLCommand::Params, AtLeast<1> > commands;
+
+ Params()
+ : commands("command")
+ {
+ }
+ };
+
+ LLCommandManager();
+ ~LLCommandManager();
+
+ U32 commandCount() const;
+ LLCommand * getCommand(U32 commandIndex);
+ LLCommand * getCommand(const LLCommandId& commandId);
+
+ static bool load();
+
+protected:
+ void addCommand(LLCommand * command);
+
+private:
+ typedef std::map CommandIndexMap;
+ typedef std::vector CommandVector;
+
+ CommandVector mCommands;
+ CommandIndexMap mCommandIndices;
+};
+
+
+#endif // LL_LLCOMMANDMANAGER_H
diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp
index ca2dc644a4..3396213f1c 100644
--- a/indra/llui/lldockablefloater.cpp
+++ b/indra/llui/lldockablefloater.cpp
@@ -82,7 +82,7 @@ BOOL LLDockableFloater::postBuild()
mForceDocking = true;
}
- mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png");
+ mDockTongue = LLUI::getUIImage("Flyout_Pointer");
LLFloater::setDocked(true);
return LLView::postBuild();
}
@@ -162,10 +162,15 @@ void LLDockableFloater::setVisible(BOOL visible)
void LLDockableFloater::setMinimized(BOOL minimize)
{
- if(minimize)
+ if(minimize && isDocked())
{
+ // minimizing a docked floater just hides it
setVisible(FALSE);
}
+ else
+ {
+ LLFloater::setMinimized(minimize);
+ }
}
LLView * LLDockableFloater::getDockWidget()
@@ -234,8 +239,21 @@ void LLDockableFloater::setDockControl(LLDockControl* dockControl)
setDocked(isDocked());
}
-const LLUIImagePtr& LLDockableFloater::getDockTongue()
+const LLUIImagePtr& LLDockableFloater::getDockTongue(LLDockControl::DocAt dock_side)
{
+ switch(dock_side)
+ {
+ case LLDockControl::LEFT:
+ mDockTongue = LLUI::getUIImage("Flyout_Left");
+ break;
+ case LLDockControl::RIGHT:
+ mDockTongue = LLUI::getUIImage("Flyout_Right");
+ break;
+ default:
+ mDockTongue = LLUI::getUIImage("Flyout_Pointer");
+ break;
+ }
+
return mDockTongue;
}
diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h
index 8deb6c1159..89c9852f4a 100644
--- a/indra/llui/lldockablefloater.h
+++ b/indra/llui/lldockablefloater.h
@@ -113,6 +113,8 @@ public:
bool getUniqueDocking() { return mUniqueDocking; }
bool getUseTongue() { return mUseTongue; }
+
+ void setUseTongue(bool use_tongue) { mUseTongue = use_tongue;}
private:
/**
* Provides unique of dockable floater.
@@ -122,7 +124,7 @@ private:
protected:
void setDockControl(LLDockControl* dockControl);
- const LLUIImagePtr& getDockTongue();
+ const LLUIImagePtr& getDockTongue(LLDockControl::DocAt dock_side = LLDockControl::TOP);
// Checks if docking should be forced.
// It may be useful e.g. if floater created in mouselook mode (see EXT-5609)
diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp
index b1c27126d9..af39e41fa6 100644
--- a/indra/llui/lldockcontrol.cpp
+++ b/indra/llui/lldockcontrol.cpp
@@ -92,19 +92,24 @@ void LLDockControl::setDock(LLView* dockWidget)
void LLDockControl::getAllowedRect(LLRect& rect)
{
- rect = mDockableFloater->getRootView()->getRect();
+ rect = mDockableFloater->getRootView()->getChild("non_toolbar_panel")->getRect();
}
void LLDockControl::repositionDockable()
{
+ if (!mDockWidget) return;
LLRect dockRect = mDockWidget->calcScreenRect();
LLRect rootRect;
+ LLRect floater_rect = mDockableFloater->calcScreenRect();
mGetAllowedRectCallback(rootRect);
- // recalculate dockable position if dock position changed, dock visibility changed,
- // root view rect changed or recalculation is forced
- if (mPrevDockRect != dockRect || mDockWidgetVisible != isDockVisible()
- || mRootRect != rootRect || mRecalculateDocablePosition)
+ // recalculate dockable position if:
+ if (mPrevDockRect != dockRect //dock position changed
+ || mDockWidgetVisible != isDockVisible() //dock visibility changed
+ || mRootRect != rootRect //root view rect changed
+ || mFloaterRect != floater_rect //floater rect changed
+ || mRecalculateDockablePosition //recalculation is forced
+ )
{
// undock dockable and off() if dock not visible
if (!isDockVisible())
@@ -135,7 +140,8 @@ void LLDockControl::repositionDockable()
mPrevDockRect = dockRect;
mRootRect = rootRect;
- mRecalculateDocablePosition = false;
+ mFloaterRect = floater_rect;
+ mRecalculateDockablePosition = false;
mDockWidgetVisible = isDockVisible();
}
}
@@ -160,7 +166,7 @@ bool LLDockControl::isDockVisible()
case TOP:
{
// check is dock inside parent rect
- // assume that parent for all dockable flaoters
+ // assume that parent for all dockable floaters
// is the root view
LLRect dockParentRect =
mDockWidget->getRootView()->calcScreenRect();
@@ -202,21 +208,33 @@ void LLDockControl::moveDockable()
switch (mDockAt)
{
case LEFT:
- x = dockRect.mLeft;
- y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
- // check is dockable inside root view rect
- if (x < rootRect.mLeft)
- {
- x = rootRect.mLeft;
- }
- if (x + dockableRect.getWidth() > rootRect.mRight)
- {
- x = rootRect.mRight - dockableRect.getWidth();
- }
+
+ x = dockRect.mLeft - dockableRect.getWidth();
+ y = dockRect.getCenterY() + dockableRect.getHeight() / 2;
- mDockTongueX = x + dockableRect.getWidth()/2 - mDockTongue->getWidth() / 2;
+ if (use_tongue)
+ {
+ x -= mDockTongue->getWidth();
+ }
+
+ mDockTongueX = dockableRect.mRight;
+ mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2;
- mDockTongueY = dockRect.mTop;
+ break;
+
+ case RIGHT:
+
+ x = dockRect.mRight;
+ y = dockRect.getCenterY() + dockableRect.getHeight() / 2;
+
+ if (use_tongue)
+ {
+ x += mDockTongue->getWidth();
+ }
+
+ mDockTongueX = dockRect.mRight;
+ mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2;
+
break;
case TOP:
@@ -314,13 +332,12 @@ void LLDockControl::moveDockable()
dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
dockableRect.getHeight());
}
- LLRect localDocableParentRect;
- mDockableFloater->getParent()->screenRectToLocal(dockableRect,
- &localDocableParentRect);
- mDockableFloater->setRect(localDocableParentRect);
- mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY,
- &mDockTongueX, &mDockTongueY);
+ LLRect localDocableParentRect;
+
+ mDockableFloater->getParent()->screenRectToLocal(dockableRect, &localDocableParentRect);
+ mDockableFloater->setRect(localDocableParentRect);
+ mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, &mDockTongueX, &mDockTongueY);
}
@@ -329,7 +346,7 @@ void LLDockControl::on()
if (isDockVisible())
{
mEnabled = true;
- mRecalculateDocablePosition = true;
+ mRecalculateDockablePosition = true;
}
}
@@ -340,7 +357,7 @@ void LLDockControl::off()
void LLDockControl::forceRecalculatePosition()
{
- mRecalculateDocablePosition = true;
+ mRecalculateDockablePosition = true;
}
void LLDockControl::drawToungue()
diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h
index 2e7359245f..c9602011f6 100644
--- a/indra/llui/lldockcontrol.h
+++ b/indra/llui/lldockcontrol.h
@@ -43,6 +43,7 @@ public:
{
TOP,
LEFT,
+ RIGHT,
BOTTOM
};
@@ -79,12 +80,13 @@ private:
private:
get_allowed_rect_callback_t mGetAllowedRectCallback;
bool mEnabled;
- bool mRecalculateDocablePosition;
+ bool mRecalculateDockablePosition;
bool mDockWidgetVisible;
DocAt mDockAt;
LLView* mDockWidget;
LLRect mPrevDockRect;
LLRect mRootRect;
+ LLRect mFloaterRect;
LLFloater* mDockableFloater;
LLUIImagePtr mDockTongue;
S32 mDockTongueX;
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 0bbefb90ec..f391a53e47 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -58,13 +58,24 @@
#include "llhelp.h"
#include "llmultifloater.h"
#include "llsdutil.h"
-#include "../newview/llviewercontrol.h"
+#include
-#include
+#include "../newview/llviewercontrol.h" // This is a nasty hack ...
// use this to control "jumping" behavior when Ctrl-Tabbing
const S32 TABBED_FLOATER_OFFSET = 0;
+namespace LLInitParam
+{
+ void TypeValues::declareValues()
+ {
+ declare("none", LLFloaterEnums::OPEN_POSITIONING_NONE);
+ declare("cascading", LLFloaterEnums::OPEN_POSITIONING_CASCADING);
+ declare("centered", LLFloaterEnums::OPEN_POSITIONING_CENTERED);
+ declare("specified", LLFloaterEnums::OPEN_POSITIONING_SPECIFIED);
+ }
+}
+
std::string LLFloater::sButtonNames[BUTTON_COUNT] =
{
"llfloater_close_btn", //BUTTON_CLOSE
@@ -103,7 +114,6 @@ LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
LLMultiFloater* LLFloater::sHostp = NULL;
BOOL LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting
-LLFloater::handle_map_t LLFloater::sFloaterMap;
LLFloaterView* gFloaterView = NULL;
@@ -157,7 +167,7 @@ LLFloater::Params::Params()
: title("title"),
short_title("short_title"),
single_instance("single_instance", false),
- auto_tile("auto_tile", false),
+ reuse_instance("reuse_instance", false),
can_resize("can_resize", false),
can_minimize("can_minimize", true),
can_close("can_close", true),
@@ -168,7 +178,10 @@ LLFloater::Params::Params()
save_rect("save_rect", false),
save_visibility("save_visibility", false),
can_dock("can_dock", false),
- open_centered("open_centered", true),
+ show_title("show_title", true),
+ open_positioning("open_positioning", LLFloaterEnums::OPEN_POSITIONING_NONE),
+ specified_left("specified_left"),
+ specified_bottom("specified_bottom"),
header_height("header_height", 0),
legacy_header_height("legacy_header_height", 0),
close_image("close_image"),
@@ -184,7 +197,8 @@ LLFloater::Params::Params()
dock_pressed_image("dock_pressed_image"),
help_pressed_image("help_pressed_image"),
open_callback("open_callback"),
- close_callback("close_callback")
+ close_callback("close_callback"),
+ follows("follows")
{
changeDefault(visible, false);
}
@@ -230,13 +244,16 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
mTitle(p.title),
mShortTitle(p.short_title),
mSingleInstance(p.single_instance),
+ mReuseInstance(p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance), // reuse single-instance floaters by default
mKey(key),
- mAutoTile(p.auto_tile),
mCanTearOff(p.can_tear_off),
mCanMinimize(p.can_minimize),
mCanClose(p.can_close),
mDragOnLeft(p.can_drag_on_left),
mResizable(p.can_resize),
+ mOpenPositioning(p.open_positioning),
+ mSpecifiedLeft(p.specified_left),
+ mSpecifiedBottom(p.specified_bottom),
mMinWidth(p.min_width),
mMinHeight(p.min_height),
mHeaderHeight(p.header_height),
@@ -256,7 +273,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
mMinimizeSignal(NULL)
// mNotificationContext(NULL)
{
- mHandle.bind(this);
// mNotificationContext = new LLFloaterNotificationContext(getHandle());
// Clicks stop here.
@@ -311,9 +327,6 @@ void LLFloater::initFloater(const Params& p)
// Floaters are created in the invisible state
setVisible(FALSE);
- // add self to handle->floater map
- sFloaterMap[mHandle] = this;
-
if (!getParent())
{
gFloaterView->addChild(this);
@@ -464,15 +477,24 @@ void LLFloater::layoutResizeCtrls()
mResizeHandle[3]->setRect(rect);
}
-void LLFloater::enableResizeCtrls(bool enable)
+void LLFloater::enableResizeCtrls(bool enable, bool width, bool height)
{
+ mResizeBar[LLResizeBar::LEFT]->setVisible(enable && width);
+ mResizeBar[LLResizeBar::LEFT]->setEnabled(enable && width);
+
+ mResizeBar[LLResizeBar::TOP]->setVisible(enable && height);
+ mResizeBar[LLResizeBar::TOP]->setEnabled(enable && height);
+
+ mResizeBar[LLResizeBar::RIGHT]->setVisible(enable && width);
+ mResizeBar[LLResizeBar::RIGHT]->setEnabled(enable && width);
+
+ mResizeBar[LLResizeBar::BOTTOM]->setVisible(enable && height);
+ mResizeBar[LLResizeBar::BOTTOM]->setEnabled(enable && height);
+
for (S32 i = 0; i < 4; ++i)
{
- mResizeBar[i]->setVisible(enable);
- mResizeBar[i]->setEnabled(enable);
-
- mResizeHandle[i]->setVisible(enable);
- mResizeHandle[i]->setEnabled(enable);
+ mResizeHandle[i]->setVisible(enable && width && height);
+ mResizeHandle[i]->setEnabled(enable && width && height);
}
}
@@ -514,8 +536,6 @@ LLFloater::~LLFloater()
storeMinimizeStateControl();
setMinimized( FALSE );
- sFloaterMap.erase(mHandle);
-
delete mDragHandle;
for (S32 i = 0; i < 4; i++)
{
@@ -523,7 +543,6 @@ LLFloater::~LLFloater()
delete mResizeHandle[i];
}
- storeRectControl();
setVisible(false); // We're not visible if we're destroyed
storeVisibilityControl();
storeDockStateControl();
@@ -681,15 +700,23 @@ void LLFloater::openFloater(const LLSD& key)
}
else
{
- // AO: setMinimized(FALSE);
-
+ LLFloater* floater_to_stack = LLFloaterReg::getLastFloaterInGroup(mInstanceName);
+ if (!floater_to_stack)
+ {
+ floater_to_stack = LLFloaterReg::getLastFloaterCascading();
+ }
+ applyControlsAndPosition(floater_to_stack);
+
// AO: Always unminimize notecards *HACK*
// TS: scripts too
+
+// setMinimized(FALSE);
if ((strcmp(getName().c_str(),"preview notecard") == 0) ||
(strcmp(getName().c_str(),"preview lsl text") == 0))
{
setMinimized(FALSE);
}
+
setVisibleAndFrontmost(mAutoFocus);
}
@@ -781,12 +808,19 @@ void LLFloater::closeFloater(bool app_quitting)
else
{
setVisible(FALSE);
+ if (!mReuseInstance)
+ {
+ destroy();
+ }
}
}
else
{
setVisible(FALSE); // hide before destroying (so handleVisibilityChange() gets called)
- destroy();
+ if (!mReuseInstance)
+ {
+ destroy();
+ }
}
}
}
@@ -851,45 +885,59 @@ LLMultiFloater* LLFloater::getHost()
return (LLMultiFloater*)mHostHandle.get();
}
-void LLFloater::applySavedVariables()
+void LLFloater::applyControlsAndPosition(LLFloater* other)
{
- applyRectControl();
- applyDockState();
+ if (!applyDockState())
+ {
+ if (!applyRectControl())
+ {
+ applyPositioning(other);
+ }
+ }
applyMinimizedState();
}
-void LLFloater::applyRectControl()
+bool LLFloater::applyRectControl()
{
- // first, center on screen if requested
- if (mOpenCentered)
- {
- center();
- }
+ bool saved_rect = false;
- // override center if we have saved rect control
- // only if we are torn off -Zi
- if (mTornOff && mRectControl.size() > 1)
+ LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName);
+ if (last_in_group && last_in_group != this)
{
+ // other floaters in our group, position ourselves relative to them and don't save the rect
+ mRectControl.clear();
+ mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP;
+ }
+ else if (mRectControl.size() > 1)
+ {
+ // If we have a saved rect, use it
const LLRect& rect = getControlGroup()->getRect(mRectControl);
- if (rect.getWidth() > 0 && rect.getHeight() > 0)
+ saved_rect = rect.notEmpty();
+ if (saved_rect)
{
- translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom);
+ setOrigin(rect.mLeft, rect.mBottom);
+
if (mResizable)
{
reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
}
}
}
+
+ return saved_rect;
}
-void LLFloater::applyDockState()
+bool LLFloater::applyDockState()
{
+ bool docked = false;
+
if (mDocStateControl.size() > 1)
{
- bool dockState = getControlGroup()->getBOOL(mDocStateControl);
- setDocked(dockState);
+ docked = getControlGroup()->getBOOL(mDocStateControl);
+ setDocked(docked);
}
+ return docked;
}
void LLFloater::applyMinimizedState()
@@ -901,6 +949,56 @@ void LLFloater::applyMinimizedState()
}
}
+void LLFloater::applyPositioning(LLFloater* other)
+{
+ // Otherwise position according to the positioning code
+ switch (mOpenPositioning)
+ {
+ case LLFloaterEnums::OPEN_POSITIONING_CENTERED:
+ center();
+ break;
+
+ case LLFloaterEnums::OPEN_POSITIONING_SPECIFIED:
+ {
+ // Translate relative to snap rect
+ setOrigin(mSpecifiedLeft, mSpecifiedBottom);
+ const LLRect& snap_rect = gFloaterView->getSnapRect();
+ translate(snap_rect.mLeft, snap_rect.mBottom);
+ translateIntoRect(snap_rect, FALSE);
+ }
+ break;
+
+ case LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP:
+ case LLFloaterEnums::OPEN_POSITIONING_CASCADING:
+ if (other != NULL && other != this)
+ {
+ stackWith(*other);
+ }
+ else
+ {
+ static const U32 CASCADING_FLOATER_HOFFSET = 0;
+ static const U32 CASCADING_FLOATER_VOFFSET = 0;
+
+ const LLRect& snap_rect = gFloaterView->getSnapRect();
+
+ const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET;
+ const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET;
+
+ S32 rect_height = getRect().getHeight();
+ setOrigin(horizontal_offset, vertical_offset - rect_height);
+
+ translate(snap_rect.mLeft, snap_rect.mBottom);
+ translateIntoRect(snap_rect, FALSE);
+ }
+ break;
+
+ case LLFloaterEnums::OPEN_POSITIONING_NONE:
+ default:
+ // Do nothing
+ break;
+ }
+}
+
void LLFloater::applyTitle()
{
if (!mDragHandle)
@@ -981,7 +1079,9 @@ BOOL LLFloater::canSnapTo(const LLView* other_view)
if (other_view != getParent())
{
const LLFloater* other_floaterp = dynamic_cast(other_view);
- if (other_floaterp && other_floaterp->getSnapTarget() == getHandle() && mDependents.find(other_floaterp->getHandle()) != mDependents.end())
+ if (other_floaterp
+ && other_floaterp->getSnapTarget() == getHandle()
+ && mDependents.find(other_floaterp->getHandle()) != mDependents.end())
{
// this is a dependent that is already snapped to us, so don't snap back to it
return FALSE;
@@ -1013,9 +1113,10 @@ void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)
const LLRect old_rect = getRect();
LLView::handleReshape(new_rect, by_user);
- if (by_user)
+ if (by_user && !isMinimized())
{
storeRectControl();
+ mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE;
}
// if not minimized, adjust all snapped dependents to new shape
@@ -1075,7 +1176,7 @@ void LLFloater::setMinimized(BOOL minimize)
if (minimize == mMinimized) return;
- if(mMinimizeSignal)
+ if (mMinimizeSignal)
{
(*mMinimizeSignal)(this, LLSD(minimize));
}
@@ -1129,10 +1230,6 @@ void LLFloater::setMinimized(BOOL minimize)
mButtonsEnabled[BUTTON_RESTORE] = TRUE;
}
- if (mDragHandle)
- {
- mDragHandle->setVisible(TRUE);
- }
setBorderVisible(TRUE);
for(handle_set_iter_t dependent_it = mDependents.begin();
@@ -1296,19 +1393,9 @@ void LLFloater::setIsChrome(BOOL is_chrome)
mButtons[BUTTON_CLOSE]->setToolTip(LLStringExplicit(getButtonTooltip(Params(), BUTTON_CLOSE, is_chrome)));
}
- // no titles displayed on "chrome" floaters
- if (mDragHandle)
- mDragHandle->setTitleVisible(!is_chrome);
-
LLPanel::setIsChrome(is_chrome);
}
-void LLFloater::setTitleVisible(bool visible)
-{
- if (mDragHandle)
- mDragHandle->setTitleVisible(visible);
-}
-
// Change the draw style to account for the foreground state.
void LLFloater::setForeground(BOOL front)
{
@@ -1396,7 +1483,10 @@ void LLFloater::moveResizeHandlesToFront()
BOOL LLFloater::isFrontmost()
{
- return gFloaterView && gFloaterView->getFrontmost() == this && getVisible();
+ LLFloaterView* floater_view = getParentByType();
+ return getVisible()
+ && (floater_view
+ && floater_view->getFrontmost() == this);
}
void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition)
@@ -1469,6 +1559,7 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
if(offerClickToButton(x, y, mask, BUTTON_CLOSE)) return TRUE;
if(offerClickToButton(x, y, mask, BUTTON_RESTORE)) return TRUE;
if(offerClickToButton(x, y, mask, BUTTON_TEAR_OFF)) return TRUE;
+ if(offerClickToButton(x, y, mask, BUTTON_DOCK)) return TRUE;
// Otherwise pass to drag handle for movement
return mDragHandle->handleMouseDown(x, y, mask);
@@ -1574,6 +1665,13 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock)
{
mDocked = docked;
mButtonsEnabled[BUTTON_DOCK] = !mDocked;
+
+ if (mDocked)
+ {
+ setMinimized(FALSE);
+ mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE;
+ }
+
updateTitleButtons();
storeDockStateControl();
@@ -1668,18 +1766,17 @@ void LLFloater::onClickHelp( LLFloater* self )
LLFloater* LLFloater::getClosableFloaterFromFocus()
{
LLFloater* focused_floater = NULL;
-
- handle_map_iter_t iter;
- for(iter = sFloaterMap.begin(); iter != sFloaterMap.end(); ++iter)
+ LLInstanceTracker::instance_iter it = beginInstances();
+ LLInstanceTracker::instance_iter end_it = endInstances();
+ for (; it != end_it; ++it)
{
- focused_floater = iter->second;
- if (focused_floater->hasFocus())
+ if (it->hasFocus())
{
break;
}
}
- if (iter == sFloaterMap.end())
+ if (it == endInstances())
{
// nothing found, return
return NULL;
@@ -1828,7 +1925,7 @@ void LLFloater::draw()
{
drawChild(mButtons[i]);
}
- drawChild(mDragHandle);
+ drawChild(mDragHandle, 0, 0, TRUE);
}
else
{
@@ -1945,6 +2042,12 @@ void LLFloater::setCanDrag(BOOL can_drag)
}
}
+bool LLFloater::getCanDrag()
+{
+ return mDragHandle->getEnabled();
+}
+
+
void LLFloater::updateTitleButtons()
{
static LLUICachedControl floater_close_box_size ("UIFloaterCloseBoxSize", 0);
@@ -2166,8 +2269,15 @@ LLFloaterView::LLFloaterView (const Params& p)
// By default, adjust vertical.
void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- S32 old_width = getRect().getWidth();
- S32 old_height = getRect().getHeight();
+ S32 old_right = mLastSnapRect.mRight;
+ S32 old_top = mLastSnapRect.mTop;
+
+ LLView::reshape(width, height, called_from_parent);
+
+ S32 new_right = getSnapRect().mRight;
+ S32 new_top = getSnapRect().mTop;
+
+ mLastSnapRect = getSnapRect();
for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
{
@@ -2175,66 +2285,48 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)
LLFloater* floaterp = (LLFloater*)viewp;
if (floaterp->isDependent())
{
- // dependents use same follow flags as their "dependee"
+ // dependents are moved with their "dependee"
continue;
}
- // Make if follow the edge it is closest to
- U32 follow_flags = 0x0;
-
- if (floaterp->isMinimized())
- {
- follow_flags |= (FOLLOWS_LEFT | FOLLOWS_TOP);
- }
- else
+ if (!floaterp->isMinimized())
{
LLRect r = floaterp->getRect();
// Compute absolute distance from each edge of screen
S32 left_offset = llabs(r.mLeft - 0);
- S32 right_offset = llabs(old_width - r.mRight);
+ S32 right_offset = llabs(old_right - r.mRight);
- S32 top_offset = llabs(old_height - r.mTop);
+ S32 top_offset = llabs(old_top - r.mTop);
S32 bottom_offset = llabs(r.mBottom - 0);
+ S32 translate_x = 0;
+ S32 translate_y = 0;
- if (left_offset < right_offset)
+ if (left_offset > right_offset)
{
- follow_flags |= FOLLOWS_LEFT;
- }
- else
- {
- follow_flags |= FOLLOWS_RIGHT;
+ translate_x = new_right - old_right;
}
- // "No vertical adjustment" usually means that the bottom of the view
- // has been pushed up or down. Hence we want the floaters to follow
- // the top.
if (top_offset < bottom_offset)
{
- follow_flags |= FOLLOWS_TOP;
+ translate_y = new_top - old_top;
}
- else
+
+ // don't reposition immovable floaters
+ if (floaterp->getCanDrag())
{
- follow_flags |= FOLLOWS_BOTTOM;
+ floaterp->translate(translate_x, translate_y);
}
- }
-
- floaterp->setFollows(follow_flags);
-
- //RN: all dependent floaters copy follow behavior of "parent"
- for(LLFloater::handle_set_iter_t dependent_it = floaterp->mDependents.begin();
- dependent_it != floaterp->mDependents.end(); ++dependent_it)
- {
- LLFloater* dependent_floaterp = dependent_it->get();
- if (dependent_floaterp)
+ BOOST_FOREACH(LLHandle dependent_floater, floaterp->mDependents)
{
- dependent_floaterp->setFollows(follow_flags);
+ if (dependent_floater.get())
+ {
+ dependent_floater.get()->translate(translate_x, translate_y);
+ }
}
}
}
-
- LLView::reshape(width, height, called_from_parent);
}
@@ -2575,6 +2667,52 @@ void LLFloaterView::closeAllChildren(bool app_quitting)
}
}
+void LLFloaterView::hiddenFloaterClosed(LLFloater* floater)
+{
+ for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end();
+ it != end_it;
+ ++it)
+ {
+ if (it->first.get() == floater)
+ {
+ it->second.disconnect();
+ mHiddenFloaters.erase(it);
+ break;
+ }
+ }
+}
+
+void LLFloaterView::hideAllFloaters()
+{
+ child_list_t child_list = *(getChildList());
+
+ for (child_list_iter_t it = child_list.begin(); it != child_list.end(); ++it)
+ {
+ LLFloater* floaterp = dynamic_cast(*it);
+ if (floaterp && floaterp->getVisible())
+ {
+ floaterp->setVisible(false);
+ boost::signals2::connection connection = floaterp->mCloseSignal.connect(boost::bind(&LLFloaterView::hiddenFloaterClosed, this, floaterp));
+ mHiddenFloaters.push_back(std::make_pair(floaterp->getHandle(), connection));
+ }
+ }
+}
+
+void LLFloaterView::showHiddenFloaters()
+{
+ for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end();
+ it != end_it;
+ ++it)
+ {
+ LLFloater* floaterp = it->first.get();
+ if (floaterp)
+ {
+ floaterp->setVisible(true);
+ }
+ it->second.disconnect();
+ }
+ mHiddenFloaters.clear();
+}
BOOL LLFloaterView::allChildrenClosed()
{
@@ -2608,6 +2746,12 @@ void LLFloaterView::shiftFloaters(S32 x_offset, S32 y_offset)
void LLFloaterView::refresh()
{
+ LLRect snap_rect = getSnapRect();
+ if (snap_rect != mLastSnapRect)
+ {
+ reshape(getRect().getWidth(), getRect().getHeight(), TRUE);
+ }
+
// Constrain children to be entirely on the screen
for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
{
@@ -2673,7 +2817,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
}
// move window fully onscreen
- if (floater->translateIntoRect( getLocalRect(), allow_partial_outside ))
+ if (floater->translateIntoRect( getSnapRect(), allow_partial_outside ))
{
floater->clearSnapTarget();
}
@@ -2903,7 +3047,6 @@ void LLFloater::setInstanceName(const std::string& name)
{
mMinimizeStateControl = LLFloaterReg::declareMinimizeStateControl(ctrl_name);
}
-
}
}
@@ -2950,6 +3093,9 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
// control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
LLPanel::initFromParams(p);
+ // override any follows flags
+ setFollows(FOLLOWS_NONE);
+
mTitle = p.title;
mShortTitle = p.short_title;
applyTitle();
@@ -2965,8 +3111,11 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
mHeaderHeight = p.header_height;
mLegacyHeaderHeight = p.legacy_header_height;
mSingleInstance = p.single_instance;
- mAutoTile = p.auto_tile;
- mOpenCentered = p.open_centered;
+ mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance;
+
+ mOpenPositioning = p.open_positioning;
+ mSpecifiedLeft = p.specified_left;
+ mSpecifiedBottom = p.specified_bottom;
// ## Zi: Optional Drop Shadows
// we do this here because the values in the constructor get ignored, probably due to
@@ -2981,7 +3130,6 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
{
mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set
}
-
if(p.save_dock_state)
{
mDocStateControl = "t"; // flag to build mDocStateControl name once mInstanceName is set
@@ -2992,13 +3140,18 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
// open callback
if (p.open_callback.isProvided())
{
- mOpenSignal.connect(initCommitCallback(p.open_callback));
+ setOpenCallback(initCommitCallback(p.open_callback));
}
// close callback
if (p.close_callback.isProvided())
{
setCloseCallback(initCommitCallback(p.close_callback));
}
+
+ if (mDragHandle)
+ {
+ mDragHandle->setTitleVisible(p.show_title);
+ }
}
boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_t::slot_type& cb )
@@ -3007,6 +3160,11 @@ boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_
return mMinimizeSignal->connect(cb);
}
+boost::signals2::connection LLFloater::setOpenCallback( const commit_signal_t::slot_type& cb )
+{
+ return mOpenSignal.connect(cb);
+}
+
boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::slot_type& cb )
{
return mCloseSignal.connect(cb);
@@ -3051,7 +3209,9 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
return FALSE;
}
- parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName());
+ Params referenced_params;
+ parser.readXUI(referenced_xml, referenced_params, LLUICtrlFactory::getInstance()->getCurFileName());
+ params.fillFrom(referenced_params);
// add children using dimensions from referenced xml for consistent layout
setShape(params.rect);
@@ -3241,7 +3401,6 @@ void LLFloater::stackWith(LLFloater& other)
next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight());
- mRectControl.clear(); // don't save rect of stacked floaters
setShape(next_rect);
}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 7995de9409..389be3ed0c 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -35,6 +35,7 @@
#include "lluuid.h"
//#include "llnotificationsutil.h"
#include
+#include
class LLDragHandle;
class LLResizeHandle;
@@ -59,11 +60,35 @@ const BOOL CLOSE_NO = FALSE;
const BOOL ADJUST_VERTICAL_YES = TRUE;
const BOOL ADJUST_VERTICAL_NO = FALSE;
-class LLFloater : public LLPanel
+namespace LLFloaterEnums
{
-friend class LLFloaterView;
-friend class LLFloaterReg;
-friend class LLMultiFloater;
+ enum EOpenPositioning
+ {
+ OPEN_POSITIONING_NONE,
+ OPEN_POSITIONING_CASCADING,
+ OPEN_POSITIONING_CASCADE_GROUP,
+ OPEN_POSITIONING_CENTERED,
+ OPEN_POSITIONING_SPECIFIED,
+ OPEN_POSITIONING_COUNT
+ };
+}
+
+namespace LLInitParam
+{
+ template<>
+ struct TypeValues : public TypeValuesHelper
+ {
+ static void declareValues();
+ };
+}
+
+
+class LLFloater : public LLPanel, public LLInstanceTracker
+{
+ friend class LLFloaterView;
+ friend class LLFloaterReg;
+ friend class LLMultiFloater;
+
public:
struct KeyCompare
{
@@ -95,7 +120,7 @@ public:
short_title;
Optional single_instance,
- auto_tile,
+ reuse_instance,
can_resize,
can_minimize,
can_close,
@@ -106,7 +131,13 @@ public:
save_visibility,
save_dock_state,
can_dock,
- open_centered;
+ show_title;
+
+ Optional open_positioning;
+ Optional specified_left;
+ Optional specified_bottom;
+
+
Optional header_height,
legacy_header_height; // HACK see initFromXML()
@@ -126,6 +157,8 @@ public:
Optional open_callback,
close_callback;
+
+ Ignored follows;
Params();
};
@@ -145,6 +178,7 @@ public:
bool buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL);
boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb );
+ boost::signals2::connection setOpenCallback( const commit_signal_t::slot_type& cb );
boost::signals2::connection setCloseCallback( const commit_signal_t::slot_type& cb );
void initFromParams(const LLFloater::Params& p);
@@ -181,7 +215,6 @@ public:
void setShortTitle( const std::string& short_title );
std::string getShortTitle() const;
void setHideOnMinimize(bool hide);
- void setTitleVisible(bool visible);
virtual void setMinimized(BOOL b);
void moveResizeHandlesToFront();
void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE);
@@ -205,6 +238,7 @@ public:
void setCanTearOff(BOOL can_tear_off);
virtual void setCanResize(BOOL can_resize);
void setCanDrag(BOOL can_drag);
+ bool getCanDrag();
void setHost(LLMultiFloater* host);
BOOL isResizable() const { return mResizable; }
void setResizeLimits( S32 min_width, S32 min_height );
@@ -253,7 +287,7 @@ public:
void clearSnapTarget() { mSnappedTo.markDead(); }
LLHandle getSnapTarget() const { return mSnappedTo; }
- LLHandle getHandle() const { return mHandle; }
+ LLHandle getHandle() const { return getDerivedHandle(); }
const LLSD& getKey() { return mKey; }
virtual bool matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); }
@@ -267,8 +301,6 @@ public:
virtual void setTornOff(bool torn_off) { mTornOff = torn_off; }
- void stackWith(LLFloater& other);
-
// Return a closeable floater, if any, given the current focus.
static LLFloater* getClosableFloaterFromFocus();
@@ -292,16 +324,22 @@ public:
void updateTransparency(ETypeTransparency transparency_type);
-protected:
- virtual void applySavedVariables();
+ void enableResizeCtrls(bool enable, bool width = true, bool height = true);
- void applyRectControl();
- void applyDockState();
- void applyMinimizedState();
+ bool isPositioning(LLFloaterEnums::EOpenPositioning p) const { return (p == mOpenPositioning); }
+protected:
+ void applyControlsAndPosition(LLFloater* other);
+
+ void stackWith(LLFloater& other);
+
+ virtual bool applyRectControl();
+ bool applyDockState();
+ void applyPositioning(LLFloater* other);
void storeRectControl();
void storeVisibilityControl();
void storeDockStateControl();
void storeMinimizeStateControl();
+ void applyMinimizedState();
void setKey(const LLSD& key);
void setInstanceName(const std::string& name);
@@ -343,7 +381,6 @@ private:
BOOL offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index);
void addResizeCtrls();
void layoutResizeCtrls();
- void enableResizeCtrls(bool enable);
void addDragHandle();
void layoutDragHandle(); // repair layout
@@ -382,8 +419,8 @@ private:
LLUIString mShortTitle;
BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater
+ bool mReuseInstance; // true if we want to hide the floater when we close it instead of destroying it
std::string mInstanceName; // Store the instance name so we can remove ourselves from the list
- BOOL mAutoTile; // TRUE if placement of new instances tiles
BOOL mDropShadow; // ## Zi: Optional Drop Shadows
BOOL mCanTearOff;
@@ -391,8 +428,11 @@ private:
BOOL mCanClose;
BOOL mDragOnLeft;
BOOL mResizable;
- bool mOpenCentered;
bool mHideOnMinimize;
+
+ LLFloaterEnums::EOpenPositioning mOpenPositioning;
+ S32 mSpecifiedLeft;
+ S32 mSpecifiedBottom;
S32 mMinWidth;
S32 mMinHeight;
@@ -431,18 +471,9 @@ private:
typedef void(*click_callback)(LLFloater*);
static click_callback sButtonCallbacks[BUTTON_COUNT];
- typedef std::map, LLFloater*> handle_map_t;
- typedef std::map, LLFloater*>::iterator handle_map_iter_t;
- static handle_map_t sFloaterMap;
-
- std::vector > mMinimizedHiddenChildren;
-
BOOL mHasBeenDraggedWhileMinimized;
S32 mPreviousMinimizedBottom;
S32 mPreviousMinimizedLeft;
-
-// LLFloaterNotificationContext* mNotificationContext;
- LLRootHandle mHandle;
};
@@ -490,6 +521,10 @@ public:
BOOL allChildrenClosed();
void shiftFloaters(S32 x_offset, S32 y_offset);
+ void hideAllFloaters();
+ void showHiddenFloaters();
+
+
LLFloater* getFrontmost() const;
LLFloater* getBackmost() const;
LLFloater* getParentFloater(LLView* viewp) const;
@@ -504,11 +539,16 @@ public:
void setFloaterSnapView(LLHandle snap_view) {mSnapView = snap_view; }
private:
+ void hiddenFloaterClosed(LLFloater* floater);
+
+ LLRect mLastSnapRect;
LLHandle mSnapView;
BOOL mFocusCycleMode;
S32 mSnapOffsetBottom;
S32 mSnapOffsetRight;
S32 mMinimizePositionVOffset;
+ typedef std::vector, boost::signals2::connection> > hidden_floaters_t;
+ hidden_floaters_t mHiddenFloaters;
};
//
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index b7f39f5340..5404e71c6e 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -64,19 +64,57 @@ void LLFloaterReg::add(const std::string& name, const std::string& filename, con
//static
LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name)
{
- LLRect rect;
const std::string& groupname = sGroupMap[name];
if (!groupname.empty())
{
instance_list_t& list = sInstanceMap[groupname];
if (!list.empty())
{
- return list.back();
+ for (instance_list_t::reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter)
+ {
+ LLFloater* inst = *iter;
+
+ if (inst->getVisible() && !inst->isMinimized())
+ {
+ return inst;
+ }
+ }
}
}
return NULL;
}
+LLFloater* LLFloaterReg::getLastFloaterCascading()
+{
+ LLRect candidate_rect;
+ candidate_rect.mTop = 100000;
+ LLFloater* candidate_floater = NULL;
+
+ std::map::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
+ for( ; it != it_end; ++it)
+ {
+ const std::string& group_name = it->second;
+
+ instance_list_t& instances = sInstanceMap[group_name];
+
+ for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
+ {
+ LLFloater* inst = *iter;
+
+ if (inst->getVisible() && inst->isPositioning(LLFloaterEnums::OPEN_POSITIONING_CASCADING))
+ {
+ if (candidate_rect.mTop > inst->getRect().mTop)
+ {
+ candidate_floater = inst;
+ candidate_rect = inst->getRect();
+ }
+ }
+ }
+ }
+
+ return candidate_floater;
+}
+
//static
LLFloater* LLFloaterReg::findInstance(const std::string& name, const LLSD& key)
{
@@ -112,21 +150,24 @@ LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)
if (!groupname.empty())
{
instance_list_t& list = sInstanceMap[groupname];
- int index = list.size();
res = build_func(key);
-
+ if (!res)
+ {
+ llwarns << "Failed to build floater type: '" << name << "'." << llendl;
+ return NULL;
+ }
bool success = res->buildFromFile(xui_file, NULL);
if (!success)
{
llwarns << "Failed to build floater type: '" << name << "'." << llendl;
return NULL;
}
-
+
// Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe
if (res->mKey.isUndefined())
{
- res->mKey = key;
+ res->mKey = key;
}
res->setInstanceName(name);
@@ -142,20 +183,13 @@ LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)
res->setHideOnMinimize(true);
}
- res->applySavedVariables(); // Can't apply rect and dock state until setting instance name
- if (res->mAutoTile && !res->getHost() && index > 0)
- {
- LLFloater* last_floater = getLastFloaterInGroup(groupname);
- if (last_floater)
- {
- res->stackWith(*last_floater);
- gFloaterView->adjustToFitScreen(res, true);
- }
- }
- else
- {
- gFloaterView->adjustToFitScreen(res, false);
- }
+
+ LLFloater *last_floater = (list.empty() ? NULL : list.back());
+
+ res->applyControlsAndPosition(last_floater);
+
+ gFloaterView->adjustToFitScreen(res, false);
+
list.push_back(res);
}
}
@@ -444,70 +478,71 @@ void LLFloaterReg::registerControlVariables()
}
}
-// Callbacks
-
-// static
-// Call once (i.e use for init callbacks)
-void LLFloaterReg::initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname)
+//static
+void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key)
{
- // Get the visibility control name for the floater
- std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
- // Set the control value to the floater visibility control (Sets the value as well)
- ctrl->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
-}
+ //
+ // Floaters controlled by the toolbar behave a bit differently from others.
+ // Namely they have 3-4 states as defined in the design wiki page here:
+ // https://wiki.lindenlab.com/wiki/FUI_Button_states
+ //
+ // The basic idea is this:
+ // * If the target floater is minimized, this button press will un-minimize it.
+ // * Else if the target floater is closed open it.
+ // * Else if the target floater does not have focus, give it focus.
+ // * Also, if it is not on top, bring it forward when focus is given.
+ // * Else the target floater is open, close it.
+ //
-// callback args may use "floatername.key" format
-static void parse_name_key(std::string& name, LLSD& key)
-{
- std::string instname = name;
- std::size_t dotpos = instname.find(".");
- if (dotpos != std::string::npos)
+ std::string name = sdname.asString();
+ LLFloater* instance = getInstance(name, key);
+
+ if (!instance)
{
- name = instname.substr(0, dotpos);
- key = LLSD(instname.substr(dotpos+1, std::string::npos));
+ lldebugs << "Unable to get instance of floater '" << name << "'" << llendl;
+ }
+ else if (instance->isMinimized())
+ {
+ instance->setMinimized(FALSE);
+ instance->setVisibleAndFrontmost();
+ }
+ else if (!instance->isShown())
+ {
+ instance->openFloater(key);
+ instance->setVisibleAndFrontmost();
+ }
+ else if (!instance->isFrontmost())
+ {
+ instance->setVisibleAndFrontmost();
+ }
+ else
+ {
+ instance->closeFloater();
}
}
-//static
-void LLFloaterReg::showFloaterInstance(const LLSD& sdname)
+// static
+U32 LLFloaterReg::getVisibleFloaterInstanceCount()
{
- LLSD key;
- std::string name = sdname.asString();
- parse_name_key(name, key);
- showInstance(name, key, TRUE);
-}
-//static
-void LLFloaterReg::hideFloaterInstance(const LLSD& sdname)
-{
- LLSD key;
- std::string name = sdname.asString();
- parse_name_key(name, key);
- hideInstance(name, key);
-}
-//static
-void LLFloaterReg::toggleFloaterInstance(const LLSD& sdname)
-{
- LLSD key;
- std::string name = sdname.asString();
- parse_name_key(name, key);
- toggleInstance(name, key);
-}
+ U32 count = 0;
-//static
-bool LLFloaterReg::floaterInstanceVisible(const LLSD& sdname)
-{
- LLSD key;
- std::string name = sdname.asString();
- parse_name_key(name, key);
- return instanceVisible(name, key);
-}
+ std::map::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
+ for( ; it != it_end; ++it)
+ {
+ const std::string& group_name = it->second;
-//static
-bool LLFloaterReg::floaterInstanceMinimized(const LLSD& sdname)
-{
- LLSD key;
- std::string name = sdname.asString();
- parse_name_key(name, key);
- LLFloater* instance = findInstance(name, key);
- return LLFloater::isShown(instance);
+ instance_list_t& instances = sInstanceMap[group_name];
+
+ for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
+ {
+ LLFloater* inst = *iter;
+
+ if (inst->getVisible() && !inst->isMinimized())
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
}
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index c3830a168d..804b441688 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -99,6 +99,7 @@ public:
// Helpers
static LLFloater* getLastFloaterInGroup(const std::string& name);
+ static LLFloater* getLastFloaterCascading();
// Find / get (create) / remove / destroy
static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD());
@@ -137,12 +138,7 @@ public:
static void registerControlVariables();
// Callback wrappers
- static void initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname);
- static void showFloaterInstance(const LLSD& sdname);
- static void hideFloaterInstance(const LLSD& sdname);
- static void toggleFloaterInstance(const LLSD& sdname);
- static bool floaterInstanceVisible(const LLSD& sdname);
- static bool floaterInstanceMinimized(const LLSD& sdname);
+ static void toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key = LLSD());
// Typed find / get / show
template
@@ -165,6 +161,7 @@ public:
static void blockShowFloaters(bool value) { sBlockShowFloaters = value;}
+ static U32 getVisibleFloaterInstanceCount();
};
#endif
diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h
index 8c000eee48..37c657dd92 100644
--- a/indra/llui/llhandle.h
+++ b/indra/llui/llhandle.h
@@ -28,17 +28,18 @@
#define LLHANDLE_H
#include "llpointer.h"
+#include
+#include
-template
class LLTombStone : public LLRefCount
{
public:
- LLTombStone(T* target = NULL) : mTarget(target) {}
+ LLTombStone(void* target = NULL) : mTarget(target) {}
- void setTarget(T* target) { mTarget = target; }
- T* getTarget() const { return mTarget; }
+ void setTarget(void* target) { mTarget = target; }
+ void* getTarget() const { return mTarget; }
private:
- T* mTarget;
+ mutable void* mTarget;
};
// LLHandles are used to refer to objects whose lifetime you do not control or influence.
@@ -53,13 +54,15 @@ private:
template
class LLHandle
{
+ template friend class LLHandle;
+ template friend class LLHandleProvider;
public:
LLHandle() : mTombStone(getDefaultTombStone()) {}
- const LLHandle& operator =(const LLHandle& other)
- {
- mTombStone = other.mTombStone;
- return *this;
- }
+
+ template
+ LLHandle(const LLHandle& other, typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0)
+ : mTombStone(other.mTombStone)
+ {}
bool isDead() const
{
@@ -73,7 +76,7 @@ public:
T* get() const
{
- return mTombStone->getTarget();
+ return reinterpret_cast(mTombStone->getTarget());
}
friend bool operator== (const LLHandle& lhs, const LLHandle& rhs)
@@ -94,12 +97,13 @@ public:
}
protected:
- LLPointer > mTombStone;
+ LLPointer mTombStone;
private:
- static LLPointer >& getDefaultTombStone()
+ typedef T* pointer_t;
+ static LLPointer& getDefaultTombStone()
{
- static LLPointer > sDefaultTombStone = new LLTombStone;
+ static LLPointer sDefaultTombStone = new LLTombStone;
return sDefaultTombStone;
}
};
@@ -108,23 +112,26 @@ template
class LLRootHandle : public LLHandle
{
public:
+ typedef LLRootHandle self_t;
+ typedef LLHandle base_t;
+
LLRootHandle(T* object) { bind(object); }
LLRootHandle() {};
~LLRootHandle() { unbind(); }
- // this is redundant, since a LLRootHandle *is* an LLHandle
- LLHandle getHandle() { return LLHandle(*this); }
+ // this is redundant, since an LLRootHandle *is* an LLHandle
+ //LLHandle getHandle() { return LLHandle(*this); }
void bind(T* object)
{
// unbind existing tombstone
if (LLHandle::mTombStone.notNull())
{
- if (LLHandle::mTombStone->getTarget() == object) return;
+ if (LLHandle::mTombStone->getTarget() == (void*)object) return;
LLHandle::mTombStone->setTarget(NULL);
}
// tombstone reference counted, so no paired delete
- LLHandle::mTombStone = new LLTombStone(object);
+ LLHandle::mTombStone = new LLTombStone((void*)object);
}
void unbind()
@@ -142,6 +149,15 @@ private:
template
class LLHandleProvider
{
+public:
+ LLHandle getHandle() const
+ {
+ // perform lazy binding to avoid small tombstone allocations for handle
+ // providers whose handles are never referenced
+ mHandle.bind(static_cast(const_cast* >(this)));
+ return mHandle;
+ }
+
protected:
typedef LLHandle handle_type_t;
LLHandleProvider()
@@ -149,16 +165,17 @@ protected:
// provided here to enforce T deriving from LLHandleProvider
}
- LLHandle getHandle()
- {
- // perform lazy binding to avoid small tombstone allocations for handle
- // providers whose handles are never referenced
- mHandle.bind(static_cast(this));
- return mHandle;
+ template
+ LLHandle getDerivedHandle(typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) const
+ {
+ LLHandle downcast_handle;
+ downcast_handle.mTombStone = getHandle().mTombStone;
+ return downcast_handle;
}
+
private:
- LLRootHandle mHandle;
+ mutable LLRootHandle mHandle;
};
#endif
diff --git a/indra/llui/llhelp.h b/indra/llui/llhelp.h
index 83317bd03c..1726347a78 100644
--- a/indra/llui/llhelp.h
+++ b/indra/llui/llhelp.h
@@ -32,6 +32,7 @@ class LLHelp
{
public:
virtual void showTopic(const std::string &topic) = 0;
+ virtual std::string getURL(const std::string &topic) = 0;
// return default (fallback) topic name suitable for showTopic()
virtual std::string defaultTopic() = 0;
// return topic to use before the user logs in
diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h
index 0376c7cd64..ac34015393 100644
--- a/indra/llui/llkeywords.h
+++ b/indra/llui/llkeywords.h
@@ -51,8 +51,7 @@ public:
* - TWO_SIDED_DELIMITER are for delimiters that end with a different delimiter than they open with.
* - DOUBLE_QUOTATION_MARKS are for delimiting areas using the same delimiter to open and close.
*/
- // typedef enum TOKEN_TYPE
- enum TOKEN_TYPE // That typedef makes GCC >= 4.6 really angry, rightfully so.
+ enum TOKEN_TYPE
{
WORD,
LINE,
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index a250404292..0e7060e22c 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -47,6 +47,19 @@ void LLLayoutStack::OrientationNames::declareValues()
//
// LLLayoutPanel
//
+LLLayoutPanel::Params::Params()
+: expanded_min_dim("expanded_min_dim", 0),
+ min_dim("min_dim", 0),
+ max_dim("max_dim", S32_MAX),
+ user_resize("user_resize", true),
+ auto_resize("auto_resize", true)
+{
+ addSynonym(min_dim, "min_width");
+ addSynonym(min_dim, "min_height");
+ addSynonym(max_dim, "max_width");
+ addSynonym(max_dim, "max_height");
+}
+
LLLayoutPanel::LLLayoutPanel(const Params& p)
: LLPanel(p),
mExpandedMinDimSpecified(false),
@@ -58,7 +71,9 @@ LLLayoutPanel::LLLayoutPanel(const Params& p)
mCollapsed(FALSE),
mCollapseAmt(0.f),
mVisibleAmt(1.f), // default to fully visible
- mResizeBar(NULL)
+ mResizeBar(NULL),
+ mFractionalSize(0.f),
+ mOrientation(LLLayoutStack::HORIZONTAL)
{
// Set the expanded min dim if it is provided, otherwise it gets the p.min_dim value
if (p.expanded_min_dim.isProvided())
@@ -88,9 +103,22 @@ LLLayoutPanel::~LLLayoutPanel()
mResizeBar = NULL;
}
-F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation)
+void LLLayoutPanel::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- if (orientation == LLLayoutStack::HORIZONTAL)
+ if (mOrientation == LLLayoutStack::HORIZONTAL)
+ {
+ mFractionalSize += width - llround(mFractionalSize);
+ }
+ else
+ {
+ mFractionalSize += height - llround(mFractionalSize);
+ }
+ LLPanel::reshape(width, height, called_from_parent);
+}
+
+F32 LLLayoutPanel::getCollapseFactor()
+{
+ if (mOrientation == LLLayoutStack::HORIZONTAL)
{
F32 collapse_amt =
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)getRelevantMinDim() / (F32)llmax(1, getRect().getWidth()));
@@ -149,11 +177,11 @@ void LLLayoutStack::draw()
// scale clipping rectangle by visible amount
if (mOrientation == HORIZONTAL)
{
- clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor(mOrientation));
+ clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
}
else
{
- clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor(mOrientation));
+ clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
}
LLPanel* panelp = (*panel_it);
@@ -193,36 +221,15 @@ bool LLLayoutStack::addChild(LLView* child, S32 tab_group)
LLLayoutPanel* panelp = dynamic_cast(child);
if (panelp)
{
+ panelp->mFractionalSize = (mOrientation == HORIZONTAL)
+ ? panelp->getRect().getWidth()
+ : panelp->getRect().getHeight();
+ panelp->setOrientation(mOrientation);
mPanels.push_back(panelp);
}
return LLView::addChild(child, tab_group);
}
-
-S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
-{
- // if we are spanning our children (crude upward propagation of size)
- // then don't enforce our size on our children
- if (mOrientation == HORIZONTAL)
- {
- cur_height = llmax(mMinHeight, getRect().getHeight());
- }
-
- return cur_height;
-}
-
-S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
-{
- // if we are spanning our children (crude upward propagation of size)
- // then don't enforce our size on our children
- if (mOrientation == VERTICAL)
- {
- cur_width = llmax(mMinWidth, getRect().getWidth());
- }
-
- return cur_width;
-}
-
void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front)
{
LLLayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move);
@@ -317,9 +324,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
createResizeBars();
// calculate current extents
- S32 total_width = 0;
- S32 total_height = 0;
+ F32 total_size = 0.f;
+ //
+ // animate visibility
+ //
e_panel_list_t::iterator panel_it;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
@@ -361,179 +370,110 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
}
}
- if (panelp->mCollapsed)
- {
- panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
- }
- else
- {
- panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
- }
+ F32 collapse_state = panelp->mCollapsed ? 1.f : 0.f;
+ panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant));
- if (mOrientation == HORIZONTAL)
+ total_size += panelp->mFractionalSize * panelp->getCollapseFactor();
+ // want n-1 panel gaps for n panels
+ if (panel_it != mPanels.begin())
{
- // enforce minimize size constraint by default
- if (panelp->getRect().getWidth() < panelp->getRelevantMinDim())
- {
- panelp->reshape(panelp->getRelevantMinDim(), panelp->getRect().getHeight());
- }
- total_width += llround(panelp->getRect().getWidth() * panelp->getCollapseFactor(mOrientation));
- // want n-1 panel gaps for n panels
- if (panel_it != mPanels.begin())
- {
- total_width += mPanelSpacing;
- }
- }
- else //VERTICAL
- {
- // enforce minimize size constraint by default
- if (panelp->getRect().getHeight() < panelp->getRelevantMinDim())
- {
- panelp->reshape(panelp->getRect().getWidth(), panelp->getRelevantMinDim());
- }
- total_height += llround(panelp->getRect().getHeight() * panelp->getCollapseFactor(mOrientation));
- if (panel_it != mPanels.begin())
- {
- total_height += mPanelSpacing;
- }
+ total_size += mPanelSpacing;
}
}
S32 num_resizable_panels = 0;
- S32 shrink_headroom_available = 0;
- S32 shrink_headroom_total = 0;
+ F32 shrink_headroom_available = 0.f;
+ F32 shrink_headroom_total = 0.f;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
+ LLLayoutPanel* panelp = (*panel_it);
+
// panels that are not fully visible do not count towards shrink headroom
- if ((*panel_it)->getCollapseFactor(mOrientation) < 1.f)
+ if (panelp->getCollapseFactor() < 1.f)
{
continue;
}
- S32 relevant_dimension = (mOrientation == HORIZONTAL) ? (*panel_it)->getRect().getWidth() : (*panel_it)->getRect().getHeight();
- S32 relevant_min = (*panel_it)->getRelevantMinDim();
+ F32 cur_size = panelp->mFractionalSize;
+ F32 min_size = (F32)panelp->getRelevantMinDim();
// if currently resizing a panel or the panel is flagged as not automatically resizing
// only track total available headroom, but don't use it for automatic resize logic
- if ((*panel_it)->mResizeBar->hasMouseCapture()
- || (!(*panel_it)->mAutoResize
+ if (panelp->mResizeBar->hasMouseCapture()
+ || (!panelp->mAutoResize
&& !force_resize))
{
- shrink_headroom_total += relevant_dimension - relevant_min;
+ shrink_headroom_total += cur_size - min_size;
}
else
{
num_resizable_panels++;
- shrink_headroom_available += relevant_dimension - relevant_min;
- shrink_headroom_total += relevant_dimension - relevant_min;
+ shrink_headroom_available += cur_size - min_size;
+ shrink_headroom_total += cur_size - min_size;
}
}
// calculate how many pixels need to be distributed among layout panels
// positive means panels need to grow, negative means shrink
- S32 pixels_to_distribute;
- if (mOrientation == HORIZONTAL)
- {
- pixels_to_distribute = getRect().getWidth() - total_width;
- }
- else //VERTICAL
- {
- pixels_to_distribute = getRect().getHeight() - total_height;
- }
+ F32 pixels_to_distribute = (mOrientation == HORIZONTAL)
+ ? getRect().getWidth() - total_size
+ : getRect().getHeight() - total_size;
// now we distribute the pixels...
- S32 cur_x = 0;
- S32 cur_y = getRect().getHeight();
+ F32 cur_x = 0.f;
+ F32 cur_y = (F32)getRect().getHeight();
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
LLLayoutPanel* panelp = (*panel_it);
- S32 cur_width = panelp->getRect().getWidth();
- S32 cur_height = panelp->getRect().getHeight();
- S32 new_width = cur_width;
- S32 new_height = cur_height;
- S32 relevant_min = panelp->getRelevantMinDim();
-
- if (mOrientation == HORIZONTAL)
- {
- new_width = llmax(relevant_min, new_width);
- }
- else
- {
- new_height = llmax(relevant_min, new_height);
- }
- S32 delta_size = 0;
+ F32 min_size = panelp->getRelevantMinDim();
+ F32 delta_size = 0.f;
// if panel can automatically resize (not animating, and resize flag set)...
- if (panelp->getCollapseFactor(mOrientation) == 1.f
+ if (panelp->getCollapseFactor() == 1.f
&& (force_resize || panelp->mAutoResize)
&& !panelp->mResizeBar->hasMouseCapture())
{
- if (mOrientation == HORIZONTAL)
+ if (pixels_to_distribute < 0.f)
{
- // if we're shrinking
- if (pixels_to_distribute < 0)
- {
- // shrink proportionally to amount over minimum
- // so we can do this in one pass
- delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - relevant_min) / (F32)shrink_headroom_available)) : 0;
- shrink_headroom_available -= (cur_width - relevant_min);
- }
- else
- {
- // grow all elements equally
- delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
- num_resizable_panels--;
- }
- pixels_to_distribute -= delta_size;
- new_width = llmax(relevant_min, cur_width + delta_size);
+ // shrink proportionally to amount over minimum
+ // so we can do this in one pass
+ delta_size = (shrink_headroom_available > 0.f)
+ ? pixels_to_distribute * ((F32)(panelp->mFractionalSize - min_size) / shrink_headroom_available)
+ : 0.f;
+ shrink_headroom_available -= (panelp->mFractionalSize - min_size);
}
else
{
- new_width = getDefaultWidth(new_width);
- }
-
- if (mOrientation == VERTICAL)
- {
- if (pixels_to_distribute < 0)
- {
- // shrink proportionally to amount over minimum
- // so we can do this in one pass
- delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - relevant_min) / (F32)shrink_headroom_available)) : 0;
- shrink_headroom_available -= (cur_height - relevant_min);
- }
- else
- {
- delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
- num_resizable_panels--;
- }
- pixels_to_distribute -= delta_size;
- new_height = llmax(relevant_min, cur_height + delta_size);
- }
- else
- {
- new_height = getDefaultHeight(new_height);
- }
- }
- else
- {
- if (mOrientation == HORIZONTAL)
- {
- new_height = getDefaultHeight(new_height);
- }
- else // VERTICAL
- {
- new_width = getDefaultWidth(new_width);
+ // grow all elements equally
+ delta_size = pixels_to_distribute / (F32)num_resizable_panels;
+ num_resizable_panels--;
}
+
+ panelp->mFractionalSize = llmax(min_size, panelp->mFractionalSize + delta_size);
+ pixels_to_distribute -= delta_size;
}
// adjust running headroom count based on new sizes
shrink_headroom_total += delta_size;
LLRect panel_rect;
- panel_rect.setLeftTopAndSize(cur_x, cur_y, new_width, new_height);
+ if (mOrientation == HORIZONTAL)
+ {
+ panel_rect.setLeftTopAndSize(llround(cur_x),
+ llround(cur_y),
+ llround(panelp->mFractionalSize),
+ getRect().getHeight());
+ }
+ else
+ {
+ panel_rect.setLeftTopAndSize(llround(cur_x),
+ llround(cur_y),
+ getRect().getWidth(),
+ llround(panelp->mFractionalSize));
+ }
panelp->setShape(panel_rect);
LLRect resize_bar_rect = panel_rect;
@@ -549,13 +489,14 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
}
(*panel_it)->mResizeBar->setRect(resize_bar_rect);
+ F32 size = ((*panel_it)->mFractionalSize * (*panel_it)->getCollapseFactor()) + (F32)mPanelSpacing;
if (mOrientation == HORIZONTAL)
{
- cur_x += llround(new_width * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;
+ cur_x += size;
}
else //VERTICAL
{
- cur_y -= llround(new_height * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;
+ cur_y -= size;
}
}
@@ -570,13 +511,13 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
{
(*panel_it)->mResizeBar->setResizeLimits(
relevant_min,
- relevant_min + shrink_headroom_total);
+ relevant_min + llround(shrink_headroom_total));
}
else //VERTICAL
{
(*panel_it)->mResizeBar->setResizeLimits(
relevant_min,
- relevant_min + shrink_headroom_total);
+ relevant_min + llround(shrink_headroom_total));
}
// toggle resize bars based on panel visibility, resizability, etc
@@ -599,8 +540,8 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
// not enough room to fit existing contents
if (force_resize == FALSE
// layout did not complete by reaching target position
- && ((mOrientation == VERTICAL && cur_y != -mPanelSpacing)
- || (mOrientation == HORIZONTAL && cur_x != getRect().getWidth() + mPanelSpacing)))
+ && ((mOrientation == VERTICAL && llround(cur_y) != -mPanelSpacing)
+ || (mOrientation == HORIZONTAL && llround(cur_x) != getRect().getWidth() + mPanelSpacing)))
{
// do another layout pass with all stacked elements contributing
// even those that don't usually resize
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index d8ef0aeaca..3b308a359d 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -126,8 +126,6 @@ protected:
private:
void createResizeBars();
void calcMinExtents();
- S32 getDefaultHeight(S32 cur_height);
- S32 getDefaultWidth(S32 cur_width);
const ELayoutOrientation mOrientation;
@@ -163,24 +161,15 @@ public:
Optional user_resize,
auto_resize;
- Params()
- : expanded_min_dim("expanded_min_dim", 0),
- min_dim("min_dim", 0),
- max_dim("max_dim", 0),
- user_resize("user_resize", true),
- auto_resize("auto_resize", true)
- {
- addSynonym(min_dim, "min_width");
- addSynonym(min_dim, "min_height");
- addSynonym(max_dim, "max_width");
- addSynonym(max_dim, "max_height");
- }
+ Params();
};
~LLLayoutPanel();
void initFromParams(const Params& p);
+ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+
S32 getMinDim() const { return mMinDim; }
void setMinDim(S32 value) { mMinDim = value; if (!mExpandedMinDimSpecified) mExpandedMinDim = value; }
@@ -202,22 +191,25 @@ public:
return min_dim;
}
+ F32 getCollapseFactor();
+ void setOrientation(LLLayoutStack::ELayoutOrientation orientation) { mOrientation = orientation; }
+
protected:
LLLayoutPanel(const Params& p);
- F32 getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation);
-
- bool mExpandedMinDimSpecified;
- S32 mExpandedMinDim;
+ bool mExpandedMinDimSpecified;
+ S32 mExpandedMinDim;
- S32 mMinDim;
- S32 mMaxDim;
- BOOL mAutoResize;
- BOOL mUserResize;
- BOOL mCollapsed;
+ S32 mMinDim;
+ S32 mMaxDim;
+ bool mAutoResize;
+ bool mUserResize;
+ bool mCollapsed;
+ F32 mVisibleAmt;
+ F32 mCollapseAmt;
+ F32 mFractionalSize;
+ LLLayoutStack::ELayoutOrientation mOrientation;
class LLResizeBar* mResizeBar;
- F32 mVisibleAmt;
- F32 mCollapseAmt;
};
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index b2f3c36e3e..a284f5c8a3 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -66,7 +66,7 @@ public:
typedef boost::function keystroke_callback_t;
- struct MaxLength : public LLInitParam::Choice
+ struct MaxLength : public LLInitParam::ChoiceBlock
{
Alternative bytes, chars;
diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp
index c4eec1835c..6ac38f5ad4 100644
--- a/indra/llui/llloadingindicator.cpp
+++ b/indra/llui/llloadingindicator.cpp
@@ -34,6 +34,7 @@
// Project includes
#include "lluictrlfactory.h"
#include "lluiimage.h"
+#include "boost/foreach.hpp"
// registered in llui.cpp to avoid being left out by MS linker
//static LLDefaultChildRegistry::Register r("loading_indicator");
@@ -51,11 +52,9 @@ LLLoadingIndicator::LLLoadingIndicator(const Params& p)
void LLLoadingIndicator::initFromParams(const Params& p)
{
- for (LLInitParam::ParamIterator::const_iterator it = p.images().image.begin(), end_it = p.images().image.end();
- it != end_it;
- ++it)
+ BOOST_FOREACH(LLUIImage* image, p.images.image)
{
- mImages.push_back(it->getValue());
+ mImages.push_back(image);
}
// Start timer for switching images.
diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h
index 7c44478848..c1f979c111 100644
--- a/indra/llui/llloadingindicator.h
+++ b/indra/llui/llloadingindicator.h
@@ -51,7 +51,7 @@ class LLLoadingIndicator
LOG_CLASS(LLLoadingIndicator);
public:
- struct Images : public LLInitParam::Block
+ struct Images : public LLInitParam::BatchBlock
{
Multiple image;
@@ -63,7 +63,7 @@ public:
struct Params : public LLInitParam::Block
{
Optional images_per_sec;
- Batch images;
+ Optional images;
Params()
: images_per_sec("images_per_sec", 1.0f),
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 456eeaded9..c2b28271fa 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -941,9 +941,14 @@ LLMenuItemBranchGL::LLMenuItemBranchGL(const LLMenuItemBranchGL::Params& p)
LLMenuItemBranchGL::~LLMenuItemBranchGL()
{
- LLView::deleteViewByHandle(mBranchHandle);
+ if (mBranchHandle.get())
+ {
+ mBranchHandle.get()->die();
+ }
}
+
+
// virtual
LLView* LLMenuItemBranchGL::getChildView(const std::string& name, BOOL recurse) const
{
@@ -1680,7 +1685,8 @@ LLMenuGL::LLMenuGL(const LLMenuGL::Params& p)
mSpilloverMenu(NULL),
mJumpKey(p.jump_key),
mCreateJumpKeys(p.create_jump_keys),
- mNeedsArrange(FALSE),
+ mNeedsArrange(FALSE),
+ mResetScrollPositionOnShow(true),
mShortcutPad(p.shortcut_pad)
{
typedef boost::tokenizer > tokenizer;
@@ -1725,7 +1731,7 @@ void LLMenuGL::setCanTearOff(BOOL tear_off)
{
LLMenuItemTearOffGL::Params p;
mTearOffItem = LLUICtrlFactory::create(p);
- addChildInBack(mTearOffItem);
+ addChild(mTearOffItem);
}
else if (!tear_off && mTearOffItem != NULL)
{
@@ -3037,7 +3043,7 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
S32 mouse_x, mouse_y;
// Resetting scrolling position
- if (menu->isScrollable())
+ if (menu->isScrollable() && menu->isScrollPositionOnShowReset())
{
menu->mFirstVisibleItem = NULL;
}
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index e93827bd44..bd565f8907 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -516,6 +516,9 @@ public:
static class LLMenuHolderGL* sMenuContainer;
+ void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; }
+ bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; }
+
protected:
void createSpilloverBranch();
void cleanupSpilloverBranch();
@@ -565,6 +568,7 @@ private:
KEY mJumpKey;
BOOL mCreateJumpKeys;
S32 mShortcutPad;
+ bool mResetScrollPositionOnShow;
}; // end class LLMenuGL
@@ -677,7 +681,7 @@ public:
BOOL appendContextSubMenu(LLContextMenu *menu);
- LLHandle getHandle() { mHandle.bind(this); return mHandle; }
+ LLHandle getHandle() { return getDerivedHandle(); }
// [SL:KB] - Patch: Misc-Spellcheck | Checked: 2010-12-19 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
// NOTE: this is currently only used for spell checking so don't presume this will return something meaningful elsewhere
diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp
index 43281d7443..2987b6ab11 100644
--- a/indra/llui/llmultifloater.cpp
+++ b/indra/llui/llmultifloater.cpp
@@ -205,7 +205,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
// update torn off status and remove title bar
floaterp->setTornOff(FALSE);
- floaterp->setTitleVisible(FALSE);
+ // floaterp->setTitleVisible(FALSE);
LLRect rect = floaterp->getRect();
rect.mTop -= floaterp->getHeaderHeight();
floaterp->setRect(rect);
@@ -315,7 +315,7 @@ void LLMultiFloater::removeFloater(LLFloater* floaterp)
// update torn off status and add title bar
floaterp->setTornOff(TRUE);
- floaterp->setTitleVisible(TRUE);
+ // floaterp->setTitleVisible(TRUE);
LLRect rect = floaterp->getRect();
rect.mTop += floaterp->getHeaderHeight();
floaterp->setRect(rect);
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index c0b3506a5f..21927b1452 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -46,6 +46,7 @@
#include
#include
+#include
const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
@@ -416,23 +417,17 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
mSoundEffect = LLUUID(LLUI::sSettingGroups["config"]->getString(p.sound));
}
- for(LLInitParam::ParamIterator::const_iterator it = p.unique.contexts.begin(),
- end_it = p.unique.contexts.end();
- it != end_it;
- ++it)
+ BOOST_FOREACH(const LLNotificationTemplate::UniquenessContext& context, p.unique.contexts)
{
- mUniqueContext.push_back(it->value);
+ mUniqueContext.push_back(context.value);
}
lldebugs << "notification \"" << mName << "\": tag count is " << p.tags.size() << llendl;
- for(LLInitParam::ParamIterator::const_iterator it = p.tags.begin(),
- end_it = p.tags.end();
- it != end_it;
- ++it)
+ BOOST_FOREACH(const LLNotificationTemplate::Tag& tag, p.tags)
{
- lldebugs << " tag \"" << std::string(it->value) << "\"" << llendl;
- mTags.push_back(it->value);
+ lldebugs << " tag \"" << std::string(tag.value) << "\"" << llendl;
+ mTags.push_back(tag.value);
}
mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form));
@@ -1404,14 +1399,12 @@ void replaceFormText(LLNotificationForm::Params& form, const std::string& patter
{
form.ignore.text = replace;
}
- for (LLInitParam::ParamIterator::iterator it = form.form_elements.elements.begin(),
- end_it = form.form_elements.elements.end();
- it != end_it;
- ++it)
+
+ BOOST_FOREACH(LLNotificationForm::FormElement& element, form.form_elements.elements)
{
- if (it->button.isChosen() && it->button.text() == pattern)
+ if (element.button.isChosen() && element.button.text() == pattern)
{
- it->button.text = replace;
+ element.button.text = replace;
}
}
}
@@ -1460,48 +1453,42 @@ bool LLNotifications::loadTemplates()
mTemplates.clear();
- for(LLInitParam::ParamIterator::const_iterator it = params.strings.begin(), end_it = params.strings.end();
- it != end_it;
- ++it)
+ BOOST_FOREACH(LLNotificationTemplate::GlobalString& string, params.strings)
{
- mGlobalStrings[it->name] = it->value;
+ mGlobalStrings[string.name] = string.value;
}
std::map form_templates;
- for(LLInitParam::ParamIterator::const_iterator it = params.templates.begin(), end_it = params.templates.end();
- it != end_it;
- ++it)
+ BOOST_FOREACH(LLNotificationTemplate::Template& notification_template, params.templates)
{
- form_templates[it->name] = it->form;
+ form_templates[notification_template.name] = notification_template.form;
}
- for(LLInitParam::ParamIterator::iterator it = params.notifications.begin(), end_it = params.notifications.end();
- it != end_it;
- ++it)
+ BOOST_FOREACH(LLNotificationTemplate::Params& notification, params.notifications)
{
- if (it->form_ref.form_template.isChosen())
+ if (notification.form_ref.form_template.isChosen())
{
// replace form contents from template
- it->form_ref.form = form_templates[it->form_ref.form_template.name];
- if(it->form_ref.form_template.yes_text.isProvided())
+ notification.form_ref.form = form_templates[notification.form_ref.form_template.name];
+ if(notification.form_ref.form_template.yes_text.isProvided())
{
- replaceFormText(it->form_ref.form, "$yestext", it->form_ref.form_template.yes_text);
+ replaceFormText(notification.form_ref.form, "$yestext", notification.form_ref.form_template.yes_text);
}
- if(it->form_ref.form_template.no_text.isProvided())
+ if(notification.form_ref.form_template.no_text.isProvided())
{
- replaceFormText(it->form_ref.form, "$notext", it->form_ref.form_template.no_text);
+ replaceFormText(notification.form_ref.form, "$notext", notification.form_ref.form_template.no_text);
}
- if(it->form_ref.form_template.cancel_text.isProvided())
+ if(notification.form_ref.form_template.cancel_text.isProvided())
{
- replaceFormText(it->form_ref.form, "$canceltext", it->form_ref.form_template.cancel_text);
+ replaceFormText(notification.form_ref.form, "$canceltext", notification.form_ref.form_template.cancel_text);
}
- if(it->form_ref.form_template.ignore_text.isProvided())
+ if(notification.form_ref.form_template.ignore_text.isProvided())
{
- replaceFormText(it->form_ref.form, "$ignoretext", it->form_ref.form_template.ignore_text);
+ replaceFormText(notification.form_ref.form, "$ignoretext", notification.form_ref.form_template.ignore_text);
}
}
- mTemplates[it->name] = LLNotificationTemplatePtr(new LLNotificationTemplate(*it));
+ mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification));
}
return true;
@@ -1524,12 +1511,9 @@ bool LLNotifications::loadVisibilityRules()
mVisibilityRules.clear();
- for(LLInitParam::ParamIterator::iterator it = params.rules.begin(),
- end_it = params.rules.end();
- it != end_it;
- ++it)
+ BOOST_FOREACH(LLNotificationVisibilityRule::Rule& rule, params.rules)
{
- mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(*it)));
+ mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(rule)));
}
return true;
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 7235e69beb..95f9cb7d8f 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -201,7 +201,7 @@ public:
FormInput();
};
- struct FormElement : public LLInitParam::Choice
+ struct FormElement : public LLInitParam::ChoiceBlock
{
Alternative button;
Alternative input;
@@ -312,7 +312,7 @@ public:
Optional context;
Optional responder;
- struct Functor : public LLInitParam::Choice
+ struct Functor : public LLInitParam::ChoiceBlock
{
Alternative name;
Alternative function;
diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h
index ab777d37a5..fb50c9c123 100644
--- a/indra/llui/llnotificationtemplate.h
+++ b/indra/llui/llnotificationtemplate.h
@@ -91,7 +91,7 @@ struct LLNotificationTemplate
//
// as well as
// ...
- Flag dummy_val;
+ Optional dummy_val;
public:
Multiple contexts;
@@ -147,7 +147,7 @@ struct LLNotificationTemplate
{}
};
- struct FormRef : public LLInitParam::Choice
+ struct FormRef : public LLInitParam::ChoiceBlock
{
Alternative form;
Alternative form_template;
diff --git a/indra/llui/llnotificationvisibilityrule.h b/indra/llui/llnotificationvisibilityrule.h
index 78bdec2a8f..78788a275c 100644
--- a/indra/llui/llnotificationvisibilityrule.h
+++ b/indra/llui/llnotificationvisibilityrule.h
@@ -59,7 +59,7 @@ struct LLNotificationVisibilityRule
{}
};
- struct Rule : public LLInitParam::Choice
+ struct Rule : public LLInitParam::ChoiceBlock
{
Alternative show;
Alternative hide;
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index aeb73771db..7845cc73e4 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -122,8 +122,6 @@ LLPanel::LLPanel(const LLPanel::Params& p)
{
addBorder(p.border);
}
-
- mPanelHandle.bind(this);
}
LLPanel::~LLPanel()
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 790025cb2d..f620201020 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -96,9 +96,6 @@ public:
Params();
};
- // valid children for LLPanel are stored in this registry
- typedef LLDefaultChildRegistry child_registry_t;
-
protected:
friend class LLUICtrlFactory;
// RN: for some reason you can't just use LLUICtrlFactory::getDefaultParams as a default argument in VC8
@@ -138,6 +135,8 @@ public:
const LLColor4& getBackgroundColor() const { return mBgOpaqueColor; }
void setTransparentColor(const LLColor4& color) { mBgAlphaColor = color; }
const LLColor4& getTransparentColor() const { return mBgAlphaColor; }
+ void setBackgroundImage(LLUIImage* image) { mBgOpaqueImage = image; }
+ void setTransparentImage(LLUIImage* image) { mBgAlphaImage = image; }
LLPointer getBackgroundImage() const { return mBgOpaqueImage; }
LLPointer