Merge branch 'BatchIndexing' of https://github.com/Shyotl/SingularityViewer into future

This commit is contained in:
Siana Gearz
2011-09-19 02:09:47 +02:00
625 changed files with 14231 additions and 6192 deletions

View File

@@ -19,3 +19,8 @@ set(LLCOMMON_INCLUDE_DIRS
) )
set(LLCOMMON_LIBRARIES llcommon) 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)

View File

@@ -2,9 +2,9 @@
include(Prebuilt) include(Prebuilt)
if (NOT STANDALONE) if (NOT STANDALONE)
use_prebuilt_binary(GL) use_prebuilt_binary(glext)
# possible glh_linear should have its own .cmake file instead # possible glh_linear should have its own .cmake file instead
#use_prebuilt_binary(glh_linear) #use_prebuilt_binary(glh_linear)
# actually... not any longer, it's now in git -SG # 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) endif (NOT STANDALONE)

View File

@@ -89,7 +89,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
//******************************** //********************************
LLAPRFile infile ; LLAPRFile infile ;
infile.open(in_fname,LL_APR_RB, LLAPRFile::global); infile.open(in_fname,LL_APR_RB);
//******************************** //********************************
if (!infile.getFileHandle()) 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; S32 data_left = 0;
LLAPRFile infile ; LLAPRFile infile ;
infile.open(in_fname,LL_APR_RB, LLAPRFile::global); infile.open(in_fname,LL_APR_RB);
if (!infile.getFileHandle()) if (!infile.getFileHandle())
{ {
llwarns << "Couldn't open temporary ogg file for writing: " << in_fname 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 ; LLAPRFile outfile ;
outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global); outfile.open(out_fname,LL_APR_WPB);
if (!outfile.getFileHandle()) if (!outfile.getFileHandle())
{ {
llwarns << "Couldn't open upload sound file for reading: " << in_fname llwarns << "Couldn't open upload sound file for reading: " << in_fname

View File

@@ -226,7 +226,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName); std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
LLAPRFile infile ; LLAPRFile infile ;
infile.open(path, LL_APR_R, LLAPRFile::global); infile.open(path, LL_APR_R);
apr_file_t *fp = infile.getFileHandle(); apr_file_t *fp = infile.getFileHandle();
if (!fp) if (!fp)
return E_ST_NO_XLT_FILE; return E_ST_NO_XLT_FILE;

View File

@@ -42,7 +42,7 @@
#include "llmotioncontroller.h" #include "llmotioncontroller.h"
#include "llvisualparam.h" #include "llvisualparam.h"
#include "string_table.h" #include "string_table.h"
#include "llmemory.h" #include "llpointer.h"
#include "llthread.h" #include "llthread.h"
class LLPolyMesh; class LLPolyMesh;

View File

@@ -37,7 +37,7 @@
// Header Files // Header Files
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "lljoint.h" #include "lljoint.h"
#include "llmemory.h" #include "llrefcount.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// class LLJointState // class LLJointState

View File

@@ -163,8 +163,6 @@ void LLPose::setWeight(F32 weight)
// there was a crash here // there was a crash here
// </edit> // </edit>
llassert_always(iter->second.notNull()); llassert_always(iter->second.notNull());
if(!iter->second) //uhoh...
continue;
iter->second->setWeight(weight); iter->second->setWeight(weight);
} }
mWeight = weight; mWeight = weight;

View File

@@ -40,6 +40,8 @@
#include "lljointstate.h" #include "lljointstate.h"
#include "lljoint.h" #include "lljoint.h"
#include "llmap.h" #include "llmap.h"
#include "llpointer.h"
#include <map> #include <map>
#include <string> #include <string>

View File

@@ -211,7 +211,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
BOOL LLStateDiagram::saveDotFile(const std::string& filename) BOOL LLStateDiagram::saveDotFile(const std::string& filename)
{ {
LLAPRFile outfile ; LLAPRFile outfile ;
outfile.open(filename, LL_APR_W, LLAPRFile::global); outfile.open(filename, LL_APR_W);
apr_file_t* dot_file = outfile.getFileHandle() ; apr_file_t* dot_file = outfile.getFileHandle() ;
if (!dot_file) if (!dot_file)

View File

@@ -196,6 +196,7 @@ set(llcommon_HEADER_FILES
llsys.h llsys.h
llthread.h llthread.h
lltimer.h lltimer.h
lltreeiterators.h
lluri.h lluri.h
lluuid.h lluuid.h
lluuidhashmap.h lluuidhashmap.h
@@ -232,6 +233,7 @@ target_link_libraries(
${EXPAT_LIBRARIES} ${EXPAT_LIBRARIES}
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
${WINDOWS_LIBRARIES} ${WINDOWS_LIBRARIES}
${BOOST_REGEX_LIBRARY}
${CWDEBUG_LIBRARIES} ${CWDEBUG_LIBRARIES}
${CORESERVICES_LIBRARY} ${CORESERVICES_LIBRARY}
) )

View File

@@ -191,6 +191,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
return status; 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 // File I/O
S32 LLAPRFile::read(void *buf, S32 nbytes) S32 LLAPRFile::read(void *buf, S32 nbytes)
{ {

View File

@@ -150,10 +150,11 @@ public:
}; };
LLAPRFile() ; 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() ; ~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() ; apr_status_t close() ;
// Returns actual offset, -1 if seek fails // Returns actual offset, -1 if seek fails

View File

@@ -35,6 +35,7 @@
#include "llassettype.h" #include "llassettype.h"
#include "lldictionary.h" #include "lldictionary.h"
#include "llmemory.h" #include "llmemory.h"
#include "llsingleton.h"
///---------------------------------------------------------------------------- ///----------------------------------------------------------------------------
/// Class LLAssetType /// Class LLAssetType

View File

@@ -44,63 +44,40 @@
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
//std::list<LLEventTimer*> LLEventTimer::sActiveList;
LLEventTimer::LLEventTimer(F32 period) LLEventTimer::LLEventTimer(F32 period)
: mEventTimer() : mEventTimer()
{ {
mPeriod = period; mPeriod = period;
//sActiveList.push_back(this);
} }
LLEventTimer::LLEventTimer(const LLDate& time) LLEventTimer::LLEventTimer(const LLDate& time)
: mEventTimer() : mEventTimer()
{ {
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
//sActiveList.push_back(this);
} }
LLEventTimer::~LLEventTimer() LLEventTimer::~LLEventTimer()
{ {
//sActiveList.remove(this);
} }
//static //static
void LLEventTimer::updateClass() void LLEventTimer::updateClass()
{ {
std::list<LLEventTimer*> completed_timers; std::list<LLEventTimer*> completed_timers;
for (instance_iter iter = beginInstances(); iter != endInstances(); )
/*{
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 );
}
}
}
}*/
{ {
LLInstanceTrackerScopedGuard guard; LLEventTimer& timer = *iter++;
for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ) F32 et = timer.mEventTimer.getElapsedTimeF32();
{ if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
LLEventTimer& timer = *iter++; timer.mEventTimer.reset();
F32 et = timer.mEventTimer.getElapsedTimeF32(); if ( timer.tick() )
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { {
timer.mEventTimer.reset(); completed_timers.push_back( &timer );
if ( timer.tick() )
{
completed_timers.push_back( &timer );
}
} }
} }
} }
if ( completed_timers.size() > 0 ) if ( completed_timers.size() > 0 )
{ {
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin(); for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();

View File

@@ -56,11 +56,6 @@ public:
protected: protected:
LLTimer mEventTimer; LLTimer mEventTimer;
F32 mPeriod; F32 mPeriod;
//private:
//list of active timers
// static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
}; };
#endif //LL_EVENTTIMER_H #endif //LL_EVENTTIMER_H

View File

@@ -36,6 +36,7 @@
#include "llfoldertype.h" #include "llfoldertype.h"
#include "lldictionary.h" #include "lldictionary.h"
#include "llmemory.h" #include "llmemory.h"
#include "llsingleton.h"
///---------------------------------------------------------------------------- ///----------------------------------------------------------------------------
/// Class LLFolderType /// Class LLFolderType
@@ -95,7 +96,12 @@ LLFolderDictionary::LLFolderDictionary()
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE)); addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE)); addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE)); 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_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)); addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
}; };

View File

@@ -87,9 +87,14 @@ public:
FT_OUTFIT = 47, FT_OUTFIT = 47,
FT_MY_OUTFITS = 48, 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 FT_NONE = -1
}; };

View File

@@ -49,6 +49,7 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
protected: protected:
static void * & getInstances(std::type_info const & info); static void * & getInstances(std::type_info const & info);
}; };
/// This mix-in class adds support for tracking all instances of the specified class parameter T /// 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 /// 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 /// 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 typename std::map<KEY, T*> InstanceMap;
typedef LLInstanceTracker<T, KEY> MyT; 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: public:
/// Dereferencing key_iter gives you a const KEY& class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter; {
/// Dereferencing instance_iter gives you a T& public:
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter; 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) static T* getInstance(const KEY& k)
{ {
@@ -72,42 +140,47 @@ public:
return (found == getMap_().end()) ? NULL : found->second; 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() static key_iter beginKeys()
{ {
return boost::make_transform_iterator(getMap_().begin(), return key_iter(getMap_().begin());
boost::bind(&InstanceMap::value_type::first, _1));
} }
static key_iter endKeys() static key_iter endKeys()
{ {
return boost::make_transform_iterator(getMap_().end(), return key_iter(getMap_().end());
boost::bind(&InstanceMap::value_type::first, _1));
} }
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: protected:
LLInstanceTracker(KEY key) { add_(key); } 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 void setKey(KEY key) { remove_(); add_(key); }
virtual const KEY& getKey() const { return mKey; } virtual const KEY& getKey() const { return mInstanceKey; }
private: private:
void add_(KEY key) void add_(KEY key)
{ {
mKey = key; mInstanceKey = key;
getMap_()[key] = static_cast<T*>(this); getMap_()[key] = static_cast<T*>(this);
} }
void remove_() void remove_()
{ {
getMap_().erase(mKey); getMap_().erase(mInstanceKey);
} }
static InstanceMap& getMap_() static InstanceMap& getMap_()
@@ -122,9 +195,12 @@ private:
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* /// explicit specialization for default case where KEY is T*
/// use a simple std::set<T*> /// use a simple std::set<T*>
template<typename T> template<typename T>
@@ -133,42 +209,55 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
typedef typename std::set<T*> InstanceSet; typedef typename std::set<T*> InstanceSet;
typedef LLInstanceTracker<T, T*> MyT; typedef LLInstanceTracker<T, T*> MyT;
public: 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 /// for completeness of analogy with the generic implementation
static T* getInstance(T* k) { return k; } static T* getInstance(T* k) { return k; }
static S32 instanceCount() { return getSet_().size(); } static S32 instanceCount() { return getSet_().size(); }
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
// 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
{ {
public: public:
LLInstanceTrackerScopedGuard() instance_iter(const typename InstanceSet::iterator& it)
: mIterator(it)
{ {
++sIterationNestDepth; ++sIterationNestDepth;
} }
~LLInstanceTrackerScopedGuard() instance_iter(const instance_iter& other)
: mIterator(other.mIterator)
{
++sIterationNestDepth;
}
~instance_iter()
{ {
--sIterationNestDepth; --sIterationNestDepth;
} }
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); } private:
static instance_iter endInstances() { return instance_iter(getSet_().end()); } friend class boost::iterator_core_access;
static key_iter beginKeys() { return getSet_().begin(); }
static key_iter endKeys() { return getSet_().end(); } 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: protected:
LLInstanceTracker() 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. // 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)); getSet_().insert(static_cast<T*>(this));
} }
virtual ~LLInstanceTracker() virtual ~LLInstanceTracker()
@@ -180,7 +269,6 @@ protected:
LLInstanceTracker(const LLInstanceTracker& other) LLInstanceTracker(const LLInstanceTracker& other)
{ {
//llassert(sIterationNestDepth == 0);
getSet_().insert(static_cast<T*>(this)); getSet_().insert(static_cast<T*>(this));
} }

View File

