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_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)
if (NOT STANDALONE)
use_prebuilt_binary(GL)
use_prebuilt_binary(glext)
# possible glh_linear should have its own .cmake file instead
#use_prebuilt_binary(glh_linear)
# actually... not any longer, it's now in git -SG
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
endif (NOT STANDALONE)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -191,6 +191,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
return status;
}
apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
{
return open(filename, flags, use_global_pool ? LLAPRFile::global : LLAPRFile::local);
}
// File I/O
S32 LLAPRFile::read(void *buf, S32 nbytes)
{

View File

@@ -150,10 +150,11 @@ public:
};
LLAPRFile() ;
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type);
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type = LLAPRFile::global);
~LLAPRFile() ;
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type = LLAPRFile::global, S32* sizep = NULL);
apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use global pool.
apr_status_t close() ;
// Returns actual offset, -1 if seek fails

View File

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

View File

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

View File

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

View File

@@ -36,6 +36,7 @@
#include "llfoldertype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsingleton.h"
///----------------------------------------------------------------------------
/// Class LLFolderType
@@ -95,7 +96,12 @@ LLFolderDictionary::LLFolderDictionary()
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE));
addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
};

View File

@@ -87,9 +87,14 @@ public:
FT_OUTFIT = 47,
FT_MY_OUTFITS = 48,
FT_INBOX = 49,
FT_MESH = 49,
FT_COUNT = 50,
FT_INBOX = 50,
FT_OUTBOX = 51,
FT_BASIC_ROOT = 52,
FT_COUNT,
FT_NONE = -1
};

View File

@@ -49,6 +49,7 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
protected:
static void * & getInstances(std::type_info const & info);
};
/// This mix-in class adds support for tracking all instances of the specified class parameter T
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
/// If KEY is not provided, then instances are stored in a simple set
@@ -58,13 +59,80 @@ class LLInstanceTracker : public LLInstanceTrackerBase
{
typedef typename std::map<KEY, T*> InstanceMap;
typedef LLInstanceTracker<T, KEY> MyT;
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
public:
/// Dereferencing key_iter gives you a const KEY&
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
/// Dereferencing instance_iter gives you a T&
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
{
public:
typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
instance_iter(const typename InstanceMap::iterator& it)
: mIterator(it)
{
++sIterationNestDepth;
}
~instance_iter()
{
--sIterationNestDepth;
}
private:
friend class boost::iterator_core_access;
void increment() { mIterator++; }
bool equal(instance_iter const& other) const
{
return mIterator == other.mIterator;
}
T& dereference() const
{
return *(mIterator->second);
}
typename InstanceMap::iterator mIterator;
};
class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
{
public:
typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
key_iter(typename InstanceMap::iterator it)
: mIterator(it)
{
++sIterationNestDepth;
}
key_iter(const key_iter& other)
: mIterator(other.mIterator)
{
++sIterationNestDepth;
}
~key_iter()
{
--sIterationNestDepth;
}
private:
friend class boost::iterator_core_access;
void increment() { mIterator++; }
bool equal(key_iter const& other) const
{
return mIterator == other.mIterator;
}
KEY& dereference() const
{
return const_cast<KEY&>(mIterator->first);
}
typename InstanceMap::iterator mIterator;
};
static T* getInstance(const KEY& k)
{
@@ -72,42 +140,47 @@ public:
return (found == getMap_().end()) ? NULL : found->second;
}
static instance_iter beginInstances()
{
return instance_iter(getMap_().begin());
}
static instance_iter endInstances()
{
return instance_iter(getMap_().end());
}
static S32 instanceCount() { return getMap_().size(); }
static key_iter beginKeys()
{
return boost::make_transform_iterator(getMap_().begin(),
boost::bind(&InstanceMap::value_type::first, _1));
return key_iter(getMap_().begin());
}
static key_iter endKeys()
{
return boost::make_transform_iterator(getMap_().end(),
boost::bind(&InstanceMap::value_type::first, _1));
return key_iter(getMap_().end());
}
static instance_iter beginInstances()
{
return instance_iter(boost::make_transform_iterator(getMap_().begin(),
boost::bind(&InstanceMap::value_type::second, _1)));
}
static instance_iter endInstances()
{
return instance_iter(boost::make_transform_iterator(getMap_().end(),
boost::bind(&InstanceMap::value_type::second, _1)));
}
static S32 instanceCount() { return getMap_().size(); }
protected:
LLInstanceTracker(KEY key) { add_(key); }
virtual ~LLInstanceTracker() { remove_(); }
virtual ~LLInstanceTracker()
{
// it's unsafe to delete instances of this type while all instances are being iterated over.
llassert(sIterationNestDepth == 0);
remove_();
}
virtual void setKey(KEY key) { remove_(); add_(key); }
virtual const KEY& getKey() const { return mKey; }
virtual const KEY& getKey() const { return mInstanceKey; }
private:
void add_(KEY key)
{
mKey = key;
mInstanceKey = key;
getMap_()[key] = static_cast<T*>(this);
}
void remove_()
{
getMap_().erase(mKey);
getMap_().erase(mInstanceKey);
}
static InstanceMap& getMap_()
@@ -122,9 +195,12 @@ private:
private:
KEY mKey;
KEY mInstanceKey;
static S32 sIterationNestDepth;
};
template <typename T, typename KEY> S32 LLInstanceTracker<T, KEY>::sIterationNestDepth = 0;
/// explicit specialization for default case where KEY is T*
/// use a simple std::set<T*>
template<typename T>
@@ -133,42 +209,55 @@ class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
typedef typename std::set<T*> InstanceSet;
typedef LLInstanceTracker<T, T*> MyT;
public:
/// Dereferencing key_iter gives you a T* (since T* is the key)
typedef typename InstanceSet::iterator key_iter;
/// Dereferencing instance_iter gives you a T&
typedef boost::indirect_iterator<key_iter> instance_iter;
/// for completeness of analogy with the generic implementation
static T* getInstance(T* k) { return k; }
static S32 instanceCount() { return getSet_().size(); }
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
// that it treats deletes of this type as errors as long as there is an instance of
// this class alive in scope somewhere (i.e. deleting while iterating is bad).
class LLInstanceTrackerScopedGuard
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
{
public:
LLInstanceTrackerScopedGuard()
instance_iter(const typename InstanceSet::iterator& it)
: mIterator(it)
{
++sIterationNestDepth;
}
~LLInstanceTrackerScopedGuard()
instance_iter(const instance_iter& other)
: mIterator(other.mIterator)
{
++sIterationNestDepth;
}
~instance_iter()
{
--sIterationNestDepth;
}
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
static key_iter beginKeys() { return getSet_().begin(); }
static key_iter endKeys() { return getSet_().end(); }
private:
friend class boost::iterator_core_access;
void increment() { mIterator++; }
bool equal(instance_iter const& other) const
{
return mIterator == other.mIterator;
}
T& dereference() const
{
return **mIterator;
}
typename InstanceSet::iterator mIterator;
};
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
protected:
LLInstanceTracker()
{
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
//llassert(sIterationNestDepth == 0);
getSet_().insert(static_cast<T*>(this));
}
virtual ~LLInstanceTracker()
@@ -180,7 +269,6 @@ protected:
LLInstanceTracker(const LLInstanceTracker& other)
{
//llassert(sIterationNestDepth == 0);
getSet_().insert(static_cast<T*>(this));
}

View File

@@ -118,6 +118,62 @@ public:
THROTTLE_BLOCKED, // rate exceed, block key
};
F64 getActionCount(const T& id)
{
U64 now = 0;
if ( mIsRealtime )
{
now = LLKeyThrottleImpl<T>::getTime();
}
else
{
now = LLKeyThrottleImpl<T>::getFrame();
}
if (now >= (m.startTime + m.intervalLength))
{
if (now < (m.startTime + 2 * m.intervalLength))
{
// prune old data
delete m.prevMap;
m.prevMap = m.currMap;
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.startTime += m.intervalLength;
}
else
{
// lots of time has passed, all data is stale
delete m.prevMap;
delete m.currMap;
m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.startTime = now;
}
}
U32 prevCount = 0;
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
if (prev != m.prevMap->end())
{
prevCount = prev->second.count;
}
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
// curr.count is the number of keys in
// this current 'time slice' from the beginning of it until now
// prevCount is the number of keys in the previous
// time slice scaled to be one full time slice back from the current
// (now) time.
// compute current, windowed rate
F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
return averageCount;
}
// call each time the key wants use
State noteAction(const T& id, S32 weight = 1)
{

View File

@@ -48,6 +48,7 @@ const U32 AGENT_TYPING = 0x0200;
const U32 AGENT_CROUCHING = 0x0400;
const U32 AGENT_BUSY = 0x0800;
const U32 AGENT_ALWAYS_RUN = 0x1000;
const U32 AGENT_AUTOPILOT = 0x2000;
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
const S32 LSL_REMOTE_DATA_REQUEST = 2;
@@ -184,6 +185,10 @@ const S32 OBJECT_VELOCITY = 5;
const S32 OBJECT_OWNER = 6;
const S32 OBJECT_GROUP = 7;
const S32 OBJECT_CREATOR = 8;
const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
const S32 OBJECT_SCRIPT_MEMORY = 11;
const S32 OBJECT_SCRIPT_TIME = 12;
// changed() event flags
const U32 CHANGED_NONE = 0x0;
@@ -198,5 +203,17 @@ const U32 CHANGED_OWNER = 0x80;
const U32 CHANGED_REGION = 0x100;
const U32 CHANGED_TELEPORT = 0x200;
const U32 CHANGED_REGION_START = 0x400;
const U32 CHANGED_MEDIA = 0x800;
// Possible error results
const U32 LSL_STATUS_OK = 0;
const U32 LSL_STATUS_MALFORMED_PARAMS = 1000;
const U32 LSL_STATUS_TYPE_MISMATCH = 1001;
const U32 LSL_STATUS_BOUNDS_ERROR = 1002;
const U32 LSL_STATUS_NOT_FOUND = 1003;
const U32 LSL_STATUS_NOT_SUPPORTED = 1004;
const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
// Start per-function errors below, starting at 2000:
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
#endif

View File

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

View File

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

View File

@@ -107,7 +107,17 @@
#endif
// Deal with the differences on Windows
// Static linking with apr on windows needs to be declared.
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
#ifndef APR_DECLARE_STATIC
#define APR_DECLARE_STATIC // For APR on Windows
#endif
#ifndef APU_DECLARE_STATIC
#define APU_DECLARE_STATIC // For APR util on Windows
#endif
#endif
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
#define CURL_STATICLIB 1
@@ -159,12 +169,19 @@
#define LL_DLLIMPORT
#endif // LL_WINDOWS
#ifdef llcommon_EXPORTS
// Compiling llcommon (shared)
#define LL_COMMON_API LL_DLLEXPORT
#else // llcommon_EXPORTS
// Using llcommon (shared)
#define LL_COMMON_API LL_DLLIMPORT
#endif // llcommon_EXPORTS
#if LL_COMMON_LINK_SHARED
// CMake automagically defines llcommon_EXPORTS only when building llcommon
// sources, and only when llcommon is a shared library (i.e. when
// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
// otherwise we can't distinguish between (non-llcommon source) and (llcommon
// not shared).
# if defined(llcommon_EXPORTS)
# define LL_COMMON_API LL_DLLEXPORT
# else //llcommon_EXPORTS
# define LL_COMMON_API LL_DLLIMPORT
# endif //llcommon_EXPORTS
#else // LL_COMMON_LINK_SHARED
# define LL_COMMON_API
#endif // LL_COMMON_LINK_SHARED
#endif // not LL_LINDEN_PREPROCESSOR_H

View File

@@ -102,7 +102,7 @@ int LLProcessLauncher::launch(void)
STARTUPINFOA sinfo;
memset(&sinfo, 0, sizeof(sinfo));
std::string args = "\"" + mExecutable + "\"";
std::string args = mExecutable;
for(int i = 0; i < (int)mLaunchArguments.size(); i++)
{
args += " ";
@@ -114,10 +114,30 @@ int LLProcessLauncher::launch(void)
char *args2 = new char[args.size() + 1];
strcpy(args2, args.c_str());
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
const char * working_directory = 0;
if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str();
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) )
{
// TODO: do better than returning the OS-specific error code on failure...
result = GetLastError();
LPTSTR error_str = 0;
if(
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
result,
0,
(LPTSTR)&error_str,
0,
NULL)
!= 0)
{
char message[256];
wcstombs(message, error_str, 256);
message[255] = 0;
llwarns << "CreateProcessA failed: " << message << llendl;
LocalFree(error_str);
}
if(result == 0)
{
// Make absolutely certain we return a non-zero value on failure.

View File

@@ -31,8 +31,9 @@
#include "linden_common.h"
#include "llqueuedthread.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)
{
makeMap(impl).insert(k, v);
#ifdef LL_MSVC7
return *dynamic_cast<LLSD*>(this);
#else
return *this;
#endif
return *this;
}
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
@@ -784,11 +780,7 @@ void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
LLSD& LLSD::with(Integer i, const LLSD& v)
{
makeArray(impl).insert(i, v);
#ifdef LL_MSVC7
return *dynamic_cast<LLSD*>(this);
#else
return *this;
#endif
return *this;
}
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }

