Merge branch 'BatchIndexing' of https://github.com/Shyotl/SingularityViewer into future
This commit is contained in:
@@ -19,3 +19,8 @@ set(LLCOMMON_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
set(LLCOMMON_LIBRARIES llcommon)
|
||||
|
||||
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
|
||||
if(LLCOMMON_LINK_SHARED)
|
||||
add_definitions(-DLL_COMMON_LINK_SHARED=1)
|
||||
endif(LLCOMMON_LINK_SHARED)
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
include(Prebuilt)
|
||||
|
||||
if (NOT STANDALONE)
|
||||
use_prebuilt_binary(GL)
|
||||
use_prebuilt_binary(glext)
|
||||
# possible glh_linear should have its own .cmake file instead
|
||||
#use_prebuilt_binary(glh_linear)
|
||||
# actually... not any longer, it's now in git -SG
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
endif (NOT STANDALONE)
|
||||
|
||||
@@ -89,7 +89,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
|
||||
|
||||
//********************************
|
||||
LLAPRFile infile ;
|
||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
//********************************
|
||||
if (!infile.getFileHandle())
|
||||
{
|
||||
@@ -240,7 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
|
||||
S32 data_left = 0;
|
||||
|
||||
LLAPRFile infile ;
|
||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
if (!infile.getFileHandle())
|
||||
{
|
||||
llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
|
||||
@@ -249,7 +249,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
|
||||
}
|
||||
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global);
|
||||
outfile.open(out_fname,LL_APR_WPB);
|
||||
if (!outfile.getFileHandle())
|
||||
{
|
||||
llwarns << "Couldn't open upload sound file for reading: " << in_fname
|
||||
|
||||
@@ -226,7 +226,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
|
||||
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
|
||||
|
||||
LLAPRFile infile ;
|
||||
infile.open(path, LL_APR_R, LLAPRFile::global);
|
||||
infile.open(path, LL_APR_R);
|
||||
apr_file_t *fp = infile.getFileHandle();
|
||||
if (!fp)
|
||||
return E_ST_NO_XLT_FILE;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "llmotioncontroller.h"
|
||||
#include "llvisualparam.h"
|
||||
#include "string_table.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llthread.h"
|
||||
|
||||
class LLPolyMesh;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "lljoint.h"
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLJointState
|
||||
|
||||
@@ -163,8 +163,6 @@ void LLPose::setWeight(F32 weight)
|
||||
// there was a crash here
|
||||
// </edit>
|
||||
llassert_always(iter->second.notNull());
|
||||
if(!iter->second) //uhoh...
|
||||
continue;
|
||||
iter->second->setWeight(weight);
|
||||
}
|
||||
mWeight = weight;
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "lljointstate.h"
|
||||
#include "lljoint.h"
|
||||
#include "llmap.h"
|
||||
#include "llpointer.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
|
||||
BOOL LLStateDiagram::saveDotFile(const std::string& filename)
|
||||
{
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(filename, LL_APR_W, LLAPRFile::global);
|
||||
outfile.open(filename, LL_APR_W);
|
||||
apr_file_t* dot_file = outfile.getFileHandle() ;
|
||||
|
||||
if (!dot_file)
|
||||
|
||||
@@ -196,6 +196,7 @@ set(llcommon_HEADER_FILES
|
||||
llsys.h
|
||||
llthread.h
|
||||
lltimer.h
|
||||
lltreeiterators.h
|
||||
lluri.h
|
||||
lluuid.h
|
||||
lluuidhashmap.h
|
||||
@@ -232,6 +233,7 @@ target_link_libraries(
|
||||
${EXPAT_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${WINDOWS_LIBRARIES}
|
||||
${BOOST_REGEX_LIBRARY}
|
||||
${CWDEBUG_LIBRARIES}
|
||||
${CORESERVICES_LIBRARY}
|
||||
)
|
||||
|
||||
@@ -191,6 +191,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
|
||||
return status;
|
||||
}
|
||||
|
||||
apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
|
||||
{
|
||||
return open(filename, flags, use_global_pool ? LLAPRFile::global : LLAPRFile::local);
|
||||
}
|
||||
// File I/O
|
||||
S32 LLAPRFile::read(void *buf, S32 nbytes)
|
||||
{
|
||||
|
||||
@@ -150,10 +150,11 @@ public:
|
||||
};
|
||||
|
||||
LLAPRFile() ;
|
||||
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type);
|
||||
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type = LLAPRFile::global);
|
||||
~LLAPRFile() ;
|
||||
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type = LLAPRFile::global, S32* sizep = NULL);
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use global pool.
|
||||
apr_status_t close() ;
|
||||
|
||||
// Returns actual offset, -1 if seek fails
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llassettype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLAssetType
|
||||
|
||||
@@ -44,63 +44,40 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//std::list<LLEventTimer*> LLEventTimer::sActiveList;
|
||||
|
||||
LLEventTimer::LLEventTimer(F32 period)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = period;
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
LLEventTimer::LLEventTimer(const LLDate& time)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
LLEventTimer::~LLEventTimer()
|
||||
LLEventTimer::~LLEventTimer()
|
||||
{
|
||||
//sActiveList.remove(this);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLEventTimer::updateClass()
|
||||
{
|
||||
std::list<LLEventTimer*> completed_timers;
|
||||
|
||||
/*{
|
||||
for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
|
||||
{
|
||||
LLEventTimer* timer = *iter++;
|
||||
F32 et = timer->mEventTimer.getElapsedTimeF32();
|
||||
if (timer->mEventTimer.getStarted() && et > timer->mPeriod) {
|
||||
timer->mEventTimer.reset();
|
||||
if ( timer->tick() )
|
||||
{
|
||||
completed_timers.push_back( timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
for (instance_iter iter = beginInstances(); iter != endInstances(); )
|
||||
{
|
||||
LLInstanceTrackerScopedGuard guard;
|
||||
for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
|
||||
{
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( completed_timers.size() > 0 )
|
||||
{
|
||||
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
|
||||
|
||||
@@ -56,11 +56,6 @@ public:
|
||||
protected:
|
||||
LLTimer mEventTimer;
|
||||
F32 mPeriod;
|
||||
|
||||
//private:
|
||||
//list of active timers
|
||||
// static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
|
||||
};
|
||||
|
||||
|
||||
#endif //LL_EVENTTIMER_H
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "llfoldertype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFolderType
|
||||
@@ -95,7 +96,12 @@ LLFolderDictionary::LLFolderDictionary()
|
||||
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
|
||||
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
|
||||
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
|
||||
addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE));
|
||||
addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
|
||||
};
|
||||
|
||||
@@ -87,9 +87,14 @@ public:
|
||||
FT_OUTFIT = 47,
|
||||
FT_MY_OUTFITS = 48,
|
||||
|
||||
FT_INBOX = 49,
|
||||
FT_MESH = 49,
|
||||
|
||||
FT_COUNT = 50,
|
||||
FT_INBOX = 50,
|
||||
FT_OUTBOX = 51,
|
||||
|
||||
FT_BASIC_ROOT = 52,
|
||||
|
||||
FT_COUNT,
|
||||
|
||||
FT_NONE = -1
|
||||
};
|
||||
|
||||
@@ -49,6 +49,7 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
|
||||
protected:
|
||||
static void * & getInstances(std::type_info const & info);
|
||||
};
|
||||
|
||||
/// This mix-in class adds support for tracking all instances of the specified class parameter T
|
||||
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
|
||||
/// If KEY is not provided, then instances are stored in a simple set
|
||||
@@ -58,13 +59,80 @@ class LLInstanceTracker : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef typename std::map<KEY, T*> InstanceMap;
|
||||
typedef LLInstanceTracker<T, KEY> MyT;
|
||||
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
|
||||
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a const KEY&
|
||||
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
|
||||
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
|
||||
|
||||
instance_iter(const typename InstanceMap::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--sIterationNestDepth;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(instance_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
T& dereference() const
|
||||
{
|
||||
return *(mIterator->second);
|
||||
}
|
||||
|
||||
typename InstanceMap::iterator mIterator;
|
||||
};
|
||||
|
||||
class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
|
||||
|
||||
key_iter(typename InstanceMap::iterator it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
}
|
||||
|
||||
key_iter(const key_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
}
|
||||
|
||||
~key_iter()
|
||||
{
|
||||
--sIterationNestDepth;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(key_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
KEY& dereference() const
|
||||
{
|
||||
return const_cast<KEY&>(mIterator->first);
|
||||
}
|
||||
|
||||
typename InstanceMap::iterator mIterator;
|
||||
};
|
||||
|
||||
static T* getInstance(const KEY& k)
|
||||
{
|
||||
@@ -72,42 +140,47 @@ public:
|
||||
return (found == getMap_().end()) ? NULL : found->second;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(getMap_().begin());
|
||||
}
|
||||
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(getMap_().end());
|
||||
}
|
||||
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
|
||||
static key_iter beginKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
return key_iter(getMap_().begin());
|
||||
}
|
||||
static key_iter endKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
return key_iter(getMap_().end());
|
||||
}
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
|
||||
protected:
|
||||
LLInstanceTracker(KEY key) { add_(key); }
|
||||
virtual ~LLInstanceTracker() { remove_(); }
|
||||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert(sIterationNestDepth == 0);
|
||||
remove_();
|
||||
}
|
||||
virtual void setKey(KEY key) { remove_(); add_(key); }
|
||||
virtual const KEY& getKey() const { return mKey; }
|
||||
virtual const KEY& getKey() const { return mInstanceKey; }
|
||||
|
||||
private:
|
||||
void add_(KEY key)
|
||||
{
|
||||
mKey = key;
|
||||
mInstanceKey = key;
|
||||
getMap_()[key] = static_cast<T*>(this);
|
||||
}
|
||||
void remove_()
|
||||
{
|
||||
getMap_().erase(mKey);
|
||||
getMap_().erase(mInstanceKey);
|
||||
}
|
||||
|
||||
static InstanceMap& getMap_()
|
||||
@@ -122,9 +195,12 @@ private:
|
||||
|
||||
private:
|
||||
|
||||
KEY mKey;
|
||||
KEY mInstanceKey;
|
||||
static S32 sIterationNestDepth;
|
||||
};
|
||||
|
||||
template <typename T, typename KEY> S32 LLInstanceTracker<T, KEY>::sIterationNestDepth = 0;
|
||||
|
||||
/// explicit specialization for default case where KEY is T*
|
||||
/// use a simple std::set<T*>
|
||||
template<typename T>
|
||||
@@ -133,42 +209,55 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
typedef LLInstanceTracker<T, T*> MyT;
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a T* (since T* is the key)
|
||||
typedef typename InstanceSet::iterator key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator<key_iter> instance_iter;
|
||||
|
||||
/// for completeness of analogy with the generic implementation
|
||||
static T* getInstance(T* k) { return k; }
|
||||
static S32 instanceCount() { return getSet_().size(); }
|
||||
|
||||
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
|
||||
// that it treats deletes of this type as errors as long as there is an instance of
|
||||
// this class alive in scope somewhere (i.e. deleting while iterating is bad).
|
||||
class LLInstanceTrackerScopedGuard
|
||||
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
LLInstanceTrackerScopedGuard()
|
||||
instance_iter(const typename InstanceSet::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
}
|
||||
|
||||
~LLInstanceTrackerScopedGuard()
|
||||
instance_iter(const instance_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--sIterationNestDepth;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
static key_iter beginKeys() { return getSet_().begin(); }
|
||||
static key_iter endKeys() { return getSet_().end(); }
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(instance_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
T& dereference() const
|
||||
{
|
||||
return **mIterator;
|
||||
}
|
||||
|
||||
typename InstanceSet::iterator mIterator;
|
||||
};
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
|
||||
protected:
|
||||
LLInstanceTracker()
|
||||
{
|
||||
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
@@ -180,7 +269,6 @@ protected:
|
||||
|
||||
LLInstanceTracker(const LLInstanceTracker& other)
|
||||
{
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,62 @@ public:
|
||||
THROTTLE_BLOCKED, // rate exceed, block key
|
||||
};
|
||||
|
||||
F64 getActionCount(const T& id)
|
||||
{
|
||||
U64 now = 0;
|
||||
if ( mIsRealtime )
|
||||
{
|
||||
now = LLKeyThrottleImpl<T>::getTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
now = LLKeyThrottleImpl<T>::getFrame();
|
||||
}
|
||||
|
||||
if (now >= (m.startTime + m.intervalLength))
|
||||
{
|
||||
if (now < (m.startTime + 2 * m.intervalLength))
|
||||
{
|
||||
// prune old data
|
||||
delete m.prevMap;
|
||||
m.prevMap = m.currMap;
|
||||
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
|
||||
m.startTime += m.intervalLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// lots of time has passed, all data is stale
|
||||
delete m.prevMap;
|
||||
delete m.currMap;
|
||||
m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
|
||||
m.startTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
U32 prevCount = 0;
|
||||
|
||||
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
|
||||
if (prev != m.prevMap->end())
|
||||
{
|
||||
prevCount = prev->second.count;
|
||||
}
|
||||
|
||||
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
|
||||
|
||||
// curr.count is the number of keys in
|
||||
// this current 'time slice' from the beginning of it until now
|
||||
// prevCount is the number of keys in the previous
|
||||
// time slice scaled to be one full time slice back from the current
|
||||
// (now) time.
|
||||
|
||||
// compute current, windowed rate
|
||||
F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
|
||||
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
|
||||
return averageCount;
|
||||
}
|
||||
// call each time the key wants use
|
||||
State noteAction(const T& id, S32 weight = 1)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ const U32 AGENT_TYPING = 0x0200;
|
||||
const U32 AGENT_CROUCHING = 0x0400;
|
||||
const U32 AGENT_BUSY = 0x0800;
|
||||
const U32 AGENT_ALWAYS_RUN = 0x1000;
|
||||
const U32 AGENT_AUTOPILOT = 0x2000;
|
||||
|
||||
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
|
||||
const S32 LSL_REMOTE_DATA_REQUEST = 2;
|
||||
@@ -184,6 +185,10 @@ const S32 OBJECT_VELOCITY = 5;
|
||||
const S32 OBJECT_OWNER = 6;
|
||||
const S32 OBJECT_GROUP = 7;
|
||||
const S32 OBJECT_CREATOR = 8;
|
||||
const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
|
||||
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
|
||||
const S32 OBJECT_SCRIPT_MEMORY = 11;
|
||||
const S32 OBJECT_SCRIPT_TIME = 12;
|
||||
|
||||
// changed() event flags
|
||||
const U32 CHANGED_NONE = 0x0;
|
||||
@@ -198,5 +203,17 @@ const U32 CHANGED_OWNER = 0x80;
|
||||
const U32 CHANGED_REGION = 0x100;
|
||||
const U32 CHANGED_TELEPORT = 0x200;
|
||||
const U32 CHANGED_REGION_START = 0x400;
|
||||
const U32 CHANGED_MEDIA = 0x800;
|
||||
|
||||
// Possible error results
|
||||
const U32 LSL_STATUS_OK = 0;
|
||||
const U32 LSL_STATUS_MALFORMED_PARAMS = 1000;
|
||||
const U32 LSL_STATUS_TYPE_MISMATCH = 1001;
|
||||
const U32 LSL_STATUS_BOUNDS_ERROR = 1002;
|
||||
const U32 LSL_STATUS_NOT_FOUND = 1003;
|
||||
const U32 LSL_STATUS_NOT_SUPPORTED = 1004;
|
||||
const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
|
||||
|
||||
// Start per-function errors below, starting at 2000:
|
||||
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
|
||||
#endif
|
||||
|
||||
@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
|
||||
{
|
||||
sDestroyImmediate = b;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL LLMortician::getZealous()
|
||||
{
|
||||
return sDestroyImmediate;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ public:
|
||||
|
||||
// sets destroy immediate true
|
||||
static void setZealous(BOOL b);
|
||||
static BOOL getZealous();
|
||||
|
||||
private:
|
||||
static BOOL sDestroyImmediate;
|
||||
|
||||
@@ -107,7 +107,17 @@
|
||||
|
||||
#endif
|
||||
|
||||
// Deal with the differences on Windows
|
||||
|
||||
// Static linking with apr on windows needs to be declared.
|
||||
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
|
||||
#ifndef APR_DECLARE_STATIC
|
||||
#define APR_DECLARE_STATIC // For APR on Windows
|
||||
#endif
|
||||
#ifndef APU_DECLARE_STATIC
|
||||
#define APU_DECLARE_STATIC // For APR util on Windows
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LL_WINDOWS)
|
||||
#define BOOST_REGEX_NO_LIB 1
|
||||
#define CURL_STATICLIB 1
|
||||
@@ -159,12 +169,19 @@
|
||||
#define LL_DLLIMPORT
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
#ifdef llcommon_EXPORTS
|
||||
// Compiling llcommon (shared)
|
||||
#define LL_COMMON_API LL_DLLEXPORT
|
||||
#else // llcommon_EXPORTS
|
||||
// Using llcommon (shared)
|
||||
#define LL_COMMON_API LL_DLLIMPORT
|
||||
#endif // llcommon_EXPORTS
|
||||
#if LL_COMMON_LINK_SHARED
|
||||
// CMake automagically defines llcommon_EXPORTS only when building llcommon
|
||||
// sources, and only when llcommon is a shared library (i.e. when
|
||||
// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
|
||||
// otherwise we can't distinguish between (non-llcommon source) and (llcommon
|
||||
// not shared).
|
||||
# if defined(llcommon_EXPORTS)
|
||||
# define LL_COMMON_API LL_DLLEXPORT
|
||||
# else //llcommon_EXPORTS
|
||||
# define LL_COMMON_API LL_DLLIMPORT
|
||||
# endif //llcommon_EXPORTS
|
||||
#else // LL_COMMON_LINK_SHARED
|
||||
# define LL_COMMON_API
|
||||
#endif // LL_COMMON_LINK_SHARED
|
||||
|
||||
#endif // not LL_LINDEN_PREPROCESSOR_H
|
||||
|
||||
@@ -102,7 +102,7 @@ int LLProcessLauncher::launch(void)
|
||||
STARTUPINFOA sinfo;
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
|
||||
std::string args = "\"" + mExecutable + "\"";
|
||||
std::string args = mExecutable;
|
||||
for(int i = 0; i < (int)mLaunchArguments.size(); i++)
|
||||
{
|
||||
args += " ";
|
||||
@@ -114,10 +114,30 @@ int LLProcessLauncher::launch(void)
|
||||
char *args2 = new char[args.size() + 1];
|
||||
strcpy(args2, args.c_str());
|
||||
|
||||
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
|
||||
const char * working_directory = 0;
|
||||
if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str();
|
||||
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) )
|
||||
{
|
||||
// TODO: do better than returning the OS-specific error code on failure...
|
||||
result = GetLastError();
|
||||
|
||||
LPTSTR error_str = 0;
|
||||
if(
|
||||
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
result,
|
||||
0,
|
||||
(LPTSTR)&error_str,
|
||||
0,
|
||||
NULL)
|
||||
!= 0)
|
||||
{
|
||||
char message[256];
|
||||
wcstombs(message, error_str, 256);
|
||||
message[255] = 0;
|
||||
llwarns << "CreateProcessA failed: " << message << llendl;
|
||||
LocalFree(error_str);
|
||||
}
|
||||
|
||||
if(result == 0)
|
||||
{
|
||||
// Make absolutely certain we return a non-zero value on failure.
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llqueuedthread.h"
|
||||
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h"
|
||||
#include "lltimer.h" // ms_sleep()
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
@@ -754,11 +754,7 @@ void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v);
|
||||
LLSD& LLSD::with(const String& k, const LLSD& v)
|
||||
{
|
||||
makeMap(impl).insert(k, v);
|
||||
#ifdef LL_MSVC7
|
||||
return *dynamic_cast<LLSD*>(this);
|
||||
#else
|
||||
return *this;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
|
||||
|
||||
@@ -784,11 +780,7 @@ void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
|
||||
LLSD& LLSD::with(Integer i, const LLSD& v)
|
||||
{
|
||||
makeArray(impl).insert(i, v);
|
||||
#ifdef LL_MSVC7
|
||||
return *dynamic_cast<LLSD*>(this);
|
||||
#else
|
||||
return *this;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
|
||||
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llstreamtools.h" // for fullread
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -36,8 +36,9 @@
|
||||
#define LL_LLSDSERIALIZE_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsd.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
/**
|
||||
* @class LLSDParser
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <deque>
|
||||
|
||||
#include "apr_base64.h"
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
case ELEMENT_INTEGER:
|
||||
{
|
||||
S32 i;
|
||||
// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
|
||||
if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
|
||||
{ // See if sscanf works - it's faster
|
||||
value = i;
|
||||
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
|
||||
case ELEMENT_REAL:
|
||||
{
|
||||
F64 r;
|
||||
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||
{ // See if sscanf works - it's faster
|
||||
value = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = LLSD(mCurrentContent).asReal();
|
||||
}
|
||||
value = LLSD(mCurrentContent).asReal();
|
||||
// removed since this breaks when locale has decimal separator that isn't '.'
|
||||
// investigated changing local to something compatible each time but deemed higher
|
||||
// risk that just using LLSD.asReal() each time.
|
||||
//F64 r;
|
||||
//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||
//{ // See if sscanf works - it's faster
|
||||
// value = r;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// value = LLSD(mCurrentContent).asReal();
|
||||
//}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
|
||||
case ELEMENT_BINARY:
|
||||
{
|
||||
S32 len = apr_base64_decode_len(mCurrentContent.c_str());
|
||||
// Regex is expensive, but only fix for whitespace in base64,
|
||||
// created by python and other non-linden systems - DEV-39358
|
||||
// Fortunately we have very little binary passing now,
|
||||
// so performance impact shold be negligible. + poppy 2009-09-04
|
||||
boost::regex r;
|
||||
r.assign("\\s");
|
||||
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
|
||||
S32 len = apr_base64_decode_len(stripped.c_str());
|
||||
std::vector<U8> data;
|
||||
data.resize(len);
|
||||
len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
|
||||
len = apr_base64_decode_binary(&data[0], stripped.c_str());
|
||||
data.resize(len);
|
||||
value = data;
|
||||
break;
|
||||
|
||||
@@ -46,6 +46,12 @@
|
||||
#endif
|
||||
|
||||
#include "llsdserialize.h"
|
||||
#include "stringize.h"
|
||||
#include "is_approx_equal_fraction.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
// U32
|
||||
LLSD ll_sd_from_U32(const U32 val)
|
||||
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* ll_pretty_print_sd_ptr(const LLSD* sd)
|
||||
{
|
||||
if (sd)
|
||||
{
|
||||
return ll_pretty_print_sd(*sd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* ll_pretty_print_sd(const LLSD& sd)
|
||||
{
|
||||
const U32 bufferSize = 10 * 1024;
|
||||
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Helpers for llsd_matches()
|
||||
*****************************************************************************/
|
||||
// raw data used for LLSD::Type lookup
|
||||
struct Data
|
||||
{
|
||||
LLSD::Type type;
|
||||
const char* name;
|
||||
} typedata[] =
|
||||
{
|
||||
#define def(type) { LLSD::type, #type + 4 }
|
||||
def(TypeUndefined),
|
||||
def(TypeBoolean),
|
||||
def(TypeInteger),
|
||||
def(TypeReal),
|
||||
def(TypeString),
|
||||
def(TypeUUID),
|
||||
def(TypeDate),
|
||||
def(TypeURI),
|
||||
def(TypeBinary),
|
||||
def(TypeMap),
|
||||
def(TypeArray)
|
||||
#undef def
|
||||
};
|
||||
|
||||
// LLSD::Type lookup class into which we load the above static data
|
||||
class TypeLookup
|
||||
{
|
||||
typedef std::map<LLSD::Type, std::string> MapType;
|
||||
|
||||
public:
|
||||
TypeLookup()
|
||||
{
|
||||
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
|
||||
{
|
||||
mMap[di->type] = di->name;
|
||||
}
|
||||
}
|
||||
|
||||
std::string lookup(LLSD::Type type) const
|
||||
{
|
||||
MapType::const_iterator found = mMap.find(type);
|
||||
if (found != mMap.end())
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
return STRINGIZE("<unknown LLSD type " << type << ">");
|
||||
}
|
||||
|
||||
private:
|
||||
MapType mMap;
|
||||
};
|
||||
|
||||
// static instance of the lookup class
|
||||
static const TypeLookup sTypes;
|
||||
|
||||
// describe a mismatch; phrasing may want tweaking
|
||||
const std::string op(" required instead of ");
|
||||
|
||||
// llsd_matches() wants to identify specifically where in a complex prototype
|
||||
// structure the mismatch occurred. This entails passing a prefix string,
|
||||
// empty for the top-level call. If the prototype contains an array of maps,
|
||||
// and the mismatch occurs in the second map in a key 'foo', we want to
|
||||
// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
|
||||
// want to omit the entire prefix -- including colon -- if the mismatch is at
|
||||
// top level. This helper accepts the (possibly empty) recursively-accumulated
|
||||
// prefix string, returning either empty or the original string with colon
|
||||
// appended.
|
||||
static std::string colon(const std::string& pfx)
|
||||
{
|
||||
if (pfx.empty())
|
||||
return pfx;
|
||||
return pfx + ": ";
|
||||
}
|
||||
|
||||
// param type for match_types
|
||||
typedef std::vector<LLSD::Type> TypeVector;
|
||||
|
||||
// The scalar cases in llsd_matches() use this helper. In most cases, we can
|
||||
// accept not only the exact type specified in the prototype, but also other
|
||||
// types convertible to the expected type. That implies looping over an array
|
||||
// of such types. If the actual type doesn't match any of them, we want to
|
||||
// provide a list of acceptable conversions as well as the exact type, e.g.:
|
||||
// "Integer (or Boolean, Real, String) required instead of UUID". Both the
|
||||
// implementation and the calling logic are simplified by separating out the
|
||||
// expected type from the convertible types.
|
||||
static std::string match_types(LLSD::Type expect, // prototype.type()
|
||||
const TypeVector& accept, // types convertible to that type
|
||||
LLSD::Type actual, // type we're checking
|
||||
const std::string& pfx) // as for llsd_matches
|
||||
{
|
||||
// Trivial case: if the actual type is exactly what we expect, we're good.
|
||||
if (actual == expect)
|
||||
return "";
|
||||
|
||||
// For the rest of the logic, build up a suitable error string as we go so
|
||||
// we only have to make a single pass over the list of acceptable types.
|
||||
// If we detect success along the way, we'll simply discard the partial
|
||||
// error string.
|
||||
std::ostringstream out;
|
||||
out << colon(pfx) << sTypes.lookup(expect);
|
||||
|
||||
// If there are any convertible types, append that list.
|
||||
if (! accept.empty())
|
||||
{
|
||||
out << " (";
|
||||
const char* sep = "or ";
|
||||
for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
|
||||
ai != aend; ++ai, sep = ", ")
|
||||
{
|
||||
// Don't forget to return success if we match any of those types...
|
||||
if (actual == *ai)
|
||||
return "";
|
||||
out << sep << sTypes.lookup(*ai);
|
||||
}
|
||||
out << ')';
|
||||
}
|
||||
// If we got this far, it's because 'actual' was not one of the acceptable
|
||||
// types, so we must return an error. 'out' already contains colon(pfx)
|
||||
// and the formatted list of acceptable types, so just append the mismatch
|
||||
// phrase and the actual type.
|
||||
out << op << sTypes.lookup(actual);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
// see docstring in .h file
|
||||
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
|
||||
{
|
||||
// An undefined prototype means that any data is valid.
|
||||
// An undefined slot in an array or map prototype means that any data
|
||||
// may fill that slot.
|
||||
if (prototype.isUndefined())
|
||||
return "";
|
||||
// A prototype array must match a data array with at least as many
|
||||
// entries. Moreover, every prototype entry must match the
|
||||
// corresponding data entry.
|
||||
if (prototype.isArray())
|
||||
{
|
||||
if (! data.isArray())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
|
||||
}
|
||||
if (data.size() < prototype.size())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
|
||||
<< "Array size " << data.size());
|
||||
}
|
||||
for (LLSD::Integer i = 0; i < prototype.size(); ++i)
|
||||
{
|
||||
std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
|
||||
if (! match.empty())
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// A prototype map must match a data map. Every key in the prototype
|
||||
// must have a corresponding key in the data map; every value in the
|
||||
// prototype must match the corresponding key's value in the data.
|
||||
if (prototype.isMap())
|
||||
{
|
||||
if (! data.isMap())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
|
||||
}
|
||||
// If there are a number of keys missing from the data, it would be
|
||||
// frustrating to a coder to discover them one at a time, with a big
|
||||
// build each time. Enumerate all missing keys.
|
||||
std::ostringstream out;
|
||||
out << colon(pfx);
|
||||
const char* init = "Map missing keys: ";
|
||||
const char* sep = init;
|
||||
for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
|
||||
{
|
||||
if (! data.has(mi->first))
|
||||
{
|
||||
out << sep << mi->first;
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
// So... are we missing any keys?
|
||||
if (sep != init)
|
||||
{
|
||||
return out.str();
|
||||
}
|
||||
// Good, the data block contains all the keys required by the
|
||||
// prototype. Now match the prototype entries.
|
||||
for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
|
||||
{
|
||||
std::string match(llsd_matches(mi2->second, data[mi2->first],
|
||||
STRINGIZE("['" << mi2->first << "']")));
|
||||
if (! match.empty())
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// A String prototype can match String, Boolean, Integer, Real, UUID,
|
||||
// Date and URI, because any of these can be converted to String.
|
||||
if (prototype.isString())
|
||||
{
|
||||
static LLSD::Type accept[] =
|
||||
{
|
||||
LLSD::TypeBoolean,
|
||||
LLSD::TypeInteger,
|
||||
LLSD::TypeReal,
|
||||
LLSD::TypeUUID,
|
||||
LLSD::TypeDate,
|
||||
LLSD::TypeURI
|
||||
};
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(boost::begin(accept), boost::end(accept)),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// Boolean, Integer, Real match each other or String. TBD: ensure that
|
||||
// a String value is numeric.
|
||||
if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
|
||||
{
|
||||
static LLSD::Type all[] =
|
||||
{
|
||||
LLSD::TypeBoolean,
|
||||
LLSD::TypeInteger,
|
||||
LLSD::TypeReal,
|
||||
LLSD::TypeString
|
||||
};
|
||||
// Funny business: shuffle the set of acceptable types to include all
|
||||
// but the prototype's type. Get the acceptable types in a set.
|
||||
std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
|
||||
// Remove the prototype's type because we pass that separately.
|
||||
rest.erase(prototype.type());
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(rest.begin(), rest.end()),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// UUID, Date and URI match themselves or String.
|
||||
if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
|
||||
{
|
||||
static LLSD::Type accept[] =
|
||||
{
|
||||
LLSD::TypeString
|
||||
};
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(boost::begin(accept), boost::end(accept)),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// We don't yet know the conversion semantics associated with any new LLSD
|
||||
// data type that might be added, so until we've been extended to handle
|
||||
// them, assume it's strict: the new type matches only itself. (This is
|
||||
// true of Binary, which is why we don't handle that case separately.) Too
|
||||
// bad LLSD doesn't define isConvertible(Type to, Type from).
|
||||
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
|
||||
}
|
||||
|
||||
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
|
||||
{
|
||||
// We're comparing strict equality of LLSD representation rather than
|
||||
// performing any conversions. So if the types aren't equal, the LLSD
|
||||
// values aren't equal.
|
||||
if (lhs.type() != rhs.type())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Here we know both types are equal. Now compare values.
|
||||
switch (lhs.type())
|
||||
{
|
||||
case LLSD::TypeUndefined:
|
||||
// Both are TypeUndefined. There's nothing more to know.
|
||||
return true;
|
||||
|
||||
case LLSD::TypeReal:
|
||||
// This is where the 'bits' argument comes in handy. If passed
|
||||
// explicitly, it means to use is_approx_equal_fraction() to compare.
|
||||
if (bits >= 0)
|
||||
{
|
||||
return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
|
||||
}
|
||||
// Otherwise we compare bit representations, and the usual caveats
|
||||
// about comparing floating-point numbers apply. Omitting 'bits' when
|
||||
// comparing Real values is only useful when we expect identical bit
|
||||
// representation for a given Real value, e.g. for integer-valued
|
||||
// Reals.
|
||||
return (lhs.asReal() == rhs.asReal());
|
||||
|
||||
#define COMPARE_SCALAR(type) \
|
||||
case LLSD::Type##type: \
|
||||
/* LLSD::URI has operator!=() but not operator==() */ \
|
||||
/* rely on the optimizer for all others */ \
|
||||
return (! (lhs.as##type() != rhs.as##type()))
|
||||
|
||||
COMPARE_SCALAR(Boolean);
|
||||
COMPARE_SCALAR(Integer);
|
||||
COMPARE_SCALAR(String);
|
||||
COMPARE_SCALAR(UUID);
|
||||
COMPARE_SCALAR(Date);
|
||||
COMPARE_SCALAR(URI);
|
||||
COMPARE_SCALAR(Binary);
|
||||
|
||||
#undef COMPARE_SCALAR
|
||||
|
||||
case LLSD::TypeArray:
|
||||
{
|
||||
LLSD::array_const_iterator
|
||||
lai(lhs.beginArray()), laend(lhs.endArray()),
|
||||
rai(rhs.beginArray()), raend(rhs.endArray());
|
||||
// Compare array elements, walking the two arrays in parallel.
|
||||
for ( ; lai != laend && rai != raend; ++lai, ++rai)
|
||||
{
|
||||
// If any one array element is unequal, the arrays are unequal.
|
||||
if (! llsd_equals(*lai, *rai, bits))
|
||||
return false;
|
||||
}
|
||||
// Here we've reached the end of one or the other array. They're equal
|
||||
// only if they're BOTH at end: that is, if they have equal length too.
|
||||
return (lai == laend && rai == raend);
|
||||
}
|
||||
|
||||
case LLSD::TypeMap:
|
||||
{
|
||||
// Build a set of all rhs keys.
|
||||
std::set<LLSD::String> rhskeys;
|
||||
for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
|
||||
rmi != rmend; ++rmi)
|
||||
{
|
||||
rhskeys.insert(rmi->first);
|
||||
}
|
||||
// Now walk all the lhs keys.
|
||||
for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
|
||||
lmi != lmend; ++lmi)
|
||||
{
|
||||
// Try to erase this lhs key from the set of rhs keys. If rhs has
|
||||
// no such key, the maps are unequal. erase(key) returns count of
|
||||
// items erased.
|
||||
if (rhskeys.erase(lmi->first) != 1)
|
||||
return false;
|
||||
// Both maps have the current key. Compare values.
|
||||
if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
|
||||
return false;
|
||||
}
|
||||
// We've now established that all the lhs keys have equal values in
|
||||
// both maps. The maps are equal unless rhs contains a superset of
|
||||
// those keys.
|
||||
return rhskeys.empty();
|
||||
}
|
||||
|
||||
default:
|
||||
// We expect that every possible type() value is specifically handled
|
||||
// above. Failing to extend this switch to support a new LLSD type is
|
||||
// an error that must be brought to the coder's attention.
|
||||
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
|
||||
"unknown type " << lhs.type() << LL_ENDL;
|
||||
return false; // pacify the compiler
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#ifndef LL_LLSDUTIL_H
|
||||
#define LL_LLSDUTIL_H
|
||||
|
||||
#include "llsd.h"
|
||||
class LLSD;
|
||||
|
||||
// U32
|
||||
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
|
||||
@@ -59,6 +59,7 @@ LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
|
||||
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
|
||||
|
||||
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
|
||||
LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
|
||||
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
|
||||
|
||||
//compares the structure of an LLSD to a template LLSD and stores the
|
||||
@@ -73,6 +74,66 @@ LL_COMMON_API BOOL compare_llsd_with_template(
|
||||
const LLSD& template_llsd,
|
||||
LLSD& resultant_llsd);
|
||||
|
||||
/**
|
||||
* Recursively determine whether a given LLSD data block "matches" another
|
||||
* LLSD prototype. The returned string is empty() on success, non-empty() on
|
||||
* mismatch.
|
||||
*
|
||||
* This function tests structure (types) rather than data values. It is
|
||||
* intended for when a consumer expects an LLSD block with a particular
|
||||
* structure, and must succinctly detect whether the arriving block is
|
||||
* well-formed. For instance, a test of the form:
|
||||
* @code
|
||||
* if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
|
||||
* @endcode
|
||||
* could instead be expressed by initializing a prototype LLSD map with the
|
||||
* required keys and writing:
|
||||
* @code
|
||||
* if (! llsd_matches(prototype, data).empty())
|
||||
* @endcode
|
||||
*
|
||||
* A non-empty return value is an error-message fragment intended to indicate
|
||||
* to (English-speaking) developers where in the prototype structure the
|
||||
* mismatch occurred.
|
||||
*
|
||||
* * If a slot in the prototype isUndefined(), then anything is valid at that
|
||||
* place in the real object. (Passing prototype == LLSD() matches anything
|
||||
* at all.)
|
||||
* * An array in the prototype must match a data array at least that large.
|
||||
* (Additional entries in the data array are ignored.) Every isDefined()
|
||||
* entry in the prototype array must match the corresponding entry in the
|
||||
* data array.
|
||||
* * A map in the prototype must match a map in the data. Every key in the
|
||||
* prototype map must match a corresponding key in the data map. (Additional
|
||||
* keys in the data map are ignored.) Every isDefined() value in the
|
||||
* prototype map must match the corresponding key's value in the data map.
|
||||
* * Scalar values in the prototype are tested for @em type rather than value.
|
||||
* For instance, a String in the prototype matches any String at all. In
|
||||
* effect, storing an Integer at a particular place in the prototype asserts
|
||||
* that the caller intends to apply asInteger() to the corresponding slot in
|
||||
* the data.
|
||||
* * A String in the prototype matches String, Boolean, Integer, Real, UUID,
|
||||
* Date and URI, because asString() applied to any of these produces a
|
||||
* meaningful result.
|
||||
* * Similarly, a Boolean, Integer or Real in the prototype can match any of
|
||||
* Boolean, Integer or Real in the data -- or even String.
|
||||
* * UUID matches UUID or String.
|
||||
* * Date matches Date or String.
|
||||
* * URI matches URI or String.
|
||||
* * Binary in the prototype matches only Binary in the data.
|
||||
*
|
||||
* @TODO: when a Boolean, Integer or Real in the prototype matches a String in
|
||||
* the data, we should examine the String @em value to ensure it can be
|
||||
* meaningfully converted to the requested type. The same goes for UUID, Date
|
||||
* and URI.
|
||||
*/
|
||||
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
|
||||
|
||||
/// Deep equality. If you want to compare LLSD::Real values for approximate
|
||||
/// equality rather than bitwise equality, pass @a bits as for
|
||||
/// is_approx_equal_fraction().
|
||||
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1);
|
||||
|
||||
// Simple function to copy data out of input & output iterators if
|
||||
// there is no need for casting.
|
||||
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
||||
@@ -85,4 +146,283 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDArray
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const LLSD&);
|
||||
* ...
|
||||
* somefunc(LLSDArray("text")(17)(3.14));
|
||||
* @endcode
|
||||
*
|
||||
* For completeness, LLSDArray() with no args constructs an empty array, so
|
||||
* <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the
|
||||
* above. But for most purposes, LLSD() is already equivalent to an empty
|
||||
* array, and if you explicitly want an empty isArray(), there's
|
||||
* LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor
|
||||
* follows the principle of least astonishment.
|
||||
*/
|
||||
class LLSDArray
|
||||
{
|
||||
public:
|
||||
LLSDArray():
|
||||
_data(LLSD::emptyArray())
|
||||
{}
|
||||
|
||||
/**
|
||||
* Need an explicit copy constructor. Consider the following:
|
||||
*
|
||||
* @code
|
||||
* LLSD array_of_arrays(LLSDArray(LLSDArray(17)(34))
|
||||
* (LLSDArray("x")("y")));
|
||||
* @endcode
|
||||
*
|
||||
* The coder intends to construct [[17, 34], ["x", "y"]].
|
||||
*
|
||||
* With the compiler's implicit copy constructor, s/he gets instead
|
||||
* [17, 34, ["x", "y"]].
|
||||
*
|
||||
* The expression LLSDArray(17)(34) constructs an LLSDArray with those two
|
||||
* values. The reader assumes it should be converted to LLSD, as we always
|
||||
* want with LLSDArray, before passing it to the @em outer LLSDArray
|
||||
* constructor! This copy constructor makes that happen.
|
||||
*/
|
||||
LLSDArray(const LLSDArray& inner):
|
||||
_data(LLSD::emptyArray())
|
||||
{
|
||||
_data.append(inner);
|
||||
}
|
||||
|
||||
LLSDArray(const LLSD& value):
|
||||
_data(LLSD::emptyArray())
|
||||
{
|
||||
_data.append(value);
|
||||
}
|
||||
|
||||
LLSDArray& operator()(const LLSD& value)
|
||||
{
|
||||
_data.append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLSD() const { return _data; }
|
||||
LLSD get() const { return _data; }
|
||||
|
||||
private:
|
||||
LLSD _data;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDMap
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const LLSD&);
|
||||
* ...
|
||||
* somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14));
|
||||
* @endcode
|
||||
*
|
||||
* For completeness, LLSDMap() with no args constructs an empty map, so
|
||||
* <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map
|
||||
* equivalent to the above. But for most purposes, LLSD() is already
|
||||
* equivalent to an empty map, and if you explicitly want an empty isMap(),
|
||||
* there's LLSD::emptyMap(). However, supporting a no-args LLSDMap()
|
||||
* constructor follows the principle of least astonishment.
|
||||
*/
|
||||
class LLSDMap
|
||||
{
|
||||
public:
|
||||
LLSDMap():
|
||||
_data(LLSD::emptyMap())
|
||||
{}
|
||||
LLSDMap(const LLSD::String& key, const LLSD& value):
|
||||
_data(LLSD::emptyMap())
|
||||
{
|
||||
_data[key] = value;
|
||||
}
|
||||
|
||||
LLSDMap& operator()(const LLSD::String& key, const LLSD& value)
|
||||
{
|
||||
_data[key] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLSD() const { return _data; }
|
||||
LLSD get() const { return _data; }
|
||||
|
||||
private:
|
||||
LLSD _data;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDParam
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* LLSDParam is a customization point for passing LLSD values to function
|
||||
* parameters of more or less arbitrary type. LLSD provides a small set of
|
||||
* native conversions; but if a generic algorithm explicitly constructs an
|
||||
* LLSDParam object in the function's argument list, a consumer can provide
|
||||
* LLSDParam specializations to support more different parameter types than
|
||||
* LLSD's native conversions.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const paramtype&);
|
||||
* ...
|
||||
* somefunc(..., LLSDParam<paramtype>(someLLSD), ...);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class LLSDParam
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default implementation converts to T on construction, saves converted
|
||||
* value for later retrieval
|
||||
*/
|
||||
LLSDParam(const LLSD& value):
|
||||
_value(value)
|
||||
{}
|
||||
|
||||
operator T() const { return _value; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Turns out that several target types could accept an LLSD param using any of
|
||||
* a few different conversions, e.g. LLUUID's constructor can accept LLUUID or
|
||||
* std::string. Therefore, the compiler can't decide which LLSD conversion
|
||||
* operator to choose, even though to us it seems obvious. But that's okay, we
|
||||
* can specialize LLSDParam for such target types, explicitly specifying the
|
||||
* desired conversion -- that's part of what LLSDParam is all about. Turns out
|
||||
* we have to do that enough to make it worthwhile generalizing. Use a macro
|
||||
* because I need to specify one of the asReal, etc., explicit conversion
|
||||
* methods as well as a type. If I'm overlooking a clever way to implement
|
||||
* that using a template instead, feel free to reimplement.
|
||||
*/
|
||||
#define LLSDParam_for(T, AS) \
|
||||
template <> \
|
||||
class LLSDParam<T> \
|
||||
{ \
|
||||
public: \
|
||||
LLSDParam(const LLSD& value): \
|
||||
_value(value.AS()) \
|
||||
{} \
|
||||
\
|
||||
operator T() const { return _value; } \
|
||||
\
|
||||
private: \
|
||||
T _value; \
|
||||
}
|
||||
|
||||
LLSDParam_for(float, asReal);
|
||||
LLSDParam_for(LLUUID, asUUID);
|
||||
LLSDParam_for(LLDate, asDate);
|
||||
LLSDParam_for(LLURI, asURI);
|
||||
LLSDParam_for(LLSD::Binary, asBinary);
|
||||
|
||||
/**
|
||||
* LLSDParam<const char*> is an example of the kind of conversion you can
|
||||
* support with LLSDParam beyond native LLSD conversions. Normally you can't
|
||||
* pass an LLSD object to a function accepting const char* -- but you can
|
||||
* safely pass an LLSDParam<const char*>(yourLLSD).
|
||||
*/
|
||||
template <>
|
||||
class LLSDParam<const char*>
|
||||
{
|
||||
private:
|
||||
// The difference here is that we store a std::string rather than a const
|
||||
// char*. It's important that the LLSDParam object own the std::string.
|
||||
std::string _value;
|
||||
// We don't bother storing the incoming LLSD object, but we do have to
|
||||
// distinguish whether _value is an empty string because the LLSD object
|
||||
// contains an empty string or because it's isUndefined().
|
||||
bool _undefined;
|
||||
|
||||
public:
|
||||
LLSDParam(const LLSD& value):
|
||||
_value(value),
|
||||
_undefined(value.isUndefined())
|
||||
{}
|
||||
|
||||
// The const char* we retrieve is for storage owned by our _value member.
|
||||
// That's how we guarantee that the const char* is valid for the lifetime
|
||||
// of this LLSDParam object. Constructing your LLSDParam in the argument
|
||||
// list should ensure that the LLSDParam object will persist for the
|
||||
// duration of the function call.
|
||||
operator const char*() const
|
||||
{
|
||||
if (_undefined)
|
||||
{
|
||||
// By default, an isUndefined() LLSD object's asString() method
|
||||
// will produce an empty string. But for a function accepting
|
||||
// const char*, it's often important to be able to pass NULL, and
|
||||
// isUndefined() seems like the best way. If you want to pass an
|
||||
// empty string, you can still pass LLSD(""). Without this special
|
||||
// case, though, no LLSD value could pass NULL.
|
||||
return NULL;
|
||||
}
|
||||
return _value.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
namespace llsd
|
||||
{
|
||||
|
||||
/*****************************************************************************
|
||||
* BOOST_FOREACH() helpers for LLSD
|
||||
*****************************************************************************/
|
||||
/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... }
|
||||
class inArray
|
||||
{
|
||||
public:
|
||||
inArray(const LLSD& array):
|
||||
_array(array)
|
||||
{}
|
||||
|
||||
typedef LLSD::array_const_iterator const_iterator;
|
||||
typedef LLSD::array_iterator iterator;
|
||||
|
||||
iterator begin() { return _array.beginArray(); }
|
||||
iterator end() { return _array.endArray(); }
|
||||
const_iterator begin() const { return _array.beginArray(); }
|
||||
const_iterator end() const { return _array.endArray(); }
|
||||
|
||||
private:
|
||||
LLSD _array;
|
||||
};
|
||||
|
||||
/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator.
|
||||
typedef std::map<LLSD::String, LLSD>::value_type MapEntry;
|
||||
|
||||
/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... }
|
||||
class inMap
|
||||
{
|
||||
public:
|
||||
inMap(const LLSD& map):
|
||||
_map(map)
|
||||
{}
|
||||
|
||||
typedef LLSD::map_const_iterator const_iterator;
|
||||
typedef LLSD::map_iterator iterator;
|
||||
|
||||
iterator begin() { return _map.beginMap(); }
|
||||
iterator end() { return _map.endMap(); }
|
||||
const_iterator begin() const { return _map.beginMap(); }
|
||||
const_iterator end() const { return _map.endMap(); }
|
||||
|
||||
private:
|
||||
LLSD _map;
|
||||
};
|
||||
|
||||
} // namespace llsd
|
||||
|
||||
#endif // LL_LLSDUTIL_H
|
||||
|
||||
@@ -100,12 +100,6 @@ private:
|
||||
DELETED
|
||||
} EInitState;
|
||||
|
||||
static void deleteSingleton()
|
||||
{
|
||||
delete getData().mSingletonInstance;
|
||||
getData().mSingletonInstance = NULL;
|
||||
}
|
||||
|
||||
// stores pointer to singleton instance
|
||||
// and tracks initialization state of singleton
|
||||
struct SingletonInstanceData
|
||||
@@ -120,7 +114,11 @@ private:
|
||||
|
||||
~SingletonInstanceData()
|
||||
{
|
||||
deleteSingleton();
|
||||
SingletonInstanceData& data = getData();
|
||||
if (data.mInitState != DELETED)
|
||||
{
|
||||
deleteSingleton();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -132,6 +130,14 @@ public:
|
||||
data.mInitState = DELETED;
|
||||
}
|
||||
|
||||
// Can be used to control when the singleton is deleted. Not normally needed.
|
||||
static void deleteSingleton()
|
||||
{
|
||||
delete getData().mSingletonInstance;
|
||||
getData().mSingletonInstance = NULL;
|
||||
getData().mInitState = DELETED;
|
||||
}
|
||||
|
||||
static SingletonInstanceData& getData()
|
||||
{
|
||||
// this is static to cache the lookup results
|
||||
|
||||
@@ -43,9 +43,10 @@
|
||||
|
||||
|
||||
// statics
|
||||
BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
|
||||
S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
|
||||
LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
|
||||
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
|
||||
LLStat::stat_map_t LLStat::sStatList;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Live config file to trigger stats logging
|
||||
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
|
||||
|
||||
F32 duration = 0.f;
|
||||
F32 interval = 0.f;
|
||||
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||
|
||||
const char * w = "duration";
|
||||
if (stats_config.has(w))
|
||||
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
|
||||
{
|
||||
interval = (F32)stats_config[w].asReal();
|
||||
}
|
||||
w = "flags";
|
||||
if (stats_config.has(w))
|
||||
{
|
||||
flags = (S32)stats_config[w].asInteger();
|
||||
if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
|
||||
duration > 0)
|
||||
{ // No flags passed in, but have a duration, so reset to basic stats
|
||||
flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||
}
|
||||
}
|
||||
|
||||
mStatsp->setReportPerformanceDuration( duration );
|
||||
mStatsp->setReportPerformanceDuration( duration, flags );
|
||||
mStatsp->setReportPerformanceInterval( interval );
|
||||
|
||||
if ( duration > 0 )
|
||||
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
|
||||
}
|
||||
}
|
||||
|
||||
// Set length of performance stat recording
|
||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
||||
// Set length of performance stat recording.
|
||||
// If turning stats on, caller must provide flags
|
||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
|
||||
{
|
||||
if ( seconds <= 0.f )
|
||||
{
|
||||
mReportPerformanceStatEnd = 0.0;
|
||||
LLPerfBlock::setStatsEnabled( FALSE );
|
||||
LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
|
||||
mFrameStatsFile.close();
|
||||
LLPerfBlock::clearDynamicStats();
|
||||
}
|
||||
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
||||
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
|
||||
// Clear failure flag to try and create the log file once
|
||||
mFrameStatsFileFailure = FALSE;
|
||||
LLPerfBlock::setStatsEnabled( TRUE );
|
||||
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
|
||||
LLPerfBlock::setStatsFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta
|
||||
}
|
||||
}
|
||||
|
||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
|
||||
// These are also turned on or off via the switch passed in
|
||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||
LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
{
|
||||
if (!sStatsEnabled) return;
|
||||
if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
|
||||
{ // These are off unless the base set is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
initDynamicStat(key);
|
||||
}
|
||||
|
||||
|
||||
// Use this constructor for dynamically created LLPerfBlock time slices
|
||||
// that are only enabled by specific control flags
|
||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
{
|
||||
if ((sStatsFlags & flags) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == key2 || strlen(key2) == 0)
|
||||
{
|
||||
@@ -629,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the result data map if dynamic stats are enabled
|
||||
void LLPerfBlock::initDynamicStat(const std::string& key)
|
||||
{
|
||||
// Early exit if dynamic stats aren't enabled.
|
||||
if (!sStatsEnabled) return;
|
||||
if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
|
||||
return;
|
||||
|
||||
mLastPath = sCurrentStatPath; // Save and restore current path
|
||||
sCurrentStatPath += "/" + key; // Add key to current path
|
||||
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // WTF? Shouldn't have a NULL pointer in the map.
|
||||
{ // Shouldn't have a NULL pointer in the map.
|
||||
llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
|
||||
}
|
||||
}
|
||||
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
||||
LLTimer LLStat::sTimer;
|
||||
LLFrameTimer LLStat::sFrameTimer;
|
||||
|
||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
void LLStat::init()
|
||||
{
|
||||
llassert(num_bins > 0);
|
||||
mUseFrameTimer = use_frame_timer;
|
||||
llassert(mNumBins > 0);
|
||||
mNumValues = 0;
|
||||
mLastValue = 0.f;
|
||||
mLastTime = 0.f;
|
||||
mNumBins = num_bins;
|
||||
mCurBin = (mNumBins-1);
|
||||
mNextBin = 0;
|
||||
mBins = new F32[mNumBins];
|
||||
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
mTime[i] = 0.0;
|
||||
mDT[i] = 0.f;
|
||||
}
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
stat_map_t::iterator iter = sStatList.find(mName);
|
||||
if (iter != sStatList.end())
|
||||
llwarns << "LLStat with duplicate name: " << mName << llendl;
|
||||
sStatList.insert(std::make_pair(mName, this));
|
||||
}
|
||||
}
|
||||
|
||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins),
|
||||
mName(name)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLStat::~LLStat()
|
||||
@@ -754,6 +805,15 @@ LLStat::~LLStat()
|
||||
delete[] mBeginTime;
|
||||
delete[] mTime;
|
||||
delete[] mDT;
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
// handle multiple entries with the same name
|
||||
stat_map_t::iterator iter = sStatList.find(mName);
|
||||
while (iter != sStatList.end() && iter->second != this)
|
||||
++iter;
|
||||
sStatList.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void LLStat::reset()
|
||||
|
||||
@@ -192,14 +192,23 @@ public:
|
||||
// Use this constructor for pre-defined LLStatTime objects
|
||||
LLPerfBlock(LLStatTime* stat);
|
||||
|
||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
|
||||
LLPerfBlock( const char* key1, const char* key2 = NULL);
|
||||
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||
LLPerfBlock( const char* key );
|
||||
|
||||
// Use this constructor for dynamically created LLPerfBlock time slices
|
||||
// that are only enabled by specific control flags
|
||||
LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
|
||||
|
||||
~LLPerfBlock();
|
||||
|
||||
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
|
||||
static S32 getStatsEnabled() { return sStatsEnabled; };
|
||||
enum
|
||||
{ // Stats bitfield flags
|
||||
LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects
|
||||
LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats
|
||||
LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls
|
||||
};
|
||||
static void setStatsFlags( S32 flags ) { sStatsFlags = flags; };
|
||||
static S32 getStatsFlags() { return sStatsFlags; };
|
||||
|
||||
static void clearDynamicStats(); // Reset maps to clear out dynamic objects
|
||||
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
|
||||
@@ -213,7 +222,7 @@ private:
|
||||
LLStatTime * mPredefinedStat; // LLStatTime object to get data
|
||||
StatEntry * mDynamicStat; // StatEntryobject to get data
|
||||
|
||||
static BOOL sStatsEnabled; // Normally FALSE
|
||||
static S32 sStatsFlags; // Control what is being recorded
|
||||
static stat_map_t sStatMap; // Map full path string to LLStatTime objects
|
||||
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
|
||||
};
|
||||
@@ -236,7 +245,7 @@ public:
|
||||
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
|
||||
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
|
||||
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
|
||||
void setReportPerformanceDuration( F32 seconds );
|
||||
void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
|
||||
void setProcessName(const std::string& process_name) { mProcessName = process_name; }
|
||||
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
|
||||
|
||||
@@ -258,8 +267,15 @@ private:
|
||||
// ----------------------------------------------------------------------------
|
||||
class LL_COMMON_API LLStat
|
||||
{
|
||||
private:
|
||||
typedef std::multimap<std::string, LLStat*> stat_map_t;
|
||||
static stat_map_t sStatList;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
~LLStat();
|
||||
|
||||
void reset();
|
||||
@@ -322,8 +338,22 @@ private:
|
||||
F32 *mDT;
|
||||
S32 mCurBin;
|
||||
S32 mNextBin;
|
||||
|
||||
std::string mName;
|
||||
|
||||
static LLTimer sTimer;
|
||||
static LLFrameTimer sFrameTimer;
|
||||
|
||||
public:
|
||||
static LLStat* getStat(const std::string& name)
|
||||
{
|
||||
// return the first stat that matches 'name'
|
||||
stat_map_t::iterator iter = sStatList.find(name);
|
||||
if (iter != sStatList.end())
|
||||
return iter->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STAT_
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
// skips spaces and tabs
|
||||
bool skip_whitespace(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while (('\t' == c || ' ' == c) && input_stream.good())
|
||||
{
|
||||
input_stream.get();
|
||||
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
|
||||
// skips whitespace, newlines, and carriage returns
|
||||
bool skip_emptyspace(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( input_stream.good()
|
||||
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) )
|
||||
{
|
||||
@@ -72,7 +72,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
|
||||
{
|
||||
while (skip_emptyspace(input_stream))
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
if ('#' == c )
|
||||
{
|
||||
while ('\n' != c && input_stream.good())
|
||||
@@ -90,7 +90,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
|
||||
|
||||
bool skip_line(std::istream& input_stream)
|
||||
{
|
||||
char c;
|
||||
int c;
|
||||
do
|
||||
{
|
||||
c = input_stream.get();
|
||||
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
|
||||
|
||||
bool skip_to_next_word(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( input_stream.good()
|
||||
&& ( (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
@@ -132,7 +132,7 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
|
||||
while (input_stream.good())
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
if (keyword[0] != c)
|
||||
{
|
||||
skip_line(input_stream);
|
||||
@@ -181,7 +181,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
|
||||
while (input_stream.good())
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
if (keyword[0] != c)
|
||||
{
|
||||
skip_line(input_stream);
|
||||
@@ -229,7 +229,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
|
||||
bool get_word(std::string& output_string, std::istream& input_stream)
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( !isspace(c)
|
||||
&& '\n' != c
|
||||
&& '\r' != c
|
||||
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
int char_count = 0;
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while (!isspace(c)
|
||||
&& '\n' != c
|
||||
&& '\r' != c
|
||||
@@ -265,7 +265,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
||||
bool get_line(std::string& output_string, std::istream& input_stream)
|
||||
{
|
||||
output_string.clear();
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
while (input_stream.good())
|
||||
{
|
||||
output_string += c;
|
||||
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
|
||||
{
|
||||
output_string.clear();
|
||||
int char_count = 0;
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
while (input_stream.good() && char_count < n)
|
||||
{
|
||||
char_count++;
|
||||
|
||||
@@ -52,6 +52,7 @@ public:
|
||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
||||
void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
|
||||
bool isStrided() const { return mTypeSize != mSkip; }
|
||||
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||
U32 getSkip() const { return mSkip; }
|
||||
Object* get() { return mObjectp; }
|
||||
@@ -70,7 +71,7 @@ public:
|
||||
//stride == sizeof(element) implies entire buffer is unstrided and thus memcpy-able, provided source buffer elements match in size.
|
||||
//Because LLStrider is often passed an LLVector3 even if the reprensentation is LLVector4 in the vertex buffer, mTypeSize is set to
|
||||
//the TRUE vbo datatype size via VertexBufferStrider::get
|
||||
if(mTypeSize == mSkip && mTypeSize == elem_size)
|
||||
if(!isStrided() && mTypeSize == elem_size)
|
||||
{
|
||||
if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
|
||||
{
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "u64.h"
|
||||
|
||||
#include "lldate.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
#include "lldate.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
@@ -55,8 +53,6 @@ const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR;
|
||||
const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
|
||||
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC;
|
||||
|
||||
LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds
|
||||
|
||||
class LL_COMMON_API LLTimer
|
||||
{
|
||||
public:
|
||||
@@ -175,4 +171,5 @@ LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstri
|
||||
LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string ×tr);
|
||||
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string ×tr);
|
||||
|
||||
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
|
||||
#endif
|
||||
|
||||
705
indra/llcommon/lltreeiterators.h
Normal file
705
indra/llcommon/lltreeiterators.h
Normal file
@@ -0,0 +1,705 @@
|
||||
/**
|
||||
* @file lltreeiterators.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2008-08-19
|
||||
* @brief This file defines iterators useful for traversing arbitrary node
|
||||
* classes, potentially polymorphic, linked into strict tree
|
||||
* structures.
|
||||
*
|
||||
* Dereferencing any one of these iterators actually yields a @em
|
||||
* pointer to the node in question. For example, given an
|
||||
* LLLinkedIter<MyNode> <tt>li</tt>, <tt>*li</tt> gets you a pointer
|
||||
* to MyNode, and <tt>**li</tt> gets you the MyNode instance itself.
|
||||
* More commonly, instead of writing <tt>li->member</tt>, you write
|
||||
* <tt>(*li)->member</tt> -- as you would if you were traversing an
|
||||
* STL container of MyNode pointers.
|
||||
*
|
||||
* It would certainly be possible to build these iterators so that
|
||||
* <tt>*iterator</tt> would return a reference to the node itself
|
||||
* rather than a pointer to the node, and for many purposes it would
|
||||
* even be more convenient. However, that would be insufficiently
|
||||
* flexible. If you want to use an iterator range to (e.g.) initialize
|
||||
* a std::vector collecting results -- you rarely want to actually @em
|
||||
* copy the nodes in question. You're much more likely to want to copy
|
||||
* <i>pointers to</i> the traversed nodes. Hence these iterators
|
||||
* produce pointers.
|
||||
*
|
||||
* Though you specify the actual NODE class as the template parameter,
|
||||
* these iterators internally use LLPtrTo<> to discover whether to
|
||||
* store and return an LLPointer<NODE> or a simple NODE*.
|
||||
*
|
||||
* By strict tree structures, we mean that each child must have
|
||||
* exactly one parent. This forbids a child claiming any ancestor as a
|
||||
* child of its own. Child nodes with multiple parents will be visited
|
||||
* once for each parent. Cycles in the graph will result in either an
|
||||
* infinite loop or an out-of-memory crash. You Have Been Warned.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_LLTREEITERATORS_H)
|
||||
#define LL_LLTREEITERATORS_H
|
||||
|
||||
#include "llptrto.h"
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
namespace LLTreeIter
|
||||
{
|
||||
/// Discriminator between LLTreeUpIter and LLTreeDownIter
|
||||
enum RootIter { UP, DOWN };
|
||||
/// Discriminator between LLTreeDFSIter, LLTreeDFSPostIter and LLTreeBFSIter
|
||||
enum WalkIter { DFS_PRE, DFS_POST, BFS };
|
||||
}
|
||||
|
||||
/**
|
||||
* LLBaseIter defines some machinery common to all these iterators. We use
|
||||
* boost::iterator_facade to define the iterator boilerplate: the conventional
|
||||
* operators and methods necessary to implement a standards-conforming
|
||||
* iterator. That allows us to specify the actual iterator semantics in terms
|
||||
* of equal(), dereference() and increment() methods.
|
||||
*/
|
||||
template <class SELFTYPE, class NODE>
|
||||
class LLBaseIter: public boost::iterator_facade<SELFTYPE,
|
||||
// use pointer type as the
|
||||
// reference type
|
||||
typename LLPtrTo<NODE>::type,
|
||||
boost::forward_traversal_tag>
|
||||
{
|
||||
protected:
|
||||
/// LLPtrTo<NODE>::type is either NODE* or LLPointer<NODE>, as appropriate
|
||||
typedef typename LLPtrTo<NODE>::type ptr_type;
|
||||
/// function that advances from this node to next accepts a node pointer
|
||||
/// and returns another
|
||||
typedef boost::function<ptr_type(const ptr_type&)> func_type;
|
||||
typedef SELFTYPE self_type;
|
||||
};
|
||||
|
||||
/// Functor returning NULL, suitable for an end-iterator's 'next' functor
|
||||
template <class NODE>
|
||||
typename LLPtrTo<NODE>::type LLNullNextFunctor(const typename LLPtrTo<NODE>::type&)
|
||||
{
|
||||
return typename LLPtrTo<NODE>::type();
|
||||
}
|
||||
|
||||
/**
|
||||
* LLLinkedIter is an iterator over an intrusive singly-linked list. The
|
||||
* beginning of the list is represented by LLLinkedIter(list head); the end is
|
||||
* represented by LLLinkedIter().
|
||||
*
|
||||
* The begin LLLinkedIter must be instantiated with a functor to extract the
|
||||
* 'next' pointer from the current node. Supposing that the link pointer is @c
|
||||
* public, something like:
|
||||
*
|
||||
* @code
|
||||
* NODE* mNext;
|
||||
* @endcode
|
||||
*
|
||||
* you can use (e.g.) <tt>boost::bind(&NODE::mNext, _1)</tt> for the purpose.
|
||||
* Alternatively, you can bind whatever accessor method is normally used to
|
||||
* advance to the next node, e.g. for:
|
||||
*
|
||||
* @code
|
||||
* NODE* next() const;
|
||||
* @endcode
|
||||
*
|
||||
* you can use <tt>boost::bind(&NODE::next, _1)</tt>.
|
||||
*/
|
||||
template <class NODE>
|
||||
class LLLinkedIter: public LLBaseIter<LLLinkedIter<NODE>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLLinkedIter<NODE>, NODE> super;
|
||||
protected:
|
||||
/// some methods need to return a reference to self
|
||||
typedef typename super::self_type self_type;
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
typedef typename super::func_type func_type;
|
||||
public:
|
||||
/// Instantiate an LLLinkedIter to start a range, or to end a range before
|
||||
/// a particular list entry. Pass a functor to extract the 'next' pointer
|
||||
/// from the current node.
|
||||
LLLinkedIter(const ptr_type& entry, const func_type& nextfunc):
|
||||
mCurrent(entry),
|
||||
mNextFunc(nextfunc)
|
||||
{}
|
||||
/// Instantiate an LLLinkedIter to end a range at the end of the list
|
||||
LLLinkedIter():
|
||||
mCurrent(),
|
||||
mNextFunc(LLNullNextFunctor<NODE>)
|
||||
{}
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
void increment()
|
||||
{
|
||||
mCurrent = mNextFunc(mCurrent);
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mCurrent == that.mCurrent; }
|
||||
/// dereference
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mCurrent); }
|
||||
|
||||
ptr_type mCurrent;
|
||||
func_type mNextFunc;
|
||||
};
|
||||
|
||||
/**
|
||||
* LLTreeUpIter walks from the node in hand to the root of the tree. The term
|
||||
* "up" is applied to a tree visualized with the root at the top.
|
||||
*
|
||||
* LLTreeUpIter is an alias for LLLinkedIter, since any linked tree that you
|
||||
* can navigate that way at all contains parent pointers.
|
||||
*/
|
||||
template <class NODE>
|
||||
class LLTreeUpIter: public LLLinkedIter<NODE>
|
||||
{
|
||||
typedef LLLinkedIter<NODE> super;
|
||||
public:
|
||||
/// Instantiate an LLTreeUpIter to start from a particular tree node, or
|
||||
/// to end a parent traversal before reaching a particular ancestor. Pass
|
||||
/// a functor to extract the 'parent' pointer from the current node.
|
||||
LLTreeUpIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& parentfunc):
|
||||
super(node, parentfunc)
|
||||
{}
|
||||
/// Instantiate an LLTreeUpIter to end a range at the root of the tree
|
||||
LLTreeUpIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* LLTreeDownIter walks from the root of the tree to the node in hand. The
|
||||
* term "down" is applied to a tree visualized with the root at the top.
|
||||
*
|
||||
* Though you instantiate the begin() LLTreeDownIter with a pointer to some
|
||||
* node at an arbitrary location in the tree, the root will be the first node
|
||||
* you dereference and the passed node will be the last node you dereference.
|
||||
*
|
||||
* On construction, LLTreeDownIter walks from the current node to the root,
|
||||
* capturing the path. Then in use, it replays that walk in reverse. As with
|
||||
* all traversals of interesting data structures, it is actively dangerous to
|
||||
* modify the tree during an LLTreeDownIter walk.
|
||||
*/
|
||||
template <class NODE>
|
||||
class LLTreeDownIter: public LLBaseIter<LLTreeDownIter<NODE>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLTreeDownIter<NODE>, NODE> super;
|
||||
typedef typename super::self_type self_type;
|
||||
protected:
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
typedef typename super::func_type func_type;
|
||||
private:
|
||||
typedef std::vector<ptr_type> list_type;
|
||||
public:
|
||||
/// Instantiate an LLTreeDownIter to end at a particular tree node. Pass a
|
||||
/// functor to extract the 'parent' pointer from the current node.
|
||||
LLTreeDownIter(const ptr_type& node,
|
||||
const func_type& parentfunc)
|
||||
{
|
||||
for (ptr_type n = node; n; n = parentfunc(n))
|
||||
mParents.push_back(n);
|
||||
}
|
||||
/// Instantiate an LLTreeDownIter representing "here", the end of the loop
|
||||
LLTreeDownIter() {}
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
void increment()
|
||||
{
|
||||
mParents.pop_back();
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mParents == that.mParents; }
|
||||
/// implement dereference/indirection operators
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mParents.back()); }
|
||||
|
||||
list_type mParents;
|
||||
};
|
||||
|
||||
/**
|
||||
* When you want to select between LLTreeUpIter and LLTreeDownIter with a
|
||||
* compile-time discriminator, use LLTreeRootIter with an LLTreeIter::RootIter
|
||||
* template arg.
|
||||
*/
|
||||
template <LLTreeIter::RootIter DISCRIM, class NODE>
|
||||
class LLTreeRootIter
|
||||
{
|
||||
enum { use_a_valid_LLTreeIter_RootIter_value = false };
|
||||
public:
|
||||
/// Bogus constructors for default (unrecognized discriminator) case
|
||||
template <typename TYPE1, typename TYPE2>
|
||||
LLTreeRootIter(TYPE1, TYPE2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
|
||||
}
|
||||
LLTreeRootIter()
|
||||
{
|
||||
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
|
||||
}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::UP
|
||||
template <class NODE>
|
||||
class LLTreeRootIter<LLTreeIter::UP, NODE>: public LLTreeUpIter<NODE>
|
||||
{
|
||||
typedef LLTreeUpIter<NODE> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeRootIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& parentfunc):
|
||||
super(node, parentfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeRootIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::DOWN
|
||||
template <class NODE>
|
||||
class LLTreeRootIter<LLTreeIter::DOWN, NODE>: public LLTreeDownIter<NODE>
|
||||
{
|
||||
typedef LLTreeDownIter<NODE> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeRootIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& parentfunc):
|
||||
super(node, parentfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeRootIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiated with a tree node, typically the root, LLTreeDFSIter "flattens"
|
||||
* a depth-first tree walk through that node and all its descendants.
|
||||
*
|
||||
* The begin() LLTreeDFSIter must be instantiated with functors to obtain from
|
||||
* a given node begin() and end() iterators for that node's children. For this
|
||||
* reason, you must specify the type of the node's child iterator as an
|
||||
* additional template parameter.
|
||||
*
|
||||
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||
* value is a @em pointer to a child tree node. For instance, if each node
|
||||
* tracks its children in an STL container of node* pointers, you can simply
|
||||
* return that container's begin() iterator.
|
||||
*
|
||||
* Alternatively, if a node tracks its children with a classic linked list,
|
||||
* write a functor returning LLLinkedIter<NODE>.
|
||||
*
|
||||
* The end() LLTreeDFSIter must, of course, match the begin() iterator's
|
||||
* template parameters, but is constructed without runtime parameters.
|
||||
*/
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeDFSIter: public LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE> super;
|
||||
typedef typename super::self_type self_type;
|
||||
protected:
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
// The func_type is different for this: from a NODE pointer, we must
|
||||
// obtain a CHILDITER.
|
||||
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||
private:
|
||||
typedef std::vector<ptr_type> list_type;
|
||||
public:
|
||||
/// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass
|
||||
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||
/// each node.
|
||||
LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
|
||||
: mBeginFunc(beginfunc),
|
||||
mEndFunc(endfunc),
|
||||
mSkipChildren(false)
|
||||
{
|
||||
// Only push back this node if it's non-NULL!
|
||||
if (node)
|
||||
mPending.push_back(node);
|
||||
}
|
||||
/// Instantiate an LLTreeDFSIter to mark the end of the walk
|
||||
LLTreeDFSIter() : mSkipChildren(false) {}
|
||||
|
||||
/// flags iterator logic to skip traversing children of current node on next increment
|
||||
void skipDescendants(bool skip = true) { mSkipChildren = skip; }
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
|
||||
void increment()
|
||||
{
|
||||
// Capture the node we were just looking at
|
||||
ptr_type current = mPending.back();
|
||||
// Remove it from mPending so we don't process it again later
|
||||
mPending.pop_back();
|
||||
if (!mSkipChildren)
|
||||
{
|
||||
// Add all its children to mPending
|
||||
addChildren(current);
|
||||
}
|
||||
// reset flag after each step
|
||||
mSkipChildren = false;
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||
/// implement dereference/indirection operators
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back()); }
|
||||
|
||||
/// Add the direct children of the specified node to mPending
|
||||
void addChildren(const ptr_type& node)
|
||||
{
|
||||
// If we just use push_back() for each child in turn, we'll end up
|
||||
// processing children in reverse order. We don't want to assume
|
||||
// CHILDITER is reversible: some of the linked trees we'll be
|
||||
// processing manage their children using singly-linked lists. So
|
||||
// figure out how many children there are, grow mPending by that size
|
||||
// and reverse-copy the children into the new space.
|
||||
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
|
||||
// grow mPending by the number of children
|
||||
mPending.resize(mPending.size() + std::distance(chi, chend));
|
||||
// reverse-copy the children into the newly-expanded space
|
||||
std::copy(chi, chend, mPending.rbegin());
|
||||
}
|
||||
|
||||
/// list of the nodes yet to be processed
|
||||
list_type mPending;
|
||||
/// functor to extract begin() child iterator
|
||||
func_type mBeginFunc;
|
||||
/// functor to extract end() child iterator
|
||||
func_type mEndFunc;
|
||||
/// flag which controls traversal of children (skip children of current node if true)
|
||||
bool mSkipChildren;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiated with a tree node, typically the root, LLTreeDFSPostIter
|
||||
* "flattens" a depth-first tree walk through that node and all its
|
||||
* descendants. Whereas LLTreeDFSIter visits each node before visiting any of
|
||||
* its children, LLTreeDFSPostIter visits all of a node's children before
|
||||
* visiting the node itself.
|
||||
*
|
||||
* The begin() LLTreeDFSPostIter must be instantiated with functors to obtain
|
||||
* from a given node begin() and end() iterators for that node's children. For
|
||||
* this reason, you must specify the type of the node's child iterator as an
|
||||
* additional template parameter.
|
||||
*
|
||||
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||
* value is a @em pointer to a child tree node. For instance, if each node
|
||||
* tracks its children in an STL container of node* pointers, you can simply
|
||||
* return that container's begin() iterator.
|
||||
*
|
||||
* Alternatively, if a node tracks its children with a classic linked list,
|
||||
* write a functor returning LLLinkedIter<NODE>.
|
||||
*
|
||||
* The end() LLTreeDFSPostIter must, of course, match the begin() iterator's
|
||||
* template parameters, but is constructed without runtime parameters.
|
||||
*/
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeDFSPostIter: public LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE> super;
|
||||
typedef typename super::self_type self_type;
|
||||
protected:
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
// The func_type is different for this: from a NODE pointer, we must
|
||||
// obtain a CHILDITER.
|
||||
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||
private:
|
||||
// Upon reaching a given node in our pending list, we need to know whether
|
||||
// we've already pushed that node's children, so we must associate a bool
|
||||
// with each node pointer.
|
||||
typedef std::vector< std::pair<ptr_type, bool> > list_type;
|
||||
public:
|
||||
/// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass
|
||||
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||
/// each node.
|
||||
LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
|
||||
: mBeginFunc(beginfunc),
|
||||
mEndFunc(endfunc),
|
||||
mSkipAncestors(false)
|
||||
{
|
||||
if (! node)
|
||||
return;
|
||||
mPending.push_back(typename list_type::value_type(node, false));
|
||||
makeCurrent();
|
||||
}
|
||||
/// Instantiate an LLTreeDFSPostIter to mark the end of the walk
|
||||
LLTreeDFSPostIter() : mSkipAncestors(false) {}
|
||||
|
||||
/// flags iterator logic to skip traversing ancestors of current node on next increment
|
||||
void skipAncestors(bool skip = true) { mSkipAncestors = skip; }
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
|
||||
void increment()
|
||||
{
|
||||
// Pop the previous current node
|
||||
mPending.pop_back();
|
||||
makeCurrent();
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||
/// implement dereference/indirection operators
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back().first); }
|
||||
|
||||
struct isOpen
|
||||
{
|
||||
bool operator()(const typename list_type::value_type& item)
|
||||
{
|
||||
return item.second;
|
||||
}
|
||||
};
|
||||
|
||||
/// Call this each time we change mPending.back() -- that is, every time
|
||||
/// we're about to change the value returned by dereference(). If we
|
||||
/// haven't yet pushed the new node's children, do so now.
|
||||
void makeCurrent()
|
||||
{
|
||||
if (mSkipAncestors)
|
||||
{
|
||||
mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end());
|
||||
mSkipAncestors = false;
|
||||
}
|
||||
|
||||
// Once we've popped the last node, this becomes a no-op.
|
||||
if (mPending.empty())
|
||||
return;
|
||||
// Here mPending.back() holds the node pointer we're proposing to
|
||||
// dereference next. Have we pushed that node's children yet?
|
||||
if (mPending.back().second)
|
||||
return; // if so, it's okay to visit this node now
|
||||
// We haven't yet pushed this node's children. Do so now. Remember
|
||||
// that we did -- while the node in question is still back().
|
||||
mPending.back().second = true;
|
||||
addChildren(mPending.back().first);
|
||||
// Now, because we've just changed mPending.back(), make that new node
|
||||
// current.
|
||||
makeCurrent();
|
||||
}
|
||||
|
||||
/// Add the direct children of the specified node to mPending
|
||||
void addChildren(const ptr_type& node)
|
||||
{
|
||||
// If we just use push_back() for each child in turn, we'll end up
|
||||
// processing children in reverse order. We don't want to assume
|
||||
// CHILDITER is reversible: some of the linked trees we'll be
|
||||
// processing manage their children using singly-linked lists. So
|
||||
// figure out how many children there are, grow mPending by that size
|
||||
// and reverse-copy the children into the new space.
|
||||
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
|
||||
// grow mPending by the number of children
|
||||
mPending.resize(mPending.size() + std::distance(chi, chend));
|
||||
// Reverse-copy the children into the newly-expanded space. We can't
|
||||
// just use std::copy() because the source is a ptr_type, whereas the
|
||||
// dest is a pair of (ptr_type, bool).
|
||||
for (typename list_type::reverse_iterator pi = mPending.rbegin(); chi != chend; ++chi, ++pi)
|
||||
{
|
||||
pi->first = *chi; // copy the child pointer
|
||||
pi->second = false; // we haven't yet pushed this child's chldren
|
||||
}
|
||||
}
|
||||
|
||||
/// list of the nodes yet to be processed
|
||||
list_type mPending;
|
||||
/// functor to extract begin() child iterator
|
||||
func_type mBeginFunc;
|
||||
/// functor to extract end() child iterator
|
||||
func_type mEndFunc;
|
||||
/// flags logic to skip traversal of ancestors of current node
|
||||
bool mSkipAncestors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiated with a tree node, typically the root, LLTreeBFSIter "flattens"
|
||||
* a breadth-first tree walk through that node and all its descendants.
|
||||
*
|
||||
* The begin() LLTreeBFSIter must be instantiated with functors to obtain from
|
||||
* a given node the begin() and end() iterators of that node's children. For
|
||||
* this reason, you must specify the type of the node's child iterator as an
|
||||
* additional template parameter.
|
||||
*
|
||||
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||
* value is a @em pointer to a child tree node. For instance, if each node
|
||||
* tracks its children in an STL container of node* pointers, you can simply
|
||||
* return that container's begin() iterator.
|
||||
*
|
||||
* Alternatively, if a node tracks its children with a classic linked list,
|
||||
* write a functor returning LLLinkedIter<NODE>.
|
||||
*
|
||||
* The end() LLTreeBFSIter must, of course, match the begin() iterator's
|
||||
* template parameters, but is constructed without runtime parameters.
|
||||
*/
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeBFSIter: public LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE> super;
|
||||
typedef typename super::self_type self_type;
|
||||
protected:
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
// The func_type is different for this: from a NODE pointer, we must
|
||||
// obtain a CHILDITER.
|
||||
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||
private:
|
||||
// We need a FIFO queue rather than a LIFO stack. Use a deque rather than
|
||||
// a vector, since vector can't implement pop_front() efficiently.
|
||||
typedef std::deque<ptr_type> list_type;
|
||||
public:
|
||||
/// Instantiate an LLTreeBFSIter to start a depth-first walk. Pass
|
||||
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||
/// each node.
|
||||
LLTreeBFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc):
|
||||
mBeginFunc(beginfunc),
|
||||
mEndFunc(endfunc)
|
||||
{
|
||||
if (node)
|
||||
mPending.push_back(node);
|
||||
}
|
||||
/// Instantiate an LLTreeBFSIter to mark the end of the walk
|
||||
LLTreeBFSIter() {}
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
/// This implementation is due to http://en.wikipedia.org/wiki/Breadth-first_search
|
||||
void increment()
|
||||
{
|
||||
// Capture the node we were just looking at
|
||||
ptr_type current = mPending.front();
|
||||
// Remove it from mPending so we don't process it again later
|
||||
mPending.pop_front();
|
||||
// Add all its children to mPending
|
||||
CHILDITER chend = mEndFunc(current);
|
||||
for (CHILDITER chi = mBeginFunc(current); chi != chend; ++chi)
|
||||
mPending.push_back(*chi);
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||
/// implement dereference/indirection operators
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.front()); }
|
||||
|
||||
/// list of the nodes yet to be processed
|
||||
list_type mPending;
|
||||
/// functor to extract begin() child iterator
|
||||
func_type mBeginFunc;
|
||||
/// functor to extract end() child iterator
|
||||
func_type mEndFunc;
|
||||
};
|
||||
|
||||
/**
|
||||
* When you want to select between LLTreeDFSIter, LLTreeDFSPostIter and
|
||||
* LLTreeBFSIter with a compile-time discriminator, use LLTreeWalkIter with an
|
||||
* LLTreeIter::WalkIter template arg.
|
||||
*/
|
||||
template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER>
|
||||
class LLTreeWalkIter
|
||||
{
|
||||
enum { use_a_valid_LLTreeIter_WalkIter_value = false };
|
||||
public:
|
||||
/// Bogus constructors for default (unrecognized discriminator) case
|
||||
template <typename TYPE1, typename TYPE2>
|
||||
LLTreeWalkIter(TYPE1, TYPE2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
|
||||
}
|
||||
LLTreeWalkIter()
|
||||
{
|
||||
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
|
||||
}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::DFS_PRE
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeWalkIter<LLTreeIter::DFS_PRE, NODE, CHILDITER>:
|
||||
public LLTreeDFSIter<NODE, CHILDITER>
|
||||
{
|
||||
typedef LLTreeDFSIter<NODE, CHILDITER> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& beginfunc,
|
||||
const typename super::func_type& endfunc):
|
||||
super(node, beginfunc, endfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeWalkIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::DFS_POST
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeWalkIter<LLTreeIter::DFS_POST, NODE, CHILDITER>:
|
||||
public LLTreeDFSPostIter<NODE, CHILDITER>
|
||||
{
|
||||
typedef LLTreeDFSPostIter<NODE, CHILDITER> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& beginfunc,
|
||||
const typename super::func_type& endfunc):
|
||||
super(node, beginfunc, endfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeWalkIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::BFS
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeWalkIter<LLTreeIter::BFS, NODE, CHILDITER>:
|
||||
public LLTreeBFSIter<NODE, CHILDITER>
|
||||
{
|
||||
typedef LLTreeBFSIter<NODE, CHILDITER> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& beginfunc,
|
||||
const typename super::func_type& endfunc):
|
||||
super(node, beginfunc, endfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeWalkIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLTREEITERATORS_H) */
|
||||
@@ -32,7 +32,7 @@
|
||||
#ifndef LL_LLECONOMY_H
|
||||
#define LL_LLECONOMY_H
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
class LLMessageSystem;
|
||||
class LLVector3;
|
||||
|
||||
@@ -36,10 +36,9 @@
|
||||
#include "lldarray.h"
|
||||
#include "llfoldertype.h"
|
||||
#include "llinventorytype.h"
|
||||
#include "llinventorydefines.h"
|
||||
#include "llmemtype.h"
|
||||
#include "llpermissions.h"
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsaleinfo.h"
|
||||
#include "llsd.h"
|
||||
#include "lluuid.h"
|
||||
@@ -304,84 +303,11 @@ protected:
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Useful bits
|
||||
// Convertors
|
||||
//
|
||||
// These functions convert between structured data and an inventory
|
||||
// item, appropriate for serialization.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This functor tests if an item is transferrable and returns true if
|
||||
// it is. Derived from unary_function<> so that the object can be used
|
||||
// in stl-compliant adaptable predicates (eg, not1<>). You might want
|
||||
// to use this in std::partition() or similar logic.
|
||||
struct IsItemTransferable : public std::unary_function<LLInventoryItem*, bool>
|
||||
{
|
||||
LLUUID mDestID;
|
||||
IsItemTransferable(const LLUUID& dest_id) : mDestID(dest_id) {}
|
||||
bool operator()(const LLInventoryItem* item) const
|
||||
{
|
||||
return (item->getPermissions().allowTransferTo(mDestID)) ? true:false;
|
||||
}
|
||||
};
|
||||
|
||||
// This functor is used to set the owner and group of inventory items,
|
||||
// for example, in a simple std::for_each() loop. Note that the call
|
||||
// to setOwnerAndGroup can fail if authority_id != LLUUID::null.
|
||||
struct SetItemOwnerAndGroup
|
||||
{
|
||||
LLUUID mAuthorityID;
|
||||
LLUUID mOwnerID;
|
||||
LLUUID mGroupID;
|
||||
SetItemOwnerAndGroup(const LLUUID& authority_id,
|
||||
const LLUUID& owner_id,
|
||||
const LLUUID& group_id) :
|
||||
mAuthorityID(authority_id), mOwnerID(owner_id), mGroupID(group_id) {}
|
||||
void operator()(LLInventoryItem* item) const
|
||||
{
|
||||
LLPermissions perm = item->getPermissions();
|
||||
bool is_atomic = (LLAssetType::AT_OBJECT == item->getType()) ? false : true;
|
||||
perm.setOwnerAndGroup(mAuthorityID, mOwnerID, mGroupID, is_atomic);
|
||||
// If no owner id is set, this is equivalent to a deed action.
|
||||
// Clear 'share with group'.
|
||||
if (mOwnerID.isNull())
|
||||
{
|
||||
perm.setMaskGroup(PERM_NONE);
|
||||
}
|
||||
item->setPermissions(perm);
|
||||
}
|
||||
};
|
||||
|
||||
// This functor is used to unset the share with group, everyone perms, and
|
||||
// for sale info for objects being sold through contents.
|
||||
struct SetNotForSale
|
||||
{
|
||||
LLUUID mAgentID;
|
||||
LLUUID mGroupID;
|
||||
SetNotForSale(const LLUUID& agent_id,
|
||||
const LLUUID& group_id) :
|
||||
mAgentID(agent_id), mGroupID(group_id) {}
|
||||
void operator()(LLInventoryItem* item) const
|
||||
{
|
||||
// Clear group & everyone permissions.
|
||||
LLPermissions perm = item->getPermissions();
|
||||
perm.setGroupBits(mAgentID, mGroupID, FALSE, PERM_MODIFY | PERM_MOVE | PERM_COPY);
|
||||
perm.setEveryoneBits(mAgentID, mGroupID, FALSE, PERM_MOVE | PERM_COPY);
|
||||
item->setPermissions(perm);
|
||||
|
||||
// Mark group & everyone permissions for overwrite on the next
|
||||
// rez if it is an object.
|
||||
if(LLAssetType::AT_OBJECT == item->getType())
|
||||
{
|
||||
U32 flags = item->getFlags();
|
||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
|
||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
|
||||
item->setFlags(flags);
|
||||
}
|
||||
|
||||
// Clear for sale info.
|
||||
item->setSaleInfo(LLSaleInfo::DEFAULT);
|
||||
}
|
||||
};
|
||||
|
||||
// These functions convert between structured data and an inventroy
|
||||
// item, appropriate for serialization.
|
||||
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
|
||||
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
|
||||
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llinventorytype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
static const std::string empty_string;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#ifndef LL_NOTECARD_H
|
||||
#define LL_NOTECARD_H
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llinventory.h"
|
||||
|
||||
class LLNotecard
|
||||
|
||||
@@ -177,7 +177,7 @@ void LLParcel::init(const LLUUID &owner_id,
|
||||
mSaleTimerExpires.stop();
|
||||
mGraceExtension = 0;
|
||||
//mExpireAction = STEA_REVERT;
|
||||
mRecordTransaction = FALSE;
|
||||
//mRecordTransaction = FALSE;
|
||||
|
||||
mAuctionID = 0;
|
||||
mInEscrow = false;
|
||||
|
||||
@@ -433,13 +433,10 @@ public:
|
||||
void completeSale(U32& type, U8& flags, LLUUID& to_id);
|
||||
void clearSale();
|
||||
|
||||
// this function returns TRUE if the parcel needs conversion to a
|
||||
// lease from a non-owned-status state.
|
||||
BOOL getRecordTransaction() const { return mRecordTransaction; }
|
||||
void setRecordTransaction(BOOL record) { mRecordTransaction = record; }
|
||||
|
||||
BOOL isMediaResetTimerExpired(const U64& time);
|
||||
|
||||
|
||||
// more accessors
|
||||
U32 getParcelFlags() const { return mParcelFlags; }
|
||||
|
||||
@@ -474,7 +471,9 @@ public:
|
||||
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
|
||||
|
||||
BOOL getAllowLandmark() const
|
||||
{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
|
||||
{ return TRUE; }
|
||||
//Perhaps revert for opensim?
|
||||
//{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
|
||||
|
||||
BOOL getAllowGroupScripts() const
|
||||
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
|
||||
@@ -620,8 +619,6 @@ protected:
|
||||
LLTimer mMediaResetTimer;
|
||||
|
||||
S32 mGraceExtension;
|
||||
BOOL mRecordTransaction;
|
||||
|
||||
|
||||
// This value is non-zero if there is an auction associated with
|
||||
// the parcel.
|
||||
|
||||
@@ -132,5 +132,7 @@ const S32 PARCEL_DETAILS_DESC = 1;
|
||||
const S32 PARCEL_DETAILS_OWNER = 2;
|
||||
const S32 PARCEL_DETAILS_GROUP = 3;
|
||||
const S32 PARCEL_DETAILS_AREA = 4;
|
||||
const S32 PARCEL_DETAILS_ID = 5;
|
||||
const S32 PARCEL_DETAILS_SEE_AVATARS = 6;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include <iostream>
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsaleinfo.h"
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include "lldefs.h"
|
||||
#include "llstl.h" // *TODO: Remove when LLString is gone
|
||||
#include "llstring.h" // *TODO: Remove when LLString is gone
|
||||
//#include "llstl.h" // *TODO: Remove when LLString is gone
|
||||
//#include "llstring.h" // *TODO: Remove when LLString is gone
|
||||
// lltut.h uses is_approx_equal_fraction(). This was moved to its own header
|
||||
// file in llcommon so we can use lltut.h for llcommon tests without making
|
||||
// llcommon depend on llmath.
|
||||
@@ -516,6 +516,12 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
|
||||
VEC_TYPE Q1 = data[data.size()/4];
|
||||
VEC_TYPE Q3 = data[data.size()-data.size()/4-1];
|
||||
|
||||
if ((F32)(Q3-Q1) < 1.f)
|
||||
{
|
||||
// not enough variation to detect outliers
|
||||
return;
|
||||
}
|
||||
|
||||
VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
|
||||
VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "xform.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include <vector>
|
||||
|
||||
template <class T> class LLTreeNode;
|
||||
|
||||
@@ -52,8 +52,6 @@
|
||||
//
|
||||
// Sorry the code is such a mess. JC
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH - GNUC
|
||||
|
||||
@@ -2080,7 +2080,7 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge
|
||||
mDetail = detail;
|
||||
mSculptLevel = -2;
|
||||
#if MESH_ENABLED
|
||||
mIsTetrahedron = FALSE;
|
||||
mIsMeshAssetLoaded = FALSE;
|
||||
mLODScaleBias.setVec(1,1,1);
|
||||
mHullPoints = NULL;
|
||||
mHullIndices = NULL;
|
||||
@@ -2103,7 +2103,7 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge
|
||||
|
||||
generate();
|
||||
|
||||
if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE)
|
||||
if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE || mParams.getSculptType() == LL_SCULPT_TYPE_MESH)
|
||||
{
|
||||
createVolumeFaces();
|
||||
}
|
||||
@@ -2414,7 +2414,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
||||
LLSD mdl;
|
||||
if (!unzip_llsd(mdl, is, size))
|
||||
{
|
||||
llwarns << "not a valid mesh asset!" << llendl;
|
||||
LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD, will probably fetch from sim again." << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2712,173 +2712,21 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
||||
return true;
|
||||
}
|
||||
|
||||
void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
|
||||
|
||||
BOOL LLVolume::isMeshAssetLoaded()
|
||||
{
|
||||
LLVector4a v0;
|
||||
v0.setSub(cv[1].getPosition(), cv[0].getNormal());
|
||||
LLVector4a v1;
|
||||
v1.setSub(cv[2].getNormal(), cv[0].getPosition());
|
||||
|
||||
cv[0].getNormal().setCross3(v0,v1);
|
||||
cv[0].getNormal().normalize3fast();
|
||||
cv[1].setNormal(cv[0].getNormal());
|
||||
cv[2].setNormal(cv[1].getNormal());
|
||||
return mIsMeshAssetLoaded;
|
||||
}
|
||||
|
||||
BOOL LLVolume::isTetrahedron()
|
||||
void LLVolume::setMeshAssetLoaded(BOOL loaded)
|
||||
{
|
||||
return mIsTetrahedron;
|
||||
}
|
||||
|
||||
void LLVolume::makeTetrahedron()
|
||||
{
|
||||
mVolumeFaces.clear();
|
||||
|
||||
LLVolumeFace face;
|
||||
|
||||
F32 x = 0.25f;
|
||||
LLVector4a p[] =
|
||||
{ //unit tetrahedron corners
|
||||
LLVector4a(x,x,x),
|
||||
LLVector4a(-x,-x,x),
|
||||
LLVector4a(-x,x,-x),
|
||||
LLVector4a(x,-x,-x)
|
||||
};
|
||||
|
||||
face.mExtents[0].splat(-x);
|
||||
face.mExtents[1].splat(x);
|
||||
|
||||
LLVolumeFace::VertexData cv[3];
|
||||
|
||||
//set texture coordinates
|
||||
cv[0].mTexCoord = LLVector2(0,0);
|
||||
cv[1].mTexCoord = LLVector2(1,0);
|
||||
cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3);
|
||||
|
||||
|
||||
//side 1
|
||||
cv[0].setPosition(p[1]);
|
||||
cv[1].setPosition(p[0]);
|
||||
cv[2].setPosition(p[2]);
|
||||
|
||||
tetrahedron_set_normal(cv);
|
||||
|
||||
face.resizeVertices(12);
|
||||
face.resizeIndices(12);
|
||||
|
||||
LLVector4a* v = (LLVector4a*) face.mPositions;
|
||||
LLVector4a* n = (LLVector4a*) face.mNormals;
|
||||
LLVector2* tc = (LLVector2*) face.mTexCoords;
|
||||
|
||||
v[0] = cv[0].getPosition();
|
||||
v[1] = cv[1].getPosition();
|
||||
v[2] = cv[2].getPosition();
|
||||
v += 3;
|
||||
|
||||
n[0] = cv[0].getNormal();
|
||||
n[1] = cv[1].getNormal();
|
||||
n[2] = cv[2].getNormal();
|
||||
n += 3;
|
||||
|
||||
if(tc)
|
||||
{
|
||||
tc[0] = cv[0].mTexCoord;
|
||||
tc[1] = cv[1].mTexCoord;
|
||||
tc[2] = cv[2].mTexCoord;
|
||||
tc += 3;
|
||||
}
|
||||
|
||||
//side 2
|
||||
cv[0].setPosition(p[3]);
|
||||
cv[1].setPosition(p[0]);
|
||||
cv[2].setPosition(p[1]);
|
||||
|
||||
tetrahedron_set_normal(cv);
|
||||
|
||||
v[0] = cv[0].getPosition();
|
||||
v[1] = cv[1].getPosition();
|
||||
v[2] = cv[2].getPosition();
|
||||
v += 3;
|
||||
|
||||
n[0] = cv[0].getNormal();
|
||||
n[1] = cv[1].getNormal();
|
||||
n[2] = cv[2].getNormal();
|
||||
n += 3;
|
||||
|
||||
if(tc)
|
||||
{
|
||||
tc[0] = cv[0].mTexCoord;
|
||||
tc[1] = cv[1].mTexCoord;
|
||||
tc[2] = cv[2].mTexCoord;
|
||||
tc += 3;
|
||||
}
|
||||
|
||||
//side 3
|
||||
cv[0].setPosition(p[3]);
|
||||
cv[1].setPosition(p[1]);
|
||||
cv[2].setPosition(p[2]);
|
||||
|
||||
tetrahedron_set_normal(cv);
|
||||
|
||||
v[0] = cv[0].getPosition();
|
||||
v[1] = cv[1].getPosition();
|
||||
v[2] = cv[2].getPosition();
|
||||
v += 3;
|
||||
|
||||
n[0] = cv[0].getNormal();
|
||||
n[1] = cv[1].getNormal();
|
||||
n[2] = cv[2].getNormal();
|
||||
n += 3;
|
||||
|
||||
if(tc)
|
||||
{
|
||||
tc[0] = cv[0].mTexCoord;
|
||||
tc[1] = cv[1].mTexCoord;
|
||||
tc[2] = cv[2].mTexCoord;
|
||||
tc += 3;
|
||||
}
|
||||
|
||||
//side 4
|
||||
cv[0].setPosition(p[2]);
|
||||
cv[1].setPosition(p[0]);
|
||||
cv[2].setPosition(p[3]);
|
||||
|
||||
tetrahedron_set_normal(cv);
|
||||
|
||||
v[0] = cv[0].getPosition();
|
||||
v[1] = cv[1].getPosition();
|
||||
v[2] = cv[2].getPosition();
|
||||
v += 3;
|
||||
|
||||
n[0] = cv[0].getNormal();
|
||||
n[1] = cv[1].getNormal();
|
||||
n[2] = cv[2].getNormal();
|
||||
n += 3;
|
||||
|
||||
if(tc)
|
||||
{
|
||||
tc[0] = cv[0].mTexCoord;
|
||||
tc[1] = cv[1].mTexCoord;
|
||||
tc[2] = cv[2].mTexCoord;
|
||||
tc += 3;
|
||||
}
|
||||
|
||||
//set index buffer
|
||||
for (U16 i = 0; i < 12; i++)
|
||||
{
|
||||
face.mIndices[i] = i;
|
||||
}
|
||||
|
||||
mVolumeFaces.push_back(face);
|
||||
mSculptLevel = 0;
|
||||
mIsTetrahedron = TRUE;
|
||||
mIsMeshAssetLoaded = loaded;
|
||||
}
|
||||
|
||||
void LLVolume::copyVolumeFaces(const LLVolume* volume)
|
||||
{
|
||||
mVolumeFaces = volume->mVolumeFaces;
|
||||
mSculptLevel = 0;
|
||||
mIsTetrahedron = FALSE;
|
||||
}
|
||||
|
||||
void LLVolume::cacheOptimize()
|
||||
@@ -2889,17 +2737,10 @@ void LLVolume::cacheOptimize()
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
S32 LLVolume::getNumFaces() const
|
||||
{
|
||||
#if MESH_ENABLED
|
||||
U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
|
||||
|
||||
if (sculpt_type == LL_SCULPT_TYPE_MESH)
|
||||
{
|
||||
return LL_SCULPT_MESH_MAX_FACES;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
return (S32)mProfilep->mFaces.size();
|
||||
return mIsMeshAssetLoaded ? getNumVolumeFaces() : (S32)mProfilep->mFaces.size();
|
||||
}
|
||||
|
||||
|
||||
@@ -7301,7 +7142,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
|
||||
resizeVertices(num_vertices);
|
||||
resizeIndices(num_indices);
|
||||
#if MESH_ENABLED
|
||||
if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
|
||||
if (!volume->isMeshAssetLoaded())
|
||||
#endif //MESH_ENABLED
|
||||
{
|
||||
mEdge.resize(num_indices);
|
||||
|
||||
@@ -59,7 +59,7 @@ class LLVolumeTriangle;
|
||||
#include "llquaternion.h"
|
||||
#include "llstrider.h"
|
||||
#include "v4coloru.h"
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llfile.h"
|
||||
|
||||
//============================================================================
|
||||
@@ -1085,15 +1085,15 @@ protected:
|
||||
public:
|
||||
virtual bool unpackVolumeFaces(std::istream& is, S32 size);
|
||||
|
||||
virtual void makeTetrahedron();
|
||||
virtual BOOL isTetrahedron();
|
||||
virtual void setMeshAssetLoaded(BOOL loaded);
|
||||
virtual BOOL isMeshAssetLoaded();
|
||||
#endif //MESH_ENABLED
|
||||
protected:
|
||||
BOOL mUnique;
|
||||
F32 mDetail;
|
||||
S32 mSculptLevel;
|
||||
#if MESH_ENABLED
|
||||
BOOL mIsTetrahedron;
|
||||
BOOL mIsMeshAssetLoaded;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLVolumeParams mParams;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <map>
|
||||
|
||||
#include "llvolume.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llthread.h"
|
||||
|
||||
class LLVolumeParams;
|
||||
|
||||
@@ -771,6 +771,8 @@ void LLCurl::Multi::run()
|
||||
void LLCurl::Multi::doPerform()
|
||||
{
|
||||
S32 q = 0;
|
||||
if (mThreaded)
|
||||
mSignal->unlock();
|
||||
for (S32 call_count = 0;
|
||||
call_count < MULTI_PERFORM_CALL_REPEAT;
|
||||
call_count += 1)
|
||||
@@ -783,6 +785,8 @@ void LLCurl::Multi::doPerform()
|
||||
}
|
||||
|
||||
}
|
||||
if (mThreaded)
|
||||
mSignal->lock();
|
||||
mQueued = q;
|
||||
mPerformState = PERFORM_STATE_COMPLETED;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "llbuffer.h"
|
||||
#include "lliopipe.h"
|
||||
#include "llsd.h"
|
||||
#include "llthread.h"
|
||||
|
||||
class LLMutex;
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
#ifndef LL_LLHTTPNODE_H
|
||||
#define LL_LLHTTPNODE_H
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsd.h"
|
||||
|
||||
class LLChainIOFactory;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llsdutil_math.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "message.h"
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
#include "llhost.h"
|
||||
#include "lluuid.h"
|
||||
#include "llsd.h"
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llpointer.h"
|
||||
#include "v3math.h"
|
||||
|
||||
class LLMessageSystem;
|
||||
|
||||
@@ -434,10 +434,9 @@ inline void LLTemplateMessageReader::getString(const char *block, const char *va
|
||||
|
||||
inline void LLTemplateMessageReader::getString(const char *block, const char *var, std::string& outstr, S32 blocknum )
|
||||
{
|
||||
char s[MTUBYTES];
|
||||
s[0] = '\0';
|
||||
char s[MTUBYTES + 1]= {0}; // every element is initialized with 0
|
||||
getData(block, var, s, 0, blocknum, MTUBYTES);
|
||||
s[MTUBYTES - 1] = '\0';
|
||||
s[MTUBYTES] = '\0';
|
||||
outstr = s;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "sound_ids.h"
|
||||
|
||||
|
||||
@@ -433,7 +433,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
|
||||
}
|
||||
else if(message_name == "sleep_time")
|
||||
{
|
||||
mSleepTime = parsed.getValueReal("time");
|
||||
mSleepTime = llmax(parsed.getValueReal("time"), 1.0 / 100.0); // clamp to maximum of 100Hz
|
||||
}
|
||||
else if(message_name == "crash")
|
||||
{
|
||||
|
||||
@@ -993,6 +993,7 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
|
||||
}
|
||||
|
||||
// Send initial sleep time
|
||||
llassert_always(mSleepTime != 0.f);
|
||||
setSleepTime(mSleepTime, true);
|
||||
|
||||
setState(STATE_RUNNING);
|
||||
|
||||
@@ -33,6 +33,7 @@ set(llprimitive_HEADER_FILES
|
||||
|
||||
legacy_object_types.h
|
||||
llmaterialtable.h
|
||||
llmediaentry.h
|
||||
llmodel.h
|
||||
llprimitive.h
|
||||
llprimtexturelist.h
|
||||
|
||||
222
indra/llprimitive/llmediaentry.h
Normal file
222
indra/llprimitive/llmediaentry.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* @file llmediaentry.h
|
||||
* @brief This is a single instance of media data related to the face of a prim
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLMEDIAENTRY_H
|
||||
#define LL_LLMEDIAENTRY_H
|
||||
|
||||
#include "llsd.h"
|
||||
#include "llstring.h"
|
||||
|
||||
// For return values of set*
|
||||
#include "lllslconstants.h"
|
||||
|
||||
class LLMediaEntry
|
||||
{
|
||||
public:
|
||||
enum MediaControls {
|
||||
STANDARD = 0,
|
||||
MINI
|
||||
};
|
||||
|
||||
// Constructors
|
||||
LLMediaEntry();
|
||||
LLMediaEntry(const LLMediaEntry &rhs);
|
||||
|
||||
LLMediaEntry &operator=(const LLMediaEntry &rhs);
|
||||
virtual ~LLMediaEntry();
|
||||
|
||||
bool operator==(const LLMediaEntry &rhs) const;
|
||||
bool operator!=(const LLMediaEntry &rhs) const;
|
||||
|
||||
// Render as LLSD
|
||||
LLSD asLLSD() const;
|
||||
void asLLSD(LLSD& sd) const;
|
||||
operator LLSD() const { return asLLSD(); }
|
||||
// Returns false iff the given LLSD contains fields that violate any bounds
|
||||
// limits.
|
||||
static bool checkLLSD(const LLSD& sd);
|
||||
// This doesn't merge, it overwrites the data, so will use
|
||||
// LLSD defaults if need be. Note: does not check limits!
|
||||
// Use checkLLSD() above first to ensure the LLSD is valid.
|
||||
void fromLLSD(const LLSD& sd);
|
||||
// This merges data from the incoming LLSD into our fields.
|
||||
// Note that it also does NOT check limits! Use checkLLSD() above first.
|
||||
void mergeFromLLSD(const LLSD& sd);
|
||||
|
||||
// "general" fields
|
||||
bool getAltImageEnable() const { return mAltImageEnable; }
|
||||
MediaControls getControls() const { return mControls; }
|
||||
std::string getCurrentURL() const { return mCurrentURL; }
|
||||
std::string getHomeURL() const { return mHomeURL; }
|
||||
bool getAutoLoop() const { return mAutoLoop; }
|
||||
bool getAutoPlay() const { return mAutoPlay; }
|
||||
bool getAutoScale() const { return mAutoScale; }
|
||||
bool getAutoZoom() const { return mAutoZoom; }
|
||||
bool getFirstClickInteract() const { return mFirstClickInteract; }
|
||||
U16 getWidthPixels() const { return mWidthPixels; }
|
||||
U16 getHeightPixels() const { return mHeightPixels; }
|
||||
|
||||
// "security" fields
|
||||
bool getWhiteListEnable() const { return mWhiteListEnable; }
|
||||
const std::vector<std::string> &getWhiteList() const { return mWhiteList; }
|
||||
|
||||
// "permissions" fields
|
||||
U8 getPermsInteract() const { return mPermsInteract; }
|
||||
U8 getPermsControl() const { return mPermsControl; }
|
||||
|
||||
// Setters. Those that return a U32 return a status error code
|
||||
// See lllslconstants.h
|
||||
|
||||
// "general" fields
|
||||
U32 setAltImageEnable(bool alt_image_enable) { mAltImageEnable = alt_image_enable; return LSL_STATUS_OK; }
|
||||
U32 setControls(MediaControls controls);
|
||||
U32 setCurrentURL(const std::string& current_url);
|
||||
U32 setHomeURL(const std::string& home_url);
|
||||
U32 setAutoLoop(bool auto_loop) { mAutoLoop = auto_loop; return LSL_STATUS_OK; }
|
||||
U32 setAutoPlay(bool auto_play) { mAutoPlay = auto_play; return LSL_STATUS_OK; }
|
||||
U32 setAutoScale(bool auto_scale) { mAutoScale = auto_scale; return LSL_STATUS_OK; }
|
||||
U32 setAutoZoom(bool auto_zoom) { mAutoZoom = auto_zoom; return LSL_STATUS_OK; }
|
||||
U32 setFirstClickInteract(bool first_click) { mFirstClickInteract = first_click; return LSL_STATUS_OK; }
|
||||
U32 setWidthPixels(U16 width);
|
||||
U32 setHeightPixels(U16 height);
|
||||
|
||||
// "security" fields
|
||||
U32 setWhiteListEnable( bool whitelist_enable ) { mWhiteListEnable = whitelist_enable; return LSL_STATUS_OK; }
|
||||
U32 setWhiteList( const std::vector<std::string> &whitelist );
|
||||
U32 setWhiteList( const LLSD &whitelist ); // takes an LLSD array
|
||||
|
||||
// "permissions" fields
|
||||
U32 setPermsInteract( U8 val );
|
||||
U32 setPermsControl( U8 val );
|
||||
|
||||
const LLUUID& getMediaID() const;
|
||||
|
||||
// Helper function to check a candidate URL against the whitelist
|
||||
// Returns true iff candidate URL passes (or if there is no whitelist), false otherwise
|
||||
bool checkCandidateUrl(const std::string& url) const;
|
||||
|
||||
public:
|
||||
// Static function to check a URL against a whitelist
|
||||
// Returns true iff url passes the given whitelist
|
||||
static bool checkUrlAgainstWhitelist(const std::string &url,
|
||||
const std::vector<std::string> &whitelist);
|
||||
|
||||
public:
|
||||
// LLSD key defines
|
||||
// "general" fields
|
||||
static const char* ALT_IMAGE_ENABLE_KEY;
|
||||
static const char* CONTROLS_KEY;
|
||||
static const char* CURRENT_URL_KEY;
|
||||
static const char* HOME_URL_KEY;
|
||||
static const char* AUTO_LOOP_KEY;
|
||||
static const char* AUTO_PLAY_KEY;
|
||||
static const char* AUTO_SCALE_KEY;
|
||||
static const char* AUTO_ZOOM_KEY;
|
||||
static const char* FIRST_CLICK_INTERACT_KEY;
|
||||
static const char* WIDTH_PIXELS_KEY;
|
||||
static const char* HEIGHT_PIXELS_KEY;
|
||||
|
||||
// "security" fields
|
||||
static const char* WHITELIST_ENABLE_KEY;
|
||||
static const char* WHITELIST_KEY;
|
||||
|
||||
// "permissions" fields
|
||||
static const char* PERMS_INTERACT_KEY;
|
||||
static const char* PERMS_CONTROL_KEY;
|
||||
|
||||
// Field enumerations & constants
|
||||
|
||||
// *NOTE: DO NOT change the order of these, and do not insert values
|
||||
// in the middle!
|
||||
// Add values to the end, and make sure to change PARAM_MAX_ID!
|
||||
enum Fields {
|
||||
ALT_IMAGE_ENABLE_ID = 0,
|
||||
CONTROLS_ID = 1,
|
||||
CURRENT_URL_ID = 2,
|
||||
HOME_URL_ID = 3,
|
||||
AUTO_LOOP_ID = 4,
|
||||
AUTO_PLAY_ID = 5,
|
||||
AUTO_SCALE_ID = 6,
|
||||
AUTO_ZOOM_ID = 7,
|
||||
FIRST_CLICK_INTERACT_ID = 8,
|
||||
WIDTH_PIXELS_ID = 9,
|
||||
HEIGHT_PIXELS_ID = 10,
|
||||
WHITELIST_ENABLE_ID = 11,
|
||||
WHITELIST_ID = 12,
|
||||
PERMS_INTERACT_ID = 13,
|
||||
PERMS_CONTROL_ID = 14,
|
||||
PARAM_MAX_ID = PERMS_CONTROL_ID
|
||||
};
|
||||
|
||||
// "permissions" values
|
||||
// (e.g. (PERM_OWNER | PERM_GROUP) sets permissions on for OWNER and GROUP
|
||||
static const U8 PERM_NONE = 0x0;
|
||||
static const U8 PERM_OWNER = 0x1;
|
||||
static const U8 PERM_GROUP = 0x2;
|
||||
static const U8 PERM_ANYONE = 0x4;
|
||||
static const U8 PERM_ALL = PERM_OWNER|PERM_GROUP|PERM_ANYONE;
|
||||
static const U8 PERM_MASK = PERM_OWNER|PERM_GROUP|PERM_ANYONE;
|
||||
|
||||
// Limits (in bytes)
|
||||
static const U32 MAX_URL_LENGTH = 1024;
|
||||
static const U32 MAX_WHITELIST_SIZE = 1024;
|
||||
static const U32 MAX_WHITELIST_COUNT = 64;
|
||||
static const U16 MAX_WIDTH_PIXELS = 2048;
|
||||
static const U16 MAX_HEIGHT_PIXELS = 2048;
|
||||
|
||||
private:
|
||||
|
||||
U32 setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit );
|
||||
U32 setCurrentURLInternal( const std::string &url, bool check_whitelist);
|
||||
bool fromLLSDInternal(const LLSD &sd, bool overwrite);
|
||||
|
||||
private:
|
||||
// "general" fields
|
||||
bool mAltImageEnable;
|
||||
MediaControls mControls;
|
||||
std::string mCurrentURL;
|
||||
std::string mHomeURL;
|
||||
bool mAutoLoop;
|
||||
bool mAutoPlay;
|
||||
bool mAutoScale;
|
||||
bool mAutoZoom;
|
||||
bool mFirstClickInteract;
|
||||
U16 mWidthPixels;
|
||||
U16 mHeightPixels;
|
||||
|
||||
// "security" fields
|
||||
bool mWhiteListEnable;
|
||||
std::vector<std::string> mWhiteList;
|
||||
|
||||
// "permissions" fields
|
||||
U8 mPermsInteract;
|
||||
U8 mPermsControl;
|
||||
|
||||
mutable LLUUID *mMediaIDp; // temporary id assigned to media on the viewer
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#if MESH_ENABLED
|
||||
#include "llmodel.h"
|
||||
#include "llmemory.h"
|
||||
#if MESH_IMPORT
|
||||
#include "llconvexdecomposition.h"
|
||||
#endif //MESH_IMPORT
|
||||
@@ -1019,10 +1020,16 @@ void LLModel::setVolumeFaceData(
|
||||
face.resizeVertices(num_verts);
|
||||
face.resizeIndices(num_indices);
|
||||
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
|
||||
if(!pos.isStrided())
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
|
||||
else
|
||||
for(U32 i=0;i<num_verts;++i) face.mPositions[i].load3(pos[i].mV);
|
||||
if (norm.get())
|
||||
{
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
|
||||
if(!norm.isStrided())
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
|
||||
else
|
||||
for(U32 i=0;i<num_verts;++i) face.mNormals[i].load3(norm[i].mV);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1032,7 +1039,10 @@ void LLModel::setVolumeFaceData(
|
||||
|
||||
if (tc.get())
|
||||
{
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
|
||||
if(!tc.isStrided())
|
||||
LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
|
||||
else
|
||||
for(U32 i=0;i<num_verts;++i) face.mTexCoords[i] = tc[i].mV;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -265,7 +265,7 @@ void LLCubeMap::setMatrix(S32 stage)
|
||||
|
||||
if (mMatrixStage < 0) return;
|
||||
|
||||
if (stage > 0)
|
||||
//if (stage > 0)
|
||||
{
|
||||
gGL.getTexUnit(stage)->activate();
|
||||
}
|
||||
@@ -284,17 +284,17 @@ void LLCubeMap::setMatrix(S32 stage)
|
||||
glLoadMatrixf((F32 *)trans.mMatrix);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
if (stage > 0)
|
||||
/*if (stage > 0)
|
||||
{
|
||||
gGL.getTexUnit(0)->activate();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void LLCubeMap::restoreMatrix()
|
||||
{
|
||||
if (mMatrixStage < 0) return;
|
||||
|
||||
if (mMatrixStage > 0)
|
||||
//if (mMatrixStage > 0)
|
||||
{
|
||||
gGL.getTexUnit(mMatrixStage)->activate();
|
||||
}
|
||||
@@ -302,10 +302,10 @@ void LLCubeMap::restoreMatrix()
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
if (mMatrixStage > 0)
|
||||
/*if (mMatrixStage > 0)
|
||||
{
|
||||
gGL.getTexUnit(0)->activate();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void LLCubeMap::setReflection (void)
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "llstacktrace.h"
|
||||
|
||||
#include "llglheaders.h"
|
||||
#include "llglslshader.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
//#define GL_STATE_VERIFY
|
||||
@@ -127,6 +128,23 @@ PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
|
||||
PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
|
||||
PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL;
|
||||
|
||||
// GL_ARB_map_buffer_range
|
||||
PFNGLMAPBUFFERRANGEPROC glMapBufferRange = NULL;
|
||||
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = NULL;
|
||||
|
||||
// GL_ARB_sync
|
||||
PFNGLFENCESYNCPROC glFenceSync = NULL;
|
||||
PFNGLISSYNCPROC glIsSync = NULL;
|
||||
PFNGLDELETESYNCPROC glDeleteSync = NULL;
|
||||
PFNGLCLIENTWAITSYNCPROC glClientWaitSync = NULL;
|
||||
PFNGLWAITSYNCPROC glWaitSync = NULL;
|
||||
PFNGLGETINTEGER64VPROC glGetInteger64v = NULL;
|
||||
PFNGLGETSYNCIVPROC glGetSynciv = NULL;
|
||||
|
||||
// GL_APPLE_flush_buffer_range
|
||||
PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE = NULL;
|
||||
PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL;
|
||||
|
||||
// vertex object prototypes
|
||||
PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL;
|
||||
PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI = NULL;
|
||||
@@ -156,27 +174,33 @@ PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
|
||||
PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
|
||||
PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
|
||||
|
||||
// GL_EXT_framebuffer_object
|
||||
PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL;
|
||||
PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL;
|
||||
PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL;
|
||||
PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL;
|
||||
PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL;
|
||||
PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL;
|
||||
PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL;
|
||||
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL;
|
||||
PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL;
|
||||
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL;
|
||||
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL;
|
||||
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;
|
||||
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;
|
||||
PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
|
||||
PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL;
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT = NULL;
|
||||
// GL_ARB_framebuffer_object
|
||||
PFNGLISRENDERBUFFERPROC glIsRenderbuffer = NULL;
|
||||
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = NULL;
|
||||
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = NULL;
|
||||
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = NULL;
|
||||
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = NULL;
|
||||
PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv = NULL;
|
||||
PFNGLISFRAMEBUFFERPROC glIsFramebuffer = NULL;
|
||||
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL;
|
||||
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = NULL;
|
||||
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL;
|
||||
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = NULL;
|
||||
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = NULL;
|
||||
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv = NULL;
|
||||
PFNGLGENERATEMIPMAPPROC glGenerateMipmap = NULL;
|
||||
PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = NULL;
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
|
||||
PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
|
||||
|
||||
//GL_ARB_texture_multisample
|
||||
PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
|
||||
PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
|
||||
PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
|
||||
PFNGLSAMPLEMASKIPROC glSampleMaski;
|
||||
|
||||
// GL_EXT_blend_func_separate
|
||||
PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
|
||||
@@ -321,10 +345,13 @@ LLGLManager::LLGLManager() :
|
||||
mHasMipMapGeneration(FALSE),
|
||||
mHasCompressedTextures(FALSE),
|
||||
mHasFramebufferObject(FALSE),
|
||||
mMaxSamples(0),
|
||||
mHasFramebufferMultisample(FALSE),
|
||||
mHasBlendFuncSeparate(FALSE),
|
||||
|
||||
mHasSync(FALSE),
|
||||
mHasVertexBufferObject(FALSE),
|
||||
mHasMapBufferRange(FALSE),
|
||||
mHasFlushBufferRange(FALSE),
|
||||
mHasPBuffer(FALSE),
|
||||
mHasShaderObjects(FALSE),
|
||||
mHasVertexShader(FALSE),
|
||||
@@ -335,6 +362,11 @@ LLGLManager::LLGLManager() :
|
||||
mHasPointParameters(FALSE),
|
||||
mHasDrawBuffers(FALSE),
|
||||
mHasTextureRectangle(FALSE),
|
||||
mHasTextureMultisample(FALSE),
|
||||
mMaxSampleMaskWords(0),
|
||||
mMaxColorTextureSamples(0),
|
||||
mMaxDepthTextureSamples(0),
|
||||
mMaxIntegerSamples(0),
|
||||
|
||||
mHasAnisotropic(FALSE),
|
||||
mHasARBEnvCombine(FALSE),
|
||||
@@ -353,6 +385,8 @@ LLGLManager::LLGLManager() :
|
||||
|
||||
mHasSeparateSpecularColor(FALSE),
|
||||
|
||||
mDebugGPU(FALSE),
|
||||
|
||||
mDriverVersionMajor(1),
|
||||
mDriverVersionMinor(0),
|
||||
mDriverVersionRelease(0),
|
||||
@@ -538,13 +572,46 @@ bool LLGLManager::initGL()
|
||||
{
|
||||
GLint num_tex_image_units;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
|
||||
mNumTextureImageUnits = num_tex_image_units;
|
||||
mNumTextureImageUnits = llmin(num_tex_image_units, 32);
|
||||
}
|
||||
|
||||
if (mHasTextureMultisample)
|
||||
{
|
||||
glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples);
|
||||
glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples);
|
||||
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples);
|
||||
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
if (mIsATI)
|
||||
{ //using multisample textures on ATI results in black screen for some reason
|
||||
mHasTextureMultisample = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mHasFramebufferObject)
|
||||
{
|
||||
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
|
||||
}
|
||||
|
||||
setToDebugGPU();
|
||||
|
||||
initGLStates();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLGLManager::setToDebugGPU()
|
||||
{
|
||||
//"MOBILE INTEL(R) 965 EXPRESS CHIP",
|
||||
if (mGLRenderer.find("INTEL") != std::string::npos && mGLRenderer.find("965") != std::string::npos)
|
||||
{
|
||||
mDebugGPU = TRUE ;
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void LLGLManager::getGLInfo(LLSD& info)
|
||||
{
|
||||
info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
|
||||
@@ -601,6 +668,14 @@ 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)
|
||||
@@ -686,6 +761,9 @@ 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);
|
||||
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);
|
||||
mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
|
||||
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
|
||||
#ifdef GL_ARB_framebuffer_object
|
||||
@@ -700,7 +778,10 @@ void LLGLManager::initExtensions()
|
||||
mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
|
||||
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);
|
||||
#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);
|
||||
mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts)
|
||||
&& ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
|
||||
@@ -879,29 +960,44 @@ void LLGLManager::initExtensions()
|
||||
mHasVertexBufferObject = FALSE;
|
||||
}
|
||||
}
|
||||
if (mHasSync)
|
||||
{
|
||||
glFenceSync = (PFNGLFENCESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glFenceSync");
|
||||
glIsSync = (PFNGLISSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glIsSync");
|
||||
glDeleteSync = (PFNGLDELETESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteSync");
|
||||
glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glClientWaitSync");
|
||||
glWaitSync = (PFNGLWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glWaitSync");
|
||||
glGetInteger64v = (PFNGLGETINTEGER64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInteger64v");
|
||||
glGetSynciv = (PFNGLGETSYNCIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetSynciv");
|
||||
}
|
||||
if (mHasMapBufferRange)
|
||||
{
|
||||
glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glMapBufferRange");
|
||||
glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glFlushMappedBufferRange");
|
||||
}
|
||||
if (mHasFramebufferObject)
|
||||
{
|
||||
llinfos << "initExtensions() FramebufferObject-related procs..." << llendl;
|
||||
glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbufferEXT");
|
||||
glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbufferEXT");
|
||||
glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffersEXT");
|
||||
glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffersEXT");
|
||||
glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageEXT");
|
||||
glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameterivEXT");
|
||||
glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebufferEXT");
|
||||
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebufferEXT");
|
||||
glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffersEXT");
|
||||
glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffersEXT");
|
||||
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatusEXT");
|
||||
glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1DEXT");
|
||||
glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2DEXT");
|
||||
glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3DEXT");
|
||||
glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbufferEXT");
|
||||
glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT");
|
||||
glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT");
|
||||
glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebufferEXT");
|
||||
glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisampleEXT");
|
||||
glFramebufferTextureLayerEXT = (PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTextureLayerEXT");
|
||||
glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbuffer");
|
||||
glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbuffer");
|
||||
glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffers");
|
||||
glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffers");
|
||||
glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorage");
|
||||
glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameteriv");
|
||||
glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebuffer");
|
||||
glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebuffer");
|
||||
glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffers");
|
||||
glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffers");
|
||||
glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatus");
|
||||
glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1D");
|
||||
glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2D");
|
||||
glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3D");
|
||||
glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbuffer");
|
||||
glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameteriv");
|
||||
glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmap");
|
||||
glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebuffer");
|
||||
glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisample");
|
||||
glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTextureLayer");
|
||||
}
|
||||
if (mHasDrawBuffers)
|
||||
{
|
||||
@@ -911,6 +1007,13 @@ void LLGLManager::initExtensions()
|
||||
{
|
||||
glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT");
|
||||
}
|
||||
if (mHasTextureMultisample)
|
||||
{
|
||||
glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage2DMultisample");
|
||||
glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample");
|
||||
glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
|
||||
glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
|
||||
}
|
||||
#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");
|
||||
@@ -1299,6 +1402,7 @@ void LLGLState::checkStates(const std::string& msg)
|
||||
|
||||
void LLGLState::checkTextureChannels(const std::string& msg)
|
||||
{
|
||||
#if 0
|
||||
if (!gDebugGL)
|
||||
{
|
||||
return;
|
||||
@@ -1458,11 +1562,12 @@ void LLGLState::checkTextureChannels(const std::string& msg)
|
||||
LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
|
||||
{
|
||||
if (!gDebugGL)
|
||||
if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1574,7 +1679,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
|
||||
}
|
||||
}
|
||||
|
||||
if (glIsEnabled(GL_TEXTURE_2D))
|
||||
/*if (glIsEnabled(GL_TEXTURE_2D))
|
||||
{
|
||||
if (!(data_mask & 0x0008))
|
||||
{
|
||||
@@ -1597,7 +1702,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
|
||||
gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
glClientActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
gGL.getTexUnit(0)->activate();
|
||||
@@ -1640,6 +1745,16 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
|
||||
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
|
||||
switch (state)
|
||||
{
|
||||
case GL_ALPHA_TEST:
|
||||
enabled = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
if (state)
|
||||
{
|
||||
@@ -1998,8 +2113,7 @@ void LLGLNamePool::release(GLuint name)
|
||||
//static
|
||||
void LLGLNamePool::upkeepPools()
|
||||
{
|
||||
tracker_t::LLInstanceTrackerScopedGuard guard;
|
||||
for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
|
||||
for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
|
||||
{
|
||||
LLGLNamePool & pool = *iter;
|
||||
pool.upkeep();
|
||||
@@ -2009,8 +2123,7 @@ void LLGLNamePool::upkeepPools()
|
||||
//static
|
||||
void LLGLNamePool::cleanupPools()
|
||||
{
|
||||
tracker_t::LLInstanceTrackerScopedGuard guard;
|
||||
for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
|
||||
for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
|
||||
{
|
||||
LLGLNamePool & pool = *iter;
|
||||
pool.cleanup();
|
||||
|
||||
@@ -89,11 +89,15 @@ public:
|
||||
BOOL mHasMipMapGeneration;
|
||||
BOOL mHasCompressedTextures;
|
||||
BOOL mHasFramebufferObject;
|
||||
S32 mMaxSamples;
|
||||
BOOL mHasFramebufferMultisample;
|
||||
BOOL mHasBlendFuncSeparate;
|
||||
|
||||
// ARB Extensions
|
||||
BOOL mHasVertexBufferObject;
|
||||
BOOL mHasSync;
|
||||
BOOL mHasMapBufferRange;
|
||||
BOOL mHasFlushBufferRange;
|
||||
BOOL mHasPBuffer;
|
||||
BOOL mHasShaderObjects;
|
||||
BOOL mHasVertexShader;
|
||||
@@ -105,6 +109,11 @@ public:
|
||||
BOOL mHasDrawBuffers;
|
||||
BOOL mHasDepthClamp;
|
||||
BOOL mHasTextureRectangle;
|
||||
BOOL mHasTextureMultisample;
|
||||
S32 mMaxSampleMaskWords;
|
||||
S32 mMaxColorTextureSamples;
|
||||
S32 mMaxDepthTextureSamples;
|
||||
S32 mMaxIntegerSamples;
|
||||
|
||||
// Other extensions.
|
||||
BOOL mHasAnisotropic;
|
||||
@@ -126,6 +135,9 @@ public:
|
||||
|
||||
// Misc extensions
|
||||
BOOL mHasSeparateSpecularColor;
|
||||
|
||||
//whether this GPU is in the debug list.
|
||||
BOOL mDebugGPU;
|
||||
|
||||
S32 mDriverVersionMajor;
|
||||
S32 mDriverVersionMinor;
|
||||
@@ -143,6 +155,7 @@ public:
|
||||
void printGLInfoString();
|
||||
void getGLInfo(LLSD& info);
|
||||
|
||||
U32 getNumFBOFSAASamples(U32 desired_samples = 32);
|
||||
// In ALL CAPS
|
||||
std::string mGLVendor;
|
||||
std::string mGLVendorShort;
|
||||
@@ -154,6 +167,7 @@ private:
|
||||
void initExtensions();
|
||||
void initGLStates();
|
||||
void initGLImages();
|
||||
void setToDebugGPU();
|
||||
};
|
||||
|
||||
extern LLGLManager gGLManager;
|
||||
|
||||
@@ -76,6 +76,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
|
||||
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
|
||||
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
|
||||
|
||||
// GL_ARB_sync
|
||||
extern PFNGLFENCESYNCPROC glFenceSync;
|
||||
extern PFNGLISSYNCPROC glIsSync;
|
||||
extern PFNGLDELETESYNCPROC glDeleteSync;
|
||||
extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
|
||||
extern PFNGLWAITSYNCPROC glWaitSync;
|
||||
extern PFNGLGETINTEGER64VPROC glGetInteger64v;
|
||||
extern PFNGLGETSYNCIVPROC glGetSynciv;
|
||||
|
||||
// GL_APPLE_flush_buffer_range
|
||||
extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
|
||||
extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
|
||||
|
||||
// GL_ARB_map_buffer_range
|
||||
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
|
||||
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
|
||||
|
||||
// GL_ATI_vertex_array_object
|
||||
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
|
||||
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
|
||||
@@ -312,6 +329,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
|
||||
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
|
||||
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
|
||||
|
||||
// GL_ARB_sync
|
||||
extern PFNGLFENCESYNCPROC glFenceSync;
|
||||
extern PFNGLISSYNCPROC glIsSync;
|
||||
extern PFNGLDELETESYNCPROC glDeleteSync;
|
||||
extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
|
||||
extern PFNGLWAITSYNCPROC glWaitSync;
|
||||
extern PFNGLGETINTEGER64VPROC glGetInteger64v;
|
||||
extern PFNGLGETSYNCIVPROC glGetSynciv;
|
||||
|
||||
// GL_APPLE_flush_buffer_range
|
||||
extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
|
||||
extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
|
||||
|
||||
// GL_ARB_map_buffer_range
|
||||
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
|
||||
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
|
||||
|
||||
// GL_ATI_vertex_array_object
|
||||
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
|
||||
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
|
||||
@@ -455,31 +489,36 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
|
||||
//GL_EXT_blend_func_separate
|
||||
extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
|
||||
|
||||
//GL_EXT_framebuffer_object
|
||||
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
|
||||
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
|
||||
extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
|
||||
extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
|
||||
extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
|
||||
extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
|
||||
extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
|
||||
extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
|
||||
extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
|
||||
extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
|
||||
extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
|
||||
extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
|
||||
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
|
||||
extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
|
||||
extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
|
||||
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
|
||||
extern PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT;
|
||||
//GL_ARB_framebuffer_object
|
||||
extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
|
||||
extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
||||
extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
|
||||
extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
||||
extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
||||
extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
|
||||
extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
|
||||
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
||||
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
|
||||
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
||||
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
|
||||
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
||||
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
|
||||
extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
|
||||
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
|
||||
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
|
||||
extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
|
||||
|
||||
//GL_ARB_draw_buffers
|
||||
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
|
||||
|
||||
//GL_ARB_texture_multisample
|
||||
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
|
||||
extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
|
||||
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
|
||||
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
|
||||
|
||||
#elif LL_WINDOWS
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -512,6 +551,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
|
||||
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
|
||||
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
|
||||
|
||||
// GL_ARB_sync
|
||||
extern PFNGLFENCESYNCPROC glFenceSync;
|
||||
extern PFNGLISSYNCPROC glIsSync;
|
||||
extern PFNGLDELETESYNCPROC glDeleteSync;
|
||||
extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
|
||||
extern PFNGLWAITSYNCPROC glWaitSync;
|
||||
extern PFNGLGETINTEGER64VPROC glGetInteger64v;
|
||||
extern PFNGLGETSYNCIVPROC glGetSynciv;
|
||||
|
||||
// GL_APPLE_flush_buffer_range
|
||||
extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
|
||||
extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
|
||||
|
||||
// GL_ARB_map_buffer_range
|
||||
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
|
||||
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
|
||||
|
||||
// GL_ATI_vertex_array_object
|
||||
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
|
||||
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
|
||||
@@ -654,31 +710,37 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
|
||||
//GL_EXT_blend_func_separate
|
||||
extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
|
||||
|
||||
//GL_EXT_framebuffer_object
|
||||
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
|
||||
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
|
||||
extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
|
||||
extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
|
||||
extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
|
||||
extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
|
||||
extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
|
||||
extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
|
||||
extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
|
||||
extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
|
||||
extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
|
||||
extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
|
||||
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
|
||||
extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
|
||||
extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
|
||||
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
|
||||
extern PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT;
|
||||
//GL_ARB_framebuffer_object
|
||||
extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
|
||||
extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
||||
extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
|
||||
extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
||||
extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
||||
extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
|
||||
extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
|
||||
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
||||
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
|
||||
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
||||
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||
extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
|
||||
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
||||
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
|
||||
extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
|
||||
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
|
||||
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
|
||||
extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
|
||||
|
||||
//GL_ARB_draw_buffers
|
||||
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
|
||||
|
||||
//GL_ARB_texture_multisample
|
||||
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
|
||||
extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
|
||||
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
|
||||
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
|
||||
|
||||
#elif LL_DARWIN
|
||||
//----------------------------------------------------------------------------
|
||||
// LL_DARWIN
|
||||
@@ -696,7 +758,7 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
//GL_EXT_blend_func_separate
|
||||
extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
|
||||
extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) ;
|
||||
|
||||
// GL_EXT_framebuffer_object
|
||||
extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
|
||||
@@ -719,6 +781,7 @@ extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_A
|
||||
|
||||
#ifndef GL_ARB_framebuffer_object
|
||||
#define glGenerateMipmap glGenerateMipmapEXT
|
||||
#define GL_MAX_SAMPLES 0x8D57
|
||||
#endif
|
||||
// GL_ARB_draw_buffers
|
||||
extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
|
||||
@@ -726,6 +789,46 @@ extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_V
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//
|
||||
// Define map buffer range headers on Mac
|
||||
//
|
||||
#ifndef GL_ARB_map_buffer_range
|
||||
#define GL_MAP_READ_BIT 0x0001
|
||||
#define GL_MAP_WRITE_BIT 0x0002
|
||||
#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
|
||||
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
|
||||
#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
|
||||
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
|
||||
#endif
|
||||
|
||||
//
|
||||
// Define multisample headers on Mac
|
||||
//
|
||||
#ifndef GL_ARB_texture_multisample
|
||||
#define GL_SAMPLE_POSITION 0x8E50
|
||||
#define GL_SAMPLE_MASK 0x8E51
|
||||
#define GL_SAMPLE_MASK_VALUE 0x8E52
|
||||
#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
|
||||
#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
|
||||
#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
|
||||
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
|
||||
#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
|
||||
#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
|
||||
#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
|
||||
#define GL_TEXTURE_SAMPLES 0x9106
|
||||
#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
|
||||
#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
|
||||
#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
|
||||
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
|
||||
#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
|
||||
#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
|
||||
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
|
||||
#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
|
||||
#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
|
||||
#define GL_MAX_INTEGER_SAMPLES 0x9110
|
||||
#endif
|
||||
|
||||
//
|
||||
// Define vertex buffer object headers on Mac
|
||||
//
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "llshadermgr.h"
|
||||
#include "llfile.h"
|
||||
#include "llrender.h"
|
||||
#include "llcontrol.h"
|
||||
|
||||
#if LL_DARWIN
|
||||
#include "OpenGL/OpenGL.h"
|
||||
@@ -54,6 +55,16 @@ using std::pair;
|
||||
using std::make_pair;
|
||||
using std::string;
|
||||
|
||||
GLhandleARB LLGLSLShader::sCurBoundShader = 0;
|
||||
LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
|
||||
bool LLGLSLShader::sNoFixedFunction = false;
|
||||
|
||||
//UI shader -- declared here so llui_libtest will link properly
|
||||
//Singu note: Not using llui_libtest... and LLViewerShaderMgr is a part of newview. So,
|
||||
// these are declared in newview/llviewershadermanager.cpp just like every other shader.
|
||||
//LLGLSLShader gUIProgram(LLViewerShaderMgr::SHADER_INTERFACE);
|
||||
//LLGLSLShader gSolidColorProgram(LLViewerShaderMgr::SHADER_INTERFACE);
|
||||
|
||||
BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
|
||||
{
|
||||
return v1 != v2;
|
||||
@@ -63,6 +74,7 @@ LLShaderFeatures::LLShaderFeatures()
|
||||
: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
|
||||
hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
|
||||
hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
|
||||
, mIndexedTextureChannels(0), disableTextureIndex(false), hasAlphaMask(false)
|
||||
#if MESH_ENABLED
|
||||
, hasObjectSkinning(false)
|
||||
#endif //MESH_ENABLED
|
||||
@@ -119,6 +131,28 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
|
||||
glDeleteObjectARB(mProgramObject);
|
||||
// Create program
|
||||
mProgramObject = glCreateProgramObjectARB();
|
||||
|
||||
static const LLCachedControl<bool> no_texture_indexing("ShyotlUseLegacyTextureBatching",false);
|
||||
if (gGLManager.mGLVersion < 3.1f || no_texture_indexing)
|
||||
{ //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<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
|
||||
for ( ; fileIter != mShaderFiles.end(); fileIter++ )
|
||||
{
|
||||
GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, mFeatures.mIndexedTextureChannels);
|
||||
LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
|
||||
if (shaderhandle > 0)
|
||||
{
|
||||
attachObject(shaderhandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Attach existing objects
|
||||
if (!LLShaderMgr::instance()->attachShaderFeatures(this))
|
||||
@@ -129,19 +163,9 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
|
||||
for ( ; fileIter != mShaderFiles.end(); fileIter++ )
|
||||
{
|
||||
GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second);
|
||||
LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
|
||||
if (mShaderLevel > 0)
|
||||
{
|
||||
attachObject(shaderhandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = FALSE;
|
||||
}
|
||||
if (gGLManager.mGLVersion < 3.1f || no_texture_indexing)
|
||||
{ //attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
|
||||
mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
|
||||
}
|
||||
|
||||
// Map attributes and uniforms
|
||||
@@ -169,6 +193,28 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
|
||||
return createShader(attributes,uniforms);
|
||||
}
|
||||
}
|
||||
else if (mFeatures.mIndexedTextureChannels > 0)
|
||||
{ //override texture channels for indexed texture rendering
|
||||
bind();
|
||||
S32 channel_count = mFeatures.mIndexedTextureChannels;
|
||||
|
||||
for (S32 i = 0; i < channel_count; i++)
|
||||
{
|
||||
uniform1i(llformat("tex%d", i), i);
|
||||
}
|
||||
|
||||
S32 cur_tex = channel_count; //adjust any texture channels that might have been overwritten
|
||||
for (U32 i = 0; i < mTexture.size(); i++)
|
||||
{
|
||||
if (mTexture[i] > -1 && mTexture[i] < channel_count)
|
||||
{
|
||||
llassert(cur_tex < gGLManager.mNumTextureImageUnits);
|
||||
uniform1i(i, cur_tex);
|
||||
mTexture[i] = cur_tex++;
|
||||
}
|
||||
}
|
||||
unbind();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -314,7 +360,8 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
|
||||
|
||||
GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
|
||||
{
|
||||
if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB)
|
||||
if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB /*||
|
||||
type == GL_SAMPLER_2D_MULTISAMPLE*/)
|
||||
{ //this here is a texture
|
||||
glUniform1iARB(location, mActiveTextureChannels);
|
||||
LL_DEBUGS("ShaderLoading") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL;
|
||||
@@ -360,10 +407,12 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
|
||||
|
||||
void LLGLSLShader::bind()
|
||||
{
|
||||
gGL.flush();
|
||||
if (gGLManager.mHasShaderObjects)
|
||||
{
|
||||
glUseProgramObjectARB(mProgramObject);
|
||||
|
||||
sCurBoundShader = mProgramObject;
|
||||
sCurBoundShaderPtr = this;
|
||||
if (mUniformsDirty)
|
||||
{
|
||||
LLShaderMgr::instance()->updateShaderUniforms(this);
|
||||
@@ -374,6 +423,7 @@ void LLGLSLShader::bind()
|
||||
|
||||
void LLGLSLShader::unbind()
|
||||
{
|
||||
gGL.flush();
|
||||
if (gGLManager.mHasShaderObjects)
|
||||
{
|
||||
stop_glerror();
|
||||
@@ -386,6 +436,8 @@ void LLGLSLShader::unbind()
|
||||
}
|
||||
}
|
||||
glUseProgramObjectARB(0);
|
||||
sCurBoundShader = 0;
|
||||
sCurBoundShaderPtr = NULL;
|
||||
stop_glerror();
|
||||
}
|
||||
}
|
||||
@@ -393,6 +445,8 @@ void LLGLSLShader::unbind()
|
||||
void LLGLSLShader::bindNoShader(void)
|
||||
{
|
||||
glUseProgramObjectARB(0);
|
||||
sCurBoundShader = 0;
|
||||
sCurBoundShaderPtr = NULL;
|
||||
}
|
||||
|
||||
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
|
||||
@@ -938,6 +992,12 @@ void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLGLSLShader::setAlphaRange(F32 minimum, F32 maximum)
|
||||
{
|
||||
uniform1f("minimum_alpha", minimum);
|
||||
uniform1f("maximum_alpha", maximum);
|
||||
}
|
||||
|
||||
void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
|
||||
{
|
||||
|
||||
@@ -53,6 +53,9 @@ public:
|
||||
#endif //MESH_ENABLED
|
||||
bool hasAtmospherics;
|
||||
bool hasGamma;
|
||||
S32 mIndexedTextureChannels;
|
||||
bool disableTextureIndex;
|
||||
bool hasAlphaMask;
|
||||
|
||||
// char numLights;
|
||||
|
||||
@@ -72,6 +75,10 @@ public:
|
||||
|
||||
LLGLSLShader(S32 shader_class);
|
||||
|
||||
static GLhandleARB sCurBoundShader;
|
||||
static LLGLSLShader* sCurBoundShaderPtr;
|
||||
static bool sNoFixedFunction;
|
||||
|
||||
void unload();
|
||||
BOOL createShader(std::vector<std::string> * attributes,
|
||||
std::vector<std::string> * uniforms);
|
||||
@@ -108,6 +115,8 @@ 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 vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
|
||||
void vertexAttrib4fv(U32 index, GLfloat* v);
|
||||
|
||||
@@ -146,4 +155,9 @@ public:
|
||||
std::string mName;
|
||||
};
|
||||
|
||||
//UI shader (declared here so llui_libtest will link properly)
|
||||
extern LLGLSLShader gUIProgram;
|
||||
//output vec4(color.rgb,color.a*tex0[tc0].a)
|
||||
extern LLGLSLShader gSolidColorProgram;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1400,22 +1400,36 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
|
||||
|
||||
void LLImageGL::deleteDeadTextures()
|
||||
{
|
||||
bool reset = false;
|
||||
|
||||
while (!sDeadTextureList.empty())
|
||||
{
|
||||
GLuint tex = sDeadTextureList.front();
|
||||
sDeadTextureList.pop_front();
|
||||
for (int i = 0; i < gGLManager.mNumTextureUnits; i++)
|
||||
for (int i = 0; i < gGLManager.mNumTextureImageUnits; i++)
|
||||
{
|
||||
if (sCurrentBoundTextures[i] == tex)
|
||||
LLTexUnit* tex_unit = gGL.getTexUnit(i);
|
||||
|
||||
if (tex_unit->getCurrTexture() == tex)
|
||||
{
|
||||
gGL.getTexUnit(i)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
tex_unit->unbind(tex_unit->getCurrType());
|
||||
stop_glerror();
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glDeleteTextures(1, &tex);
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
if (reset)
|
||||
{
|
||||
gGL.getTexUnit(0)->activate();
|
||||
}
|
||||
}
|
||||
|
||||
void LLImageGL::destroyGLTexture()
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
#include "llimage.h"
|
||||
|
||||
#include "llgltypes.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "v2math.h"
|
||||
|
||||
#include "llrender.h"
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "llvertexbuffer.h"
|
||||
#include "llcubemap.h"
|
||||
#include "llglslshader.h"
|
||||
#include "llimagegl.h"
|
||||
#include "llrendertarget.h"
|
||||
#include "lltexture.h"
|
||||
@@ -49,7 +50,9 @@ F64 gGLLastProjection[16];
|
||||
F64 gGLProjection[16];
|
||||
S32 gGLViewport[4];
|
||||
|
||||
static const U32 LL_NUM_TEXTURE_LAYERS = 8;
|
||||
U32 LLTexUnit::sWhiteTexture = 0;
|
||||
|
||||
static const U32 LL_NUM_TEXTURE_LAYERS = 32;
|
||||
static const U32 LL_NUM_LIGHT_UNITS = 8;
|
||||
|
||||
static GLenum sGLTextureType[] =
|
||||
@@ -57,6 +60,7 @@ static GLenum sGLTextureType[] =
|
||||
GL_TEXTURE_2D,
|
||||
GL_TEXTURE_RECTANGLE_ARB,
|
||||
GL_TEXTURE_CUBE_MAP_ARB
|
||||
//,GL_TEXTURE_2D_MULTISAMPLE Don't use.
|
||||
};
|
||||
|
||||
static GLint sGLAddressMode[] =
|
||||
@@ -127,7 +131,8 @@ void LLTexUnit::refreshState(void)
|
||||
// Per apple spec, don't call glEnable/glDisable when index exceeds max texture units
|
||||
// http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html
|
||||
//
|
||||
bool enableDisable = (mIndex < gGLManager.mNumTextureUnits);
|
||||
bool enableDisable = !LLGLSLShader::sNoFixedFunction &&
|
||||
(mIndex < gGLManager.mNumTextureUnits) /*&& mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE*/;
|
||||
|
||||
if (mCurrTexType != TT_NONE)
|
||||
{
|
||||
@@ -183,8 +188,11 @@ void LLTexUnit::enable(eTextureType type)
|
||||
disable(); // Force a disable of a previous texture type if it's enabled.
|
||||
}
|
||||
mCurrTexType = type;
|
||||
|
||||
gGL.flush();
|
||||
if (mIndex < gGLManager.mNumTextureUnits)
|
||||
if (!LLGLSLShader::sNoFixedFunction &&
|
||||
//type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
|
||||
mIndex < gGLManager.mNumTextureUnits)
|
||||
{
|
||||
glEnable(sGLTextureType[type]);
|
||||
}
|
||||
@@ -200,7 +208,9 @@ void LLTexUnit::disable(void)
|
||||
activate();
|
||||
unbind(mCurrTexType);
|
||||
gGL.flush();
|
||||
if (mIndex < gGLManager.mNumTextureUnits)
|
||||
if (!LLGLSLShader::sNoFixedFunction &&
|
||||
//mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
|
||||
mIndex < gGLManager.mNumTextureUnits)
|
||||
{
|
||||
glDisable(sGLTextureType[mCurrTexType]);
|
||||
}
|
||||
@@ -404,7 +414,15 @@ void LLTexUnit::unbind(eTextureType type)
|
||||
|
||||
activate();
|
||||
mCurrTexture = 0;
|
||||
glBindTexture(sGLTextureType[type], 0);
|
||||
if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
|
||||
{
|
||||
glBindTexture(sGLTextureType[type], sWhiteTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindTexture(sGLTextureType[type], 0);
|
||||
}
|
||||
stop_glerror();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,7 +444,7 @@ void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode)
|
||||
|
||||
void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option)
|
||||
{
|
||||
if (mIndex < 0 || mCurrTexture == 0) return;
|
||||
if (mIndex < 0 || mCurrTexture == 0 /*|| mCurrTexType == LLTexUnit::TT_MULTISAMPLE_TEXTURE*/) return;
|
||||
|
||||
gGL.flush();
|
||||
|
||||
@@ -474,6 +492,11 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
|
||||
|
||||
void LLTexUnit::setTextureBlendType(eTextureBlendType type)
|
||||
{
|
||||
if (LLGLSLShader::sNoFixedFunction)
|
||||
{ //texture blend type means nothing when using shaders
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIndex < 0) return;
|
||||
|
||||
// Do nothing if it's already correctly set.
|
||||
@@ -594,6 +617,11 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha)
|
||||
|
||||
void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha)
|
||||
{
|
||||
if (LLGLSLShader::sNoFixedFunction)
|
||||
{ //register combiners do nothing when not using fixed function
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIndex < 0) return;
|
||||
|
||||
activate();
|
||||
@@ -1064,6 +1092,10 @@ void LLRender::setSceneBlendType(eBlendType type)
|
||||
void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
|
||||
{
|
||||
flush();
|
||||
if (LLGLSLShader::sNoFixedFunction)
|
||||
{ //glAlphaFunc is deprecated in OpenGL 3.3
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrAlphaFunc != func ||
|
||||
mCurrAlphaFuncVal != value)
|
||||
@@ -1079,6 +1111,30 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
|
||||
glAlphaFunc(sGLCompareFunc[func], value);
|
||||
}
|
||||
}
|
||||
|
||||
if (gDebugGL)
|
||||
{ //make sure cached state is correct
|
||||
GLint cur_func = 0;
|
||||
glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func);
|
||||
|
||||
if (func == CF_DEFAULT)
|
||||
{
|
||||
func = CF_GREATER;
|
||||
}
|
||||
|
||||
if (cur_func != sGLCompareFunc[func])
|
||||
{
|
||||
llerrs << "Alpha test function corrupted!" << llendl;
|
||||
}
|
||||
|
||||
F32 ref = 0.f;
|
||||
glGetFloatv(GL_ALPHA_TEST_REF, &ref);
|
||||
|
||||
if (ref != value)
|
||||
{
|
||||
llerrs << "Alpha test value corrupted!" << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
|
||||
|
||||
@@ -58,11 +58,13 @@ class LLTexUnit
|
||||
{
|
||||
friend class LLRender;
|
||||
public:
|
||||
static U32 sWhiteTexture;
|
||||
typedef enum
|
||||
{
|
||||
TT_TEXTURE = 0, // Standard 2D Texture
|
||||
TT_RECT_TEXTURE, // Non power of 2 texture
|
||||
TT_CUBE_MAP, // 6-sided cube map texture
|
||||
//TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample Do not use
|
||||
TT_NONE // No texture type is currently enabled
|
||||
} eTextureType;
|
||||
|
||||
|
||||
@@ -44,13 +44,14 @@ void check_framebuffer_status()
|
||||
{
|
||||
if (gDebugGL)
|
||||
{
|
||||
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
break;
|
||||
default:
|
||||
llerrs <<"check_framebuffer_status failed" << llendl;
|
||||
llwarns << "check_framebuffer_status failed -- " << std::hex << status << llendl;
|
||||
ll_fail("check_framebuffer_status failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -84,9 +85,12 @@ void LLRenderTarget::setSampleBuffer(LLMultisampleBuffer* buffer)
|
||||
mSampleBuffer = buffer;
|
||||
}
|
||||
|
||||
void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo)
|
||||
bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo)
|
||||
{
|
||||
stop_glerror();
|
||||
release();
|
||||
stop_glerror();
|
||||
|
||||
mResX = resx;
|
||||
mResY = resy;
|
||||
|
||||
@@ -94,48 +98,49 @@ void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
|
||||
mUsage = usage;
|
||||
mUseDepth = depth;
|
||||
|
||||
release();
|
||||
|
||||
if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
|
||||
{
|
||||
if (depth)
|
||||
{
|
||||
stop_glerror();
|
||||
allocateDepth();
|
||||
stop_glerror();
|
||||
if (!allocateDepth())
|
||||
{
|
||||
llwarns << "Failed to allocate depth buffer for render target." << llendl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
glGenFramebuffersEXT(1, (GLuint *) &mFBO);
|
||||
glGenFramebuffers(1, (GLuint *) &mFBO);
|
||||
|
||||
if (mDepth)
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
if (mStencil)
|
||||
{
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
|
||||
stop_glerror();
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
|
||||
stop_glerror();
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
|
||||
stop_glerror();
|
||||
}
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
addColorAttachment(color_fmt);
|
||||
return addColorAttachment(color_fmt);
|
||||
}
|
||||
|
||||
void LLRenderTarget::addColorAttachment(U32 color_fmt)
|
||||
bool LLRenderTarget::addColorAttachment(U32 color_fmt)
|
||||
{
|
||||
if (color_fmt == 0)
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
U32 offset = mTex.size();
|
||||
@@ -151,52 +156,78 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt)
|
||||
|
||||
stop_glerror();
|
||||
|
||||
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
{
|
||||
clear_glerror();
|
||||
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
llwarns << "Could not allocate color buffer for render target." << llendl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
|
||||
if (offset == 0)
|
||||
{
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
|
||||
}
|
||||
else
|
||||
{ //don't filter data attachments
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
|
||||
}
|
||||
if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
|
||||
{
|
||||
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ATI doesn't support mirrored repeat for rectangular textures.
|
||||
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
|
||||
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 (mFBO)
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset,
|
||||
stop_glerror();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset,
|
||||
LLTexUnit::getInternalType(mUsage), tex, 0);
|
||||
stop_glerror();
|
||||
|
||||
check_framebuffer_status();
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
mTex.push_back(tex);
|
||||
|
||||
if (gDebugGL)
|
||||
{ //bind and unbind to validate target
|
||||
bindTarget();
|
||||
flush();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLRenderTarget::allocateDepth()
|
||||
bool LLRenderTarget::allocateDepth()
|
||||
{
|
||||
if (mStencil)
|
||||
{
|
||||
//use render buffers where stencil buffers are in play
|
||||
glGenRenderbuffersEXT(1, (GLuint *) &mDepth);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mResX, mResY);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
glGenRenderbuffers(1, (GLuint *) &mDepth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
|
||||
stop_glerror();
|
||||
clear_glerror();
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -204,8 +235,18 @@ void LLRenderTarget::allocateDepth()
|
||||
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
|
||||
U32 internal_type = LLTexUnit::getInternalType(mUsage);
|
||||
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
|
||||
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32_ARB, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
stop_glerror();
|
||||
clear_glerror();
|
||||
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
}
|
||||
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
llwarns << "Unable to allocate depth buffer for render target." << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
|
||||
@@ -228,25 +269,28 @@ void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
|
||||
if (mDepth)
|
||||
{
|
||||
stop_glerror();
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, target.mFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
|
||||
stop_glerror();
|
||||
|
||||
if (mStencil)
|
||||
{
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
|
||||
stop_glerror();
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
|
||||
stop_glerror();
|
||||
target.mStencil = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
|
||||
stop_glerror();
|
||||
}
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
target.mUseDepth = TRUE;
|
||||
check_framebuffer_status();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
target.mUseDepth = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +300,7 @@ void LLRenderTarget::release()
|
||||
{
|
||||
if (mStencil)
|
||||
{
|
||||
glDeleteRenderbuffersEXT(1, (GLuint*) &mDepth);
|
||||
glDeleteRenderbuffers(1, (GLuint*) &mDepth);
|
||||
stop_glerror();
|
||||
}
|
||||
else
|
||||
@@ -268,23 +312,23 @@ void LLRenderTarget::release()
|
||||
}
|
||||
else if (mUseDepth && mFBO)
|
||||
{ //detach shared depth buffer
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
if (mStencil)
|
||||
{ //attached as a renderbuffer
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
mStencil = false;
|
||||
}
|
||||
else
|
||||
{ //attached as a texture
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, LLTexUnit::getInternalType(mUsage), 0, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
|
||||
}
|
||||
mUseDepth = false;
|
||||
}
|
||||
|
||||
if (mFBO)
|
||||
{
|
||||
glDeleteFramebuffersEXT(1, (GLuint *) &mFBO);
|
||||
glDeleteFramebuffers(1, (GLuint *) &mFBO);
|
||||
mFBO = 0;
|
||||
}
|
||||
|
||||
@@ -294,6 +338,8 @@ void LLRenderTarget::release()
|
||||
mTex.clear();
|
||||
}
|
||||
|
||||
mResX = mResY = 0;
|
||||
|
||||
mSampleBuffer = NULL;
|
||||
sBoundTarget = NULL;
|
||||
}
|
||||
@@ -310,14 +356,14 @@ void LLRenderTarget::bindTarget()
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
stop_glerror();
|
||||
if (gGLManager.mHasDrawBuffers)
|
||||
{ //setup multiple render targets
|
||||
GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_COLOR_ATTACHMENT1_EXT,
|
||||
GL_COLOR_ATTACHMENT2_EXT,
|
||||
GL_COLOR_ATTACHMENT3_EXT};
|
||||
GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
|
||||
GL_COLOR_ATTACHMENT1,
|
||||
GL_COLOR_ATTACHMENT2,
|
||||
GL_COLOR_ATTACHMENT3};
|
||||
glDrawBuffersARB(mTex.size(), drawbuffers);
|
||||
}
|
||||
|
||||
@@ -342,7 +388,7 @@ void LLRenderTarget::unbindTarget()
|
||||
{
|
||||
if (gGLManager.mHasFramebufferObject)
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
sBoundTarget = NULL;
|
||||
}
|
||||
@@ -404,7 +450,7 @@ void LLRenderTarget::flush(bool fetch_depth)
|
||||
}
|
||||
|
||||
gGL.getTexUnit(0)->bind(this);
|
||||
glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8_EXT, 0, 0, mResX, mResY, 0);
|
||||
glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0);
|
||||
}
|
||||
|
||||
gGL.getTexUnit(0)->disable();
|
||||
@@ -412,56 +458,55 @@ void LLRenderTarget::flush(bool fetch_depth)
|
||||
else
|
||||
{
|
||||
stop_glerror();
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
|
||||
if (mSampleBuffer)
|
||||
{
|
||||
LLGLEnable multisample(GL_MULTISAMPLE_ARB);
|
||||
LLGLEnable multisample(GL_MULTISAMPLE);
|
||||
stop_glerror();
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
stop_glerror();
|
||||
check_framebuffer_status();
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mSampleBuffer->mFBO);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleBuffer->mFBO);
|
||||
check_framebuffer_status();
|
||||
|
||||
stop_glerror();
|
||||
if(gGLManager.mIsATI)
|
||||
{
|
||||
glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
glBlitFramebuffer(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
glBlitFramebuffer(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
else
|
||||
glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
{
|
||||
glBlitFramebuffer(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
stop_glerror();
|
||||
|
||||
if (mTex.size() > 1)
|
||||
{
|
||||
for (U32 i = 1; i < mTex.size(); ++i)
|
||||
{
|
||||
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
LLTexUnit::getInternalType(mUsage), mTex[i], 0);
|
||||
stop_glerror();
|
||||
glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, mSampleBuffer->mTex[i]);
|
||||
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mSampleBuffer->mTex[i]);
|
||||
stop_glerror();
|
||||
glBlitFramebufferEXT(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBlitFramebuffer(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mTex.size(); ++i)
|
||||
{
|
||||
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i,
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i,
|
||||
LLTexUnit::getInternalType(mUsage), mTex[i], 0);
|
||||
stop_glerror();
|
||||
glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+i, GL_RENDERBUFFER_EXT, mSampleBuffer->mTex[i]);
|
||||
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_RENDERBUFFER, mSampleBuffer->mTex[i]);
|
||||
stop_glerror();
|
||||
}
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,31 +533,36 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
|
||||
{
|
||||
stop_glerror();
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, source.mFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, source.mFBO);
|
||||
check_framebuffer_status();
|
||||
gGL.getTexUnit(0)->bind(this, true);
|
||||
stop_glerror();
|
||||
glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1);
|
||||
stop_glerror();
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mFBO);
|
||||
stop_glerror();
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO);
|
||||
stop_glerror();
|
||||
check_framebuffer_status();
|
||||
stop_glerror();
|
||||
if(gGLManager.mIsATI && mask & GL_STENCIL_BUFFER_BIT)
|
||||
{
|
||||
mask &= ~GL_STENCIL_BUFFER_BIT;
|
||||
glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_STENCIL_BUFFER_BIT, filter);
|
||||
glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_STENCIL_BUFFER_BIT, filter);
|
||||
}
|
||||
if(mask)
|
||||
glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
stop_glerror();
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
}
|
||||
}
|
||||
@@ -531,21 +581,21 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
|
||||
|
||||
LLGLDepthTest depth(write_depth, write_depth);
|
||||
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mSampleBuffer ? source.mSampleBuffer->mFBO : source.mFBO);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mSampleBuffer ? source.mSampleBuffer->mFBO : source.mFBO);
|
||||
stop_glerror();
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
check_framebuffer_status();
|
||||
stop_glerror();
|
||||
if(gGLManager.mIsATI && mask & GL_STENCIL_BUFFER_BIT)
|
||||
{
|
||||
mask &= ~GL_STENCIL_BUFFER_BIT;
|
||||
glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_STENCIL_BUFFER_BIT, filter);
|
||||
glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_STENCIL_BUFFER_BIT, filter);
|
||||
}
|
||||
if(mask)
|
||||
glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
stop_glerror();
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
}
|
||||
}
|
||||
@@ -580,19 +630,19 @@ void LLMultisampleBuffer::release()
|
||||
{
|
||||
if (mFBO)
|
||||
{
|
||||
glDeleteFramebuffersEXT(1, (GLuint *) &mFBO);
|
||||
glDeleteFramebuffers(1, (GLuint *) &mFBO);
|
||||
mFBO = 0;
|
||||
}
|
||||
|
||||
if (mTex.size() > 0)
|
||||
{
|
||||
glDeleteRenderbuffersEXT(mTex.size(), (GLuint *) &mTex[0]);
|
||||
glDeleteRenderbuffers(mTex.size(), (GLuint *) &mTex[0]);
|
||||
mTex.clear();
|
||||
}
|
||||
|
||||
if (mDepth)
|
||||
{
|
||||
glDeleteRenderbuffersEXT(1, (GLuint *) &mDepth);
|
||||
glDeleteRenderbuffers(1, (GLuint *) &mDepth);
|
||||
mDepth = 0;
|
||||
}
|
||||
}
|
||||
@@ -609,13 +659,13 @@ void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref)
|
||||
ref = this;
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
if (gGLManager.mHasDrawBuffers)
|
||||
{ //setup multiple render targets
|
||||
GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_COLOR_ATTACHMENT1_EXT,
|
||||
GL_COLOR_ATTACHMENT2_EXT,
|
||||
GL_COLOR_ATTACHMENT3_EXT};
|
||||
GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
|
||||
GL_COLOR_ATTACHMENT1,
|
||||
GL_COLOR_ATTACHMENT2,
|
||||
GL_COLOR_ATTACHMENT3};
|
||||
glDrawBuffersARB(ref->mTex.size(), drawbuffers);
|
||||
}
|
||||
|
||||
@@ -626,14 +676,16 @@ void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref)
|
||||
sBoundTarget = this;
|
||||
}
|
||||
|
||||
void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo )
|
||||
bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo )
|
||||
{
|
||||
allocate(resx,resy,color_fmt,depth,stencil,usage,use_fbo,2);
|
||||
return allocate(resx,resy,color_fmt,depth,stencil,usage,use_fbo,2);
|
||||
}
|
||||
|
||||
void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples )
|
||||
bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples )
|
||||
{
|
||||
release();
|
||||
stop_glerror();
|
||||
|
||||
mResX = resx;
|
||||
mResY = resy;
|
||||
|
||||
@@ -641,18 +693,18 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth
|
||||
mUseDepth = depth;
|
||||
mStencil = stencil;
|
||||
|
||||
release();
|
||||
|
||||
if (!gGLManager.mHasFramebufferMultisample)
|
||||
{
|
||||
llerrs << "Attempting to allocate unsupported render target type!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
mSamples = samples;
|
||||
mSamples = gGLManager.getNumFBOFSAASamples(samples);
|
||||
|
||||
if (mSamples <= 1)
|
||||
{
|
||||
llerrs << "Cannot create a multisample buffer with less than 2 samples." << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
@@ -663,36 +715,37 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth
|
||||
if (depth)
|
||||
{
|
||||
stop_glerror();
|
||||
allocateDepth();
|
||||
if(!allocateDepth())
|
||||
return false;
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
glGenFramebuffersEXT(1, (GLuint *) &mFBO);
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
|
||||
glGenFramebuffers(1, (GLuint *) &mFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
stop_glerror();
|
||||
clear_glerror();
|
||||
if (mDepth)
|
||||
{
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
|
||||
if (mStencil)
|
||||
{
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
|
||||
}
|
||||
check_framebuffer_status();
|
||||
}
|
||||
|
||||
stop_glerror();
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
addColorAttachment(color_fmt);
|
||||
return addColorAttachment(color_fmt);
|
||||
}
|
||||
|
||||
void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
|
||||
bool LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
|
||||
{
|
||||
if (color_fmt == 0)
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
U32 offset = mTex.size();
|
||||
@@ -703,44 +756,47 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
|
||||
}
|
||||
|
||||
U32 tex;
|
||||
glGenRenderbuffersEXT(1, &tex);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, tex);
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, color_fmt, mResX, mResY);
|
||||
glGenRenderbuffers(1, &tex);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, tex);
|
||||
stop_glerror();
|
||||
|
||||
clear_glerror();
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, color_fmt, mResX, mResY);
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
llwarns << "Unable to allocate color buffer for multisample render target." << llendl;
|
||||
return false;
|
||||
}
|
||||
if (mFBO)
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset, GL_RENDERBUFFER_EXT, tex);
|
||||
stop_glerror();
|
||||
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||
break;
|
||||
default:
|
||||
llerrs << "WTF? " << std::hex << status << llendl;
|
||||
break;
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset, GL_RENDERBUFFER, tex);
|
||||
check_framebuffer_status();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
mTex.push_back(tex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLMultisampleBuffer::allocateDepth()
|
||||
bool LLMultisampleBuffer::allocateDepth()
|
||||
{
|
||||
glGenRenderbuffersEXT(1, (GLuint* ) &mDepth);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
|
||||
glGenRenderbuffers(1, (GLuint* ) &mDepth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
|
||||
stop_glerror();
|
||||
clear_glerror();
|
||||
if (mStencil)
|
||||
{
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH24_STENCIL8_EXT, mResX, mResY);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY);
|
||||
}
|
||||
else
|
||||
{
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY);
|
||||
}
|
||||
if (glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
llwarns << "Unable to allocate depth buffer for multisample render target." << llendl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,17 +77,17 @@ public:
|
||||
//allocate resources for rendering
|
||||
//must be called before use
|
||||
//multiple calls will release previously allocated resources
|
||||
void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = FALSE);
|
||||
bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = FALSE);
|
||||
|
||||
//provide this render target with a multisample resource.
|
||||
void setSampleBuffer(LLMultisampleBuffer* buffer);
|
||||
|
||||
//add color buffer attachment
|
||||
//limit of 4 color attachments per render target
|
||||
virtual void addColorAttachment(U32 color_fmt);
|
||||
virtual bool addColorAttachment(U32 color_fmt);
|
||||
|
||||
//allocate a depth texture
|
||||
virtual void allocateDepth();
|
||||
virtual bool allocateDepth();
|
||||
|
||||
//share depth buffer with provided render target
|
||||
virtual void shareDepthBuffer(LLRenderTarget& target);
|
||||
@@ -174,10 +174,10 @@ public:
|
||||
|
||||
virtual void bindTarget();
|
||||
void bindTarget(LLRenderTarget* ref);
|
||||
virtual void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo);
|
||||
void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples);
|
||||
virtual void addColorAttachment(U32 color_fmt);
|
||||
virtual void allocateDepth();
|
||||
virtual bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo);
|
||||
bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples);
|
||||
virtual bool addColorAttachment(U32 color_fmt);
|
||||
virtual bool allocateDepth();
|
||||
};
|
||||
|
||||
#endif //!LL_MESA_HEADLESS
|
||||
|
||||
@@ -217,17 +217,79 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
|
||||
if (features->hasWaterFog)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightWaterF.glsl"))
|
||||
if (features->disableTextureIndex)
|
||||
{
|
||||
return FALSE;
|
||||
if (features->hasAlphaMask)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightWaterNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (features->hasAlphaMask)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightWaterAlphaMaskF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightWaterF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightF.glsl"))
|
||||
if (features->disableTextureIndex)
|
||||
{
|
||||
return FALSE;
|
||||
if (features->hasAlphaMask)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightAlphaMaskNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (features->hasAlphaMask)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightAlphaMaskF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,32 +300,111 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
|
||||
if (features->isShiny && features->hasWaterFog)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightShinyWaterF.glsl"))
|
||||
if (features->disableTextureIndex)
|
||||
{
|
||||
return FALSE;
|
||||
if (!shader->attachObject("lighting/lightFullbrightShinyWaterNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightShinyWaterF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
}
|
||||
}
|
||||
else if (features->hasWaterFog)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
|
||||
if (features->disableTextureIndex)
|
||||
{
|
||||
return FALSE;
|
||||
if (features->hasAlphaMask)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (features->hasAlphaMask)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightWaterAlphaMaskF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
}
|
||||
}
|
||||
|
||||
else if (features->isShiny)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl"))
|
||||
if (features->disableTextureIndex)
|
||||
{
|
||||
return FALSE;
|
||||
if (!shader->attachObject("lighting/lightFullbrightShinyNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
|
||||
if (features->disableTextureIndex)
|
||||
{
|
||||
return FALSE;
|
||||
|
||||
if (features->hasAlphaMask)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightNonIndexedAlphaMaskF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (features->hasAlphaMask)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightAlphaMaskF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,17 +415,39 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
||||
|
||||
if (features->hasWaterFog)
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightShinyWaterF.glsl"))
|
||||
if (features->disableTextureIndex)
|
||||
{
|
||||
return FALSE;
|
||||
if (!shader->attachObject("lighting/lightShinyWaterNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightShinyWaterF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightShinyF.glsl"))
|
||||
if (features->disableTextureIndex)
|
||||
{
|
||||
return FALSE;
|
||||
if (!shader->attachObject("lighting/lightShinyNonIndexedF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shader->attachObject("lighting/lightShinyF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,13 +491,16 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
|
||||
}
|
||||
}
|
||||
|
||||
GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type)
|
||||
GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels)
|
||||
{
|
||||
GLenum error;
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
GLenum error = GL_NO_ERROR;
|
||||
if (gDebugGL)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL;
|
||||
@@ -375,11 +541,121 @@ 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
|
||||
GLcharARB buff[1024];
|
||||
GLcharARB* text[1024];
|
||||
GLcharARB buff[1024] = {0};
|
||||
GLcharARB* text[1024] = {0};
|
||||
GLuint count = 0;
|
||||
|
||||
if (gGLManager.mGLVersion < 2.1f)
|
||||
{
|
||||
text[count++] = strdup("#version 110\n");
|
||||
}
|
||||
else if (gGLManager.mGLVersion < 3.f)
|
||||
{
|
||||
//set version to 1.20
|
||||
text[count++] = strdup("#version 120\n");
|
||||
}
|
||||
else
|
||||
{ //set version to 1.30
|
||||
text[count++] = strdup("#version 130\n");
|
||||
}
|
||||
|
||||
//copy preprocessor definitions into buffer
|
||||
for (std::map<std::string,std::string>::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter)
|
||||
{
|
||||
std::string define = "#define " + iter->first + " " + iter->second + "\n";
|
||||
text[count++] = (GLcharARB *) strdup(define.c_str());
|
||||
}
|
||||
|
||||
if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER_ARB)
|
||||
{
|
||||
//use specified number of texture channels for indexed texture rendering
|
||||
|
||||
/* prepend shader code that looks like this:
|
||||
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
uniform sampler2D tex2;
|
||||
.
|
||||
.
|
||||
.
|
||||
uniform sampler2D texN;
|
||||
|
||||
varying float vary_texture_index;
|
||||
|
||||
vec4 diffuseLookup(vec2 texcoord)
|
||||
{
|
||||
switch (int(vary_texture_index+0.25))
|
||||
{
|
||||
case 0: return texture2D(tex0, texcoord);
|
||||
case 1: return texture2D(tex1, texcoord);
|
||||
case 2: return texture2D(tex2, texcoord);
|
||||
.
|
||||
.
|
||||
.
|
||||
case N: return texture2D(texN, texcoord);
|
||||
}
|
||||
|
||||
return vec4(0,0,0,0);
|
||||
}
|
||||
*/
|
||||
|
||||
//uniform declartion
|
||||
for (S32 i = 0; i < texture_index_channels; ++i)
|
||||
{
|
||||
std::string decl = llformat("uniform sampler2D tex%d;\n", i);
|
||||
text[count++] = strdup(decl.c_str());
|
||||
}
|
||||
|
||||
text[count++] = strdup("varying float vary_texture_index;\n");
|
||||
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
|
||||
text[count++] = strdup("{\n");
|
||||
|
||||
|
||||
if (texture_index_channels == 1)
|
||||
{ //don't use flow control, that's silly
|
||||
text[count++] = strdup("return texture2D(tex0, texcoord);\n");
|
||||
text[count++] = strdup("}\n");
|
||||
}
|
||||
else if (gGLManager.mGLVersion >= 3.f)
|
||||
{
|
||||
text[count++] = strdup("\tswitch (int(vary_texture_index+0.25))\n");
|
||||
text[count++] = strdup("\t{\n");
|
||||
|
||||
//switch body
|
||||
for (S32 i = 0; i < texture_index_channels; ++i)
|
||||
{
|
||||
std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i);
|
||||
text[count++] = strdup(case_str.c_str());
|
||||
}
|
||||
|
||||
text[count++] = strdup("\t}\n");
|
||||
text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
|
||||
text[count++] = strdup("}\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
//switches aren't supported, make block that looks like:
|
||||
/*
|
||||
int ti = int(vary_texture_index+0.25);
|
||||
if (ti == 0) return texture2D(tex0, texcoord);
|
||||
if (ti == 1) return texture2D(tex1, texcoord);
|
||||
.
|
||||
.
|
||||
.
|
||||
if (ti == N) return texture2D(texN, texcoord);
|
||||
*/
|
||||
|
||||
text[count++] = strdup("int ti = int(vary_texture_index+0.25);\n");
|
||||
for (S32 i = 0; i < texture_index_channels; ++i)
|
||||
{
|
||||
std::string if_str = llformat("if (ti == %d) return texture2D(tex%d, texcoord);\n", i, i);
|
||||
text[count++] = strdup(if_str.c_str());
|
||||
}
|
||||
|
||||
text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
|
||||
text[count++] = strdup("}\n");
|
||||
}
|
||||
}
|
||||
//copy file into memory
|
||||
while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) )
|
||||
{
|
||||
@@ -389,51 +665,67 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
|
||||
//create shader object
|
||||
GLhandleARB ret = glCreateShaderObjectARB(type);
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
if (gDebugGL)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
//load source
|
||||
glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
|
||||
|
||||
if (gDebugGL)
|
||||
{
|
||||
//load source
|
||||
glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
//compile source
|
||||
glCompileShaderARB(ret);
|
||||
|
||||
if (gDebugGL)
|
||||
{
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
//compile source
|
||||
glCompileShaderARB(ret);
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
}
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
}
|
||||
}
|
||||
//free memory
|
||||
for (GLuint i = 0; i < count; i++)
|
||||
{
|
||||
free(text[i]);
|
||||
}
|
||||
|
||||
if (error == GL_NO_ERROR)
|
||||
{
|
||||
//check for errors
|
||||
GLint success = GL_TRUE;
|
||||
glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success);
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR || success == GL_FALSE)
|
||||
if (gDebugGL || success == GL_FALSE)
|
||||
{
|
||||
//an error occured, print log
|
||||
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
|
||||
dumpObjectLog(ret);
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
ret = 0;
|
||||
error = glGetError();
|
||||
if (error != GL_NO_ERROR || success == GL_FALSE)
|
||||
{
|
||||
//an error occured, print log
|
||||
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
|
||||
dumpObjectLog(ret);
|
||||
|
||||
std::stringstream ostr;
|
||||
//dump shader source for debugging
|
||||
for (GLuint i = 0; i < count; i++)
|
||||
{
|
||||
ostr << i << ": " << text[i];
|
||||
}
|
||||
|
||||
LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
|
||||
glDeleteObjectARB(ret); //no longer need handle
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -442,6 +734,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
}
|
||||
stop_glerror();
|
||||
|
||||
//free memory
|
||||
for (GLuint i = 0; i < count; i++)
|
||||
{
|
||||
free(text[i]);
|
||||
}
|
||||
|
||||
//successfully loaded, save results
|
||||
if (ret)
|
||||
{
|
||||
@@ -454,7 +752,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
if (shader_level > 1)
|
||||
{
|
||||
shader_level--;
|
||||
return loadShaderFile(filename,shader_level,type);
|
||||
return loadShaderFile(filename,shader_level,type,texture_index_channels);
|
||||
}
|
||||
LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
|
||||
BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
|
||||
BOOL validateProgramObject(GLhandleARB obj);
|
||||
GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type);
|
||||
GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels = -1);
|
||||
|
||||
// Implemented in the application to actually point to the shader directory.
|
||||
virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual
|
||||
@@ -66,6 +66,9 @@ public:
|
||||
|
||||
std::vector<std::string> mReservedUniforms;
|
||||
|
||||
//preprocessor definitions (name/value)
|
||||
std::map<std::string, std::string> mDefinitions;
|
||||
|
||||
protected:
|
||||
|
||||
// our parameter manager singleton instance
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#ifndef LL_TEXTURE_H
|
||||
#define LL_TEXTURE_H
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
class LLImageGL ;
|
||||
class LLTexUnit ;
|
||||
class LLFontGL ;
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "llrender.h"
|
||||
#include "llvector4a.h"
|
||||
#include "llcontrol.h"
|
||||
#include "llglslshader.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
@@ -88,6 +89,59 @@ void LLVBOPool::releaseName(GLuint name)
|
||||
LLVertexBuffer::sGLCount--;
|
||||
}
|
||||
|
||||
const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms
|
||||
|
||||
class LLGLSyncFence : public LLGLFence
|
||||
{
|
||||
public:
|
||||
#ifdef GL_ARB_sync
|
||||
GLsync mSync;
|
||||
#endif
|
||||
|
||||
LLGLSyncFence()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
mSync = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~LLGLSyncFence()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
glDeleteSync(mSync);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void placeFence()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
glDeleteSync(mSync);
|
||||
}
|
||||
mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
#ifdef GL_ARB_sync
|
||||
if (mSync)
|
||||
{
|
||||
while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
|
||||
{ //track the number of times we've waited here
|
||||
static S32 waits = 0;
|
||||
waits++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
|
||||
{
|
||||
@@ -334,6 +388,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
|
||||
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
|
||||
idx);
|
||||
stop_glerror();
|
||||
placeFence();
|
||||
}
|
||||
|
||||
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
|
||||
@@ -365,6 +420,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
|
||||
glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
|
||||
((U16*) getIndicesPointer()) + indices_offset);
|
||||
stop_glerror();
|
||||
placeFence();
|
||||
}
|
||||
|
||||
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
|
||||
@@ -390,6 +446,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
|
||||
stop_glerror();
|
||||
glDrawArrays(sGLMode[mode], first, count);
|
||||
stop_glerror();
|
||||
placeFence();
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -470,7 +527,8 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage, bool strided) :
|
||||
mResized(FALSE),
|
||||
mDynamicSize(FALSE),
|
||||
mIsStrided(strided),
|
||||
mStride(0)
|
||||
mStride(0),
|
||||
mFence(NULL)
|
||||
{
|
||||
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
|
||||
if (!sEnableVBOs)
|
||||
@@ -570,9 +628,40 @@ LLVertexBuffer::~LLVertexBuffer()
|
||||
destroyGLIndices();
|
||||
sCount--;
|
||||
|
||||
if (mFence)
|
||||
{
|
||||
delete mFence;
|
||||
}
|
||||
|
||||
mFence = NULL;
|
||||
|
||||
llassert_always(!mMappedData && !mMappedIndexData) ;
|
||||
};
|
||||
|
||||
void LLVertexBuffer::placeFence() const
|
||||
{
|
||||
/*if (!mFence && useVBOs())
|
||||
{
|
||||
if (gGLManager.mHasSync)
|
||||
{
|
||||
mFence = new LLGLSyncFence();
|
||||
}
|
||||
}
|
||||
|
||||
if (mFence)
|
||||
{
|
||||
mFence->placeFence();
|
||||
}*/
|
||||
}
|
||||
|
||||
void LLVertexBuffer::waitFence() const
|
||||
{
|
||||
/*if (mFence)
|
||||
{
|
||||
mFence->wait();
|
||||
}*/
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void LLVertexBuffer::genBuffer()
|
||||
@@ -1152,7 +1241,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index)
|
||||
void LLVertexBuffer::unmapBuffer(S32 type)
|
||||
{
|
||||
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
|
||||
if (!useVBOs())
|
||||
if (!useVBOs() || type == -2)
|
||||
{
|
||||
return ; //nothing to unmap
|
||||
}
|
||||
@@ -1605,7 +1694,14 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
|
||||
}
|
||||
if (data_mask & MAP_VERTEX)
|
||||
{
|
||||
glVertexPointer(3,GL_FLOAT, getStride(TYPE_VERTEX), (void*)(base + 0));
|
||||
if (data_mask & MAP_TEXTURE_INDEX)
|
||||
{
|
||||
glVertexPointer(4,GL_FLOAT, getStride(TYPE_VERTEX), (void*)(base + 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
glVertexPointer(3,GL_FLOAT, getStride(TYPE_VERTEX), (void*)(base + 0));
|
||||
}
|
||||
}
|
||||
|
||||
llglassertok();
|
||||
|
||||
@@ -64,6 +64,12 @@ protected:
|
||||
virtual void releaseName(GLuint name);
|
||||
};
|
||||
|
||||
class LLGLFence
|
||||
{
|
||||
public:
|
||||
virtual void placeFence() = 0;
|
||||
virtual void wait() = 0;
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
// base class
|
||||
@@ -127,6 +133,9 @@ public:
|
||||
TYPE_CLOTHWEIGHT,
|
||||
TYPE_MAX,
|
||||
TYPE_INDEX,
|
||||
|
||||
//no actual additional data, but indicates position.w is texture index
|
||||
TYPE_TEXTURE_INDEX,
|
||||
};
|
||||
enum {
|
||||
MAP_VERTEX = (1<<TYPE_VERTEX),
|
||||
@@ -141,6 +150,7 @@ public:
|
||||
MAP_WEIGHT = (1<<TYPE_WEIGHT),
|
||||
MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
|
||||
MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
|
||||
MAP_TEXTURE_INDEX = (1<<TYPE_TEXTURE_INDEX),
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -251,6 +261,12 @@ protected:
|
||||
BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded)
|
||||
S32 mOffsets[TYPE_MAX];
|
||||
|
||||
mutable LLGLFence* mFence;
|
||||
|
||||
void placeFence() const;
|
||||
void waitFence() const;
|
||||
|
||||
|
||||
public:
|
||||
static S32 sCount;
|
||||
static S32 sGLCount;
|
||||
|
||||
@@ -44,6 +44,7 @@ set(llui_SOURCE_FILES
|
||||
llmultislider.cpp
|
||||
llmultisliderctrl.cpp
|
||||
llnotifications.cpp
|
||||
llnotificationsutil.cpp
|
||||
llpanel.cpp
|
||||
llprogressbar.cpp
|
||||
llradiogroup.cpp
|
||||
@@ -100,7 +101,9 @@ set(llui_HEADER_FILES
|
||||
llmodaldialog.h
|
||||
llmultisliderctrl.h
|
||||
llmultislider.h
|
||||
llnotificationptr.h
|
||||
llnotifications.h
|
||||
llnotificationsutil.h
|
||||
llpanel.h
|
||||
llprogressbar.h
|
||||
llradiogroup.h
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include "llsd.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
/**
|
||||
* @class LLFunctorRegistry
|
||||
|
||||
@@ -77,11 +77,6 @@ S32 MENU_BAR_WIDTH = 0;
|
||||
/// Local function declarations, constants, enums, and typedefs
|
||||
///============================================================================
|
||||
|
||||
const std::string SEPARATOR_NAME("separator");
|
||||
const std::string TEAROFF_SEPARATOR_LABEL( "~~~~~~~~~~~" );
|
||||
const std::string SEPARATOR_LABEL( "-----------" );
|
||||
const std::string VERTICAL_SEPARATOR_LABEL( "|" );
|
||||
|
||||
const S32 LABEL_BOTTOM_PAD_PIXELS = 2;
|
||||
|
||||
const U32 LEFT_PAD_PIXELS = 3;
|
||||
@@ -101,7 +96,12 @@ const U32 SEPARATOR_HEIGHT_PIXELS = 8;
|
||||
const S32 TEAROFF_SEPARATOR_HEIGHT_PIXELS = 10;
|
||||
const S32 MENU_ITEM_PADDING = 4;
|
||||
|
||||
const std::string BOOLEAN_TRUE_PREFIX( "\xe2\x9c\x93" ); // U+2714 -- MC
|
||||
const std::string SEPARATOR_NAME("separator");
|
||||
const std::string SEPARATOR_LABEL( "-----------" );
|
||||
const std::string VERTICAL_SEPARATOR_LABEL( "|" );
|
||||
const std::string TEAROFF_SEPARATOR_LABEL( "~~~~~~~~~~~" );
|
||||
|
||||
const std::string BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK
|
||||
const std::string BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE
|
||||
const std::string ARROW_UP ("^^^^^^^");
|
||||
const std::string ARROW_DOWN("vvvvvvv");
|
||||
|
||||
@@ -88,8 +88,9 @@ LLMultiSlider::LLMultiSlider(
|
||||
mThumbCenterSelectedColor( LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterSelectedColor" ) ),
|
||||
mDisabledThumbColor(LLUI::sColorsGroup->getColor( "MultiSliderDisabledThumbColor" ) ),
|
||||
mTriangleColor(LLUI::sColorsGroup->getColor( "MultiSliderTriangleColor" ) ),
|
||||
mMouseDownCallback( NULL ),
|
||||
mMouseUpCallback( NULL )
|
||||
mMouseDownSignal( NULL ),
|
||||
mMouseUpSignal( NULL ),
|
||||
mThumbWidth(MULTI_THUMB_WIDTH)
|
||||
{
|
||||
mValue.emptyMap();
|
||||
mCurSlider = LLStringUtil::null;
|
||||
@@ -101,6 +102,13 @@ LLMultiSlider::LLMultiSlider(
|
||||
setValue(getValue());
|
||||
}
|
||||
|
||||
LLMultiSlider::~LLMultiSlider()
|
||||
{
|
||||
delete mMouseDownSignal;
|
||||
delete mMouseUpSignal;
|
||||
}
|
||||
|
||||
|
||||
void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from_event)
|
||||
{
|
||||
// exit if not there
|
||||
@@ -152,12 +160,12 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from
|
||||
|
||||
F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue);
|
||||
|
||||
S32 left_edge = MULTI_THUMB_WIDTH/2;
|
||||
S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2);
|
||||
S32 left_edge = mThumbWidth/2;
|
||||
S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
|
||||
|
||||
S32 x = left_edge + S32( t * (right_edge - left_edge) );
|
||||
mThumbRects[name].mLeft = x - (MULTI_THUMB_WIDTH/2);
|
||||
mThumbRects[name].mRight = x + (MULTI_THUMB_WIDTH/2);
|
||||
mThumbRects[name].mLeft = x - (mThumbWidth/2);
|
||||
mThumbRects[name].mRight = x + (mThumbWidth/2);
|
||||
}
|
||||
|
||||
void LLMultiSlider::setValue(const LLSD& value)
|
||||
@@ -211,7 +219,7 @@ const std::string& LLMultiSlider::addSlider(F32 val)
|
||||
}
|
||||
|
||||
// add a new thumb rect
|
||||
mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), MULTI_THUMB_WIDTH, 0 );
|
||||
mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 );
|
||||
|
||||
// add the value and set the current slider to this one
|
||||
mValue.insert(newName.str(), initVal);
|
||||
@@ -223,6 +231,30 @@ const std::string& LLMultiSlider::addSlider(F32 val)
|
||||
return mCurSlider;
|
||||
}
|
||||
|
||||
void LLMultiSlider::addSlider(F32 val, const std::string& name)
|
||||
{
|
||||
F32 initVal = val;
|
||||
|
||||
if(mValue.size() >= mMaxNumSliders) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool foundOne = findUnusedValue(initVal);
|
||||
if(!foundOne) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add a new thumb rect
|
||||
mThumbRects[name] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 );
|
||||
|
||||
// add the value and set the current slider to this one
|
||||
mValue.insert(name, initVal);
|
||||
mCurSlider = name;
|
||||
|
||||
// move the slider
|
||||
setSliderValue(mCurSlider, initVal, TRUE);
|
||||
}
|
||||
|
||||
bool LLMultiSlider::findUnusedValue(F32& initVal)
|
||||
{
|
||||
bool firstTry = true;
|
||||
@@ -302,8 +334,8 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if( gFocusMgr.getMouseCapture() == this )
|
||||
{
|
||||
S32 left_edge = MULTI_THUMB_WIDTH/2;
|
||||
S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2);
|
||||
S32 left_edge = mThumbWidth/2;
|
||||
S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
|
||||
|
||||
x += mMouseOffset;
|
||||
x = llclamp( x, left_edge, right_edge );
|
||||
@@ -331,10 +363,9 @@ BOOL LLMultiSlider::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
gFocusMgr.setMouseCapture( NULL );
|
||||
|
||||
if( mMouseUpCallback )
|
||||
{
|
||||
mMouseUpCallback( this, mCallbackUserData );
|
||||
}
|
||||
if (mMouseUpSignal)
|
||||
(*mMouseUpSignal)( this, LLSD() );
|
||||
|
||||
handled = TRUE;
|
||||
make_ui_sound("UISndClickRelease");
|
||||
}
|
||||
@@ -353,10 +384,8 @@ BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
setFocus(TRUE);
|
||||
}
|
||||
if( mMouseDownCallback )
|
||||
{
|
||||
mMouseDownCallback( this, mCallbackUserData );
|
||||
}
|
||||
if (mMouseDownSignal)
|
||||
(*mMouseDownSignal)( this, LLSD() );
|
||||
|
||||
if (MASK_CONTROL & mask) // if CTRL is modifying
|
||||
{
|
||||
@@ -379,7 +408,7 @@ BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
// Find the offset of the actual mouse location from the center of the thumb.
|
||||
if (mThumbRects[mCurSlider].pointInRect(x,y))
|
||||
{
|
||||
mMouseOffset = (mThumbRects[mCurSlider].mLeft + MULTI_THUMB_WIDTH/2) - x;
|
||||
mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth/2) - x;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -566,6 +595,18 @@ void LLMultiSlider::draw()
|
||||
LLUICtrl::draw();
|
||||
}
|
||||
|
||||
boost::signals2::connection LLMultiSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
|
||||
return mMouseDownSignal->connect(cb);
|
||||
}
|
||||
|
||||
boost::signals2::connection LLMultiSlider::setMouseUpCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t();
|
||||
return mMouseUpSignal->connect(cb);
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLXMLNodePtr LLMultiSlider::getXML(bool save_children) const
|
||||
{
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
virtual LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
|
||||
|
||||
virtual ~LLMultiSlider();
|
||||
void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE);
|
||||
F32 getSliderValue(const std::string& name) const;
|
||||
|
||||
@@ -80,15 +81,17 @@ public:
|
||||
void setMinValue(F32 min_value) { mMinValue = min_value; }
|
||||
void setMaxValue(F32 max_value) { mMaxValue = max_value; }
|
||||
void setIncrement(F32 increment) { mIncrement = increment; }
|
||||
void setMouseDownCallback( void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseDownCallback = cb; }
|
||||
void setMouseUpCallback( void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseUpCallback = cb; }
|
||||
|
||||
boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
|
||||
boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb );
|
||||
|
||||
bool findUnusedValue(F32& initVal);
|
||||
const std::string& addSlider();
|
||||
const std::string& addSlider(F32 val);
|
||||
void deleteSlider(const std::string& name);
|
||||
void deleteCurSlider() { deleteSlider(mCurSlider); }
|
||||
void clear();
|
||||
void addSlider(F32 val, const std::string& name);
|
||||
void deleteSlider(const std::string& name);
|
||||
void deleteCurSlider() { deleteSlider(mCurSlider); }
|
||||
void clear();
|
||||
|
||||
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
@@ -112,6 +115,7 @@ protected:
|
||||
|
||||
S32 mMouseOffset;
|
||||
LLRect mDragStartThumbRect;
|
||||
S32 mThumbWidth;
|
||||
|
||||
std::map<std::string, LLRect> mThumbRects;
|
||||
LLColor4 mTrackColor;
|
||||
@@ -121,8 +125,8 @@ protected:
|
||||
LLColor4 mDisabledThumbColor;
|
||||
LLColor4 mTriangleColor;
|
||||
|
||||
void (*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata);
|
||||
void (*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata);
|
||||
commit_signal_t* mMouseDownSignal;
|
||||
commit_signal_t* mMouseUpSignal;
|
||||
};
|
||||
|
||||
#endif // LL_LLSLIDER_H
|
||||
|
||||
@@ -78,9 +78,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const std::string& name, const LLRect& rect
|
||||
mEditor( NULL ),
|
||||
mTextBox( NULL ),
|
||||
mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
|
||||
mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
|
||||
mSliderMouseUpCallback( NULL ),
|
||||
mSliderMouseDownCallback( NULL )
|
||||
mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) )
|
||||
{
|
||||
S32 top = getRect().getHeight();
|
||||
S32 bottom = 0;
|
||||
@@ -421,37 +419,14 @@ void LLMultiSliderCtrl::setPrecision(S32 precision)
|
||||
updateText();
|
||||
}
|
||||
|
||||
void LLMultiSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) )
|
||||
boost::signals2::connection LLMultiSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
mSliderMouseDownCallback = slider_mousedown_callback;
|
||||
mMultiSlider->setMouseDownCallback( LLMultiSliderCtrl::onSliderMouseDown );
|
||||
return mMultiSlider->setMouseDownCallback( cb );
|
||||
}
|
||||
|
||||
// static
|
||||
void LLMultiSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
|
||||
boost::signals2::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
|
||||
if( self->mSliderMouseDownCallback )
|
||||
{
|
||||
self->mSliderMouseDownCallback( self, self->mCallbackUserData );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLMultiSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) )
|
||||
{
|
||||
mSliderMouseUpCallback = slider_mouseup_callback;
|
||||
mMultiSlider->setMouseUpCallback( LLMultiSliderCtrl::onSliderMouseUp );
|
||||
}
|
||||
|
||||
// static
|
||||
void LLMultiSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata)
|
||||
{
|
||||
LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
|
||||
if( self->mSliderMouseUpCallback )
|
||||
{
|
||||
self->mSliderMouseUpCallback( self, self->mCallbackUserData );
|
||||
}
|
||||
return mMultiSlider->setMouseUpCallback( cb );
|
||||
}
|
||||
|
||||
void LLMultiSliderCtrl::onTabInto()
|
||||
|
||||
@@ -112,8 +112,8 @@ public:
|
||||
void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; }
|
||||
void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; }
|
||||
|
||||
void setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) );
|
||||
void setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) );
|
||||
boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
|
||||
boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
|
||||
|
||||
virtual void onTabInto();
|
||||
|
||||
@@ -124,10 +124,8 @@ public:
|
||||
virtual std::string getControlName() const;
|
||||
|
||||
static void onSliderCommit(LLUICtrl* caller, void* userdata);
|
||||
static void onSliderMouseDown(LLUICtrl* caller,void* userdata);
|
||||
static void onSliderMouseUp(LLUICtrl* caller,void* userdata);
|
||||
|
||||
static void onEditorCommit(LLUICtrl* caller, void* userdata);
|
||||
|
||||
static void onEditorCommit(LLUICtrl* ctrl, void* userdata);
|
||||
static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
|
||||
static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
|
||||
|
||||
@@ -151,9 +149,6 @@ private:
|
||||
|
||||
LLColor4 mTextEnabledColor;
|
||||
LLColor4 mTextDisabledColor;
|
||||
|
||||
void (*mSliderMouseUpCallback)( LLUICtrl* ctrl, void* userdata );
|
||||
void (*mSliderMouseDownCallback)( LLUICtrl* ctrl, void* userdata );
|
||||
};
|
||||
|
||||
#endif // LL_MULTI_SLIDERCTRL_H
|
||||
|
||||
35
indra/llui/llnotificationptr.h
Normal file
35
indra/llui/llnotificationptr.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @file llnotificationptr.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLNOTIFICATIONPTR_H
|
||||
#define LLNOTIFICATIONPTR_H
|
||||
|
||||
// Many classes just store a single LLNotificationPtr
|
||||
// and llnotifications.h is very large, so define this ligher header.
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class LLNotification;
|
||||
typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
|
||||
|
||||
#endif
|
||||
@@ -91,8 +91,9 @@
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
// we want to minimize external dependencies, but this one is important
|
||||
#include "llsd.h"
|
||||
@@ -101,9 +102,9 @@
|
||||
// and we need this to manage the notification callbacks
|
||||
#include "llfunctorregistry.h"
|
||||
#include "llui.h"
|
||||
#include "llxmlnode.h"
|
||||
#include "llnotificationptr.h"
|
||||
|
||||
class LLNotification;
|
||||
typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
|
||||
|
||||
/*****************************************************************************
|
||||
* Signal and handler declarations
|
||||
|
||||
85
indra/llui/llnotificationsutil.cpp
Normal file
85
indra/llui/llnotificationsutil.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file llnotificationsutil.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
#include "llnotifications.h"
|
||||
#include "llsd.h"
|
||||
#include "llxmlnode.h" // apparently needed to call LLNotifications::instance()
|
||||
|
||||
LLNotificationPtr LLNotificationsUtil::add(const std::string& name)
|
||||
{
|
||||
return LLNotifications::instance().add(
|
||||
LLNotification::Params(name).substitutions(LLSD()).payload(LLSD()));
|
||||
}
|
||||
|
||||
LLNotificationPtr LLNotificationsUtil::add(const std::string& name,
|
||||
const LLSD& substitutions)
|
||||
{
|
||||
return LLNotifications::instance().add(
|
||||
LLNotification::Params(name).substitutions(substitutions).payload(LLSD()));
|
||||
}
|
||||
|
||||
LLNotificationPtr LLNotificationsUtil::add(const std::string& name,
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload)
|
||||
{
|
||||
return LLNotifications::instance().add(
|
||||
LLNotification::Params(name).substitutions(substitutions).payload(payload));
|
||||
}
|
||||
|
||||
LLNotificationPtr LLNotificationsUtil::add(const std::string& name,
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload,
|
||||
const std::string& functor_name)
|
||||
{
|
||||
return LLNotifications::instance().add(
|
||||
LLNotification::Params(name).substitutions(substitutions).payload(payload).functor_name(functor_name));
|
||||
}
|
||||
|
||||
LLNotificationPtr LLNotificationsUtil::add(const std::string& name,
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload,
|
||||
boost::function<void (const LLSD&, const LLSD&)> functor)
|
||||
{
|
||||
return LLNotifications::instance().add(
|
||||
LLNotification::Params(name).substitutions(substitutions).payload(payload).functor(functor));
|
||||
}
|
||||
|
||||
S32 LLNotificationsUtil::getSelectedOption(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
return LLNotification::getSelectedOption(notification, response);
|
||||
}
|
||||
|
||||
void LLNotificationsUtil::cancel(LLNotificationPtr pNotif)
|
||||
{
|
||||
LLNotifications::instance().cancel(pNotif);
|
||||
}
|
||||
|
||||
LLNotificationPtr LLNotificationsUtil::find(LLUUID uuid)
|
||||
{
|
||||
return LLNotifications::instance().find(uuid);
|
||||
}
|
||||
66
indra/llui/llnotificationsutil.h
Normal file
66
indra/llui/llnotificationsutil.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @file llnotificationsutil.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLNOTIFICATIONSUTIL_H
|
||||
#define LLNOTIFICATIONSUTIL_H
|
||||
|
||||
// The vast majority of clients of the notifications system just want to add
|
||||
// a notification to the screen, so define this lightweight public interface
|
||||
// to avoid including the heavyweight llnotifications.h
|
||||
|
||||
#include "llnotificationptr.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
class LLSD;
|
||||
|
||||
namespace LLNotificationsUtil
|
||||
{
|
||||
LLNotificationPtr add(const std::string& name);
|
||||
|
||||
LLNotificationPtr add(const std::string& name,
|
||||
const LLSD& substitutions);
|
||||
|
||||
LLNotificationPtr add(const std::string& name,
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload);
|
||||
|
||||
LLNotificationPtr add(const std::string& name,
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload,
|
||||
const std::string& functor_name);
|
||||
|
||||
LLNotificationPtr add(const std::string& name,
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload,
|
||||
boost::function<void (const LLSD&, const LLSD&)> functor);
|
||||
|
||||
S32 getSelectedOption(const LLSD& notification, const LLSD& response);
|
||||
|
||||
void cancel(LLNotificationPtr pNotif);
|
||||
|
||||
LLNotificationPtr find(LLUUID uuid);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewborder.h"
|
||||
#include "llbutton.h"
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
// LLLayoutStack
|
||||
#include "llresizebar.h"
|
||||
@@ -1049,7 +1050,7 @@ void LLPanel::childDisplayNotFound()
|
||||
mNewExpectedMembers.clear();
|
||||
LLSD args;
|
||||
args["CONTROLS"] = msg;
|
||||
LLNotifications::instance().add("FloaterNotFound", args);
|
||||
LLNotificationsUtil::add("FloaterNotFound", args);
|
||||
}
|
||||
|
||||
void LLPanel::storeRectControl()
|
||||
|
||||
@@ -70,8 +70,8 @@ LLSlider::LLSlider(
|
||||
mTrackColor( LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ),
|
||||
mThumbOutlineColor( LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ),
|
||||
mThumbCenterColor( LLUI::sColorsGroup->getColor( "SliderThumbCenterColor" ) ),
|
||||
mMouseDownCallback( NULL ),
|
||||
mMouseUpCallback( NULL )
|
||||
mMouseDownSignal( NULL ),
|
||||
mMouseUpSignal( NULL )
|
||||
{
|
||||
mThumbImage = LLUI::getUIImage("icn_slide-thumb_dark.tga");
|
||||
mTrackImage = LLUI::getUIImage("icn_slide-groove_dark.tga");
|
||||
@@ -87,6 +87,11 @@ LLSlider::LLSlider(
|
||||
mDragStartThumbRect = mThumbRect;
|
||||
}
|
||||
|
||||
LLSlider::~LLSlider()
|
||||
{
|
||||
delete mMouseDownSignal;
|
||||
delete mMouseUpSignal;
|
||||
}
|
||||
|
||||
void LLSlider::setValue(F32 value, BOOL from_event)
|
||||
{
|
||||
@@ -109,10 +114,11 @@ void LLSlider::setValue(F32 value, BOOL from_event)
|
||||
|
||||
void LLSlider::updateThumbRect()
|
||||
{
|
||||
const S32 DEFAULT_THUMB_SIZE = 16;
|
||||
F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
|
||||
|
||||
S32 thumb_width = mThumbImage->getWidth();
|
||||
S32 thumb_height = mThumbImage->getHeight();
|
||||
S32 thumb_width = mThumbImage ? mThumbImage->getWidth() : DEFAULT_THUMB_SIZE;
|
||||
S32 thumb_height = mThumbImage ? mThumbImage->getHeight() : DEFAULT_THUMB_SIZE;
|
||||
S32 left_edge = (thumb_width / 2);
|
||||
S32 right_edge = getRect().getWidth() - (thumb_width / 2);
|
||||
|
||||
@@ -169,10 +175,9 @@ BOOL LLSlider::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
gFocusMgr.setMouseCapture( NULL );
|
||||
|
||||
if( mMouseUpCallback )
|
||||
{
|
||||
mMouseUpCallback( this, mCallbackUserData );
|
||||
}
|
||||
if (mMouseUpSignal)
|
||||
(*mMouseUpSignal)( this, getValueF32() );
|
||||
|
||||
handled = TRUE;
|
||||
make_ui_sound("UISndClickRelease");
|
||||
}
|
||||
@@ -191,10 +196,8 @@ BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
setFocus(TRUE);
|
||||
}
|
||||
if( mMouseDownCallback )
|
||||
{
|
||||
mMouseDownCallback( this, mCallbackUserData );
|
||||
}
|
||||
if (mMouseDownSignal)
|
||||
(*mMouseDownSignal)( this, getValueF32() );
|
||||
|
||||
if (MASK_CONTROL & mask) // if CTRL is modifying
|
||||
{
|
||||
@@ -309,6 +312,17 @@ LLXMLNodePtr LLSlider::getXML(bool save_children) const
|
||||
return node;
|
||||
}
|
||||
|
||||
boost::signals2::connection LLSlider::setMouseDownCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
|
||||
return mMouseDownSignal->connect(cb);
|
||||
}
|
||||
|
||||
boost::signals2::connection LLSlider::setMouseUpCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
if (!mMouseUpSignal) mMouseUpSignal = new commit_signal_t();
|
||||
return mMouseUpSignal->connect(cb);
|
||||
}
|
||||
|
||||
//static
|
||||
LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory)
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
virtual LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
|
||||
|
||||
virtual ~LLSlider();
|
||||
void setValue( F32 value, BOOL from_event = FALSE );
|
||||
F32 getValueF32() const { return mValue; }
|
||||
|
||||
@@ -71,8 +72,10 @@ public:
|
||||
void setMinValue(F32 min_value) {mMinValue = min_value; updateThumbRect(); }
|
||||
void setMaxValue(F32 max_value) {mMaxValue = max_value; updateThumbRect(); }
|
||||
void setIncrement(F32 increment) {mIncrement = increment;}
|
||||
void setMouseDownCallback( void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseDownCallback = cb; }
|
||||
void setMouseUpCallback( void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseUpCallback = cb; }
|
||||
|
||||
boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
|
||||
boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb );
|
||||
|
||||
|
||||
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
@@ -103,8 +106,8 @@ private:
|
||||
LLColor4 mThumbOutlineColor;
|
||||
LLColor4 mThumbCenterColor;
|
||||
|
||||
void (*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata);
|
||||
void (*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata);
|
||||
commit_signal_t* mMouseDownSignal;
|
||||
commit_signal_t* mMouseUpSignal;
|
||||
};
|
||||
|
||||
#endif // LL_LLSLIDER_H
|
||||
|
||||
@@ -76,9 +76,7 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect,
|
||||
mEditor( NULL ),
|
||||
mTextBox( NULL ),
|
||||
mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
|
||||
mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
|
||||
mSliderMouseUpCallback( NULL ),
|
||||
mSliderMouseDownCallback( NULL )
|
||||
mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) )
|
||||
{
|
||||
S32 top = getRect().getHeight();
|
||||
S32 bottom = 0;
|
||||
@@ -352,37 +350,14 @@ void LLSliderCtrl::setPrecision(S32 precision)
|
||||
updateText();
|
||||
}
|
||||
|
||||
void LLSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) )
|
||||
boost::signals2::connection LLSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
mSliderMouseDownCallback = slider_mousedown_callback;
|
||||
mSlider->setMouseDownCallback( LLSliderCtrl::onSliderMouseDown );
|
||||
return mSlider->setMouseDownCallback( cb );
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
|
||||
boost::signals2::connection LLSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
|
||||
{
|
||||
LLSliderCtrl* self = (LLSliderCtrl*) userdata;
|
||||
if( self->mSliderMouseDownCallback )
|
||||
{
|
||||
self->mSliderMouseDownCallback( self, self->mCallbackUserData );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) )
|
||||
{
|
||||
mSliderMouseUpCallback = slider_mouseup_callback;
|
||||
mSlider->setMouseUpCallback( LLSliderCtrl::onSliderMouseUp );
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata)
|
||||
{
|
||||
LLSliderCtrl* self = (LLSliderCtrl*) userdata;
|
||||
if( self->mSliderMouseUpCallback )
|
||||
{
|
||||
self->mSliderMouseUpCallback( self, self->mCallbackUserData );
|
||||
}
|
||||
return mSlider->setMouseUpCallback( cb );
|
||||
}
|
||||
|
||||
void LLSliderCtrl::onTabInto()
|
||||
|
||||
@@ -75,14 +75,18 @@ public:
|
||||
virtual LLSD getValue() const { return LLSD(getValueF32()); }
|
||||
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
|
||||
|
||||
virtual void setMinValue(LLSD min_value) { setMinValue((F32)min_value.asReal()); }
|
||||
virtual void setMaxValue(LLSD max_value) { setMaxValue((F32)max_value.asReal()); }
|
||||
|
||||
|
||||
BOOL isMouseHeldDown() const { return mSlider->hasMouseCapture(); }
|
||||
|
||||
|
||||
virtual void setPrecision(S32 precision);
|
||||
|
||||
virtual void setEnabled( BOOL b );
|
||||
virtual void clear();
|
||||
virtual void setPrecision(S32 precision);
|
||||
|
||||
virtual void setMinValue(LLSD min_value) { setMinValue((F32)min_value.asReal()); }
|
||||
virtual void setMaxValue(LLSD max_value) { setMaxValue((F32)max_value.asReal()); }
|
||||
void setMinValue(F32 min_value) { mSlider->setMinValue(min_value); updateText(); }
|
||||
void setMaxValue(F32 max_value) { mSlider->setMaxValue(max_value); updateText(); }
|
||||
void setIncrement(F32 increment) { mSlider->setIncrement(increment);}
|
||||
@@ -94,8 +98,8 @@ public:
|
||||
void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; }
|
||||
void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; }
|
||||
|
||||
void setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) );
|
||||
void setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) );
|
||||
boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
|
||||
boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
|
||||
|
||||
virtual void onTabInto();
|
||||
|
||||
@@ -111,8 +115,6 @@ public:
|
||||
virtual std::string getControlName() const { return mSlider->getControlName(); }
|
||||
|
||||
static void onSliderCommit(LLUICtrl* caller, void* userdata);
|
||||
static void onSliderMouseDown(LLUICtrl* caller,void* userdata);
|
||||
static void onSliderMouseUp(LLUICtrl* caller,void* userdata);
|
||||
|
||||
static void onEditorCommit(LLUICtrl* caller, void* userdata);
|
||||
static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
|
||||
@@ -138,9 +140,6 @@ private:
|
||||
|
||||
LLColor4 mTextEnabledColor;
|
||||
LLColor4 mTextDisabledColor;
|
||||
|
||||
void (*mSliderMouseUpCallback)( LLUICtrl* ctrl, void* userdata );
|
||||
void (*mSliderMouseDownCallback)( LLUICtrl* ctrl, void* userdata );
|
||||
};
|
||||
|
||||
#endif // LL_LLSLIDERCTRL_H
|
||||
|
||||
@@ -487,8 +487,15 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
|
||||
|
||||
if (solid_color)
|
||||
{
|
||||
gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
|
||||
gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
|
||||
if (LLGLSLShader::sNoFixedFunction)
|
||||
{
|
||||
gSolidColorProgram.bind();
|
||||
}
|
||||
else
|
||||
{
|
||||
gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
|
||||
gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
|
||||
}
|
||||
}
|
||||
|
||||
gGL.pushMatrix();
|
||||
@@ -624,7 +631,14 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
|
||||
|
||||
if (solid_color)
|
||||
{
|
||||
gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
|
||||
if (LLGLSLShader::sNoFixedFunction)
|
||||
{
|
||||
gUIProgram.bind();
|
||||
}
|
||||
else
|
||||
{
|
||||
gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "llcontrol.h"
|
||||
#include "llrect.h"
|
||||
#include "llcoord.h"
|
||||
#include "llglslshader.h"
|
||||
//#include "llhtmlhelp.h"
|
||||
#include "llgl.h" // *TODO: break this dependency
|
||||
#include <stack>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user