@@ -118,6 +118,62 @@ public:
THROTTLE_BLOCKED, // rate exceed, block key 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 // call each time the key wants use
State noteAction(const T& id, S32 weight = 1) State noteAction(const T& id, S32 weight = 1)
{ {

View File

@@ -48,6 +48,7 @@ const U32 AGENT_TYPING = 0x0200;
const U32 AGENT_CROUCHING = 0x0400; const U32 AGENT_CROUCHING = 0x0400;
const U32 AGENT_BUSY = 0x0800; const U32 AGENT_BUSY = 0x0800;
const U32 AGENT_ALWAYS_RUN = 0x1000; const U32 AGENT_ALWAYS_RUN = 0x1000;
const U32 AGENT_AUTOPILOT = 0x2000;
const S32 LSL_REMOTE_DATA_CHANNEL = 1; const S32 LSL_REMOTE_DATA_CHANNEL = 1;
const S32 LSL_REMOTE_DATA_REQUEST = 2; const S32 LSL_REMOTE_DATA_REQUEST = 2;
@@ -184,6 +185,10 @@ const S32 OBJECT_VELOCITY = 5;
const S32 OBJECT_OWNER = 6; const S32 OBJECT_OWNER = 6;
const S32 OBJECT_GROUP = 7; const S32 OBJECT_GROUP = 7;
const S32 OBJECT_CREATOR = 8; 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 // changed() event flags
const U32 CHANGED_NONE = 0x0; const U32 CHANGED_NONE = 0x0;
@@ -198,5 +203,17 @@ const U32 CHANGED_OWNER = 0x80;
const U32 CHANGED_REGION = 0x100; const U32 CHANGED_REGION = 0x100;
const U32 CHANGED_TELEPORT = 0x200; const U32 CHANGED_TELEPORT = 0x200;
const U32 CHANGED_REGION_START = 0x400; 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 #endif

View File

@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
{ {
sDestroyImmediate = b; sDestroyImmediate = b;
} }
// static
BOOL LLMortician::getZealous()
{
return sDestroyImmediate;
}

View File

@@ -46,7 +46,6 @@ public:
// sets destroy immediate true // sets destroy immediate true
static void setZealous(BOOL b); static void setZealous(BOOL b);
static BOOL getZealous();
private: private:
static BOOL sDestroyImmediate; static BOOL sDestroyImmediate;

View File

@@ -107,7 +107,17 @@
#endif #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) #if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1 #define BOOST_REGEX_NO_LIB 1
#define CURL_STATICLIB 1 #define CURL_STATICLIB 1
@@ -159,12 +169,19 @@
#define LL_DLLIMPORT #define LL_DLLIMPORT
#endif // LL_WINDOWS #endif // LL_WINDOWS
#ifdef llcommon_EXPORTS #if LL_COMMON_LINK_SHARED
// Compiling llcommon (shared) // CMake automagically defines llcommon_EXPORTS only when building llcommon
#define LL_COMMON_API LL_DLLEXPORT // sources, and only when llcommon is a shared library (i.e. when
#else // llcommon_EXPORTS // LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
// Using llcommon (shared) // otherwise we can't distinguish between (non-llcommon source) and (llcommon
#define LL_COMMON_API LL_DLLIMPORT // not shared).
#endif // llcommon_EXPORTS # 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 #endif // not LL_LINDEN_PREPROCESSOR_H

View File

@@ -102,7 +102,7 @@ int LLProcessLauncher::launch(void)
STARTUPINFOA sinfo; STARTUPINFOA sinfo;
memset(&sinfo, 0, sizeof(sinfo)); memset(&sinfo, 0, sizeof(sinfo));
std::string args = "\"" + mExecutable + "\""; std::string args = mExecutable;
for(int i = 0; i < (int)mLaunchArguments.size(); i++) for(int i = 0; i < (int)mLaunchArguments.size(); i++)
{ {
args += " "; args += " ";
@@ -114,10 +114,30 @@ int LLProcessLauncher::launch(void)
char *args2 = new char[args.size() + 1]; char *args2 = new char[args.size() + 1];
strcpy(args2, args.c_str()); 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(); 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) if(result == 0)
{ {
// Make absolutely certain we return a non-zero value on failure. // Make absolutely certain we return a non-zero value on failure.

View File

@@ -31,8 +31,9 @@
#include "linden_common.h" #include "linden_common.h"
#include "llqueuedthread.h" #include "llqueuedthread.h"
#include "llstl.h" #include "llstl.h"
#include "lltimer.h" #include "lltimer.h" // ms_sleep()
//============================================================================ //============================================================================

View File

@@ -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) LLSD& LLSD::with(const String& k, const LLSD& v)
{ {
makeMap(impl).insert(k, v); makeMap(impl).insert(k, v);
#ifdef LL_MSVC7 return *this;
return *dynamic_cast<LLSD*>(this);
#else
return *this;
#endif
} }
void LLSD::erase(const String& k) { makeMap(impl).erase(k); } 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) LLSD& LLSD::with(Integer i, const LLSD& v)
{ {
makeArray(impl).insert(i, v); makeArray(impl).insert(i, v);
#ifdef LL_MSVC7 return *this;
return *dynamic_cast<LLSD*>(this);
#else
return *this;
#endif
} }
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); } void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); } void LLSD::erase(Integer i) { makeArray(impl).erase(i); }

View File

@@ -34,7 +34,7 @@
#include "linden_common.h" #include "linden_common.h"
#include "llsdserialize.h" #include "llsdserialize.h"
#include "llmemory.h" #include "llpointer.h"
#include "llstreamtools.h" // for fullread #include "llstreamtools.h" // for fullread
#include <iostream> #include <iostream>

View File

@@ -36,8 +36,9 @@
#define LL_LLSDSERIALIZE_H #define LL_LLSDSERIALIZE_H
#include <iosfwd> #include <iosfwd>
#include "llpointer.h"
#include "llrefcount.h"
#include "llsd.h" #include "llsd.h"
#include "llmemory.h"
/** /**
* @class LLSDParser * @class LLSDParser

View File

@@ -37,6 +37,7 @@
#include <deque> #include <deque>
#include "apr_base64.h" #include "apr_base64.h"
#include <boost/regex.hpp>
extern "C" extern "C"
{ {
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_INTEGER: case ELEMENT_INTEGER:
{ {
S32 i; 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 ) if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
{ // See if sscanf works - it's faster { // See if sscanf works - it's faster
value = i; value = i;
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_REAL: case ELEMENT_REAL:
{ {
F64 r; value = LLSD(mCurrentContent).asReal();
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 ) // removed since this breaks when locale has decimal separator that isn't '.'
{ // See if sscanf works - it's faster // investigated changing local to something compatible each time but deemed higher
value = r; // risk that just using LLSD.asReal() each time.
} //F64 r;
else //if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
{ //{ // See if sscanf works - it's faster
value = LLSD(mCurrentContent).asReal(); // value = r;
} //}
//else
//{
// value = LLSD(mCurrentContent).asReal();
//}
} }
break; break;
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_BINARY: 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; std::vector<U8> data;
data.resize(len); 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); data.resize(len);
value = data; value = data;
break; break;

View File

@@ -46,6 +46,12 @@
#endif #endif
#include "llsdserialize.h" #include "llsdserialize.h"
#include "stringize.h"
#include "is_approx_equal_fraction.h"
#include <map>
#include <set>
#include <boost/range.hpp>
// U32 // U32
LLSD ll_sd_from_U32(const U32 val) LLSD ll_sd_from_U32(const U32 val)
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
return buffer; 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) char* ll_pretty_print_sd(const LLSD& sd)
{ {
const U32 bufferSize = 10 * 1024; const U32 bufferSize = 10 * 1024;
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
return TRUE; 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
}
}

View File

@@ -35,7 +35,7 @@
#ifndef LL_LLSDUTIL_H #ifndef LL_LLSDUTIL_H
#define LL_LLSDUTIL_H #define LL_LLSDUTIL_H
#include "llsd.h" class LLSD;
// U32 // U32
LL_COMMON_API LLSD ll_sd_from_U32(const 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); LL_COMMON_API char* ll_print_sd(const LLSD& sd);
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode. // 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); LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
//compares the structure of an LLSD to a template LLSD and stores the //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, const LLSD& template_llsd,
LLSD& resultant_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 // Simple function to copy data out of input & output iterators if
// there is no need for casting. // there is no need for casting.
template<typename Input> LLSD llsd_copy_array(Input iter, Input end) 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; 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 #endif // LL_LLSDUTIL_H

View File

@@ -100,12 +100,6 @@ private:
DELETED DELETED
} EInitState; } EInitState;
static void deleteSingleton()
{
delete getData().mSingletonInstance;
getData().mSingletonInstance = NULL;
}
// stores pointer to singleton instance // stores pointer to singleton instance
// and tracks initialization state of singleton // and tracks initialization state of singleton
struct SingletonInstanceData struct SingletonInstanceData
@@ -120,7 +114,11 @@ private:
~SingletonInstanceData() ~SingletonInstanceData()
{ {
deleteSingleton(); SingletonInstanceData& data = getData();
if (data.mInitState != DELETED)
{
deleteSingleton();
}
} }
}; };
@@ -132,6 +130,14 @@ public:
data.mInitState = DELETED; 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() static SingletonInstanceData& getData()
{ {
// this is static to cache the lookup results // this is static to cache the lookup results

View File

@@ -43,9 +43,10 @@
// statics // 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 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" std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
LLStat::stat_map_t LLStat::sStatList;
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// Live config file to trigger stats logging // Live config file to trigger stats logging
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
F32 duration = 0.f; F32 duration = 0.f;
F32 interval = 0.f; F32 interval = 0.f;
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
const char * w = "duration"; const char * w = "duration";
if (stats_config.has(w)) if (stats_config.has(w))
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
{ {
interval = (F32)stats_config[w].asReal(); 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 ); mStatsp->setReportPerformanceInterval( interval );
if ( duration > 0 ) if ( duration > 0 )
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
} }
} }
// Set length of performance stat recording // Set length of performance stat recording.
void LLPerfStats::setReportPerformanceDuration( F32 seconds ) // If turning stats on, caller must provide flags
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
{ {
if ( seconds <= 0.f ) if ( seconds <= 0.f )
{ {
mReportPerformanceStatEnd = 0.0; mReportPerformanceStatEnd = 0.0;
LLPerfBlock::setStatsEnabled( FALSE ); LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
mFrameStatsFile.close(); mFrameStatsFile.close();
LLPerfBlock::clearDynamicStats(); LLPerfBlock::clearDynamicStats();
} }
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds); mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
// Clear failure flag to try and create the log file once // Clear failure flag to try and create the log file once
mFrameStatsFileFailure = FALSE; mFrameStatsFileFailure = FALSE;
LLPerfBlock::setStatsEnabled( TRUE );
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame) 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. // Use this constructor for normal, optional LLPerfBlock time slices
// These are also turned on or off via the switch passed in LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : 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) 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) void LLPerfBlock::initDynamicStat(const std::string& key)
{ {
// Early exit if dynamic stats aren't enabled. // 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 mLastPath = sCurrentStatPath; // Save and restore current path
sCurrentStatPath += "/" + key; // Add key to current path sCurrentStatPath += "/" + key; // Add key to current path
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
} }
} }
else 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; llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
} }
} }
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
LLTimer LLStat::sTimer; LLTimer LLStat::sTimer;
LLFrameTimer LLStat::sFrameTimer; LLFrameTimer LLStat::sFrameTimer;
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer) void LLStat::init()
{ {
llassert(num_bins > 0); llassert(mNumBins > 0);
mUseFrameTimer = use_frame_timer;
mNumValues = 0; mNumValues = 0;
mLastValue = 0.f; mLastValue = 0.f;
mLastTime = 0.f; mLastTime = 0.f;
mNumBins = num_bins;
mCurBin = (mNumBins-1); mCurBin = (mNumBins-1);
mNextBin = 0; mNextBin = 0;
mBins = new F32[mNumBins]; mBins = new F32[mNumBins];
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
mTime[i] = 0.0; mTime[i] = 0.0;
mDT[i] = 0.f; 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() LLStat::~LLStat()
@@ -754,6 +805,15 @@ LLStat::~LLStat()
delete[] mBeginTime; delete[] mBeginTime;
delete[] mTime; delete[] mTime;
delete[] mDT; 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() void LLStat::reset()

View File

@@ -192,14 +192,23 @@ public:
// Use this constructor for pre-defined LLStatTime objects // Use this constructor for pre-defined LLStatTime objects
LLPerfBlock(LLStatTime* stat); LLPerfBlock(LLStatTime* stat);
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key // Use this constructor for normal, optional LLPerfBlock time slices
LLPerfBlock( const char* key1, const char* key2 = NULL); 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(); ~LLPerfBlock();
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; }; enum
static S32 getStatsEnabled() { return sStatsEnabled; }; { // 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 clearDynamicStats(); // Reset maps to clear out dynamic objects
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
@@ -213,7 +222,7 @@ private:
LLStatTime * mPredefinedStat; // LLStatTime object to get data LLStatTime * mPredefinedStat; // LLStatTime object to get data
StatEntry * mDynamicStat; // StatEntryobject 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 stat_map_t sStatMap; // Map full path string to LLStatTime objects
static std::string sCurrentStatPath; // Something like "frame/physics/physics step" static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
}; };
@@ -236,7 +245,7 @@ public:
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); }; BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; }; F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; }; 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 setProcessName(const std::string& process_name) { mProcessName = process_name; }
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; } void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
@@ -258,8 +267,15 @@ private:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class LL_COMMON_API LLStat class LL_COMMON_API LLStat
{ {
private:
typedef std::multimap<std::string, LLStat*> stat_map_t;
static stat_map_t sStatList;
void init();
public: 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(); ~LLStat();
void reset(); void reset();
@@ -322,8 +338,22 @@ private:
F32 *mDT; F32 *mDT;
S32 mCurBin; S32 mCurBin;
S32 mNextBin; S32 mNextBin;
std::string mName;
static LLTimer sTimer; static LLTimer sTimer;
static LLFrameTimer sFrameTimer; 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_ #endif // LL_STAT_

View File

@@ -45,7 +45,7 @@
// skips spaces and tabs // skips spaces and tabs
bool skip_whitespace(std::istream& input_stream) bool skip_whitespace(std::istream& input_stream)
{ {
char c = input_stream.peek(); int c = input_stream.peek();
while (('\t' == c || ' ' == c) && input_stream.good()) while (('\t' == c || ' ' == c) && input_stream.good())
{ {
input_stream.get(); input_stream.get();
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
// skips whitespace, newlines, and carriage returns // skips whitespace, newlines, and carriage returns
bool skip_emptyspace(std::istream& input_stream) bool skip_emptyspace(std::istream& input_stream)
{ {
char c = input_stream.peek(); int c = input_stream.peek();
while ( input_stream.good() while ( input_stream.good()
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) ) && ('\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)) while (skip_emptyspace(input_stream))
{ {
char c = input_stream.peek(); int c = input_stream.peek();
if ('#' == c ) if ('#' == c )
{ {
while ('\n' != c && input_stream.good()) 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) bool skip_line(std::istream& input_stream)
{ {
char c; int c;
do do
{ {
c = input_stream.get(); c = input_stream.get();
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
bool skip_to_next_word(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() while ( input_stream.good()
&& ( (c >= 'a' && c <= 'z') && ( (c >= 'a' && c <= 'z')
|| (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()) while (input_stream.good())
{ {
skip_emptyspace(input_stream); skip_emptyspace(input_stream);
char c = input_stream.get(); int c = input_stream.get();
if (keyword[0] != c) if (keyword[0] != c)
{ {
skip_line(input_stream); 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()) while (input_stream.good())
{ {
skip_emptyspace(input_stream); skip_emptyspace(input_stream);
char c = input_stream.get(); int c = input_stream.get();
if (keyword[0] != c) if (keyword[0] != c)
{ {
skip_line(input_stream); 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) bool get_word(std::string& output_string, std::istream& input_stream)
{ {
skip_emptyspace(input_stream); skip_emptyspace(input_stream);
char c = input_stream.peek(); int c = input_stream.peek();
while ( !isspace(c) while ( !isspace(c)
&& '\n' != c && '\n' != c
&& '\r' != c && '\r' != c
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
{ {
skip_emptyspace(input_stream); skip_emptyspace(input_stream);
int char_count = 0; int char_count = 0;
char c = input_stream.peek(); int c = input_stream.peek();
while (!isspace(c) while (!isspace(c)
&& '\n' != c && '\n' != c
&& '\r' != 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) bool get_line(std::string& output_string, std::istream& input_stream)
{ {
output_string.clear(); output_string.clear();
char c = input_stream.get(); int c = input_stream.get();
while (input_stream.good()) while (input_stream.good())
{ {
output_string += c; output_string += c;
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
{ {
output_string.clear(); output_string.clear();
int char_count = 0; int char_count = 0;
char c = input_stream.get(); int c = input_stream.get();
while (input_stream.good() && char_count < n) while (input_stream.good() && char_count < n)
{ {
char_count++; char_count++;

View File

@@ -52,6 +52,7 @@ public:
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));} void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : 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;} void skip(const U32 index) { mBytep += mSkip*index;}
U32 getSkip() const { return mSkip; } U32 getSkip() const { return mSkip; }
Object* get() { return mObjectp; } 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. //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 //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 //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. if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
{ {

View File

@@ -36,6 +36,8 @@
#include "u64.h" #include "u64.h"
#include "lldate.h"
#if LL_WINDOWS #if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN
# include <winsock2.h> # include <winsock2.h>

View File

@@ -39,8 +39,6 @@
#include <limits.h> #include <limits.h>
#include "stdtypes.h" #include "stdtypes.h"
#include "llpreprocessor.h"
#include "lldate.h"
#include <string> #include <string>
#include <list> #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 U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC; 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 class LL_COMMON_API LLTimer
{ {
public: 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 &timestr); LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string &timestr);
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string &timestr); LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string &timestr);
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
#endif #endif

View 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) */