View File

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

View File

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

View File

@@ -37,6 +37,7 @@
#include <deque>
#include "apr_base64.h"
#include <boost/regex.hpp>
extern "C"
{
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_INTEGER:
{
S32 i;
// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
{ // See if sscanf works - it's faster
value = i;
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_REAL:
{
F64 r;
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
{ // See if sscanf works - it's faster
value = r;
}
else
{
value = LLSD(mCurrentContent).asReal();
}
value = LLSD(mCurrentContent).asReal();
// removed since this breaks when locale has decimal separator that isn't '.'
// investigated changing local to something compatible each time but deemed higher
// risk that just using LLSD.asReal() each time.
//F64 r;
//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
//{ // See if sscanf works - it's faster
// value = r;
//}
//else
//{
// value = LLSD(mCurrentContent).asReal();
//}
}
break;
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_BINARY:
{
S32 len = apr_base64_decode_len(mCurrentContent.c_str());
// Regex is expensive, but only fix for whitespace in base64,
// created by python and other non-linden systems - DEV-39358
// Fortunately we have very little binary passing now,
// so performance impact shold be negligible. + poppy 2009-09-04
boost::regex r;
r.assign("\\s");
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
S32 len = apr_base64_decode_len(stripped.c_str());
std::vector<U8> data;
data.resize(len);
len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
len = apr_base64_decode_binary(&data[0], stripped.c_str());
data.resize(len);
value = data;
break;

View File

@@ -46,6 +46,12 @@
#endif
#include "llsdserialize.h"
#include "stringize.h"
#include "is_approx_equal_fraction.h"
#include <map>
#include <set>
#include <boost/range.hpp>
// U32
LLSD ll_sd_from_U32(const U32 val)
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
return buffer;
}
char* ll_pretty_print_sd_ptr(const LLSD* sd)
{
if (sd)
{
return ll_pretty_print_sd(*sd);
}
return NULL;
}
char* ll_pretty_print_sd(const LLSD& sd)
{
const U32 bufferSize = 10 * 1024;
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
return TRUE;
}
/*****************************************************************************
* Helpers for llsd_matches()
*****************************************************************************/
// raw data used for LLSD::Type lookup
struct Data
{
LLSD::Type type;
const char* name;
} typedata[] =
{
#define def(type) { LLSD::type, #type + 4 }
def(TypeUndefined),
def(TypeBoolean),
def(TypeInteger),
def(TypeReal),
def(TypeString),
def(TypeUUID),
def(TypeDate),
def(TypeURI),
def(TypeBinary),
def(TypeMap),
def(TypeArray)
#undef def
};
// LLSD::Type lookup class into which we load the above static data
class TypeLookup
{
typedef std::map<LLSD::Type, std::string> MapType;
public:
TypeLookup()
{
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
{
mMap[di->type] = di->name;
}
}
std::string lookup(LLSD::Type type) const
{
MapType::const_iterator found = mMap.find(type);
if (found != mMap.end())
{
return found->second;
}
return STRINGIZE("<unknown LLSD type " << type << ">");
}
private:
MapType mMap;
};
// static instance of the lookup class
static const TypeLookup sTypes;
// describe a mismatch; phrasing may want tweaking
const std::string op(" required instead of ");
// llsd_matches() wants to identify specifically where in a complex prototype
// structure the mismatch occurred. This entails passing a prefix string,
// empty for the top-level call. If the prototype contains an array of maps,
// and the mismatch occurs in the second map in a key 'foo', we want to
// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
// want to omit the entire prefix -- including colon -- if the mismatch is at
// top level. This helper accepts the (possibly empty) recursively-accumulated
// prefix string, returning either empty or the original string with colon
// appended.
static std::string colon(const std::string& pfx)
{
if (pfx.empty())
return pfx;
return pfx + ": ";
}
// param type for match_types
typedef std::vector<LLSD::Type> TypeVector;
// The scalar cases in llsd_matches() use this helper. In most cases, we can
// accept not only the exact type specified in the prototype, but also other
// types convertible to the expected type. That implies looping over an array
// of such types. If the actual type doesn't match any of them, we want to
// provide a list of acceptable conversions as well as the exact type, e.g.:
// "Integer (or Boolean, Real, String) required instead of UUID". Both the
// implementation and the calling logic are simplified by separating out the
// expected type from the convertible types.
static std::string match_types(LLSD::Type expect, // prototype.type()
const TypeVector& accept, // types convertible to that type
LLSD::Type actual, // type we're checking
const std::string& pfx) // as for llsd_matches
{
// Trivial case: if the actual type is exactly what we expect, we're good.
if (actual == expect)
return "";
// For the rest of the logic, build up a suitable error string as we go so
// we only have to make a single pass over the list of acceptable types.
// If we detect success along the way, we'll simply discard the partial
// error string.
std::ostringstream out;
out << colon(pfx) << sTypes.lookup(expect);
// If there are any convertible types, append that list.
if (! accept.empty())
{
out << " (";
const char* sep = "or ";
for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
ai != aend; ++ai, sep = ", ")
{
// Don't forget to return success if we match any of those types...
if (actual == *ai)
return "";
out << sep << sTypes.lookup(*ai);
}
out << ')';
}
// If we got this far, it's because 'actual' was not one of the acceptable
// types, so we must return an error. 'out' already contains colon(pfx)
// and the formatted list of acceptable types, so just append the mismatch
// phrase and the actual type.
out << op << sTypes.lookup(actual);
return out.str();
}
// see docstring in .h file
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
{
// An undefined prototype means that any data is valid.
// An undefined slot in an array or map prototype means that any data
// may fill that slot.
if (prototype.isUndefined())
return "";
// A prototype array must match a data array with at least as many
// entries. Moreover, every prototype entry must match the
// corresponding data entry.
if (prototype.isArray())
{
if (! data.isArray())
{
return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
}
if (data.size() < prototype.size())
{
return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
<< "Array size " << data.size());
}
for (LLSD::Integer i = 0; i < prototype.size(); ++i)
{
std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
if (! match.empty())
{
return match;
}
}
return "";
}
// A prototype map must match a data map. Every key in the prototype
// must have a corresponding key in the data map; every value in the
// prototype must match the corresponding key's value in the data.
if (prototype.isMap())
{
if (! data.isMap())
{
return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
}
// If there are a number of keys missing from the data, it would be
// frustrating to a coder to discover them one at a time, with a big
// build each time. Enumerate all missing keys.
std::ostringstream out;
out << colon(pfx);
const char* init = "Map missing keys: ";
const char* sep = init;
for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
{
if (! data.has(mi->first))
{
out << sep << mi->first;
sep = ", ";
}
}
// So... are we missing any keys?
if (sep != init)
{
return out.str();
}
// Good, the data block contains all the keys required by the
// prototype. Now match the prototype entries.
for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
{
std::string match(llsd_matches(mi2->second, data[mi2->first],
STRINGIZE("['" << mi2->first << "']")));
if (! match.empty())
{
return match;
}
}
return "";
}
// A String prototype can match String, Boolean, Integer, Real, UUID,
// Date and URI, because any of these can be converted to String.
if (prototype.isString())
{
static LLSD::Type accept[] =
{
LLSD::TypeBoolean,
LLSD::TypeInteger,
LLSD::TypeReal,
LLSD::TypeUUID,
LLSD::TypeDate,
LLSD::TypeURI
};
return match_types(prototype.type(),
TypeVector(boost::begin(accept), boost::end(accept)),
data.type(),
pfx);
}
// Boolean, Integer, Real match each other or String. TBD: ensure that
// a String value is numeric.
if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
{
static LLSD::Type all[] =
{
LLSD::TypeBoolean,
LLSD::TypeInteger,
LLSD::TypeReal,
LLSD::TypeString
};
// Funny business: shuffle the set of acceptable types to include all
// but the prototype's type. Get the acceptable types in a set.
std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
// Remove the prototype's type because we pass that separately.
rest.erase(prototype.type());
return match_types(prototype.type(),
TypeVector(rest.begin(), rest.end()),
data.type(),
pfx);
}
// UUID, Date and URI match themselves or String.
if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
{
static LLSD::Type accept[] =
{
LLSD::TypeString
};
return match_types(prototype.type(),
TypeVector(boost::begin(accept), boost::end(accept)),
data.type(),
pfx);
}
// We don't yet know the conversion semantics associated with any new LLSD
// data type that might be added, so until we've been extended to handle
// them, assume it's strict: the new type matches only itself. (This is
// true of Binary, which is why we don't handle that case separately.) Too
// bad LLSD doesn't define isConvertible(Type to, Type from).
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
}
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
{
// We're comparing strict equality of LLSD representation rather than
// performing any conversions. So if the types aren't equal, the LLSD
// values aren't equal.
if (lhs.type() != rhs.type())
{
return false;
}
// Here we know both types are equal. Now compare values.
switch (lhs.type())
{
case LLSD::TypeUndefined:
// Both are TypeUndefined. There's nothing more to know.
return true;
case LLSD::TypeReal:
// This is where the 'bits' argument comes in handy. If passed
// explicitly, it means to use is_approx_equal_fraction() to compare.
if (bits >= 0)
{
return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
}
// Otherwise we compare bit representations, and the usual caveats
// about comparing floating-point numbers apply. Omitting 'bits' when
// comparing Real values is only useful when we expect identical bit
// representation for a given Real value, e.g. for integer-valued
// Reals.
return (lhs.asReal() == rhs.asReal());
#define COMPARE_SCALAR(type) \
case LLSD::Type##type: \
/* LLSD::URI has operator!=() but not operator==() */ \
/* rely on the optimizer for all others */ \
return (! (lhs.as##type() != rhs.as##type()))
COMPARE_SCALAR(Boolean);
COMPARE_SCALAR(Integer);
COMPARE_SCALAR(String);
COMPARE_SCALAR(UUID);
COMPARE_SCALAR(Date);
COMPARE_SCALAR(URI);
COMPARE_SCALAR(Binary);
#undef COMPARE_SCALAR
case LLSD::TypeArray:
{
LLSD::array_const_iterator
lai(lhs.beginArray()), laend(lhs.endArray()),
rai(rhs.beginArray()), raend(rhs.endArray());
// Compare array elements, walking the two arrays in parallel.
for ( ; lai != laend && rai != raend; ++lai, ++rai)
{
// If any one array element is unequal, the arrays are unequal.
if (! llsd_equals(*lai, *rai, bits))
return false;
}
// Here we've reached the end of one or the other array. They're equal
// only if they're BOTH at end: that is, if they have equal length too.
return (lai == laend && rai == raend);
}
case LLSD::TypeMap:
{
// Build a set of all rhs keys.
std::set<LLSD::String> rhskeys;
for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
rmi != rmend; ++rmi)
{
rhskeys.insert(rmi->first);
}
// Now walk all the lhs keys.
for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
lmi != lmend; ++lmi)
{
// Try to erase this lhs key from the set of rhs keys. If rhs has
// no such key, the maps are unequal. erase(key) returns count of
// items erased.
if (rhskeys.erase(lmi->first) != 1)
return false;
// Both maps have the current key. Compare values.
if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
return false;
}
// We've now established that all the lhs keys have equal values in
// both maps. The maps are equal unless rhs contains a superset of
// those keys.
return rhskeys.empty();
}
default:
// We expect that every possible type() value is specifically handled
// above. Failing to extend this switch to support a new LLSD type is
// an error that must be brought to the coder's attention.
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
"unknown type " << lhs.type() << LL_ENDL;
return false; // pacify the compiler
}
}

View File

@@ -35,7 +35,7 @@
#ifndef LL_LLSDUTIL_H
#define LL_LLSDUTIL_H
#include "llsd.h"
class LLSD;
// U32
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
@@ -59,6 +59,7 @@ LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
//compares the structure of an LLSD to a template LLSD and stores the
@@ -73,6 +74,66 @@ LL_COMMON_API BOOL compare_llsd_with_template(
const LLSD& template_llsd,
LLSD& resultant_llsd);
/**
* Recursively determine whether a given LLSD data block "matches" another
* LLSD prototype. The returned string is empty() on success, non-empty() on
* mismatch.
*
* This function tests structure (types) rather than data values. It is
* intended for when a consumer expects an LLSD block with a particular
* structure, and must succinctly detect whether the arriving block is
* well-formed. For instance, a test of the form:
* @code
* if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
* @endcode
* could instead be expressed by initializing a prototype LLSD map with the
* required keys and writing:
* @code
* if (! llsd_matches(prototype, data).empty())
* @endcode
*
* A non-empty return value is an error-message fragment intended to indicate
* to (English-speaking) developers where in the prototype structure the
* mismatch occurred.
*
* * If a slot in the prototype isUndefined(), then anything is valid at that
* place in the real object. (Passing prototype == LLSD() matches anything
* at all.)
* * An array in the prototype must match a data array at least that large.
* (Additional entries in the data array are ignored.) Every isDefined()
* entry in the prototype array must match the corresponding entry in the
* data array.
* * A map in the prototype must match a map in the data. Every key in the
* prototype map must match a corresponding key in the data map. (Additional
* keys in the data map are ignored.) Every isDefined() value in the
* prototype map must match the corresponding key's value in the data map.
* * Scalar values in the prototype are tested for @em type rather than value.
* For instance, a String in the prototype matches any String at all. In
* effect, storing an Integer at a particular place in the prototype asserts
* that the caller intends to apply asInteger() to the corresponding slot in
* the data.
* * A String in the prototype matches String, Boolean, Integer, Real, UUID,
* Date and URI, because asString() applied to any of these produces a
* meaningful result.
* * Similarly, a Boolean, Integer or Real in the prototype can match any of
* Boolean, Integer or Real in the data -- or even String.
* * UUID matches UUID or String.
* * Date matches Date or String.
* * URI matches URI or String.
* * Binary in the prototype matches only Binary in the data.
*
* @TODO: when a Boolean, Integer or Real in the prototype matches a String in
* the data, we should examine the String @em value to ensure it can be
* meaningfully converted to the requested type. The same goes for UUID, Date
* and URI.
*/
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
/// Deep equality. If you want to compare LLSD::Real values for approximate
/// equality rather than bitwise equality, pass @a bits as for
/// is_approx_equal_fraction().
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1);
// Simple function to copy data out of input & output iterators if
// there is no need for casting.
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
@@ -85,4 +146,283 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
return dest;
}
/*****************************************************************************
* LLSDArray
*****************************************************************************/
/**
* Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage:
*
* @code
* void somefunc(const LLSD&);
* ...
* somefunc(LLSDArray("text")(17)(3.14));
* @endcode
*
* For completeness, LLSDArray() with no args constructs an empty array, so
* <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the
* above. But for most purposes, LLSD() is already equivalent to an empty
* array, and if you explicitly want an empty isArray(), there's
* LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor
* follows the principle of least astonishment.
*/
class LLSDArray
{
public:
LLSDArray():
_data(LLSD::emptyArray())
{}
/**
* Need an explicit copy constructor. Consider the following:
*
* @code
* LLSD array_of_arrays(LLSDArray(LLSDArray(17)(34))
* (LLSDArray("x")("y")));
* @endcode
*
* The coder intends to construct [[17, 34], ["x", "y"]].
*
* With the compiler's implicit copy constructor, s/he gets instead
* [17, 34, ["x", "y"]].
*
* The expression LLSDArray(17)(34) constructs an LLSDArray with those two
* values. The reader assumes it should be converted to LLSD, as we always
* want with LLSDArray, before passing it to the @em outer LLSDArray
* constructor! This copy constructor makes that happen.
*/
LLSDArray(const LLSDArray& inner):
_data(LLSD::emptyArray())
{
_data.append(inner);
}
LLSDArray(const LLSD& value):
_data(LLSD::emptyArray())
{
_data.append(value);
}
LLSDArray& operator()(const LLSD& value)
{
_data.append(value);
return *this;
}
operator LLSD() const { return _data; }
LLSD get() const { return _data; }
private:
LLSD _data;
};
/*****************************************************************************
* LLSDMap
*****************************************************************************/
/**
* Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage:
*
* @code
* void somefunc(const LLSD&);
* ...
* somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14));
* @endcode
*
* For completeness, LLSDMap() with no args constructs an empty map, so
* <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map
* equivalent to the above. But for most purposes, LLSD() is already
* equivalent to an empty map, and if you explicitly want an empty isMap(),
* there's LLSD::emptyMap(). However, supporting a no-args LLSDMap()
* constructor follows the principle of least astonishment.
*/
class LLSDMap
{
public:
LLSDMap():
_data(LLSD::emptyMap())
{}
LLSDMap(const LLSD::String& key, const LLSD& value):
_data(LLSD::emptyMap())
{
_data[key] = value;
}
LLSDMap& operator()(const LLSD::String& key, const LLSD& value)
{
_data[key] = value;
return *this;
}
operator LLSD() const { return _data; }
LLSD get() const { return _data; }
private:
LLSD _data;
};
/*****************************************************************************
* LLSDParam
*****************************************************************************/
/**
* LLSDParam is a customization point for passing LLSD values to function
* parameters of more or less arbitrary type. LLSD provides a small set of
* native conversions; but if a generic algorithm explicitly constructs an
* LLSDParam object in the function's argument list, a consumer can provide
* LLSDParam specializations to support more different parameter types than
* LLSD's native conversions.
*
* Usage:
*
* @code
* void somefunc(const paramtype&);
* ...
* somefunc(..., LLSDParam<paramtype>(someLLSD), ...);
* @endcode
*/
template <typename T>
class LLSDParam
{
public:
/**
* Default implementation converts to T on construction, saves converted
* value for later retrieval
*/
LLSDParam(const LLSD& value):
_value(value)
{}
operator T() const { return _value; }
private:
T _value;
};
/**
* Turns out that several target types could accept an LLSD param using any of
* a few different conversions, e.g. LLUUID's constructor can accept LLUUID or
* std::string. Therefore, the compiler can't decide which LLSD conversion
* operator to choose, even though to us it seems obvious. But that's okay, we
* can specialize LLSDParam for such target types, explicitly specifying the
* desired conversion -- that's part of what LLSDParam is all about. Turns out
* we have to do that enough to make it worthwhile generalizing. Use a macro
* because I need to specify one of the asReal, etc., explicit conversion
* methods as well as a type. If I'm overlooking a clever way to implement
* that using a template instead, feel free to reimplement.
*/
#define LLSDParam_for(T, AS) \
template <> \
class LLSDParam<T> \
{ \
public: \
LLSDParam(const LLSD& value): \
_value(value.AS()) \
{} \
\
operator T() const { return _value; } \
\
private: \
T _value; \
}
LLSDParam_for(float, asReal);
LLSDParam_for(LLUUID, asUUID);
LLSDParam_for(LLDate, asDate);
LLSDParam_for(LLURI, asURI);
LLSDParam_for(LLSD::Binary, asBinary);
/**
* LLSDParam<const char*> is an example of the kind of conversion you can
* support with LLSDParam beyond native LLSD conversions. Normally you can't
* pass an LLSD object to a function accepting const char* -- but you can
* safely pass an LLSDParam<const char*>(yourLLSD).
*/
template <>
class LLSDParam<const char*>
{
private:
// The difference here is that we store a std::string rather than a const
// char*. It's important that the LLSDParam object own the std::string.
std::string _value;
// We don't bother storing the incoming LLSD object, but we do have to
// distinguish whether _value is an empty string because the LLSD object
// contains an empty string or because it's isUndefined().
bool _undefined;
public:
LLSDParam(const LLSD& value):
_value(value),
_undefined(value.isUndefined())
{}
// The const char* we retrieve is for storage owned by our _value member.
// That's how we guarantee that the const char* is valid for the lifetime
// of this LLSDParam object. Constructing your LLSDParam in the argument
// list should ensure that the LLSDParam object will persist for the
// duration of the function call.
operator const char*() const
{
if (_undefined)
{
// By default, an isUndefined() LLSD object's asString() method
// will produce an empty string. But for a function accepting
// const char*, it's often important to be able to pass NULL, and
// isUndefined() seems like the best way. If you want to pass an
// empty string, you can still pass LLSD(""). Without this special
// case, though, no LLSD value could pass NULL.
return NULL;
}
return _value.c_str();
}
};
namespace llsd
{
/*****************************************************************************
* BOOST_FOREACH() helpers for LLSD
*****************************************************************************/
/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... }
class inArray
{
public:
inArray(const LLSD& array):
_array(array)
{}
typedef LLSD::array_const_iterator const_iterator;
typedef LLSD::array_iterator iterator;
iterator begin() { return _array.beginArray(); }
iterator end() { return _array.endArray(); }
const_iterator begin() const { return _array.beginArray(); }
const_iterator end() const { return _array.endArray(); }
private:
LLSD _array;
};
/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator.
typedef std::map<LLSD::String, LLSD>::value_type MapEntry;
/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... }
class inMap
{
public:
inMap(const LLSD& map):
_map(map)
{}
typedef LLSD::map_const_iterator const_iterator;
typedef LLSD::map_iterator iterator;
iterator begin() { return _map.beginMap(); }
iterator end() { return _map.endMap(); }
const_iterator begin() const { return _map.beginMap(); }
const_iterator end() const { return _map.endMap(); }
private:
LLSD _map;
};
} // namespace llsd
#endif // LL_LLSDUTIL_H