View File

@@ -32,7 +32,7 @@
#ifndef LL_LLECONOMY_H #ifndef LL_LLECONOMY_H
#define LL_LLECONOMY_H #define LL_LLECONOMY_H
#include "llmemory.h" #include "llsingleton.h"
class LLMessageSystem; class LLMessageSystem;
class LLVector3; class LLVector3;

View File

@@ -36,10 +36,9 @@
#include "lldarray.h" #include "lldarray.h"
#include "llfoldertype.h" #include "llfoldertype.h"
#include "llinventorytype.h" #include "llinventorytype.h"
#include "llinventorydefines.h"
#include "llmemtype.h" #include "llmemtype.h"
#include "llpermissions.h" #include "llpermissions.h"
#include "llmemory.h" #include "llrefcount.h"
#include "llsaleinfo.h" #include "llsaleinfo.h"
#include "llsd.h" #include "llsd.h"
#include "lluuid.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); LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item); LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat); LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);

View File

@@ -35,6 +35,7 @@
#include "llinventorytype.h" #include "llinventorytype.h"
#include "lldictionary.h" #include "lldictionary.h"
#include "llmemory.h" #include "llmemory.h"
#include "llsingleton.h"
static const std::string empty_string; static const std::string empty_string;

View File

@@ -33,7 +33,7 @@
#ifndef LL_NOTECARD_H #ifndef LL_NOTECARD_H
#define LL_NOTECARD_H #define LL_NOTECARD_H
#include "llmemory.h" #include "llpointer.h"
#include "llinventory.h" #include "llinventory.h"
class LLNotecard class LLNotecard

View File

@@ -177,7 +177,7 @@ void LLParcel::init(const LLUUID &owner_id,
mSaleTimerExpires.stop(); mSaleTimerExpires.stop();
mGraceExtension = 0; mGraceExtension = 0;
//mExpireAction = STEA_REVERT; //mExpireAction = STEA_REVERT;
mRecordTransaction = FALSE; //mRecordTransaction = FALSE;
mAuctionID = 0; mAuctionID = 0;
mInEscrow = false; mInEscrow = false;

View File

@@ -433,13 +433,10 @@ public:
void completeSale(U32& type, U8& flags, LLUUID& to_id); void completeSale(U32& type, U8& flags, LLUUID& to_id);
void clearSale(); 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); BOOL isMediaResetTimerExpired(const U64& time);
// more accessors // more accessors
U32 getParcelFlags() const { return mParcelFlags; } U32 getParcelFlags() const { return mParcelFlags; }
@@ -474,7 +471,9 @@ public:
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; } { return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
BOOL getAllowLandmark() const 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 BOOL getAllowGroupScripts() const
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; } { return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
@@ -620,8 +619,6 @@ protected:
LLTimer mMediaResetTimer; LLTimer mMediaResetTimer;
S32 mGraceExtension; S32 mGraceExtension;
BOOL mRecordTransaction;
// This value is non-zero if there is an auction associated with // This value is non-zero if there is an auction associated with
// the parcel. // the parcel.

View File

@@ -132,5 +132,7 @@ const S32 PARCEL_DETAILS_DESC = 1;
const S32 PARCEL_DETAILS_OWNER = 2; const S32 PARCEL_DETAILS_OWNER = 2;
const S32 PARCEL_DETAILS_GROUP = 3; const S32 PARCEL_DETAILS_GROUP = 3;
const S32 PARCEL_DETAILS_AREA = 4; const S32 PARCEL_DETAILS_AREA = 4;
const S32 PARCEL_DETAILS_ID = 5;
const S32 PARCEL_DETAILS_SEE_AVATARS = 6;
#endif #endif

View File

@@ -30,8 +30,8 @@
* $/LicenseInfo$ * $/LicenseInfo$
*/ */
#include "linden_common.h"
#include <iostream> #include <iostream>
#include "linden_common.h"
#include "llsaleinfo.h" #include "llsaleinfo.h"

View File

@@ -37,8 +37,8 @@
#include <cstdlib> #include <cstdlib>
#include <vector> #include <vector>
#include "lldefs.h" #include "lldefs.h"
#include "llstl.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 //#include "llstring.h" // *TODO: Remove when LLString is gone
// lltut.h uses is_approx_equal_fraction(). This was moved to its own header // 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 // file in llcommon so we can use lltut.h for llcommon tests without making
// llcommon depend on llmath. // 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 Q1 = data[data.size()/4];
VEC_TYPE Q3 = data[data.size()-data.size()/4-1]; 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 min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1)); VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));

View File

@@ -34,7 +34,8 @@
#include "stdtypes.h" #include "stdtypes.h"
#include "xform.h" #include "xform.h"
#include "llmemory.h" #include "llpointer.h"
#include "llrefcount.h"
#include <vector> #include <vector>
template <class T> class LLTreeNode; template <class T> class LLTreeNode;

View File

@@ -52,8 +52,6 @@
// //
// Sorry the code is such a mess. JC // Sorry the code is such a mess. JC
#include "llpreprocessor.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// LLV4MATH - GNUC // LLV4MATH - GNUC

View File

@@ -2080,7 +2080,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
mDetail = detail; mDetail = detail;
mSculptLevel = -2; mSculptLevel = -2;
#if MESH_ENABLED #if MESH_ENABLED
mIsTetrahedron = FALSE; mIsMeshAssetLoaded = FALSE;
mLODScaleBias.setVec(1,1,1); mLODScaleBias.setVec(1,1,1);
mHullPoints = NULL; mHullPoints = NULL;
mHullIndices = NULL; mHullIndices = NULL;
@@ -2103,7 +2103,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
generate(); 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(); createVolumeFaces();
} }
@@ -2414,7 +2414,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
LLSD mdl; LLSD mdl;
if (!unzip_llsd(mdl, is, size)) 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; return false;
} }
@@ -2712,173 +2712,21 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
return true; return true;
} }
void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
BOOL LLVolume::isMeshAssetLoaded()
{ {
LLVector4a v0; return mIsMeshAssetLoaded;
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());
} }
BOOL LLVolume::isTetrahedron() void LLVolume::setMeshAssetLoaded(BOOL loaded)
{ {
return mIsTetrahedron; mIsMeshAssetLoaded = loaded;
}
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;
} }
void LLVolume::copyVolumeFaces(const LLVolume* volume) void LLVolume::copyVolumeFaces(const LLVolume* volume)
{ {
mVolumeFaces = volume->mVolumeFaces; mVolumeFaces = volume->mVolumeFaces;
mSculptLevel = 0; mSculptLevel = 0;
mIsTetrahedron = FALSE;
} }
void LLVolume::cacheOptimize() void LLVolume::cacheOptimize()
@@ -2889,17 +2737,10 @@ void LLVolume::cacheOptimize()
} }
} }
#endif //MESH_ENABLED #endif //MESH_ENABLED
S32 LLVolume::getNumFaces() const S32 LLVolume::getNumFaces() const
{ {
#if MESH_ENABLED return mIsMeshAssetLoaded ? getNumVolumeFaces() : (S32)mProfilep->mFaces.size();
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();
} }
@@ -7301,7 +7142,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
resizeVertices(num_vertices); resizeVertices(num_vertices);
resizeIndices(num_indices); resizeIndices(num_indices);
#if MESH_ENABLED #if MESH_ENABLED
if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) if (!volume->isMeshAssetLoaded())
#endif //MESH_ENABLED #endif //MESH_ENABLED
{ {
mEdge.resize(num_indices); mEdge.resize(num_indices);

View File

@@ -59,7 +59,7 @@ class LLVolumeTriangle;
#include "llquaternion.h" #include "llquaternion.h"
#include "llstrider.h" #include "llstrider.h"
#include "v4coloru.h" #include "v4coloru.h"
#include "llmemory.h" #include "llrefcount.h"
#include "llfile.h" #include "llfile.h"
//============================================================================ //============================================================================
@@ -1085,15 +1085,15 @@ protected:
public: public:
virtual bool unpackVolumeFaces(std::istream& is, S32 size); virtual bool unpackVolumeFaces(std::istream& is, S32 size);
virtual void makeTetrahedron(); virtual void setMeshAssetLoaded(BOOL loaded);
virtual BOOL isTetrahedron(); virtual BOOL isMeshAssetLoaded();
#endif //MESH_ENABLED #endif //MESH_ENABLED
protected: protected:
BOOL mUnique; BOOL mUnique;
F32 mDetail; F32 mDetail;
S32 mSculptLevel; S32 mSculptLevel;
#if MESH_ENABLED #if MESH_ENABLED
BOOL mIsTetrahedron; BOOL mIsMeshAssetLoaded;
#endif //MESH_ENABLED #endif //MESH_ENABLED
LLVolumeParams mParams; LLVolumeParams mParams;

View File

@@ -36,7 +36,7 @@
#include <map> #include <map>
#include "llvolume.h" #include "llvolume.h"
#include "llmemory.h" #include "llpointer.h"
#include "llthread.h" #include "llthread.h"
class LLVolumeParams; class LLVolumeParams;

View File

@@ -771,6 +771,8 @@ void LLCurl::Multi::run()
void LLCurl::Multi::doPerform() void LLCurl::Multi::doPerform()
{ {
S32 q = 0; S32 q = 0;
if (mThreaded)
mSignal->unlock();
for (S32 call_count = 0; for (S32 call_count = 0;
call_count < MULTI_PERFORM_CALL_REPEAT; call_count < MULTI_PERFORM_CALL_REPEAT;
call_count += 1) call_count += 1)
@@ -783,6 +785,8 @@ void LLCurl::Multi::doPerform()
} }
} }
if (mThreaded)
mSignal->lock();
mQueued = q; mQueued = q;
mPerformState = PERFORM_STATE_COMPLETED; mPerformState = PERFORM_STATE_COMPLETED;
} }

View File

@@ -47,6 +47,7 @@
#include "llbuffer.h" #include "llbuffer.h"
#include "lliopipe.h" #include "lliopipe.h"
#include "llsd.h" #include "llsd.h"
#include "llthread.h"
class LLMutex; class LLMutex;

View File

@@ -33,7 +33,8 @@
#ifndef LL_LLHTTPNODE_H #ifndef LL_LLHTTPNODE_H
#define LL_LLHTTPNODE_H #define LL_LLHTTPNODE_H
#include "llmemory.h" #include "llpointer.h"
#include "llrefcount.h"
#include "llsd.h" #include "llsd.h"
class LLChainIOFactory; class LLChainIOFactory;

View File

@@ -41,7 +41,7 @@
#include "llsd.h" #include "llsd.h"
#include "llsdserialize.h" #include "llsdserialize.h"
#include "llsdutil_math.h" #include "llsdutil_math.h"
#include "llmemory.h" #include "llpointer.h"
#include "message.h" #include "message.h"
#include "message.h" #include "message.h"

View File

@@ -36,7 +36,8 @@
#include "llhost.h" #include "llhost.h"
#include "lluuid.h" #include "lluuid.h"
#include "llsd.h" #include "llsd.h"
#include "llmemory.h" #include "llrefcount.h"
#include "llpointer.h"
#include "v3math.h" #include "v3math.h"
class LLMessageSystem; class LLMessageSystem;

View File

@@ -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 ) inline void LLTemplateMessageReader::getString(const char *block, const char *var, std::string& outstr, S32 blocknum )
{ {
char s[MTUBYTES]; char s[MTUBYTES + 1]= {0}; // every element is initialized with 0
s[0] = '\0';
getData(block, var, s, 0, blocknum, MTUBYTES); getData(block, var, s, 0, blocknum, MTUBYTES);
s[MTUBYTES - 1] = '\0'; s[MTUBYTES] = '\0';
outstr = s; outstr = s;
} }

View File

@@ -29,6 +29,7 @@
* COMPLETENESS OR PERFORMANCE. * COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$ * $/LicenseInfo$
*/ */
#include "linden_common.h"
#include "sound_ids.h" #include "sound_ids.h"

View File

@@ -433,7 +433,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
} }
else if(message_name == "sleep_time") 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") else if(message_name == "crash")
{ {

View File

@@ -993,6 +993,7 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
} }
// Send initial sleep time // Send initial sleep time
llassert_always(mSleepTime != 0.f);
setSleepTime(mSleepTime, true); setSleepTime(mSleepTime, true);
setState(STATE_RUNNING); setState(STATE_RUNNING);

View File

@@ -33,6 +33,7 @@ set(llprimitive_HEADER_FILES
legacy_object_types.h legacy_object_types.h
llmaterialtable.h llmaterialtable.h
llmediaentry.h
llmodel.h llmodel.h
llprimitive.h llprimitive.h
llprimtexturelist.h llprimtexturelist.h

View 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

View File

@@ -28,6 +28,7 @@
#if MESH_ENABLED #if MESH_ENABLED
#include "llmodel.h" #include "llmodel.h"
#include "llmemory.h"
#if MESH_IMPORT #if MESH_IMPORT
#include "llconvexdecomposition.h" #include "llconvexdecomposition.h"
#endif //MESH_IMPORT #endif //MESH_IMPORT
@@ -1019,10 +1020,16 @@ void LLModel::setVolumeFaceData(
face.resizeVertices(num_verts); face.resizeVertices(num_verts);
face.resizeIndices(num_indices); 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()) 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 else
{ {
@@ -1032,7 +1039,10 @@ void LLModel::setVolumeFaceData(
if (tc.get()) 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 else
{ {

View File

@@ -265,7 +265,7 @@ void LLCubeMap::setMatrix(S32 stage)
if (mMatrixStage < 0) return; if (mMatrixStage < 0) return;
if (stage > 0) //if (stage > 0)
{ {
gGL.getTexUnit(stage)->activate(); gGL.getTexUnit(stage)->activate();
} }
@@ -284,17 +284,17 @@ void LLCubeMap::setMatrix(S32 stage)
glLoadMatrixf((F32 *)trans.mMatrix); glLoadMatrixf((F32 *)trans.mMatrix);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
if (stage > 0) /*if (stage > 0)
{ {
gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->activate();
} }*/
} }
void LLCubeMap::restoreMatrix() void LLCubeMap::restoreMatrix()
{ {
if (mMatrixStage < 0) return; if (mMatrixStage < 0) return;
if (mMatrixStage > 0) //if (mMatrixStage > 0)
{ {
gGL.getTexUnit(mMatrixStage)->activate(); gGL.getTexUnit(mMatrixStage)->activate();
} }
@@ -302,10 +302,10 @@ void LLCubeMap::restoreMatrix()
glPopMatrix(); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
if (mMatrixStage > 0) /*if (mMatrixStage > 0)
{ {
gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->activate();
} }*/
} }
void LLCubeMap::setReflection (void) void LLCubeMap::setReflection (void)

View File

@@ -53,6 +53,7 @@
#include "llstacktrace.h" #include "llstacktrace.h"
#include "llglheaders.h" #include "llglheaders.h"
#include "llglslshader.h"
#ifdef _DEBUG #ifdef _DEBUG
//#define GL_STATE_VERIFY //#define GL_STATE_VERIFY
@@ -127,6 +128,23 @@ PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL; PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = 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 // vertex object prototypes
PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL; PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL;
PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI = NULL; PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI = NULL;
@@ -156,27 +174,33 @@ PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL; PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL; PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
// GL_EXT_framebuffer_object // GL_ARB_framebuffer_object
PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL; PFNGLISRENDERBUFFERPROC glIsRenderbuffer = NULL;
PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL; PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = NULL;
PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL; PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = NULL;
PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL; PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = NULL;
PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL; PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = NULL;
PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL; PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv = NULL;
PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL; PFNGLISFRAMEBUFFERPROC glIsFramebuffer = NULL;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL;
PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = NULL;
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = NULL;
PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL; PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = NULL;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL;
PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = NULL;
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv = NULL;
PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; PFNGLGENERATEMIPMAPPROC glGenerateMipmap = NULL;
PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL; PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = NULL;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = NULL; PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT = NULL; PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
//GL_ARB_texture_multisample
PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
PFNGLSAMPLEMASKIPROC glSampleMaski;
// GL_EXT_blend_func_separate // GL_EXT_blend_func_separate
PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL; PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
@@ -321,10 +345,13 @@ LLGLManager::LLGLManager() :
mHasMipMapGeneration(FALSE), mHasMipMapGeneration(FALSE),
mHasCompressedTextures(FALSE), mHasCompressedTextures(FALSE),
mHasFramebufferObject(FALSE), mHasFramebufferObject(FALSE),
mMaxSamples(0),
mHasFramebufferMultisample(FALSE), mHasFramebufferMultisample(FALSE),
mHasBlendFuncSeparate(FALSE), mHasBlendFuncSeparate(FALSE),
mHasSync(FALSE),
mHasVertexBufferObject(FALSE), mHasVertexBufferObject(FALSE),
mHasMapBufferRange(FALSE),
mHasFlushBufferRange(FALSE),
mHasPBuffer(FALSE), mHasPBuffer(FALSE),
mHasShaderObjects(FALSE), mHasShaderObjects(FALSE),
mHasVertexShader(FALSE), mHasVertexShader(FALSE),
@@ -335,6 +362,11 @@ LLGLManager::LLGLManager() :
mHasPointParameters(FALSE), mHasPointParameters(FALSE),
mHasDrawBuffers(FALSE), mHasDrawBuffers(FALSE),
mHasTextureRectangle(FALSE), mHasTextureRectangle(FALSE),
mHasTextureMultisample(FALSE),
mMaxSampleMaskWords(0),
mMaxColorTextureSamples(0),
mMaxDepthTextureSamples(0),
mMaxIntegerSamples(0),
mHasAnisotropic(FALSE), mHasAnisotropic(FALSE),
mHasARBEnvCombine(FALSE), mHasARBEnvCombine(FALSE),
@@ -353,6 +385,8 @@ LLGLManager::LLGLManager() :
mHasSeparateSpecularColor(FALSE), mHasSeparateSpecularColor(FALSE),
mDebugGPU(FALSE),
mDriverVersionMajor(1), mDriverVersionMajor(1),
mDriverVersionMinor(0), mDriverVersionMinor(0),
mDriverVersionRelease(0), mDriverVersionRelease(0),
@@ -538,13 +572,46 @@ bool LLGLManager::initGL()
{ {
GLint num_tex_image_units; GLint num_tex_image_units;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &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(); initGLStates();
return true; 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) void LLGLManager::getGLInfo(LLSD& info)
{ {
info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR)); info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
@@ -601,6 +668,14 @@ std::string LLGLManager::getRawGLString()
return gl_string; 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() void LLGLManager::shutdownGL()
{ {
if (mInited) if (mInited)
@@ -686,6 +761,9 @@ void LLGLManager::initExtensions()
mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts); mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts); mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", 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); 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 // mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
#ifdef GL_ARB_framebuffer_object #ifdef GL_ARB_framebuffer_object
@@ -700,7 +778,10 @@ void LLGLManager::initExtensions()
mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", 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); mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
#endif
mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts); mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", 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); && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
@@ -879,29 +960,44 @@ void LLGLManager::initExtensions()
mHasVertexBufferObject = FALSE; 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) if (mHasFramebufferObject)
{ {
llinfos << "initExtensions() FramebufferObject-related procs..." << llendl; llinfos << "initExtensions() FramebufferObject-related procs..." << llendl;
glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbufferEXT"); glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbuffer");
glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbufferEXT"); glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbuffer");
glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffersEXT"); glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffers");
glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffersEXT"); glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffers");
glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageEXT"); glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorage");
glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameterivEXT"); glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameteriv");
glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebufferEXT"); glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebuffer");
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebufferEXT"); glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebuffer");
glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffersEXT"); glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffers");
glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffersEXT"); glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffers");
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatusEXT"); glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatus");
glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1DEXT"); glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1D");
glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2DEXT"); glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2D");
glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3DEXT"); glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3D");
glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbufferEXT"); glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbuffer");
glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT"); glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameteriv");
glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT"); glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmap");
glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebufferEXT"); glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebuffer");
glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisampleEXT"); glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisample");
glFramebufferTextureLayerEXT = (PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTextureLayerEXT"); glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTextureLayer");
} }
if (mHasDrawBuffers) if (mHasDrawBuffers)
{ {
@@ -911,6 +1007,13 @@ void LLGLManager::initExtensions()
{ {
glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT"); 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 #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 // 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"); 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) void LLGLState::checkTextureChannels(const std::string& msg)
{ {
#if 0
if (!gDebugGL) if (!gDebugGL)
{ {
return; return;
@@ -1458,11 +1562,12 @@ void LLGLState::checkTextureChannels(const std::string& msg)
LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL; LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL;
} }
} }
#endif
} }
void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
{ {
if (!gDebugGL) if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
{ {
return; 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)) 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; gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl;
} }
} }
} }*/
glClientActiveTextureARB(GL_TEXTURE0_ARB); glClientActiveTextureARB(GL_TEXTURE0_ARB);
gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->activate();
@@ -1640,6 +1745,16 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
LLGLState::LLGLState(LLGLenum state, S32 enabled) : LLGLState::LLGLState(LLGLenum state, S32 enabled) :
mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE) 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(); stop_glerror();
if (state) if (state)
{ {
@@ -1998,8 +2113,7 @@ void LLGLNamePool::release(GLuint name)
//static //static
void LLGLNamePool::upkeepPools() void LLGLNamePool::upkeepPools()
{ {
tracker_t::LLInstanceTrackerScopedGuard guard; for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
{ {
LLGLNamePool & pool = *iter; LLGLNamePool & pool = *iter;
pool.upkeep(); pool.upkeep();
@@ -2009,8 +2123,7 @@ void LLGLNamePool::upkeepPools()
//static //static
void LLGLNamePool::cleanupPools() void LLGLNamePool::cleanupPools()
{ {
tracker_t::LLInstanceTrackerScopedGuard guard; for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
{ {
LLGLNamePool & pool = *iter; LLGLNamePool & pool = *iter;
pool.cleanup(); pool.cleanup();

View File

@@ -89,11 +89,15 @@ public:
BOOL mHasMipMapGeneration; BOOL mHasMipMapGeneration;
BOOL mHasCompressedTextures; BOOL mHasCompressedTextures;
BOOL mHasFramebufferObject; BOOL mHasFramebufferObject;
S32 mMaxSamples;
BOOL mHasFramebufferMultisample; BOOL mHasFramebufferMultisample;
BOOL mHasBlendFuncSeparate; BOOL mHasBlendFuncSeparate;
// ARB Extensions // ARB Extensions
BOOL mHasVertexBufferObject; BOOL mHasVertexBufferObject;
BOOL mHasSync;
BOOL mHasMapBufferRange;
BOOL mHasFlushBufferRange;
BOOL mHasPBuffer; BOOL mHasPBuffer;
BOOL mHasShaderObjects; BOOL mHasShaderObjects;
BOOL mHasVertexShader; BOOL mHasVertexShader;
@@ -105,6 +109,11 @@ public:
BOOL mHasDrawBuffers; BOOL mHasDrawBuffers;
BOOL mHasDepthClamp; BOOL mHasDepthClamp;
BOOL mHasTextureRectangle; BOOL mHasTextureRectangle;
BOOL mHasTextureMultisample;
S32 mMaxSampleMaskWords;
S32 mMaxColorTextureSamples;
S32 mMaxDepthTextureSamples;
S32 mMaxIntegerSamples;
// Other extensions. // Other extensions.
BOOL mHasAnisotropic; BOOL mHasAnisotropic;
@@ -126,6 +135,9 @@ public:
// Misc extensions // Misc extensions
BOOL mHasSeparateSpecularColor; BOOL mHasSeparateSpecularColor;
//whether this GPU is in the debug list.
BOOL mDebugGPU;
S32 mDriverVersionMajor; S32 mDriverVersionMajor;
S32 mDriverVersionMinor; S32 mDriverVersionMinor;
@@ -143,6 +155,7 @@ public:
void printGLInfoString(); void printGLInfoString();
void getGLInfo(LLSD& info); void getGLInfo(LLSD& info);
U32 getNumFBOFSAASamples(U32 desired_samples = 32);
// In ALL CAPS // In ALL CAPS
std::string mGLVendor; std::string mGLVendor;
std::string mGLVendorShort; std::string mGLVendorShort;
@@ -154,6 +167,7 @@ private:
void initExtensions(); void initExtensions();
void initGLStates(); void initGLStates();
void initGLImages(); void initGLImages();
void setToDebugGPU();
}; };
extern LLGLManager gGLManager; extern LLGLManager gGLManager;

View File

@@ -76,6 +76,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; 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 // GL_ATI_vertex_array_object
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
@@ -312,6 +329,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; 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 // GL_ATI_vertex_array_object
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
@@ -455,31 +489,36 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
//GL_EXT_blend_func_separate //GL_EXT_blend_func_separate
extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
//GL_EXT_framebuffer_object //GL_ARB_framebuffer_object
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
extern PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT; extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
//GL_ARB_draw_buffers //GL_ARB_draw_buffers
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
//GL_ARB_texture_multisample
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
#elif LL_WINDOWS #elif LL_WINDOWS
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -512,6 +551,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; 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 // GL_ATI_vertex_array_object
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
@@ -654,31 +710,37 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
//GL_EXT_blend_func_separate //GL_EXT_blend_func_separate
extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
//GL_EXT_framebuffer_object //GL_ARB_framebuffer_object
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
extern PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT; extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
//GL_ARB_draw_buffers //GL_ARB_draw_buffers
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
//GL_ARB_texture_multisample
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
#elif LL_DARWIN #elif LL_DARWIN
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// LL_DARWIN // LL_DARWIN
@@ -696,7 +758,7 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
#include <AvailabilityMacros.h> #include <AvailabilityMacros.h>
//GL_EXT_blend_func_separate //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 // GL_EXT_framebuffer_object
extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; 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 #ifndef GL_ARB_framebuffer_object
#define glGenerateMipmap glGenerateMipmapEXT #define glGenerateMipmap glGenerateMipmapEXT
#define GL_MAX_SAMPLES 0x8D57
#endif #endif
// GL_ARB_draw_buffers // GL_ARB_draw_buffers
extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; 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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #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 // Define vertex buffer object headers on Mac
// //

View File

@@ -37,6 +37,7 @@
#include "llshadermgr.h" #include "llshadermgr.h"
#include "llfile.h" #include "llfile.h"
#include "llrender.h" #include "llrender.h"
#include "llcontrol.h"
#if LL_DARWIN #if LL_DARWIN
#include "OpenGL/OpenGL.h" #include "OpenGL/OpenGL.h"
@@ -54,6 +55,16 @@ using std::pair;
using std::make_pair; using std::make_pair;
using std::string; 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) BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
{ {
return v1 != v2; return v1 != v2;
@@ -63,6 +74,7 @@ LLShaderFeatures::LLShaderFeatures()
: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false), : calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false), hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
hasGamma(false), hasLighting(false), calculatesAtmospherics(false) hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
, mIndexedTextureChannels(0), disableTextureIndex(false), hasAlphaMask(false)
#if MESH_ENABLED #if MESH_ENABLED
, hasObjectSkinning(false) , hasObjectSkinning(false)
#endif //MESH_ENABLED #endif //MESH_ENABLED
@@ -119,6 +131,28 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
glDeleteObjectARB(mProgramObject); glDeleteObjectARB(mProgramObject);
// Create program // Create program
mProgramObject = glCreateProgramObjectARB(); 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 // Attach existing objects
if (!LLShaderMgr::instance()->attachShaderFeatures(this)) if (!LLShaderMgr::instance()->attachShaderFeatures(this))
@@ -129,19 +163,9 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
return FALSE; return FALSE;
} }
vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin(); if (gGLManager.mGLVersion < 3.1f || no_texture_indexing)
for ( ; fileIter != mShaderFiles.end(); fileIter++ ) { //attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
{ mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
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;
}
} }
// Map attributes and uniforms // Map attributes and uniforms
@@ -169,6 +193,28 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
return createShader(attributes,uniforms); 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; return success;
} }
@@ -314,7 +360,8 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type) 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 { //this here is a texture
glUniform1iARB(location, mActiveTextureChannels); glUniform1iARB(location, mActiveTextureChannels);
LL_DEBUGS("ShaderLoading") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL; LL_DEBUGS("ShaderLoading") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL;
@@ -360,10 +407,12 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
void LLGLSLShader::bind() void LLGLSLShader::bind()
{ {
gGL.flush();
if (gGLManager.mHasShaderObjects) if (gGLManager.mHasShaderObjects)
{ {
glUseProgramObjectARB(mProgramObject); glUseProgramObjectARB(mProgramObject);
sCurBoundShader = mProgramObject;
sCurBoundShaderPtr = this;
if (mUniformsDirty) if (mUniformsDirty)
{ {
LLShaderMgr::instance()->updateShaderUniforms(this); LLShaderMgr::instance()->updateShaderUniforms(this);
@@ -374,6 +423,7 @@ void LLGLSLShader::bind()
void LLGLSLShader::unbind() void LLGLSLShader::unbind()
{ {
gGL.flush();
if (gGLManager.mHasShaderObjects) if (gGLManager.mHasShaderObjects)
{ {
stop_glerror(); stop_glerror();
@@ -386,6 +436,8 @@ void LLGLSLShader::unbind()
} }
} }
glUseProgramObjectARB(0); glUseProgramObjectARB(0);
sCurBoundShader = 0;
sCurBoundShaderPtr = NULL;
stop_glerror(); stop_glerror();
} }
} }
@@ -393,6 +445,8 @@ void LLGLSLShader::unbind()
void LLGLSLShader::bindNoShader(void) void LLGLSLShader::bindNoShader(void)
{ {
glUseProgramObjectARB(0); glUseProgramObjectARB(0);
sCurBoundShader = 0;
sCurBoundShaderPtr = NULL;
} }
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode) 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) void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{ {

View File

@@ -53,6 +53,9 @@ public:
#endif //MESH_ENABLED #endif //MESH_ENABLED
bool hasAtmospherics; bool hasAtmospherics;
bool hasGamma; bool hasGamma;
S32 mIndexedTextureChannels;
bool disableTextureIndex;
bool hasAlphaMask;
// char numLights; // char numLights;
@@ -72,6 +75,10 @@ public:
LLGLSLShader(S32 shader_class); LLGLSLShader(S32 shader_class);
static GLhandleARB sCurBoundShader;
static LLGLSLShader* sCurBoundShaderPtr;
static bool sNoFixedFunction;
void unload(); void unload();
BOOL createShader(std::vector<std::string> * attributes, BOOL createShader(std::vector<std::string> * attributes,
std::vector<std::string> * uniforms); std::vector<std::string> * uniforms);
@@ -108,6 +115,8 @@ public:
void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); 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 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 vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void vertexAttrib4fv(U32 index, GLfloat* v); void vertexAttrib4fv(U32 index, GLfloat* v);
@@ -146,4 +155,9 @@ public:
std::string mName; 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 #endif

View File

@@ -1400,22 +1400,36 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
void LLImageGL::deleteDeadTextures() void LLImageGL::deleteDeadTextures()
{ {
bool reset = false;
while (!sDeadTextureList.empty()) while (!sDeadTextureList.empty())
{ {
GLuint tex = sDeadTextureList.front(); GLuint tex = sDeadTextureList.front();
sDeadTextureList.pop_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(); stop_glerror();
if (i > 0)
{
reset = true;
}
} }
} }
glDeleteTextures(1, &tex); glDeleteTextures(1, &tex);
stop_glerror(); stop_glerror();
} }
if (reset)
{
gGL.getTexUnit(0)->activate();
}
} }
void LLImageGL::destroyGLTexture() void LLImageGL::destroyGLTexture()