View File

@@ -100,12 +100,6 @@ private:
DELETED
} EInitState;
static void deleteSingleton()
{
delete getData().mSingletonInstance;
getData().mSingletonInstance = NULL;
}
// stores pointer to singleton instance
// and tracks initialization state of singleton
struct SingletonInstanceData
@@ -120,7 +114,11 @@ private:
~SingletonInstanceData()
{
deleteSingleton();
SingletonInstanceData& data = getData();
if (data.mInitState != DELETED)
{
deleteSingleton();
}
}
};
@@ -132,6 +130,14 @@ public:
data.mInitState = DELETED;
}
// Can be used to control when the singleton is deleted. Not normally needed.
static void deleteSingleton()
{
delete getData().mSingletonInstance;
getData().mSingletonInstance = NULL;
getData().mInitState = DELETED;
}
static SingletonInstanceData& getData()
{
// this is static to cache the lookup results

View File

@@ -43,9 +43,10 @@
// statics
BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
LLStat::stat_map_t LLStat::sStatList;
//------------------------------------------------------------------------
// Live config file to trigger stats logging
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
F32 duration = 0.f;
F32 interval = 0.f;
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
const char * w = "duration";
if (stats_config.has(w))
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
{
interval = (F32)stats_config[w].asReal();
}
w = "flags";
if (stats_config.has(w))
{
flags = (S32)stats_config[w].asInteger();
if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
duration > 0)
{ // No flags passed in, but have a duration, so reset to basic stats
flags = LLPerfBlock::LLSTATS_BASIC_STATS;
}
}
mStatsp->setReportPerformanceDuration( duration );
mStatsp->setReportPerformanceDuration( duration, flags );
mStatsp->setReportPerformanceInterval( interval );
if ( duration > 0 )
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
}
}
// Set length of performance stat recording
void LLPerfStats::setReportPerformanceDuration( F32 seconds )
// Set length of performance stat recording.
// If turning stats on, caller must provide flags
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
{
if ( seconds <= 0.f )
{
mReportPerformanceStatEnd = 0.0;
LLPerfBlock::setStatsEnabled( FALSE );
LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
mFrameStatsFile.close();
LLPerfBlock::clearDynamicStats();
}
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
// Clear failure flag to try and create the log file once
mFrameStatsFileFailure = FALSE;
LLPerfBlock::setStatsEnabled( TRUE );
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
LLPerfBlock::setStatsFlags(flags);
}
}
@@ -611,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta
}
}
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
// These are also turned on or off via the switch passed in
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
// Use this constructor for normal, optional LLPerfBlock time slices
LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
{
if (!sStatsEnabled) return;
if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
{ // These are off unless the base set is enabled
return;
}
initDynamicStat(key);
}
// Use this constructor for dynamically created LLPerfBlock time slices
// that are only enabled by specific control flags
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
{
if ((sStatsFlags & flags) == 0)
{
return;
}
if (NULL == key2 || strlen(key2) == 0)
{
@@ -629,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat
}
}
// Set up the result data map if dynamic stats are enabled
void LLPerfBlock::initDynamicStat(const std::string& key)
{
// Early exit if dynamic stats aren't enabled.
if (!sStatsEnabled) return;
if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
return;
mLastPath = sCurrentStatPath; // Save and restore current path
sCurrentStatPath += "/" + key; // Add key to current path
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
}
}
else
{ // WTF? Shouldn't have a NULL pointer in the map.
{ // Shouldn't have a NULL pointer in the map.
llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
}
}
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
LLTimer LLStat::sTimer;
LLFrameTimer LLStat::sFrameTimer;
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
void LLStat::init()
{
llassert(num_bins > 0);
mUseFrameTimer = use_frame_timer;
llassert(mNumBins > 0);
mNumValues = 0;
mLastValue = 0.f;
mLastTime = 0.f;
mNumBins = num_bins;
mCurBin = (mNumBins-1);
mNextBin = 0;
mBins = new F32[mNumBins];
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
mTime[i] = 0.0;
mDT[i] = 0.f;
}
if (!mName.empty())
{
stat_map_t::iterator iter = sStatList.find(mName);
if (iter != sStatList.end())
llwarns << "LLStat with duplicate name: " << mName << llendl;
sStatList.insert(std::make_pair(mName, this));
}
}
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
: mUseFrameTimer(use_frame_timer),
mNumBins(num_bins)
{
init();
}
LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
: mUseFrameTimer(use_frame_timer),
mNumBins(num_bins),
mName(name)
{
init();
}
LLStat::~LLStat()
@@ -754,6 +805,15 @@ LLStat::~LLStat()
delete[] mBeginTime;
delete[] mTime;
delete[] mDT;
if (!mName.empty())
{
// handle multiple entries with the same name
stat_map_t::iterator iter = sStatList.find(mName);
while (iter != sStatList.end() && iter->second != this)
++iter;
sStatList.erase(iter);
}
}
void LLStat::reset()