View File

@@ -37,7 +37,8 @@
#include "llimage.h" #include "llimage.h"
#include "llgltypes.h" #include "llgltypes.h"
#include "llmemory.h" #include "llpointer.h"
#include "llrefcount.h"
#include "v2math.h" #include "v2math.h"
#include "llrender.h" #include "llrender.h"

View File

@@ -36,6 +36,7 @@
#include "llvertexbuffer.h" #include "llvertexbuffer.h"
#include "llcubemap.h" #include "llcubemap.h"
#include "llglslshader.h"
#include "llimagegl.h" #include "llimagegl.h"
#include "llrendertarget.h" #include "llrendertarget.h"
#include "lltexture.h" #include "lltexture.h"
@@ -49,7 +50,9 @@ F64 gGLLastProjection[16];
F64 gGLProjection[16]; F64 gGLProjection[16];
S32 gGLViewport[4]; 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 const U32 LL_NUM_LIGHT_UNITS = 8;
static GLenum sGLTextureType[] = static GLenum sGLTextureType[] =
@@ -57,6 +60,7 @@ static GLenum sGLTextureType[] =
GL_TEXTURE_2D, GL_TEXTURE_2D,
GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_RECTANGLE_ARB,
GL_TEXTURE_CUBE_MAP_ARB GL_TEXTURE_CUBE_MAP_ARB
//,GL_TEXTURE_2D_MULTISAMPLE Don't use.
}; };
static GLint sGLAddressMode[] = 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 // 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 // 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) 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. disable(); // Force a disable of a previous texture type if it's enabled.
} }
mCurrTexType = type; mCurrTexType = type;
gGL.flush(); gGL.flush();
if (mIndex < gGLManager.mNumTextureUnits) if (!LLGLSLShader::sNoFixedFunction &&
//type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
mIndex < gGLManager.mNumTextureUnits)
{ {
glEnable(sGLTextureType[type]); glEnable(sGLTextureType[type]);
} }
@@ -200,7 +208,9 @@ void LLTexUnit::disable(void)
activate(); activate();
unbind(mCurrTexType); unbind(mCurrTexType);
gGL.flush(); gGL.flush();
if (mIndex < gGLManager.mNumTextureUnits) if (!LLGLSLShader::sNoFixedFunction &&
//mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
mIndex < gGLManager.mNumTextureUnits)
{ {
glDisable(sGLTextureType[mCurrTexType]); glDisable(sGLTextureType[mCurrTexType]);
} }
@@ -404,7 +414,15 @@ void LLTexUnit::unbind(eTextureType type)
activate(); activate();
mCurrTexture = 0; 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) 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(); gGL.flush();
@@ -474,6 +492,11 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
void LLTexUnit::setTextureBlendType(eTextureBlendType type) void LLTexUnit::setTextureBlendType(eTextureBlendType type)
{ {
if (LLGLSLShader::sNoFixedFunction)
{ //texture blend type means nothing when using shaders
return;
}
if (mIndex < 0) return; if (mIndex < 0) return;
// Do nothing if it's already correctly set. // 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) 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; if (mIndex < 0) return;
activate(); activate();
@@ -1064,6 +1092,10 @@ void LLRender::setSceneBlendType(eBlendType type)
void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
{ {
flush(); flush();
if (LLGLSLShader::sNoFixedFunction)
{ //glAlphaFunc is deprecated in OpenGL 3.3
return;
}
if (mCurrAlphaFunc != func || if (mCurrAlphaFunc != func ||
mCurrAlphaFuncVal != value) mCurrAlphaFuncVal != value)
@@ -1079,6 +1111,30 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
glAlphaFunc(sGLCompareFunc[func], 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) void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)

View File

@@ -58,11 +58,13 @@ class LLTexUnit
{ {
friend class LLRender; friend class LLRender;
public: public:
static U32 sWhiteTexture;
typedef enum typedef enum
{ {
TT_TEXTURE = 0, // Standard 2D Texture TT_TEXTURE = 0, // Standard 2D Texture
TT_RECT_TEXTURE, // Non power of 2 texture TT_RECT_TEXTURE, // Non power of 2 texture
TT_CUBE_MAP, // 6-sided cube map 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 TT_NONE // No texture type is currently enabled
} eTextureType; } eTextureType;

View File

@@ -44,13 +44,14 @@ void check_framebuffer_status()
{ {
if (gDebugGL) if (gDebugGL)
{ {
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
switch (status) switch (status)
{ {
case GL_FRAMEBUFFER_COMPLETE_EXT: case GL_FRAMEBUFFER_COMPLETE:
break; break;
default: default:
llerrs <<"check_framebuffer_status failed" << llendl; llwarns << "check_framebuffer_status failed -- " << std::hex << status << llendl;
ll_fail("check_framebuffer_status failed");
break; break;
} }
} }
@@ -84,9 +85,12 @@ void LLRenderTarget::setSampleBuffer(LLMultisampleBuffer* buffer)
mSampleBuffer = 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(); stop_glerror();
release();
stop_glerror();
mResX = resx; mResX = resx;
mResY = resy; mResY = resy;
@@ -94,48 +98,49 @@ void LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
mUsage = usage; mUsage = usage;
mUseDepth = depth; mUseDepth = depth;
release();
if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject) if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
{ {
if (depth) if (depth)
{ {
stop_glerror(); if (!allocateDepth())
allocateDepth(); {
stop_glerror(); llwarns << "Failed to allocate depth buffer for render target." << llendl;
return false;
}
} }
glGenFramebuffersEXT(1, (GLuint *) &mFBO); glGenFramebuffers(1, (GLuint *) &mFBO);
if (mDepth) if (mDepth)
{ {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (mStencil) 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(); 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(); stop_glerror();
} }
else 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(); stop_glerror();
} }
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
stop_glerror(); 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) if (color_fmt == 0)
{ {
return; return true;
} }
U32 offset = mTex.size(); U32 offset = mTex.size();
@@ -151,52 +156,78 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt)
stop_glerror(); 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(); stop_glerror();
if (offset == 0)
{ {
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); if (offset == 0)
} { //use bilinear filtering on single texture render targets that aren't multisampled
else gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
{ //don't filter data attachments stop_glerror();
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); }
} else
if (mUsage != LLTexUnit::TT_RECT_TEXTURE) { //don't filter data attachments
{ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR); stop_glerror();
} }
else
{ if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
// ATI doesn't support mirrored repeat for rectangular textures. {
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); 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) if (mFBO)
{ {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); stop_glerror();
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset, glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset,
LLTexUnit::getInternalType(mUsage), tex, 0); LLTexUnit::getInternalType(mUsage), tex, 0);
stop_glerror(); stop_glerror();
check_framebuffer_status(); check_framebuffer_status();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
mTex.push_back(tex); mTex.push_back(tex);
if (gDebugGL)
{ //bind and unbind to validate target
bindTarget();
flush();
}
return true;
} }
void LLRenderTarget::allocateDepth() bool LLRenderTarget::allocateDepth()
{ {
if (mStencil) if (mStencil)
{ {
//use render buffers where stencil buffers are in play //use render buffers where stencil buffers are in play
glGenRenderbuffersEXT(1, (GLuint *) &mDepth); glGenRenderbuffers(1, (GLuint *) &mDepth);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth); glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mResX, mResY); stop_glerror();
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); clear_glerror();
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
} }
else else
{ {
@@ -204,8 +235,18 @@ void LLRenderTarget::allocateDepth()
gGL.getTexUnit(0)->bindManual(mUsage, mDepth); gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage); U32 internal_type = LLTexUnit::getInternalType(mUsage);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); 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) void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
@@ -228,25 +269,28 @@ void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
if (mDepth) if (mDepth)
{ {
stop_glerror(); stop_glerror();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, target.mFBO); glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
stop_glerror(); stop_glerror();
if (mStencil) 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(); 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(); stop_glerror();
target.mStencil = true; target.mStencil = true;
} }
else 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(); 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) if (mStencil)
{ {
glDeleteRenderbuffersEXT(1, (GLuint*) &mDepth); glDeleteRenderbuffers(1, (GLuint*) &mDepth);
stop_glerror(); stop_glerror();
} }
else else
@@ -268,23 +312,23 @@ void LLRenderTarget::release()
} }
else if (mUseDepth && mFBO) else if (mUseDepth && mFBO)
{ //detach shared depth buffer { //detach shared depth buffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (mStencil) if (mStencil)
{ //attached as a renderbuffer { //attached as a renderbuffer
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
mStencil = false; mStencil = false;
} }
else else
{ //attached as a texture { //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; mUseDepth = false;
} }
if (mFBO) if (mFBO)
{ {
glDeleteFramebuffersEXT(1, (GLuint *) &mFBO); glDeleteFramebuffers(1, (GLuint *) &mFBO);
mFBO = 0; mFBO = 0;
} }
@@ -294,6 +338,8 @@ void LLRenderTarget::release()
mTex.clear(); mTex.clear();
} }
mResX = mResY = 0;
mSampleBuffer = NULL; mSampleBuffer = NULL;
sBoundTarget = NULL; sBoundTarget = NULL;
} }
@@ -310,14 +356,14 @@ void LLRenderTarget::bindTarget()
} }
else else
{ {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
stop_glerror(); stop_glerror();
if (gGLManager.mHasDrawBuffers) if (gGLManager.mHasDrawBuffers)
{ //setup multiple render targets { //setup multiple render targets
GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT, GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3_EXT}; GL_COLOR_ATTACHMENT3};
glDrawBuffersARB(mTex.size(), drawbuffers); glDrawBuffersARB(mTex.size(), drawbuffers);
} }
@@ -342,7 +388,7 @@ void LLRenderTarget::unbindTarget()
{ {
if (gGLManager.mHasFramebufferObject) if (gGLManager.mHasFramebufferObject)
{ {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
sBoundTarget = NULL; sBoundTarget = NULL;
} }
@@ -404,7 +450,7 @@ void LLRenderTarget::flush(bool fetch_depth)
} }
gGL.getTexUnit(0)->bind(this); 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(); gGL.getTexUnit(0)->disable();
@@ -412,56 +458,55 @@ void LLRenderTarget::flush(bool fetch_depth)
else else
{ {
stop_glerror(); stop_glerror();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
stop_glerror(); stop_glerror();
if (mSampleBuffer) if (mSampleBuffer)
{ {
LLGLEnable multisample(GL_MULTISAMPLE_ARB); LLGLEnable multisample(GL_MULTISAMPLE);
stop_glerror(); stop_glerror();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
stop_glerror(); stop_glerror();
check_framebuffer_status(); check_framebuffer_status();
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mSampleBuffer->mFBO); glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleBuffer->mFBO);
check_framebuffer_status(); check_framebuffer_status();
stop_glerror(); stop_glerror();
if(gGLManager.mIsATI) if(gGLManager.mIsATI)
{ {
glBlitFramebufferEXT(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_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_STENCIL_BUFFER_BIT, GL_NEAREST);
} }
else 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(); stop_glerror();
if (mTex.size() > 1) if (mTex.size() > 1)
{ {
for (U32 i = 1; i < mTex.size(); ++i) 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); LLTexUnit::getInternalType(mUsage), mTex[i], 0);
stop_glerror(); 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(); 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(); stop_glerror();
} }
for (U32 i = 0; i < mTex.size(); ++i) 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); LLTexUnit::getInternalType(mUsage), mTex[i], 0);
stop_glerror(); 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(); 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(); stop_glerror();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, source.mFBO); glBindFramebuffer(GL_FRAMEBUFFER, source.mFBO);
check_framebuffer_status();
gGL.getTexUnit(0)->bind(this, true); gGL.getTexUnit(0)->bind(this, true);
stop_glerror(); stop_glerror();
glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1); glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1);
stop_glerror(); stop_glerror();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror(); stop_glerror();
} }
else else
{ {
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO); glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mFBO);
stop_glerror(); stop_glerror();
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO);
stop_glerror(); stop_glerror();
check_framebuffer_status(); check_framebuffer_status();
stop_glerror(); stop_glerror();
if(gGLManager.mIsATI && mask & GL_STENCIL_BUFFER_BIT) if(gGLManager.mIsATI && mask & GL_STENCIL_BUFFER_BIT)
{ {
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) 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(); 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(); stop_glerror();
} }
} }
@@ -531,21 +581,21 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
LLGLDepthTest depth(write_depth, write_depth); 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(); stop_glerror();
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
stop_glerror(); stop_glerror();
check_framebuffer_status(); check_framebuffer_status();
stop_glerror(); stop_glerror();
if(gGLManager.mIsATI && mask & GL_STENCIL_BUFFER_BIT) if(gGLManager.mIsATI && mask & GL_STENCIL_BUFFER_BIT)
{ {
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) 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(); stop_glerror();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror(); stop_glerror();
} }
} }
@@ -580,19 +630,19 @@ void LLMultisampleBuffer::release()
{ {
if (mFBO) if (mFBO)
{ {
glDeleteFramebuffersEXT(1, (GLuint *) &mFBO); glDeleteFramebuffers(1, (GLuint *) &mFBO);
mFBO = 0; mFBO = 0;
} }
if (mTex.size() > 0) if (mTex.size() > 0)
{ {
glDeleteRenderbuffersEXT(mTex.size(), (GLuint *) &mTex[0]); glDeleteRenderbuffers(mTex.size(), (GLuint *) &mTex[0]);
mTex.clear(); mTex.clear();
} }
if (mDepth) if (mDepth)
{ {
glDeleteRenderbuffersEXT(1, (GLuint *) &mDepth); glDeleteRenderbuffers(1, (GLuint *) &mDepth);
mDepth = 0; mDepth = 0;
} }
} }
@@ -609,13 +659,13 @@ void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref)
ref = this; ref = this;
} }
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
if (gGLManager.mHasDrawBuffers) if (gGLManager.mHasDrawBuffers)
{ //setup multiple render targets { //setup multiple render targets
GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT, GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3_EXT}; GL_COLOR_ATTACHMENT3};
glDrawBuffersARB(ref->mTex.size(), drawbuffers); glDrawBuffersARB(ref->mTex.size(), drawbuffers);
} }
@@ -626,14 +676,16 @@ void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref)
sBoundTarget = this; 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(); stop_glerror();
mResX = resx; mResX = resx;
mResY = resy; mResY = resy;
@@ -641,18 +693,18 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth
mUseDepth = depth; mUseDepth = depth;
mStencil = stencil; mStencil = stencil;
release();
if (!gGLManager.mHasFramebufferMultisample) if (!gGLManager.mHasFramebufferMultisample)
{ {
llerrs << "Attempting to allocate unsupported render target type!" << llendl; llerrs << "Attempting to allocate unsupported render target type!" << llendl;
return false;
} }
mSamples = samples; mSamples = gGLManager.getNumFBOFSAASamples(samples);
if (mSamples <= 1) if (mSamples <= 1)
{ {
llerrs << "Cannot create a multisample buffer with less than 2 samples." << llendl; llerrs << "Cannot create a multisample buffer with less than 2 samples." << llendl;
return false;
} }
stop_glerror(); stop_glerror();
@@ -663,36 +715,37 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth
if (depth) if (depth)
{ {
stop_glerror(); stop_glerror();
allocateDepth(); if(!allocateDepth())
return false;
stop_glerror(); stop_glerror();
} }
glGenFramebuffers(1, (GLuint *) &mFBO);
glGenFramebuffersEXT(1, (GLuint *) &mFBO); glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
stop_glerror();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); clear_glerror();
if (mDepth) 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) 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(); stop_glerror();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror(); 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) if (color_fmt == 0)
{ {
return; return true;
} }
U32 offset = mTex.size(); U32 offset = mTex.size();
@@ -703,44 +756,47 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
} }
U32 tex; U32 tex;
glGenRenderbuffersEXT(1, &tex); glGenRenderbuffers(1, &tex);
glBindRenderbuffer(GL_RENDERBUFFER, tex);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, tex);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, color_fmt, mResX, mResY);
stop_glerror(); 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) if (mFBO)
{ {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset, GL_RENDERBUFFER_EXT, tex); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset, GL_RENDERBUFFER, tex);
stop_glerror(); check_framebuffer_status();
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); glBindFramebuffer(GL_FRAMEBUFFER, 0);
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
break;
default:
llerrs << "WTF? " << std::hex << status << llendl;
break;
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
} }
mTex.push_back(tex); mTex.push_back(tex);
return true;
} }
void LLMultisampleBuffer::allocateDepth() bool LLMultisampleBuffer::allocateDepth()
{ {
glGenRenderbuffersEXT(1, (GLuint* ) &mDepth); glGenRenderbuffers(1, (GLuint* ) &mDepth);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth); glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
stop_glerror();
clear_glerror();
if (mStencil) if (mStencil)
{ {
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH24_STENCIL8_EXT, mResX, mResY); glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY);
} }
else 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;
} }

View File

@@ -77,17 +77,17 @@ public:
//allocate resources for rendering //allocate resources for rendering
//must be called before use //must be called before use
//multiple calls will release previously allocated resources //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. //provide this render target with a multisample resource.
void setSampleBuffer(LLMultisampleBuffer* buffer); void setSampleBuffer(LLMultisampleBuffer* buffer);
//add color buffer attachment //add color buffer attachment
//limit of 4 color attachments per render target //limit of 4 color attachments per render target
virtual void addColorAttachment(U32 color_fmt); virtual bool addColorAttachment(U32 color_fmt);
//allocate a depth texture //allocate a depth texture
virtual void allocateDepth(); virtual bool allocateDepth();
//share depth buffer with provided render target //share depth buffer with provided render target
virtual void shareDepthBuffer(LLRenderTarget& target); virtual void shareDepthBuffer(LLRenderTarget& target);
@@ -174,10 +174,10 @@ public:
virtual void bindTarget(); virtual void bindTarget();
void bindTarget(LLRenderTarget* ref); void bindTarget(LLRenderTarget* ref);
virtual void allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo); virtual bool 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); bool 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 bool addColorAttachment(U32 color_fmt);
virtual void allocateDepth(); virtual bool allocateDepth();
}; };
#endif //!LL_MESA_HEADLESS #endif //!LL_MESA_HEADLESS

View File