View File

@@ -192,14 +192,23 @@ public:
// Use this constructor for pre-defined LLStatTime objects
LLPerfBlock(LLStatTime* stat);
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
LLPerfBlock( const char* key1, const char* key2 = NULL);
// Use this constructor for normal, optional LLPerfBlock time slices
LLPerfBlock( const char* key );
// Use this constructor for dynamically created LLPerfBlock time slices
// that are only enabled by specific control flags
LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
~LLPerfBlock();
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
static S32 getStatsEnabled() { return sStatsEnabled; };
enum
{ // Stats bitfield flags
LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects
LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats
LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls
};
static void setStatsFlags( S32 flags ) { sStatsFlags = flags; };
static S32 getStatsFlags() { return sStatsFlags; };
static void clearDynamicStats(); // Reset maps to clear out dynamic objects
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
@@ -213,7 +222,7 @@ private:
LLStatTime * mPredefinedStat; // LLStatTime object to get data
StatEntry * mDynamicStat; // StatEntryobject to get data
static BOOL sStatsEnabled; // Normally FALSE
static S32 sStatsFlags; // Control what is being recorded
static stat_map_t sStatMap; // Map full path string to LLStatTime objects
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
};
@@ -236,7 +245,7 @@ public:
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
void setReportPerformanceDuration( F32 seconds );
void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
void setProcessName(const std::string& process_name) { mProcessName = process_name; }
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
@@ -258,8 +267,15 @@ private:
// ----------------------------------------------------------------------------
class LL_COMMON_API LLStat
{
private:
typedef std::multimap<std::string, LLStat*> stat_map_t;
static stat_map_t sStatList;
void init();
public:
LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE);
LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
~LLStat();
void reset();
@@ -322,8 +338,22 @@ private:
F32 *mDT;
S32 mCurBin;
S32 mNextBin;
std::string mName;
static LLTimer sTimer;
static LLFrameTimer sFrameTimer;
public:
static LLStat* getStat(const std::string& name)
{
// return the first stat that matches 'name'
stat_map_t::iterator iter = sStatList.find(name);
if (iter != sStatList.end())
return iter->second;
else
return NULL;
}
};
#endif // LL_STAT_

View File