@@ -217,17 +217,79 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
if (features->hasWaterFog) 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 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 (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) 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) 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 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 (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 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; GLenum error = GL_NO_ERROR;
error = glGetError(); if (gDebugGL)
if (error != GL_NO_ERROR)
{ {
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; 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 //we can't have any lines longer than 1024 characters
//or any shaders longer than 1024 lines... deal - DaveP //or any shaders longer than 1024 lines... deal - DaveP
GLcharARB buff[1024]; GLcharARB buff[1024] = {0};
GLcharARB* text[1024]; GLcharARB* text[1024] = {0};
GLuint count = 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 //copy file into memory
while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) ) while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) )
{ {
@@ -389,51 +665,67 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
//create shader object //create shader object
GLhandleARB ret = glCreateShaderObjectARB(type); GLhandleARB ret = glCreateShaderObjectARB(type);
error = glGetError(); if (gDebugGL)
if (error != GL_NO_ERROR)
{ {
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(); error = glGetError();
if (error != GL_NO_ERROR) if (error != GL_NO_ERROR)
{ {
LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL; LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
glDeleteObjectARB(ret); //no longer need handle glDeleteObjectARB(ret); //no longer need handle
} }
else }
//compile source
glCompileShaderARB(ret);
if (gDebugGL)
{
error = glGetError();
if (error != GL_NO_ERROR)
{ {
//compile source LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
glCompileShaderARB(ret); glDeleteObjectARB(ret); //no longer need handle
error = glGetError();
if (error != GL_NO_ERROR)
{
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) if (error == GL_NO_ERROR)
{ {
//check for errors //check for errors
GLint success = GL_TRUE; GLint success = GL_TRUE;
glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success); glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success);
error = glGetError(); if (gDebugGL || success == GL_FALSE)
if (error != GL_NO_ERROR || success == GL_FALSE)
{ {
//an error occured, print log error = glGetError();
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL; if (error != GL_NO_ERROR || success == GL_FALSE)
dumpObjectLog(ret); {
glDeleteObjectARB(ret); //no longer need handle //an error occured, print log
ret = 0; 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 else
@@ -442,6 +734,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
} }
stop_glerror(); stop_glerror();
//free memory
for (GLuint i = 0; i < count; i++)
{
free(text[i]);
}
//successfully loaded, save results //successfully loaded, save results
if (ret) if (ret)
{ {
@@ -454,7 +752,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
if (shader_level > 1) if (shader_level > 1)
{ {
shader_level--; 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; LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL;
} }

View File

@@ -49,7 +49,7 @@ public:
void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE); void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE); BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
BOOL validateProgramObject(GLhandleARB obj); 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. // Implemented in the application to actually point to the shader directory.
virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual
@@ -66,6 +66,9 @@ public:
std::vector<std::string> mReservedUniforms; std::vector<std::string> mReservedUniforms;
//preprocessor definitions (name/value)
std::map<std::string, std::string> mDefinitions;
protected: protected:
// our parameter manager singleton instance // our parameter manager singleton instance

View File

@@ -39,7 +39,7 @@
#ifndef LL_TEXTURE_H #ifndef LL_TEXTURE_H
#define LL_TEXTURE_H #define LL_TEXTURE_H
#include "llmemory.h" #include "llrefcount.h"
class LLImageGL ; class LLImageGL ;
class LLTexUnit ; class LLTexUnit ;
class LLFontGL ; class LLFontGL ;

View File

@@ -42,6 +42,7 @@
#include "llrender.h" #include "llrender.h"
#include "llvector4a.h" #include "llvector4a.h"
#include "llcontrol.h" #include "llcontrol.h"
#include "llglslshader.h"
//============================================================================ //============================================================================
@@ -88,6 +89,59 @@ void LLVBOPool::releaseName(GLuint name)
LLVertexBuffer::sGLCount--; 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] = 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, glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
idx); idx);
stop_glerror(); stop_glerror();
placeFence();
} }
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const 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, glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
((U16*) getIndicesPointer()) + indices_offset); ((U16*) getIndicesPointer()) + indices_offset);
stop_glerror(); stop_glerror();
placeFence();
} }
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const 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(); stop_glerror();
glDrawArrays(sGLMode[mode], first, count); glDrawArrays(sGLMode[mode], first, count);
stop_glerror(); stop_glerror();
placeFence();
} }
//static //static
@@ -470,7 +527,8 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage, bool strided) :
mResized(FALSE), mResized(FALSE),
mDynamicSize(FALSE), mDynamicSize(FALSE),
mIsStrided(strided), mIsStrided(strided),
mStride(0) mStride(0),
mFence(NULL)
{ {
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
if (!sEnableVBOs) if (!sEnableVBOs)
@@ -570,9 +628,40 @@ LLVertexBuffer::~LLVertexBuffer()
destroyGLIndices(); destroyGLIndices();
sCount--; sCount--;
if (mFence)
{
delete mFence;
}
mFence = NULL;
llassert_always(!mMappedData && !mMappedIndexData) ; 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() void LLVertexBuffer::genBuffer()
@@ -1152,7 +1241,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index)
void LLVertexBuffer::unmapBuffer(S32 type) void LLVertexBuffer::unmapBuffer(S32 type)
{ {
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
if (!useVBOs()) if (!useVBOs() || type == -2)
{ {
return ; //nothing to unmap return ; //nothing to unmap
} }
@@ -1605,7 +1694,14 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
} }
if (data_mask & MAP_VERTEX) 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(); llglassertok();

View File

@@ -64,6 +64,12 @@ protected:
virtual void releaseName(GLuint name); virtual void releaseName(GLuint name);
}; };
class LLGLFence
{
public:
virtual void placeFence() = 0;
virtual void wait() = 0;
};
//============================================================================ //============================================================================
// base class // base class
@@ -127,6 +133,9 @@ public:
TYPE_CLOTHWEIGHT, TYPE_CLOTHWEIGHT,
TYPE_MAX, TYPE_MAX,
TYPE_INDEX, TYPE_INDEX,
//no actual additional data, but indicates position.w is texture index
TYPE_TEXTURE_INDEX,
}; };
enum { enum {
MAP_VERTEX = (1<<TYPE_VERTEX), MAP_VERTEX = (1<<TYPE_VERTEX),
@@ -141,6 +150,7 @@ public:
MAP_WEIGHT = (1<<TYPE_WEIGHT), MAP_WEIGHT = (1<<TYPE_WEIGHT),
MAP_WEIGHT4 = (1<<TYPE_WEIGHT4), MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT), MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
MAP_TEXTURE_INDEX = (1<<TYPE_TEXTURE_INDEX),
}; };
protected: protected:
@@ -251,6 +261,12 @@ protected:
BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded) BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded)
S32 mOffsets[TYPE_MAX]; S32 mOffsets[TYPE_MAX];
mutable LLGLFence* mFence;
void placeFence() const;
void waitFence() const;
public: public:
static S32 sCount; static S32 sCount;
static S32 sGLCount; static S32 sGLCount;

View File