@@ -45,7 +45,7 @@
// skips spaces and tabs
bool skip_whitespace(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while (('\t' == c || ' ' == c) && input_stream.good())
{
input_stream.get();
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
// skips whitespace, newlines, and carriage returns
bool skip_emptyspace(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while ( input_stream.good()
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) )
{
@@ -72,7 +72,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
{
while (skip_emptyspace(input_stream))
{
char c = input_stream.peek();
int c = input_stream.peek();
if ('#' == c )
{
while ('\n' != c && input_stream.good())
@@ -90,7 +90,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
bool skip_line(std::istream& input_stream)
{
char c;
int c;
do
{
c = input_stream.get();
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
bool skip_to_next_word(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while ( input_stream.good()
&& ( (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
@@ -132,7 +132,7 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
while (input_stream.good())
{
skip_emptyspace(input_stream);
char c = input_stream.get();
int c = input_stream.get();
if (keyword[0] != c)
{
skip_line(input_stream);
@@ -181,7 +181,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
while (input_stream.good())
{
skip_emptyspace(input_stream);
char c = input_stream.get();
int c = input_stream.get();
if (keyword[0] != c)
{
skip_line(input_stream);
@@ -229,7 +229,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
bool get_word(std::string& output_string, std::istream& input_stream)
{
skip_emptyspace(input_stream);
char c = input_stream.peek();
int c = input_stream.peek();
while ( !isspace(c)
&& '\n' != c
&& '\r' != c
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
{
skip_emptyspace(input_stream);
int char_count = 0;
char c = input_stream.peek();
int c = input_stream.peek();
while (!isspace(c)
&& '\n' != c
&& '\r' != c
@@ -265,7 +265,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
bool get_line(std::string& output_string, std::istream& input_stream)
{
output_string.clear();
char c = input_stream.get();
int c = input_stream.get();
while (input_stream.good())
{
output_string += c;
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
{
output_string.clear();
int char_count = 0;
char c = input_stream.get();
int c = input_stream.get();
while (input_stream.good() && char_count < n)
{
char_count++;

View File

@@ -52,6 +52,7 @@ public:
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
bool isStrided() const { return mTypeSize != mSkip; }
void skip(const U32 index) { mBytep += mSkip*index;}
U32 getSkip() const { return mSkip; }
Object* get() { return mObjectp; }
@@ -70,7 +71,7 @@ public:
//stride == sizeof(element) implies entire buffer is unstrided and thus memcpy-able, provided source buffer elements match in size.
//Because LLStrider is often passed an LLVector3 even if the reprensentation is LLVector4 in the vertex buffer, mTypeSize is set to
//the TRUE vbo datatype size via VertexBufferStrider::get
if(mTypeSize == mSkip && mTypeSize == elem_size)
if(!isStrided() && mTypeSize == elem_size)
{
if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
{

View File

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

View File

@@ -39,8 +39,6 @@
#include <limits.h>
#include "stdtypes.h"
#include "llpreprocessor.h"
#include "lldate.h"
#include <string>
#include <list>
@@ -55,8 +53,6 @@ const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR;
const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC;
LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds
class LL_COMMON_API LLTimer
{
public:
@@ -175,4 +171,5 @@ LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstri
LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string &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

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
#define LL_LLECONOMY_H
#include "llmemory.h"
#include "llsingleton.h"
class LLMessageSystem;
class LLVector3;

View File

@@ -36,10 +36,9 @@
#include "lldarray.h"
#include "llfoldertype.h"
#include "llinventorytype.h"
#include "llinventorydefines.h"
#include "llmemtype.h"
#include "llpermissions.h"
#include "llmemory.h"
#include "llrefcount.h"
#include "llsaleinfo.h"
#include "llsd.h"
#include "lluuid.h"
@@ -304,84 +303,11 @@ protected:
//-----------------------------------------------------------------------------
// Useful bits
// Convertors
//
// These functions convert between structured data and an inventory
// item, appropriate for serialization.
//-----------------------------------------------------------------------------
// This functor tests if an item is transferrable and returns true if
// it is. Derived from unary_function<> so that the object can be used
// in stl-compliant adaptable predicates (eg, not1<>). You might want
// to use this in std::partition() or similar logic.
struct IsItemTransferable : public std::unary_function<LLInventoryItem*, bool>
{
LLUUID mDestID;
IsItemTransferable(const LLUUID& dest_id) : mDestID(dest_id) {}
bool operator()(const LLInventoryItem* item) const
{
return (item->getPermissions().allowTransferTo(mDestID)) ? true:false;
}
};
// This functor is used to set the owner and group of inventory items,
// for example, in a simple std::for_each() loop. Note that the call
// to setOwnerAndGroup can fail if authority_id != LLUUID::null.
struct SetItemOwnerAndGroup
{
LLUUID mAuthorityID;
LLUUID mOwnerID;
LLUUID mGroupID;
SetItemOwnerAndGroup(const LLUUID& authority_id,
const LLUUID& owner_id,
const LLUUID& group_id) :
mAuthorityID(authority_id), mOwnerID(owner_id), mGroupID(group_id) {}
void operator()(LLInventoryItem* item) const
{
LLPermissions perm = item->getPermissions();
bool is_atomic = (LLAssetType::AT_OBJECT == item->getType()) ? false : true;
perm.setOwnerAndGroup(mAuthorityID, mOwnerID, mGroupID, is_atomic);
// If no owner id is set, this is equivalent to a deed action.
// Clear 'share with group'.
if (mOwnerID.isNull())
{
perm.setMaskGroup(PERM_NONE);
}
item->setPermissions(perm);
}
};
// This functor is used to unset the share with group, everyone perms, and
// for sale info for objects being sold through contents.
struct SetNotForSale
{
LLUUID mAgentID;
LLUUID mGroupID;
SetNotForSale(const LLUUID& agent_id,
const LLUUID& group_id) :
mAgentID(agent_id), mGroupID(group_id) {}
void operator()(LLInventoryItem* item) const
{
// Clear group & everyone permissions.
LLPermissions perm = item->getPermissions();
perm.setGroupBits(mAgentID, mGroupID, FALSE, PERM_MODIFY | PERM_MOVE | PERM_COPY);
perm.setEveryoneBits(mAgentID, mGroupID, FALSE, PERM_MOVE | PERM_COPY);
item->setPermissions(perm);
// Mark group & everyone permissions for overwrite on the next
// rez if it is an object.
if(LLAssetType::AT_OBJECT == item->getType())
{
U32 flags = item->getFlags();
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
item->setFlags(flags);
}
// Clear for sale info.
item->setSaleInfo(LLSaleInfo::DEFAULT);
}
};
// These functions convert between structured data and an inventroy
// item, appropriate for serialization.
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);

View File

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

View File

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

View File

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

View File

@@ -433,13 +433,10 @@ public:
void completeSale(U32& type, U8& flags, LLUUID& to_id);
void clearSale();
// this function returns TRUE if the parcel needs conversion to a
// lease from a non-owned-status state.
BOOL getRecordTransaction() const { return mRecordTransaction; }
void setRecordTransaction(BOOL record) { mRecordTransaction = record; }
BOOL isMediaResetTimerExpired(const U64& time);
// more accessors
U32 getParcelFlags() const { return mParcelFlags; }
@@ -474,7 +471,9 @@ public:
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
BOOL getAllowLandmark() const
{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
{ return TRUE; }
//Perhaps revert for opensim?
//{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
BOOL getAllowGroupScripts() const
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
@@ -620,8 +619,6 @@ protected:
LLTimer mMediaResetTimer;
S32 mGraceExtension;
BOOL mRecordTransaction;
// This value is non-zero if there is an auction associated with
// the parcel.

View File

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

View File

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

View File

@@ -37,8 +37,8 @@
#include <cstdlib>
#include <vector>
#include "lldefs.h"
#include "llstl.h" // *TODO: Remove when LLString is gone
#include "llstring.h" // *TODO: Remove when LLString is gone
//#include "llstl.h" // *TODO: Remove when LLString is gone
//#include "llstring.h" // *TODO: Remove when LLString is gone
// lltut.h uses is_approx_equal_fraction(). This was moved to its own header
// file in llcommon so we can use lltut.h for llcommon tests without making
// llcommon depend on llmath.
@@ -516,6 +516,12 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
VEC_TYPE Q1 = data[data.size()/4];
VEC_TYPE Q3 = data[data.size()-data.size()/4-1];
if ((F32)(Q3-Q1) < 1.f)
{
// not enough variation to detect outliers
return;
}
VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));

View File

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

View File

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

View File

@@ -2080,7 +2080,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
mDetail = detail;
mSculptLevel = -2;
#if MESH_ENABLED
mIsTetrahedron = FALSE;
mIsMeshAssetLoaded = FALSE;
mLODScaleBias.setVec(1,1,1);
mHullPoints = NULL;
mHullIndices = NULL;
@@ -2103,7 +2103,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
generate();
if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE)
if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE || mParams.getSculptType() == LL_SCULPT_TYPE_MESH)
{
createVolumeFaces();
}
@@ -2414,7 +2414,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
LLSD mdl;
if (!unzip_llsd(mdl, is, size))
{
llwarns << "not a valid mesh asset!" << llendl;
LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD, will probably fetch from sim again." << llendl;
return false;
}
@@ -2712,173 +2712,21 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
return true;
}
void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
BOOL LLVolume::isMeshAssetLoaded()
{
LLVector4a v0;
v0.setSub(cv[1].getPosition(), cv[0].getNormal());
LLVector4a v1;
v1.setSub(cv[2].getNormal(), cv[0].getPosition());
cv[0].getNormal().setCross3(v0,v1);
cv[0].getNormal().normalize3fast();
cv[1].setNormal(cv[0].getNormal());
cv[2].setNormal(cv[1].getNormal());
return mIsMeshAssetLoaded;
}
BOOL LLVolume::isTetrahedron()
void LLVolume::setMeshAssetLoaded(BOOL loaded)
{
return mIsTetrahedron;
}
void LLVolume::makeTetrahedron()
{
mVolumeFaces.clear();
LLVolumeFace face;
F32 x = 0.25f;
LLVector4a p[] =
{ //unit tetrahedron corners
LLVector4a(x,x,x),
LLVector4a(-x,-x,x),
LLVector4a(-x,x,-x),
LLVector4a(x,-x,-x)
};
face.mExtents[0].splat(-x);
face.mExtents[1].splat(x);
LLVolumeFace::VertexData cv[3];
//set texture coordinates
cv[0].mTexCoord = LLVector2(0,0);
cv[1].mTexCoord = LLVector2(1,0);
cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3);
//side 1
cv[0].setPosition(p[1]);
cv[1].setPosition(p[0]);
cv[2].setPosition(p[2]);
tetrahedron_set_normal(cv);
face.resizeVertices(12);
face.resizeIndices(12);
LLVector4a* v = (LLVector4a*) face.mPositions;
LLVector4a* n = (LLVector4a*) face.mNormals;
LLVector2* tc = (LLVector2*) face.mTexCoords;
v[0] = cv[0].getPosition();
v[1] = cv[1].getPosition();
v[2] = cv[2].getPosition();
v += 3;
n[0] = cv[0].getNormal();
n[1] = cv[1].getNormal();
n[2] = cv[2].getNormal();
n += 3;
if(tc)
{
tc[0] = cv[0].mTexCoord;
tc[1] = cv[1].mTexCoord;
tc[2] = cv[2].mTexCoord;
tc += 3;
}
//side 2
cv[0].setPosition(p[3]);
cv[1].setPosition(p[0]);
cv[2].setPosition(p[1]);
tetrahedron_set_normal(cv);
v[0] = cv[0].getPosition();
v[1] = cv[1].getPosition();
v[2] = cv[2].getPosition();
v += 3;
n[0] = cv[0].getNormal();
n[1] = cv[1].getNormal();
n[2] = cv[2].getNormal();
n += 3;
if(tc)
{
tc[0] = cv[0].mTexCoord;
tc[1] = cv[1].mTexCoord;
tc[2] = cv[2].mTexCoord;
tc += 3;
}
//side 3
cv[0].setPosition(p[3]);
cv[1].setPosition(p[1]);
cv[2].setPosition(p[2]);
tetrahedron_set_normal(cv);
v[0] = cv[0].getPosition();
v[1] = cv[1].getPosition();
v[2] = cv[2].getPosition();
v += 3;
n[0] = cv[0].getNormal();
n[1] = cv[1].getNormal();
n[2] = cv[2].getNormal();
n += 3;
if(tc)
{
tc[0] = cv[0].mTexCoord;
tc[1] = cv[1].mTexCoord;
tc[2] = cv[2].mTexCoord;
tc += 3;
}
//side 4
cv[0].setPosition(p[2]);
cv[1].setPosition(p[0]);
cv[2].setPosition(p[3]);
tetrahedron_set_normal(cv);
v[0] = cv[0].getPosition();
v[1] = cv[1].getPosition();
v[2] = cv[2].getPosition();
v += 3;
n[0] = cv[0].getNormal();
n[1] = cv[1].getNormal();
n[2] = cv[2].getNormal();
n += 3;
if(tc)
{
tc[0] = cv[0].mTexCoord;
tc[1] = cv[1].mTexCoord;
tc[2] = cv[2].mTexCoord;
tc += 3;
}
//set index buffer
for (U16 i = 0; i < 12; i++)
{
face.mIndices[i] = i;
}
mVolumeFaces.push_back(face);
mSculptLevel = 0;
mIsTetrahedron = TRUE;
mIsMeshAssetLoaded = loaded;
}
void LLVolume::copyVolumeFaces(const LLVolume* volume)
{
mVolumeFaces = volume->mVolumeFaces;
mSculptLevel = 0;
mIsTetrahedron = FALSE;
}
void LLVolume::cacheOptimize()
@@ -2889,17 +2737,10 @@ void LLVolume::cacheOptimize()
}
}
#endif //MESH_ENABLED
S32 LLVolume::getNumFaces() const
{
#if MESH_ENABLED
U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
if (sculpt_type == LL_SCULPT_TYPE_MESH)
{
return LL_SCULPT_MESH_MAX_FACES;
}
#endif //MESH_ENABLED
return (S32)mProfilep->mFaces.size();
return mIsMeshAssetLoaded ? getNumVolumeFaces() : (S32)mProfilep->mFaces.size();
}
@@ -7301,7 +7142,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
resizeVertices(num_vertices);
resizeIndices(num_indices);
#if MESH_ENABLED
if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
if (!volume->isMeshAssetLoaded())
#endif //MESH_ENABLED
{
mEdge.resize(num_indices);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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 )
{
char s[MTUBYTES];
s[0] = '\0';
char s[MTUBYTES + 1]= {0}; // every element is initialized with 0
getData(block, var, s, 0, blocknum, MTUBYTES);
s[MTUBYTES - 1] = '\0';
s[MTUBYTES] = '\0';
outstr = s;
}

View File

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

View File

@@ -433,7 +433,7 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
}
else if(message_name == "sleep_time")
{
mSleepTime = parsed.getValueReal("time");
mSleepTime = llmax(parsed.getValueReal("time"), 1.0 / 100.0); // clamp to maximum of 100Hz
}
else if(message_name == "crash")
{

View File

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

View File

@@ -33,6 +33,7 @@ set(llprimitive_HEADER_FILES
legacy_object_types.h
llmaterialtable.h
llmediaentry.h
llmodel.h
llprimitive.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
#include "llmodel.h"
#include "llmemory.h"
#if MESH_IMPORT
#include "llconvexdecomposition.h"
#endif //MESH_IMPORT
@@ -1019,10 +1020,16 @@ void LLModel::setVolumeFaceData(
face.resizeVertices(num_verts);
face.resizeIndices(num_indices);
LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
if(!pos.isStrided())
LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
else
for(U32 i=0;i<num_verts;++i) face.mPositions[i].load3(pos[i].mV);
if (norm.get())
{
LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
if(!norm.isStrided())
LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
else
for(U32 i=0;i<num_verts;++i) face.mNormals[i].load3(norm[i].mV);
}
else
{
@@ -1032,7 +1039,10 @@ void LLModel::setVolumeFaceData(
if (tc.get())
{
LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
if(!tc.isStrided())
LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
else
for(U32 i=0;i<num_verts;++i) face.mTexCoords[i] = tc[i].mV;
}
else
{

View File

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

View File

@@ -53,6 +53,7 @@
#include "llstacktrace.h"
#include "llglheaders.h"
#include "llglslshader.h"
#ifdef _DEBUG
//#define GL_STATE_VERIFY
@@ -127,6 +128,23 @@ PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL;
// GL_ARB_map_buffer_range
PFNGLMAPBUFFERRANGEPROC glMapBufferRange = NULL;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = NULL;
// GL_ARB_sync
PFNGLFENCESYNCPROC glFenceSync = NULL;
PFNGLISSYNCPROC glIsSync = NULL;
PFNGLDELETESYNCPROC glDeleteSync = NULL;
PFNGLCLIENTWAITSYNCPROC glClientWaitSync = NULL;
PFNGLWAITSYNCPROC glWaitSync = NULL;
PFNGLGETINTEGER64VPROC glGetInteger64v = NULL;
PFNGLGETSYNCIVPROC glGetSynciv = NULL;
// GL_APPLE_flush_buffer_range
PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE = NULL;
PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL;
// vertex object prototypes
PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL;
PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI = NULL;
@@ -156,27 +174,33 @@ PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
// GL_EXT_framebuffer_object
PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL;
PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL;
PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL;
PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL;
PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL;
PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL;
PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL;
PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL;
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL;
PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL;
PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL;
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;
PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = NULL;
PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT = NULL;
// GL_ARB_framebuffer_object
PFNGLISRENDERBUFFERPROC glIsRenderbuffer = NULL;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = NULL;
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = NULL;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = NULL;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = NULL;
PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv = NULL;
PFNGLISFRAMEBUFFERPROC glIsFramebuffer = NULL;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = NULL;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = NULL;
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = NULL;
PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D = NULL;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = NULL;
PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D = NULL;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv = NULL;
PFNGLGENERATEMIPMAPPROC glGenerateMipmap = NULL;
PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = NULL;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
//GL_ARB_texture_multisample
PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
PFNGLSAMPLEMASKIPROC glSampleMaski;
// GL_EXT_blend_func_separate
PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
@@ -321,10 +345,13 @@ LLGLManager::LLGLManager() :
mHasMipMapGeneration(FALSE),
mHasCompressedTextures(FALSE),
mHasFramebufferObject(FALSE),
mMaxSamples(0),
mHasFramebufferMultisample(FALSE),
mHasBlendFuncSeparate(FALSE),
mHasSync(FALSE),
mHasVertexBufferObject(FALSE),
mHasMapBufferRange(FALSE),
mHasFlushBufferRange(FALSE),
mHasPBuffer(FALSE),
mHasShaderObjects(FALSE),
mHasVertexShader(FALSE),
@@ -335,6 +362,11 @@ LLGLManager::LLGLManager() :
mHasPointParameters(FALSE),
mHasDrawBuffers(FALSE),
mHasTextureRectangle(FALSE),
mHasTextureMultisample(FALSE),
mMaxSampleMaskWords(0),
mMaxColorTextureSamples(0),
mMaxDepthTextureSamples(0),
mMaxIntegerSamples(0),
mHasAnisotropic(FALSE),
mHasARBEnvCombine(FALSE),
@@ -353,6 +385,8 @@ LLGLManager::LLGLManager() :
mHasSeparateSpecularColor(FALSE),
mDebugGPU(FALSE),
mDriverVersionMajor(1),
mDriverVersionMinor(0),
mDriverVersionRelease(0),
@@ -538,13 +572,46 @@ bool LLGLManager::initGL()
{
GLint num_tex_image_units;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units);
mNumTextureImageUnits = num_tex_image_units;
mNumTextureImageUnits = llmin(num_tex_image_units, 32);
}
if (mHasTextureMultisample)
{
glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples);
glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples);
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples);
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
}
#if LL_WINDOWS
if (mIsATI)
{ //using multisample textures on ATI results in black screen for some reason
mHasTextureMultisample = FALSE;
}
#endif
if (mHasFramebufferObject)
{
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
}
setToDebugGPU();
initGLStates();
return true;
}
void LLGLManager::setToDebugGPU()
{
//"MOBILE INTEL(R) 965 EXPRESS CHIP",
if (mGLRenderer.find("INTEL") != std::string::npos && mGLRenderer.find("965") != std::string::npos)
{
mDebugGPU = TRUE ;
}
return ;
}
void LLGLManager::getGLInfo(LLSD& info)
{
info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
@@ -601,6 +668,14 @@ std::string LLGLManager::getRawGLString()
return gl_string;
}
U32 LLGLManager::getNumFBOFSAASamples(U32 samples)
{
samples = llmin(samples, (U32) mMaxColorTextureSamples);
samples = llmin(samples, (U32) mMaxDepthTextureSamples);
samples = llmin(samples, (U32) 4);
return samples;
}
void LLGLManager::shutdownGL()
{
if (mInited)
@@ -686,6 +761,9 @@ void LLGLManager::initExtensions()
mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
#ifdef GL_ARB_framebuffer_object
@@ -700,7 +778,10 @@ void LLGLManager::initExtensions()
mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
#if !LL_DARWIN
mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
#endif
mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts)
&& ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
@@ -879,29 +960,44 @@ void LLGLManager::initExtensions()
mHasVertexBufferObject = FALSE;
}
}
if (mHasSync)
{
glFenceSync = (PFNGLFENCESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glFenceSync");
glIsSync = (PFNGLISSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glIsSync");
glDeleteSync = (PFNGLDELETESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteSync");
glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glClientWaitSync");
glWaitSync = (PFNGLWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glWaitSync");
glGetInteger64v = (PFNGLGETINTEGER64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInteger64v");
glGetSynciv = (PFNGLGETSYNCIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetSynciv");
}
if (mHasMapBufferRange)
{
glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glMapBufferRange");
glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glFlushMappedBufferRange");
}
if (mHasFramebufferObject)
{
llinfos << "initExtensions() FramebufferObject-related procs..." << llendl;
glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbufferEXT");
glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbufferEXT");
glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffersEXT");
glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffersEXT");
glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageEXT");
glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameterivEXT");
glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebufferEXT");
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebufferEXT");
glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffersEXT");
glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffersEXT");
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatusEXT");
glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1DEXT");
glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2DEXT");
glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3DEXT");
glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbufferEXT");
glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT");
glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT");
glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebufferEXT");
glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisampleEXT");
glFramebufferTextureLayerEXT = (PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTextureLayerEXT");
glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbuffer");
glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbuffer");
glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffers");
glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffers");
glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorage");
glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameteriv");
glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebuffer");
glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebuffer");
glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffers");
glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffers");
glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatus");
glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1D");
glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2D");
glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3D");
glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbuffer");
glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameteriv");
glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmap");
glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBlitFramebuffer");
glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageMultisample");
glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTextureLayer");
}
if (mHasDrawBuffers)
{
@@ -911,6 +1007,13 @@ void LLGLManager::initExtensions()
{
glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT");
}
if (mHasTextureMultisample)
{
glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage2DMultisample");
glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample");
glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
}
#if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS
// This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah
glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
@@ -1299,6 +1402,7 @@ void LLGLState::checkStates(const std::string& msg)
void LLGLState::checkTextureChannels(const std::string& msg)
{
#if 0
if (!gDebugGL)
{
return;
@@ -1458,11 +1562,12 @@ void LLGLState::checkTextureChannels(const std::string& msg)
LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL;
}
}
#endif
}
void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
{
if (!gDebugGL)
if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
{
return;
}
@@ -1574,7 +1679,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
}
}
if (glIsEnabled(GL_TEXTURE_2D))
/*if (glIsEnabled(GL_TEXTURE_2D))
{
if (!(data_mask & 0x0008))
{
@@ -1597,7 +1702,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl;
}
}
}
}*/
glClientActiveTextureARB(GL_TEXTURE0_ARB);
gGL.getTexUnit(0)->activate();
@@ -1640,6 +1745,16 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
LLGLState::LLGLState(LLGLenum state, S32 enabled) :
mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
{
if (LLGLSLShader::sNoFixedFunction)
{ //always disable state that's deprecated post GL 3.0
switch (state)
{
case GL_ALPHA_TEST:
enabled = 0;
break;
}
}
stop_glerror();
if (state)
{
@@ -1998,8 +2113,7 @@ void LLGLNamePool::release(GLuint name)
//static
void LLGLNamePool::upkeepPools()
{
tracker_t::LLInstanceTrackerScopedGuard guard;
for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
{
LLGLNamePool & pool = *iter;
pool.upkeep();
@@ -2009,8 +2123,7 @@ void LLGLNamePool::upkeepPools()
//static
void LLGLNamePool::cleanupPools()
{
tracker_t::LLInstanceTrackerScopedGuard guard;
for (tracker_t::instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); ++iter)
for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
{
LLGLNamePool & pool = *iter;
pool.cleanup();

View File

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

View File

@@ -76,6 +76,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
// GL_ARB_sync
extern PFNGLFENCESYNCPROC glFenceSync;
extern PFNGLISSYNCPROC glIsSync;
extern PFNGLDELETESYNCPROC glDeleteSync;
extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
extern PFNGLWAITSYNCPROC glWaitSync;
extern PFNGLGETINTEGER64VPROC glGetInteger64v;
extern PFNGLGETSYNCIVPROC glGetSynciv;
// GL_APPLE_flush_buffer_range
extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
// GL_ARB_map_buffer_range
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
// GL_ATI_vertex_array_object
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
@@ -312,6 +329,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
// GL_ARB_sync
extern PFNGLFENCESYNCPROC glFenceSync;
extern PFNGLISSYNCPROC glIsSync;
extern PFNGLDELETESYNCPROC glDeleteSync;
extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
extern PFNGLWAITSYNCPROC glWaitSync;
extern PFNGLGETINTEGER64VPROC glGetInteger64v;
extern PFNGLGETSYNCIVPROC glGetSynciv;
// GL_APPLE_flush_buffer_range
extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
// GL_ARB_map_buffer_range
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
// GL_ATI_vertex_array_object
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
@@ -455,31 +489,36 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
//GL_EXT_blend_func_separate
extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
//GL_EXT_framebuffer_object
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
extern PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT;
//GL_ARB_framebuffer_object
extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
//GL_ARB_draw_buffers
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
//GL_ARB_texture_multisample
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
#elif LL_WINDOWS
//----------------------------------------------------------------------------
@@ -512,6 +551,23 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
// GL_ARB_sync
extern PFNGLFENCESYNCPROC glFenceSync;
extern PFNGLISSYNCPROC glIsSync;
extern PFNGLDELETESYNCPROC glDeleteSync;
extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
extern PFNGLWAITSYNCPROC glWaitSync;
extern PFNGLGETINTEGER64VPROC glGetInteger64v;
extern PFNGLGETSYNCIVPROC glGetSynciv;
// GL_APPLE_flush_buffer_range
extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE;
extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
// GL_ARB_map_buffer_range
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
// GL_ATI_vertex_array_object
extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
@@ -654,31 +710,37 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
//GL_EXT_blend_func_separate
extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
//GL_EXT_framebuffer_object
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
extern PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC glFramebufferTextureLayerEXT;
//GL_ARB_framebuffer_object
extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
//GL_ARB_draw_buffers
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
//GL_ARB_texture_multisample
extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
extern PFNGLSAMPLEMASKIPROC glSampleMaski;
#elif LL_DARWIN
//----------------------------------------------------------------------------
// LL_DARWIN
@@ -696,7 +758,7 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
#include <AvailabilityMacros.h>
//GL_EXT_blend_func_separate
extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) ;
// GL_EXT_framebuffer_object
extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
@@ -719,6 +781,7 @@ extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_A
#ifndef GL_ARB_framebuffer_object
#define glGenerateMipmap glGenerateMipmapEXT
#define GL_MAX_SAMPLES 0x8D57
#endif
// GL_ARB_draw_buffers
extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
@@ -726,6 +789,46 @@ extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_V
#ifdef __cplusplus
extern "C" {
#endif
//
// Define map buffer range headers on Mac
//
#ifndef GL_ARB_map_buffer_range
#define GL_MAP_READ_BIT 0x0001
#define GL_MAP_WRITE_BIT 0x0002
#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
#endif
//
// Define multisample headers on Mac
//
#ifndef GL_ARB_texture_multisample
#define GL_SAMPLE_POSITION 0x8E50
#define GL_SAMPLE_MASK 0x8E51
#define GL_SAMPLE_MASK_VALUE 0x8E52
#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
#define GL_TEXTURE_SAMPLES 0x9106
#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
#define GL_MAX_INTEGER_SAMPLES 0x9110
#endif
//
// Define vertex buffer object headers on Mac
//

View File

@@ -37,6 +37,7 @@
#include "llshadermgr.h"
#include "llfile.h"
#include "llrender.h"
#include "llcontrol.h"
#if LL_DARWIN
#include "OpenGL/OpenGL.h"
@@ -54,6 +55,16 @@ using std::pair;
using std::make_pair;
using std::string;
GLhandleARB LLGLSLShader::sCurBoundShader = 0;
LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
bool LLGLSLShader::sNoFixedFunction = false;
//UI shader -- declared here so llui_libtest will link properly
//Singu note: Not using llui_libtest... and LLViewerShaderMgr is a part of newview. So,
// these are declared in newview/llviewershadermanager.cpp just like every other shader.
//LLGLSLShader gUIProgram(LLViewerShaderMgr::SHADER_INTERFACE);
//LLGLSLShader gSolidColorProgram(LLViewerShaderMgr::SHADER_INTERFACE);
BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
{
return v1 != v2;
@@ -63,6 +74,7 @@ LLShaderFeatures::LLShaderFeatures()
: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
, mIndexedTextureChannels(0), disableTextureIndex(false), hasAlphaMask(false)
#if MESH_ENABLED
, hasObjectSkinning(false)
#endif //MESH_ENABLED
@@ -119,6 +131,28 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
glDeleteObjectARB(mProgramObject);
// Create program
mProgramObject = glCreateProgramObjectARB();
static const LLCachedControl<bool> no_texture_indexing("ShyotlUseLegacyTextureBatching",false);
if (gGLManager.mGLVersion < 3.1f || no_texture_indexing)
{ //force indexed texture channels to 1 if GL version is old (performance improvement for drivers with poor branching shader model support)
mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
}
//compile new source
vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
for ( ; fileIter != mShaderFiles.end(); fileIter++ )
{
GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, mFeatures.mIndexedTextureChannels);
LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
if (shaderhandle > 0)
{
attachObject(shaderhandle);
}
else
{
success = FALSE;
}
}
// Attach existing objects
if (!LLShaderMgr::instance()->attachShaderFeatures(this))
@@ -129,19 +163,9 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
return FALSE;
}
vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
for ( ; fileIter != mShaderFiles.end(); fileIter++ )
{
GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second);
LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
if (mShaderLevel > 0)
{
attachObject(shaderhandle);
}
else
{
success = FALSE;
}
if (gGLManager.mGLVersion < 3.1f || no_texture_indexing)
{ //attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
}
// Map attributes and uniforms
@@ -169,6 +193,28 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
return createShader(attributes,uniforms);
}
}
else if (mFeatures.mIndexedTextureChannels > 0)
{ //override texture channels for indexed texture rendering
bind();
S32 channel_count = mFeatures.mIndexedTextureChannels;
for (S32 i = 0; i < channel_count; i++)
{
uniform1i(llformat("tex%d", i), i);
}
S32 cur_tex = channel_count; //adjust any texture channels that might have been overwritten
for (U32 i = 0; i < mTexture.size(); i++)
{
if (mTexture[i] > -1 && mTexture[i] < channel_count)
{
llassert(cur_tex < gGLManager.mNumTextureImageUnits);
uniform1i(i, cur_tex);
mTexture[i] = cur_tex++;
}
}
unbind();
}
return success;
}
@@ -314,7 +360,8 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
{
if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB)
if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB /*||
type == GL_SAMPLER_2D_MULTISAMPLE*/)
{ //this here is a texture
glUniform1iARB(location, mActiveTextureChannels);
LL_DEBUGS("ShaderLoading") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL;
@@ -360,10 +407,12 @@ BOOL LLGLSLShader::link(BOOL suppress_errors)
void LLGLSLShader::bind()
{
gGL.flush();
if (gGLManager.mHasShaderObjects)
{
glUseProgramObjectARB(mProgramObject);
sCurBoundShader = mProgramObject;
sCurBoundShaderPtr = this;
if (mUniformsDirty)
{
LLShaderMgr::instance()->updateShaderUniforms(this);
@@ -374,6 +423,7 @@ void LLGLSLShader::bind()
void LLGLSLShader::unbind()
{
gGL.flush();
if (gGLManager.mHasShaderObjects)
{
stop_glerror();
@@ -386,6 +436,8 @@ void LLGLSLShader::unbind()
}
}
glUseProgramObjectARB(0);
sCurBoundShader = 0;
sCurBoundShaderPtr = NULL;
stop_glerror();
}
}
@@ -393,6 +445,8 @@ void LLGLSLShader::unbind()
void LLGLSLShader::bindNoShader(void)
{
glUseProgramObjectARB(0);
sCurBoundShader = 0;
sCurBoundShaderPtr = NULL;
}
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
@@ -938,6 +992,12 @@ void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean
}
}
void LLGLSLShader::setAlphaRange(F32 minimum, F32 maximum)
{
uniform1f("minimum_alpha", minimum);
uniform1f("maximum_alpha", maximum);
}
void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{

View File

@@ -53,6 +53,9 @@ public:
#endif //MESH_ENABLED
bool hasAtmospherics;
bool hasGamma;
S32 mIndexedTextureChannels;
bool disableTextureIndex;
bool hasAlphaMask;
// char numLights;
@@ -72,6 +75,10 @@ public:
LLGLSLShader(S32 shader_class);
static GLhandleARB sCurBoundShader;
static LLGLSLShader* sCurBoundShaderPtr;
static bool sNoFixedFunction;
void unload();
BOOL createShader(std::vector<std::string> * attributes,
std::vector<std::string> * uniforms);
@@ -108,6 +115,8 @@ public:
void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
void setAlphaRange(F32 minimum, F32 maximum);
void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void vertexAttrib4fv(U32 index, GLfloat* v);
@@ -146,4 +155,9 @@ public:
std::string mName;
};
//UI shader (declared here so llui_libtest will link properly)
extern LLGLSLShader gUIProgram;
//output vec4(color.rgb,color.a*tex0[tc0].a)
extern LLGLSLShader gSolidColorProgram;
#endif

View File

@@ -1400,22 +1400,36 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
void LLImageGL::deleteDeadTextures()
{
bool reset = false;
while (!sDeadTextureList.empty())
{
GLuint tex = sDeadTextureList.front();
sDeadTextureList.pop_front();
for (int i = 0; i < gGLManager.mNumTextureUnits; i++)
for (int i = 0; i < gGLManager.mNumTextureImageUnits; i++)
{
if (sCurrentBoundTextures[i] == tex)
LLTexUnit* tex_unit = gGL.getTexUnit(i);
if (tex_unit->getCurrTexture() == tex)
{
gGL.getTexUnit(i)->unbind(LLTexUnit::TT_TEXTURE);
tex_unit->unbind(tex_unit->getCurrType());
stop_glerror();
if (i > 0)
{
reset = true;
}
}
}
glDeleteTextures(1, &tex);
stop_glerror();
}
if (reset)
{
gGL.getTexUnit(0)->activate();
}
}
void LLImageGL::destroyGLTexture()

View File

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

View File

@@ -36,6 +36,7 @@
#include "llvertexbuffer.h"
#include "llcubemap.h"
#include "llglslshader.h"
#include "llimagegl.h"
#include "llrendertarget.h"
#include "lltexture.h"
@@ -49,7 +50,9 @@ F64 gGLLastProjection[16];
F64 gGLProjection[16];
S32 gGLViewport[4];
static const U32 LL_NUM_TEXTURE_LAYERS = 8;
U32 LLTexUnit::sWhiteTexture = 0;
static const U32 LL_NUM_TEXTURE_LAYERS = 32;
static const U32 LL_NUM_LIGHT_UNITS = 8;
static GLenum sGLTextureType[] =
@@ -57,6 +60,7 @@ static GLenum sGLTextureType[] =
GL_TEXTURE_2D,
GL_TEXTURE_RECTANGLE_ARB,
GL_TEXTURE_CUBE_MAP_ARB
//,GL_TEXTURE_2D_MULTISAMPLE Don't use.
};
static GLint sGLAddressMode[] =
@@ -127,7 +131,8 @@ void LLTexUnit::refreshState(void)
// Per apple spec, don't call glEnable/glDisable when index exceeds max texture units
// http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html
//
bool enableDisable = (mIndex < gGLManager.mNumTextureUnits);
bool enableDisable = !LLGLSLShader::sNoFixedFunction &&
(mIndex < gGLManager.mNumTextureUnits) /*&& mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE*/;
if (mCurrTexType != TT_NONE)
{
@@ -183,8 +188,11 @@ void LLTexUnit::enable(eTextureType type)
disable(); // Force a disable of a previous texture type if it's enabled.
}
mCurrTexType = type;
gGL.flush();
if (mIndex < gGLManager.mNumTextureUnits)
if (!LLGLSLShader::sNoFixedFunction &&
//type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
mIndex < gGLManager.mNumTextureUnits)
{
glEnable(sGLTextureType[type]);
}
@@ -200,7 +208,9 @@ void LLTexUnit::disable(void)
activate();
unbind(mCurrTexType);
gGL.flush();
if (mIndex < gGLManager.mNumTextureUnits)
if (!LLGLSLShader::sNoFixedFunction &&
//mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
mIndex < gGLManager.mNumTextureUnits)
{
glDisable(sGLTextureType[mCurrTexType]);
}
@@ -404,7 +414,15 @@ void LLTexUnit::unbind(eTextureType type)
activate();
mCurrTexture = 0;
glBindTexture(sGLTextureType[type], 0);
if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
{
glBindTexture(sGLTextureType[type], sWhiteTexture);
}
else
{
glBindTexture(sGLTextureType[type], 0);
}
stop_glerror();
}
}
@@ -426,7 +444,7 @@ void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode)
void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option)
{
if (mIndex < 0 || mCurrTexture == 0) return;
if (mIndex < 0 || mCurrTexture == 0 /*|| mCurrTexType == LLTexUnit::TT_MULTISAMPLE_TEXTURE*/) return;
gGL.flush();
@@ -474,6 +492,11 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
void LLTexUnit::setTextureBlendType(eTextureBlendType type)
{
if (LLGLSLShader::sNoFixedFunction)
{ //texture blend type means nothing when using shaders
return;
}
if (mIndex < 0) return;
// Do nothing if it's already correctly set.
@@ -594,6 +617,11 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha)
void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha)
{
if (LLGLSLShader::sNoFixedFunction)
{ //register combiners do nothing when not using fixed function
return;
}
if (mIndex < 0) return;
activate();
@@ -1064,6 +1092,10 @@ void LLRender::setSceneBlendType(eBlendType type)
void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
{
flush();
if (LLGLSLShader::sNoFixedFunction)
{ //glAlphaFunc is deprecated in OpenGL 3.3
return;
}
if (mCurrAlphaFunc != func ||
mCurrAlphaFuncVal != value)
@@ -1079,6 +1111,30 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
glAlphaFunc(sGLCompareFunc[func], value);
}
}
if (gDebugGL)
{ //make sure cached state is correct
GLint cur_func = 0;
glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func);
if (func == CF_DEFAULT)
{
func = CF_GREATER;
}
if (cur_func != sGLCompareFunc[func])
{
llerrs << "Alpha test function corrupted!" << llendl;
}
F32 ref = 0.f;
glGetFloatv(GL_ALPHA_TEST_REF, &ref);
if (ref != value)
{
llerrs << "Alpha test value corrupted!" << llendl;
}
}
}
void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)

View File

@@ -58,11 +58,13 @@ class LLTexUnit
{
friend class LLRender;
public:
static U32 sWhiteTexture;
typedef enum
{
TT_TEXTURE = 0, // Standard 2D Texture
TT_RECT_TEXTURE, // Non power of 2 texture
TT_CUBE_MAP, // 6-sided cube map texture
//TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample Do not use
TT_NONE // No texture type is currently enabled
} eTextureType;

View File

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

View File

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

View File

@@ -217,17 +217,79 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
if (features->hasWaterFog)
{
if (!shader->attachObject("lighting/lightWaterF.glsl"))
if (features->disableTextureIndex)
{
return FALSE;
if (features->hasAlphaMask)
{
if (!shader->attachObject("lighting/lightWaterAlphaMaskNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightWaterNonIndexedF.glsl"))
{
return FALSE;
}
}
}
else
{
if (features->hasAlphaMask)
{
if (!shader->attachObject("lighting/lightWaterAlphaMaskF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightWaterF.glsl"))
{
return FALSE;
}
}
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
}
}
else
{
if (!shader->attachObject("lighting/lightF.glsl"))
if (features->disableTextureIndex)
{
return FALSE;
if (features->hasAlphaMask)
{
if (!shader->attachObject("lighting/lightAlphaMaskNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightNonIndexedF.glsl"))
{
return FALSE;
}
}
}
else
{
if (features->hasAlphaMask)
{
if (!shader->attachObject("lighting/lightAlphaMaskF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightF.glsl"))
{
return FALSE;
}
}
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
}
}
}
@@ -238,32 +300,111 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
if (features->isShiny && features->hasWaterFog)
{
if (!shader->attachObject("lighting/lightFullbrightShinyWaterF.glsl"))
if (features->disableTextureIndex)
{
return FALSE;
if (!shader->attachObject("lighting/lightFullbrightShinyWaterNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightFullbrightShinyWaterF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
}
}
else if (features->hasWaterFog)
{
if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
if (features->disableTextureIndex)
{
return FALSE;
if (features->hasAlphaMask)
{
if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedAlphaMaskF.glsl"))
{
return FALSE;
}
}
else if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
if (features->hasAlphaMask)
{
if (!shader->attachObject("lighting/lightFullbrightWaterAlphaMaskF.glsl"))
{
return FALSE;
}
}
else if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
}
}
else if (features->isShiny)
{
if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl"))
if (features->disableTextureIndex)
{
return FALSE;
if (!shader->attachObject("lighting/lightFullbrightShinyNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
}
}
else
{
if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
if (features->disableTextureIndex)
{
return FALSE;
if (features->hasAlphaMask)
{
if (!shader->attachObject("lighting/lightFullbrightNonIndexedAlphaMaskF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightFullbrightNonIndexedF.glsl"))
{
return FALSE;
}
}
}
else
{
if (features->hasAlphaMask)
{
if (!shader->attachObject("lighting/lightFullbrightAlphaMaskF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
{
return FALSE;
}
}
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
}
}
}
@@ -274,17 +415,39 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
if (features->hasWaterFog)
{
if (!shader->attachObject("lighting/lightShinyWaterF.glsl"))
if (features->disableTextureIndex)
{
return FALSE;
if (!shader->attachObject("lighting/lightShinyWaterNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightShinyWaterF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
}
}
else
{
if (!shader->attachObject("lighting/lightShinyF.glsl"))
if (features->disableTextureIndex)
{
return FALSE;
if (!shader->attachObject("lighting/lightShinyNonIndexedF.glsl"))
{
return FALSE;
}
}
else
{
if (!shader->attachObject("lighting/lightShinyF.glsl"))
{
return FALSE;
}
shader->mFeatures.mIndexedTextureChannels = gGLManager.mNumTextureImageUnits-1;
}
}
}
@@ -328,13 +491,16 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
}
}
GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type)
GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels)
{
GLenum error;
error = glGetError();
if (error != GL_NO_ERROR)
GLenum error = GL_NO_ERROR;
if (gDebugGL)
{
LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
}
}
LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL;
@@ -375,11 +541,121 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
//we can't have any lines longer than 1024 characters
//or any shaders longer than 1024 lines... deal - DaveP
GLcharARB buff[1024];
GLcharARB* text[1024];
GLcharARB buff[1024] = {0};
GLcharARB* text[1024] = {0};
GLuint count = 0;
if (gGLManager.mGLVersion < 2.1f)
{
text[count++] = strdup("#version 110\n");
}
else if (gGLManager.mGLVersion < 3.f)
{
//set version to 1.20
text[count++] = strdup("#version 120\n");
}
else
{ //set version to 1.30
text[count++] = strdup("#version 130\n");
}
//copy preprocessor definitions into buffer
for (std::map<std::string,std::string>::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter)
{
std::string define = "#define " + iter->first + " " + iter->second + "\n";
text[count++] = (GLcharARB *) strdup(define.c_str());
}
if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER_ARB)
{
//use specified number of texture channels for indexed texture rendering
/* prepend shader code that looks like this:
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
.
.
.
uniform sampler2D texN;
varying float vary_texture_index;
vec4 diffuseLookup(vec2 texcoord)
{
switch (int(vary_texture_index+0.25))
{
case 0: return texture2D(tex0, texcoord);
case 1: return texture2D(tex1, texcoord);
case 2: return texture2D(tex2, texcoord);
.
.
.
case N: return texture2D(texN, texcoord);
}
return vec4(0,0,0,0);
}
*/
//uniform declartion
for (S32 i = 0; i < texture_index_channels; ++i)
{
std::string decl = llformat("uniform sampler2D tex%d;\n", i);
text[count++] = strdup(decl.c_str());
}
text[count++] = strdup("varying float vary_texture_index;\n");
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
text[count++] = strdup("{\n");
if (texture_index_channels == 1)
{ //don't use flow control, that's silly
text[count++] = strdup("return texture2D(tex0, texcoord);\n");
text[count++] = strdup("}\n");
}
else if (gGLManager.mGLVersion >= 3.f)
{
text[count++] = strdup("\tswitch (int(vary_texture_index+0.25))\n");
text[count++] = strdup("\t{\n");
//switch body
for (S32 i = 0; i < texture_index_channels; ++i)
{
std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i);
text[count++] = strdup(case_str.c_str());
}
text[count++] = strdup("\t}\n");
text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
text[count++] = strdup("}\n");
}
else
{
//switches aren't supported, make block that looks like:
/*
int ti = int(vary_texture_index+0.25);
if (ti == 0) return texture2D(tex0, texcoord);
if (ti == 1) return texture2D(tex1, texcoord);
.
.
.
if (ti == N) return texture2D(texN, texcoord);
*/
text[count++] = strdup("int ti = int(vary_texture_index+0.25);\n");
for (S32 i = 0; i < texture_index_channels; ++i)
{
std::string if_str = llformat("if (ti == %d) return texture2D(tex%d, texcoord);\n", i, i);
text[count++] = strdup(if_str.c_str());
}
text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
text[count++] = strdup("}\n");
}
}
//copy file into memory
while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) )
{
@@ -389,51 +665,67 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
//create shader object
GLhandleARB ret = glCreateShaderObjectARB(type);
error = glGetError();
if (error != GL_NO_ERROR)
if (gDebugGL)
{
LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
glDeleteObjectARB(ret); //no longer need handle
}
}
else
//load source
glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
if (gDebugGL)
{
//load source
glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
glDeleteObjectARB(ret); //no longer need handle
}
else
}
//compile source
glCompileShaderARB(ret);
if (gDebugGL)
{
error = glGetError();
if (error != GL_NO_ERROR)
{
//compile source
glCompileShaderARB(ret);
error = glGetError();
if (error != GL_NO_ERROR)
{
LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
glDeleteObjectARB(ret); //no longer need handle
}
LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
glDeleteObjectARB(ret); //no longer need handle
}
}
//free memory
for (GLuint i = 0; i < count; i++)
{
free(text[i]);
}
if (error == GL_NO_ERROR)
{
//check for errors
GLint success = GL_TRUE;
glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success);
error = glGetError();
if (error != GL_NO_ERROR || success == GL_FALSE)
if (gDebugGL || success == GL_FALSE)
{
//an error occured, print log
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
dumpObjectLog(ret);
glDeleteObjectARB(ret); //no longer need handle
ret = 0;
error = glGetError();
if (error != GL_NO_ERROR || success == GL_FALSE)
{
//an error occured, print log
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
dumpObjectLog(ret);
std::stringstream ostr;
//dump shader source for debugging
for (GLuint i = 0; i < count; i++)
{
ostr << i << ": " << text[i];
}
LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
glDeleteObjectARB(ret); //no longer need handle
ret = 0;
}
}
}
else
@@ -442,6 +734,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
stop_glerror();
//free memory
for (GLuint i = 0; i < count; i++)
{
free(text[i]);
}
//successfully loaded, save results
if (ret)
{
@@ -454,7 +752,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
if (shader_level > 1)
{
shader_level--;
return loadShaderFile(filename,shader_level,type);
return loadShaderFile(filename,shader_level,type,texture_index_channels);
}
LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL;
}

View File

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

View File

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

View File

@@ -42,6 +42,7 @@
#include "llrender.h"
#include "llvector4a.h"
#include "llcontrol.h"
#include "llglslshader.h"
//============================================================================
@@ -88,6 +89,59 @@ void LLVBOPool::releaseName(GLuint name)
LLVertexBuffer::sGLCount--;
}
const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms
class LLGLSyncFence : public LLGLFence
{
public:
#ifdef GL_ARB_sync
GLsync mSync;
#endif
LLGLSyncFence()
{
#ifdef GL_ARB_sync
mSync = 0;
#endif
}
virtual ~LLGLSyncFence()
{
#ifdef GL_ARB_sync
if (mSync)
{
glDeleteSync(mSync);
}
#endif
}
void placeFence()
{
#ifdef GL_ARB_sync
if (mSync)
{
glDeleteSync(mSync);
}
mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
#endif
}
void wait()
{
#ifdef GL_ARB_sync
if (mSync)
{
while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
{ //track the number of times we've waited here
static S32 waits = 0;
waits++;
}
}
#endif
}
};
S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
{
@@ -334,6 +388,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
idx);
stop_glerror();
placeFence();
}
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
@@ -365,6 +420,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
((U16*) getIndicesPointer()) + indices_offset);
stop_glerror();
placeFence();
}
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
@@ -390,6 +446,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
stop_glerror();
glDrawArrays(sGLMode[mode], first, count);
stop_glerror();
placeFence();
}
//static
@@ -470,7 +527,8 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage, bool strided) :
mResized(FALSE),
mDynamicSize(FALSE),
mIsStrided(strided),
mStride(0)
mStride(0),
mFence(NULL)
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
if (!sEnableVBOs)
@@ -570,9 +628,40 @@ LLVertexBuffer::~LLVertexBuffer()
destroyGLIndices();
sCount--;
if (mFence)
{
delete mFence;
}
mFence = NULL;
llassert_always(!mMappedData && !mMappedIndexData) ;
};
void LLVertexBuffer::placeFence() const
{
/*if (!mFence && useVBOs())
{
if (gGLManager.mHasSync)
{
mFence = new LLGLSyncFence();
}
}
if (mFence)
{
mFence->placeFence();
}*/
}
void LLVertexBuffer::waitFence() const
{
/*if (mFence)
{
mFence->wait();
}*/
}
//----------------------------------------------------------------------------
void LLVertexBuffer::genBuffer()
@@ -1152,7 +1241,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index)
void LLVertexBuffer::unmapBuffer(S32 type)
{
LLMemType mt(LLMemType::MTYPE_VERTEX_DATA);
if (!useVBOs())
if (!useVBOs() || type == -2)
{
return ; //nothing to unmap
}
@@ -1605,7 +1694,14 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
}
if (data_mask & MAP_VERTEX)
{
glVertexPointer(3,GL_FLOAT, getStride(TYPE_VERTEX), (void*)(base + 0));
if (data_mask & MAP_TEXTURE_INDEX)
{
glVertexPointer(4,GL_FLOAT, getStride(TYPE_VERTEX), (void*)(base + 0));
}
else
{
glVertexPointer(3,GL_FLOAT, getStride(TYPE_VERTEX), (void*)(base + 0));
}
}
llglassertok();

View File

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

View File

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

View File

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

View File

@@ -77,11 +77,6 @@ S32 MENU_BAR_WIDTH = 0;
/// Local function declarations, constants, enums, and typedefs
///============================================================================
const std::string SEPARATOR_NAME("separator");
const std::string TEAROFF_SEPARATOR_LABEL( "~~~~~~~~~~~" );
const std::string SEPARATOR_LABEL( "-----------" );
const std::string VERTICAL_SEPARATOR_LABEL( "|" );
const S32 LABEL_BOTTOM_PAD_PIXELS = 2;
const U32 LEFT_PAD_PIXELS = 3;
@@ -101,7 +96,12 @@ const U32 SEPARATOR_HEIGHT_PIXELS = 8;
const S32 TEAROFF_SEPARATOR_HEIGHT_PIXELS = 10;
const S32 MENU_ITEM_PADDING = 4;
const std::string BOOLEAN_TRUE_PREFIX( "\xe2\x9c\x93" ); // U+2714 -- MC
const std::string SEPARATOR_NAME("separator");
const std::string SEPARATOR_LABEL( "-----------" );
const std::string VERTICAL_SEPARATOR_LABEL( "|" );
const std::string TEAROFF_SEPARATOR_LABEL( "~~~~~~~~~~~" );
const std::string BOOLEAN_TRUE_PREFIX( "\xE2\x9C\x94" ); // U+2714 HEAVY CHECK MARK
const std::string BRANCH_SUFFIX( "\xE2\x96\xB6" ); // U+25B6 BLACK RIGHT-POINTING TRIANGLE
const std::string ARROW_UP ("^^^^^^^");
const std::string ARROW_DOWN("vvvvvvv");

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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