@@ -44,6 +44,7 @@ set(llui_SOURCE_FILES
llmultislider.cpp llmultislider.cpp
llmultisliderctrl.cpp llmultisliderctrl.cpp
llnotifications.cpp llnotifications.cpp
llnotificationsutil.cpp
llpanel.cpp llpanel.cpp
llprogressbar.cpp llprogressbar.cpp
llradiogroup.cpp llradiogroup.cpp
@@ -100,7 +101,9 @@ set(llui_HEADER_FILES
llmodaldialog.h llmodaldialog.h
llmultisliderctrl.h llmultisliderctrl.h
llmultislider.h llmultislider.h
llnotificationptr.h
llnotifications.h llnotifications.h
llnotificationsutil.h
llpanel.h llpanel.h
llprogressbar.h llprogressbar.h
llradiogroup.h llradiogroup.h

View File

@@ -40,7 +40,7 @@
#include <boost/function.hpp> #include <boost/function.hpp>
#include "llsd.h" #include "llsd.h"
#include "llmemory.h" #include "llsingleton.h"
/** /**
* @class LLFunctorRegistry * @class LLFunctorRegistry

View File

@@ -77,11 +77,6 @@ S32 MENU_BAR_WIDTH = 0;
/// Local function declarations, constants, enums, and typedefs /// 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 S32 LABEL_BOTTOM_PAD_PIXELS = 2;
const U32 LEFT_PAD_PIXELS = 3; 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 TEAROFF_SEPARATOR_HEIGHT_PIXELS = 10;
const S32 MENU_ITEM_PADDING = 4; 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 BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE
const std::string ARROW_UP ("^^^^^^^"); const std::string ARROW_UP ("^^^^^^^");
const std::string ARROW_DOWN("vvvvvvv"); const std::string ARROW_DOWN("vvvvvvv");

View File

@@ -88,8 +88,9 @@ LLMultiSlider::LLMultiSlider(
mThumbCenterSelectedColor( LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterSelectedColor" ) ), mThumbCenterSelectedColor( LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterSelectedColor" ) ),
mDisabledThumbColor(LLUI::sColorsGroup->getColor( "MultiSliderDisabledThumbColor" ) ), mDisabledThumbColor(LLUI::sColorsGroup->getColor( "MultiSliderDisabledThumbColor" ) ),
mTriangleColor(LLUI::sColorsGroup->getColor( "MultiSliderTriangleColor" ) ), mTriangleColor(LLUI::sColorsGroup->getColor( "MultiSliderTriangleColor" ) ),
mMouseDownCallback( NULL ), mMouseDownSignal( NULL ),
mMouseUpCallback( NULL ) mMouseUpSignal( NULL ),
mThumbWidth(MULTI_THUMB_WIDTH)
{ {
mValue.emptyMap(); mValue.emptyMap();
mCurSlider = LLStringUtil::null; mCurSlider = LLStringUtil::null;
@@ -101,6 +102,13 @@ LLMultiSlider::LLMultiSlider(
setValue(getValue()); setValue(getValue());
} }
LLMultiSlider::~LLMultiSlider()
{
delete mMouseDownSignal;
delete mMouseUpSignal;
}
void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from_event) void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from_event)
{ {
// exit if not there // 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); F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue);
S32 left_edge = MULTI_THUMB_WIDTH/2; S32 left_edge = mThumbWidth/2;
S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2); S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
S32 x = left_edge + S32( t * (right_edge - left_edge) ); S32 x = left_edge + S32( t * (right_edge - left_edge) );
mThumbRects[name].mLeft = x - (MULTI_THUMB_WIDTH/2); mThumbRects[name].mLeft = x - (mThumbWidth/2);
mThumbRects[name].mRight = x + (MULTI_THUMB_WIDTH/2); mThumbRects[name].mRight = x + (mThumbWidth/2);
} }
void LLMultiSlider::setValue(const LLSD& value) void LLMultiSlider::setValue(const LLSD& value)
@@ -211,7 +219,7 @@ const std::string& LLMultiSlider::addSlider(F32 val)
} }
// add a new thumb rect // 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 // add the value and set the current slider to this one
mValue.insert(newName.str(), initVal); mValue.insert(newName.str(), initVal);
@@ -223,6 +231,30 @@ const std::string& LLMultiSlider::addSlider(F32 val)
return mCurSlider; 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 LLMultiSlider::findUnusedValue(F32& initVal)
{ {
bool firstTry = true; bool firstTry = true;
@@ -302,8 +334,8 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask)
{ {
if( gFocusMgr.getMouseCapture() == this ) if( gFocusMgr.getMouseCapture() == this )
{ {
S32 left_edge = MULTI_THUMB_WIDTH/2; S32 left_edge = mThumbWidth/2;
S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2); S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
x += mMouseOffset; x += mMouseOffset;
x = llclamp( x, left_edge, right_edge ); x = llclamp( x, left_edge, right_edge );
@@ -331,10 +363,9 @@ BOOL LLMultiSlider::handleMouseUp(S32 x, S32 y, MASK mask)
{ {
gFocusMgr.setMouseCapture( NULL ); gFocusMgr.setMouseCapture( NULL );
if( mMouseUpCallback ) if (mMouseUpSignal)
{ (*mMouseUpSignal)( this, LLSD() );
mMouseUpCallback( this, mCallbackUserData );
}
handled = TRUE; handled = TRUE;
make_ui_sound("UISndClickRelease"); make_ui_sound("UISndClickRelease");
} }
@@ -353,10 +384,8 @@ BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask)
{ {
setFocus(TRUE); setFocus(TRUE);
} }
if( mMouseDownCallback ) if (mMouseDownSignal)
{ (*mMouseDownSignal)( this, LLSD() );
mMouseDownCallback( this, mCallbackUserData );
}
if (MASK_CONTROL & mask) // if CTRL is modifying 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. // Find the offset of the actual mouse location from the center of the thumb.
if (mThumbRects[mCurSlider].pointInRect(x,y)) if (mThumbRects[mCurSlider].pointInRect(x,y))
{ {
mMouseOffset = (mThumbRects[mCurSlider].mLeft + MULTI_THUMB_WIDTH/2) - x; mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth/2) - x;
} }
else else
{ {
@@ -566,6 +595,18 @@ void LLMultiSlider::draw()
LLUICtrl::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 // virtual
LLXMLNodePtr LLMultiSlider::getXML(bool save_children) const LLXMLNodePtr LLMultiSlider::getXML(bool save_children) const
{ {

View File

@@ -59,6 +59,7 @@ public:
virtual LLXMLNodePtr getXML(bool save_children = true) const; virtual LLXMLNodePtr getXML(bool save_children = true) const;
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
virtual ~LLMultiSlider();
void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE); void setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE);
F32 getSliderValue(const std::string& name) const; F32 getSliderValue(const std::string& name) const;
@@ -80,15 +81,17 @@ public:
void setMinValue(F32 min_value) { mMinValue = min_value; } void setMinValue(F32 min_value) { mMinValue = min_value; }
void setMaxValue(F32 max_value) { mMaxValue = max_value; } void setMaxValue(F32 max_value) { mMaxValue = max_value; }
void setIncrement(F32 increment) { mIncrement = increment; } 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); bool findUnusedValue(F32& initVal);
const std::string& addSlider(); const std::string& addSlider();
const std::string& addSlider(F32 val); const std::string& addSlider(F32 val);
void deleteSlider(const std::string& name); void addSlider(F32 val, const std::string& name);
void deleteCurSlider() { deleteSlider(mCurSlider); } void deleteSlider(const std::string& name);
void clear(); void deleteCurSlider() { deleteSlider(mCurSlider); }
void clear();
virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask);
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
@@ -112,6 +115,7 @@ protected:
S32 mMouseOffset; S32 mMouseOffset;
LLRect mDragStartThumbRect; LLRect mDragStartThumbRect;
S32 mThumbWidth;
std::map<std::string, LLRect> mThumbRects; std::map<std::string, LLRect> mThumbRects;
LLColor4 mTrackColor; LLColor4 mTrackColor;
@@ -121,8 +125,8 @@ protected:
LLColor4 mDisabledThumbColor; LLColor4 mDisabledThumbColor;
LLColor4 mTriangleColor; LLColor4 mTriangleColor;
void (*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata); commit_signal_t* mMouseDownSignal;
void (*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata); commit_signal_t* mMouseUpSignal;
}; };
#endif // LL_LLSLIDER_H #endif // LL_LLSLIDER_H

View File

@@ -78,9 +78,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const std::string& name, const LLRect& rect
mEditor( NULL ), mEditor( NULL ),
mTextBox( NULL ), mTextBox( NULL ),
mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) )
mSliderMouseUpCallback( NULL ),
mSliderMouseDownCallback( NULL )
{ {
S32 top = getRect().getHeight(); S32 top = getRect().getHeight();
S32 bottom = 0; S32 bottom = 0;
@@ -421,37 +419,14 @@ void LLMultiSliderCtrl::setPrecision(S32 precision)
updateText(); 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; return mMultiSlider->setMouseDownCallback( cb );
mMultiSlider->setMouseDownCallback( LLMultiSliderCtrl::onSliderMouseDown );
} }
// static boost::signals2::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
void LLMultiSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
{ {
LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata; return mMultiSlider->setMouseUpCallback( cb );
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 );
}
} }
void LLMultiSliderCtrl::onTabInto() void LLMultiSliderCtrl::onTabInto()

View File

@@ -112,8 +112,8 @@ public:
void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; } void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; }
void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; } void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; }
void setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) ); boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
void setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) ); boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
virtual void onTabInto(); virtual void onTabInto();
@@ -124,10 +124,8 @@ public:
virtual std::string getControlName() const; virtual std::string getControlName() const;
static void onSliderCommit(LLUICtrl* caller, void* userdata); 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* ctrl, void* userdata);
static void onEditorCommit(LLUICtrl* caller, void* userdata);
static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
@@ -151,9 +149,6 @@ private:
LLColor4 mTextEnabledColor; LLColor4 mTextEnabledColor;
LLColor4 mTextDisabledColor; LLColor4 mTextDisabledColor;
void (*mSliderMouseUpCallback)( LLUICtrl* ctrl, void* userdata );
void (*mSliderMouseDownCallback)( LLUICtrl* ctrl, void* userdata );
}; };
#endif // LL_MULTI_SLIDERCTRL_H #endif // LL_MULTI_SLIDERCTRL_H

View 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

View File

@@ -91,8 +91,9 @@
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/type_traits.hpp>
#include <boost/enable_shared_from_this.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 // we want to minimize external dependencies, but this one is important
#include "llsd.h" #include "llsd.h"
@@ -101,9 +102,9 @@
// and we need this to manage the notification callbacks // and we need this to manage the notification callbacks
#include "llfunctorregistry.h" #include "llfunctorregistry.h"
#include "llui.h" #include "llui.h"
#include "llxmlnode.h"
#include "llnotificationptr.h"
class LLNotification;
typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
/***************************************************************************** /*****************************************************************************
* Signal and handler declarations * Signal and handler declarations

View 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);
}

View 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

View File

@@ -54,6 +54,7 @@
#include "lluictrlfactory.h" #include "lluictrlfactory.h"
#include "llviewborder.h" #include "llviewborder.h"
#include "llbutton.h" #include "llbutton.h"
#include "llnotificationsutil.h"
// LLLayoutStack // LLLayoutStack
#include "llresizebar.h" #include "llresizebar.h"
@@ -1049,7 +1050,7 @@ void LLPanel::childDisplayNotFound()
mNewExpectedMembers.clear(); mNewExpectedMembers.clear();
LLSD args; LLSD args;
args["CONTROLS"] = msg; args["CONTROLS"] = msg;
LLNotifications::instance().add("FloaterNotFound", args); LLNotificationsUtil::add("FloaterNotFound", args);
} }
void LLPanel::storeRectControl() void LLPanel::storeRectControl()

View File

@@ -70,8 +70,8 @@ LLSlider::LLSlider(
mTrackColor( LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ), mTrackColor( LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ),
mThumbOutlineColor( LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ), mThumbOutlineColor( LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ),
mThumbCenterColor( LLUI::sColorsGroup->getColor( "SliderThumbCenterColor" ) ), mThumbCenterColor( LLUI::sColorsGroup->getColor( "SliderThumbCenterColor" ) ),
mMouseDownCallback( NULL ), mMouseDownSignal( NULL ),
mMouseUpCallback( NULL ) mMouseUpSignal( NULL )
{ {
mThumbImage = LLUI::getUIImage("icn_slide-thumb_dark.tga"); mThumbImage = LLUI::getUIImage("icn_slide-thumb_dark.tga");
mTrackImage = LLUI::getUIImage("icn_slide-groove_dark.tga"); mTrackImage = LLUI::getUIImage("icn_slide-groove_dark.tga");
@@ -87,6 +87,11 @@ LLSlider::LLSlider(
mDragStartThumbRect = mThumbRect; mDragStartThumbRect = mThumbRect;
} }
LLSlider::~LLSlider()
{
delete mMouseDownSignal;
delete mMouseUpSignal;
}
void LLSlider::setValue(F32 value, BOOL from_event) void LLSlider::setValue(F32 value, BOOL from_event)
{ {
@@ -109,10 +114,11 @@ void LLSlider::setValue(F32 value, BOOL from_event)
void LLSlider::updateThumbRect() void LLSlider::updateThumbRect()
{ {
const S32 DEFAULT_THUMB_SIZE = 16;
F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue); F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
S32 thumb_width = mThumbImage->getWidth(); S32 thumb_width = mThumbImage ? mThumbImage->getWidth() : DEFAULT_THUMB_SIZE;
S32 thumb_height = mThumbImage->getHeight(); S32 thumb_height = mThumbImage ? mThumbImage->getHeight() : DEFAULT_THUMB_SIZE;
S32 left_edge = (thumb_width / 2); S32 left_edge = (thumb_width / 2);
S32 right_edge = getRect().getWidth() - (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 ); gFocusMgr.setMouseCapture( NULL );
if( mMouseUpCallback ) if (mMouseUpSignal)
{ (*mMouseUpSignal)( this, getValueF32() );
mMouseUpCallback( this, mCallbackUserData );
}
handled = TRUE; handled = TRUE;
make_ui_sound("UISndClickRelease"); make_ui_sound("UISndClickRelease");
} }
@@ -191,10 +196,8 @@ BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
{ {
setFocus(TRUE); setFocus(TRUE);
} }
if( mMouseDownCallback ) if (mMouseDownSignal)
{ (*mMouseDownSignal)( this, getValueF32() );
mMouseDownCallback( this, mCallbackUserData );
}
if (MASK_CONTROL & mask) // if CTRL is modifying if (MASK_CONTROL & mask) // if CTRL is modifying
{ {
@@ -309,6 +312,17 @@ LLXMLNodePtr LLSlider::getXML(bool save_children) const
return node; 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 //static
LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory) LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory)

View File

@@ -55,6 +55,7 @@ public:
virtual LLXMLNodePtr getXML(bool save_children = true) const; virtual LLXMLNodePtr getXML(bool save_children = true) const;
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory); static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
virtual ~LLSlider();
void setValue( F32 value, BOOL from_event = FALSE ); void setValue( F32 value, BOOL from_event = FALSE );
F32 getValueF32() const { return mValue; } F32 getValueF32() const { return mValue; }
@@ -71,8 +72,10 @@ public:
void setMinValue(F32 min_value) {mMinValue = min_value; updateThumbRect(); } void setMinValue(F32 min_value) {mMinValue = min_value; updateThumbRect(); }
void setMaxValue(F32 max_value) {mMaxValue = max_value; updateThumbRect(); } void setMaxValue(F32 max_value) {mMaxValue = max_value; updateThumbRect(); }
void setIncrement(F32 increment) {mIncrement = increment;} 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 handleHover(S32 x, S32 y, MASK mask);
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
@@ -103,8 +106,8 @@ private:
LLColor4 mThumbOutlineColor; LLColor4 mThumbOutlineColor;
LLColor4 mThumbCenterColor; LLColor4 mThumbCenterColor;
void (*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata); commit_signal_t* mMouseDownSignal;
void (*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata); commit_signal_t* mMouseUpSignal;
}; };
#endif // LL_LLSLIDER_H #endif // LL_LLSLIDER_H

View File

@@ -76,9 +76,7 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect,
mEditor( NULL ), mEditor( NULL ),
mTextBox( NULL ), mTextBox( NULL ),
mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) )
mSliderMouseUpCallback( NULL ),
mSliderMouseDownCallback( NULL )
{ {
S32 top = getRect().getHeight(); S32 top = getRect().getHeight();
S32 bottom = 0; S32 bottom = 0;
@@ -352,37 +350,14 @@ void LLSliderCtrl::setPrecision(S32 precision)
updateText(); 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; return mSlider->setMouseDownCallback( cb );
mSlider->setMouseDownCallback( LLSliderCtrl::onSliderMouseDown );
} }
// static boost::signals2::connection LLSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
void LLSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
{ {
LLSliderCtrl* self = (LLSliderCtrl*) userdata; return mSlider->setMouseUpCallback( cb );
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 );
}
} }
void LLSliderCtrl::onTabInto() void LLSliderCtrl::onTabInto()

View File

@@ -75,14 +75,18 @@ public:
virtual LLSD getValue() const { return LLSD(getValueF32()); } virtual LLSD getValue() const { return LLSD(getValueF32()); }
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); 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(); } BOOL isMouseHeldDown() const { return mSlider->hasMouseCapture(); }
virtual void setPrecision(S32 precision);
virtual void setEnabled( BOOL b ); virtual void setEnabled( BOOL b );
virtual void clear(); 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 setMinValue(F32 min_value) { mSlider->setMinValue(min_value); updateText(); }
void setMaxValue(F32 max_value) { mSlider->setMaxValue(max_value); updateText(); } void setMaxValue(F32 max_value) { mSlider->setMaxValue(max_value); updateText(); }
void setIncrement(F32 increment) { mSlider->setIncrement(increment);} void setIncrement(F32 increment) { mSlider->setIncrement(increment);}
@@ -94,8 +98,8 @@ public:
void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; } void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; }
void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; } void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; }
void setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) ); boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
void setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) ); boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
virtual void onTabInto(); virtual void onTabInto();
@@ -111,8 +115,6 @@ public:
virtual std::string getControlName() const { return mSlider->getControlName(); } virtual std::string getControlName() const { return mSlider->getControlName(); }
static void onSliderCommit(LLUICtrl* caller, void* userdata); 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* caller, void* userdata);
static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
@@ -138,9 +140,6 @@ private:
LLColor4 mTextEnabledColor; LLColor4 mTextEnabledColor;
LLColor4 mTextDisabledColor; LLColor4 mTextDisabledColor;
void (*mSliderMouseUpCallback)( LLUICtrl* ctrl, void* userdata );
void (*mSliderMouseDownCallback)( LLUICtrl* ctrl, void* userdata );
}; };
#endif // LL_LLSLIDERCTRL_H #endif // LL_LLSLIDERCTRL_H

View File

@@ -487,8 +487,15 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
if (solid_color) if (solid_color)
{ {
gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); if (LLGLSLShader::sNoFixedFunction)
gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA); {
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(); 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) if (solid_color)
{ {
gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); if (LLGLSLShader::sNoFixedFunction)
{
gUIProgram.bind();
}
else
{
gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
}
} }
} }

View File

@@ -39,6 +39,7 @@
#include "llcontrol.h" #include "llcontrol.h"
#include "llrect.h" #include "llrect.h"
#include "llcoord.h" #include "llcoord.h"
#include "llglslshader.h"
//#include "llhtmlhelp.h" //#include "llhtmlhelp.h"
#include "llgl.h" // *TODO: break this dependency #include "llgl.h" // *TODO: break this dependency
#include <stack> #include <stack>

Some files were not shown because too many files have changed in this diff Show More