Skip to content
Snippets Groups Projects
Commit 2a61d908 authored by Xiaohong Bao's avatar Xiaohong Bao
Browse files

Merge

parents e32d1cf7 b5c834c6
No related branches found
No related tags found
No related merge requests found
Showing
with 2752 additions and 127 deletions
......@@ -52,6 +52,7 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
345b17e7cf630db77e840b4fe3451bd476d750a3 76f586a8e22b
0000000000000000000000000000000000000000 76f586a8e22b
54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f 2.5.0-beta2
b542f8134a2bb5dd054ff4e509a44b2ee463b1bf nat-eventapi2-base
7076e22f9f43f479a4ea75eac447a36364bead5a DRTVWR-5_2.2.0-beta1
9822eb3e25f7fe0c28ffd8aba45c507caa383cbc DRTVWR-3_2.2.0-beta2
b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3
......@@ -70,6 +71,7 @@ b723921b5c711bd24dbe77dc76ef488b544dac78 DRTVWR-34_2.5.0-beta3
b723921b5c711bd24dbe77dc76ef488b544dac78 2.5.0-release
b723921b5c711bd24dbe77dc76ef488b544dac78 DRTVWR-31_2.5.0-release
92e58e51776a4f8c29069b1a62ff21454d2085f0 2.6.0-start
3178e311da3a8739a85363665006ea3c4610cad4 dons-headless-hackathon-work
63a6aedfce785a6c760377bf685b2dae616797d2 2.5.1-start
4dede9ae1ec74d41f6887719f6f1de7340d8578d 2.5.1-release
4dede9ae1ec74d41f6887719f6f1de7340d8578d DRTVWR-37_2.5.1-release
......
......@@ -66,7 +66,7 @@ viewer-pre-release.viewer_channel = "Second Life Release"
viewer-pre-release.login_channel = "Second Life Release"
viewer-pre-release.build_debug_release_separately = true
viewer-pre-release.build_viewer_update_version_manager = true
viewer-pre-release.release-viewer.jira = DRTVWR-39
viewer-pre-release.release-viewer.jira = DRTVWR-42
# =======================================
# brad
# ========================================
......
......@@ -404,7 +404,7 @@
<key>hash</key>
<string>61ead113e6479452e6b690c84b4e9d30</string>
<key>url</key>
<string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/fmod-3.75-darwin-20110222.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmod-private/rev/221852/arch/Darwin/installer/fmod-3.75-darwin-20110222.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
......@@ -416,7 +416,7 @@
<key>hash</key>
<string>0c61d643db54d2e5999be8254569d8b3</string>
<key>url</key>
<string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/fmod-3.75-linux-20110223.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmod-private/rev/221852/arch/Linux/installer/fmod-3.75-linux-20110223.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
......@@ -428,7 +428,7 @@
<key>hash</key>
<string>d9a9a6ad86895353bcd63374a4c1a91d</string>
<key>url</key>
<string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/fmod-3.75-windows-20110222.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmod-private/rev/221852/arch/CYGWIN/installer/fmod-3.75-windows-20110222.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
......@@ -920,7 +920,7 @@
<key>hash</key>
<string>d91e1f483209cd3eba04135c6a59e829</string>
<key>url</key>
<string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/kdu-6.4.1-darwin-20110218.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-kdu-private/rev/221672/arch/Darwin/installer/kdu-6.4.1-darwin-20110218.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
......@@ -932,7 +932,7 @@
<key>hash</key>
<string>fbf8a4f78dff986d7c16b3a0437e033e</string>
<key>url</key>
<string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/kdu-6.4.1-linux-20110311.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-kdu-private/rev/223538/arch/Linux/installer/kdu-6.4.1-linux-20110311.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
......@@ -944,7 +944,7 @@
<key>hash</key>
<string>6cd9f36465ef73a3df34bf2b3bba2ced</string>
<key>url</key>
<string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/kdu-6.4.1-windows-20110218.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-kdu-private/rev/221672/arch/CYGWIN/installer/kdu-6.4.1-windows-20110218.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
......
......@@ -63,6 +63,7 @@ set(llcommon_SOURCE_FILES
llformat.cpp
llframetimer.cpp
llheartbeat.cpp
llinstancetracker.cpp
llliveappconfig.cpp
lllivefile.cpp
lllog.cpp
......@@ -314,6 +315,7 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
# *TODO - reenable these once tcmalloc libs no longer break the build.
#ADD_BUILD_TEST(llallocator llcommon)
......
This diff is collapsed.
This diff is collapsed.
......@@ -588,3 +588,16 @@ void LLReqID::stamp(LLSD& response) const
}
response["reqid"] = mReqid;
}
bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey)
{
// Copy 'reply' to modify it.
LLSD newreply(reply);
// Get the ["reqid"] element from request
LLReqID reqID(request);
// and copy it to 'newreply'.
reqID.stamp(newreply);
// Send reply on LLEventPump named in request[replyKey]. Don't forget to
// send the modified 'newreply' instead of the original 'reply'.
return LLEventPumps::instance().obtain(request[replyKey]).post(newreply);
}
......@@ -691,6 +691,20 @@ class LL_COMMON_API LLReqID
LLSD mReqid;
};
/**
* Conventionally send a reply to a request event.
*
* @a reply is the LLSD reply event to send
* @a request is the corresponding LLSD request event
* @a replyKey is the key in the @a request event, conventionally ["reply"],
* whose value is the name of the LLEventPump on which to send the reply.
*
* Before sending the reply event, sendReply() copies the ["reqid"] item from
* the request to the reply.
*/
LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request,
const std::string& replyKey="reply");
/**
* Base class for LLListenerWrapper. See visit_and_connect() and llwrap(). We
* provide virtual @c accept_xxx() methods, customization points allowing a
......
......@@ -32,6 +32,17 @@
// external library headers
// other Linden headers
// llinstancetracker.h is presently header-only. This file exists only because our CMake
// test macro ADD_BUILD_TEST requires it.
int dummy = 0;
//static
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
{
static std::map<std::string, void *> instances;
std::string k = info.name();
if(instances.find(k) == instances.end())
{
instances[k] = NULL;
}
return instances[k];
}
......@@ -37,14 +37,21 @@
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/indirect_iterator.hpp>
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
/// @NOTE: see explicit specialization below for default KEY==T* case
template<typename T, typename KEY = T*>
class LLInstanceTracker : boost::noncopyable
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:
......@@ -99,25 +106,26 @@ class LLInstanceTracker : boost::noncopyable
static InstanceMap& getMap_()
{
if (! sInstances)
void * & instances = getInstances(typeid(MyT));
if (! instances)
{
sInstances = new InstanceMap;
instances = new InstanceMap;
}
return *sInstances;
return * static_cast<InstanceMap*>(instances);
}
private:
KEY mKey;
static InstanceMap* sInstances;
};
/// explicit specialization for default case where KEY is T*
/// use a simple std::set<T*>
template<typename T>
class LLInstanceTracker<T, T*>
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;
......@@ -172,19 +180,17 @@ class LLInstanceTracker<T, T*>
static InstanceSet& getSet_()
{
if (! sInstances)
void * & instances = getInstances(typeid(MyT));
if (! instances)
{
sInstances = new InstanceSet;
instances = new InstanceSet;
}
return *sInstances;
return * static_cast<InstanceSet *>(instances);
}
static InstanceSet* sInstances;
static S32 sIterationNestDepth;
};
template <typename T, typename KEY> typename LLInstanceTracker<T, KEY>::InstanceMap* LLInstanceTracker<T, KEY>::sInstances = NULL;
template <typename T> typename LLInstanceTracker<T, T*>::InstanceSet* LLInstanceTracker<T, T*>::sInstances = NULL;
template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0;
#endif
......@@ -41,6 +41,7 @@
#include "llsdserialize.h"
#include "stringize.h"
#include "is_approx_equal_fraction.h"
#include <map>
#include <set>
......@@ -571,7 +572,7 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
}
bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
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
......@@ -588,6 +589,20 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
// 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==() */ \
......@@ -596,10 +611,6 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
COMPARE_SCALAR(Boolean);
COMPARE_SCALAR(Integer);
// The usual caveats about comparing floating-point numbers apply. This is
// only useful when we expect identical bit representation for a given
// Real value, e.g. for integer-valued Reals.
COMPARE_SCALAR(Real);
COMPARE_SCALAR(String);
COMPARE_SCALAR(UUID);
COMPARE_SCALAR(Date);
......@@ -617,7 +628,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
for ( ; lai != laend && rai != raend; ++lai, ++rai)
{
// If any one array element is unequal, the arrays are unequal.
if (! llsd_equals(*lai, *rai))
if (! llsd_equals(*lai, *rai, bits))
return false;
}
// Here we've reached the end of one or the other array. They're equal
......@@ -644,7 +655,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
if (rhskeys.erase(lmi->first) != 1)
return false;
// Both maps have the current key. Compare values.
if (! llsd_equals(lmi->second, rhs[lmi->first]))
if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
return false;
}
// We've now established that all the lhs keys have equal values in
......@@ -657,7 +668,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
// 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 << "): "
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
"unknown type " << lhs.type() << LL_ENDL;
return false; // pacify the compiler
}
......
......@@ -123,8 +123,10 @@ LL_COMMON_API BOOL compare_llsd_with_template(
*/
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
/// Deep equality
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs);
/// 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.
......@@ -138,4 +140,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
This diff is collapsed.
......@@ -57,9 +57,12 @@
BOOL gDebugSession = FALSE;
BOOL gDebugGL = FALSE;
BOOL gClothRipple = FALSE;
BOOL gNoRender = FALSE;
BOOL gHeadlessClient = FALSE;
BOOL gGLActive = FALSE;
static const std::string HEADLESS_VENDOR_STRING("Linden Lab");
static const std::string HEADLESS_RENDERER_STRING("Headless");
static const std::string HEADLESS_VERSION_STRING("1.0");
std::ofstream gFailLog;
......@@ -538,9 +541,19 @@ void LLGLManager::setToDebugGPU()
void LLGLManager::getGLInfo(LLSD& info)
{
info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER));
info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION));
if (gHeadlessClient)
{
info["GLInfo"]["GLVendor"] = HEADLESS_VENDOR_STRING;
info["GLInfo"]["GLRenderer"] = HEADLESS_RENDERER_STRING;
info["GLInfo"]["GLVersion"] = HEADLESS_VERSION_STRING;
return;
}
else
{
info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER));
info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION));
}
#if !LL_MESA_HEADLESS
std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts);
......@@ -556,14 +569,22 @@ void LLGLManager::getGLInfo(LLSD& info)
std::string LLGLManager::getGLInfoString()
{
std::string info_str;
std::string all_exts, line;
info_str += std::string("GL_VENDOR ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n");
info_str += std::string("GL_RENDERER ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n");
info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n");
if (gHeadlessClient)
{
info_str += std::string("GL_VENDOR ") + HEADLESS_VENDOR_STRING + std::string("\n");
info_str += std::string("GL_RENDERER ") + HEADLESS_RENDERER_STRING + std::string("\n");
info_str += std::string("GL_VERSION ") + HEADLESS_VERSION_STRING + std::string("\n");
}
else
{
info_str += std::string("GL_VENDOR ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n");
info_str += std::string("GL_RENDERER ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n");
info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n");
}
#if !LL_MESA_HEADLESS
all_exts = (const char *)gGLHExts.mSysExts;
std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts));
LLStringUtil::replaceChar(all_exts, ' ', '\n');
info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n");
#endif
......@@ -573,15 +594,21 @@ std::string LLGLManager::getGLInfoString()
void LLGLManager::printGLInfoString()
{
std::string info_str;
std::string all_exts, line;
LL_INFOS("RenderInit") << "GL_VENDOR: " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
LL_INFOS("RenderInit") << "GL_RENDERER: " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
LL_INFOS("RenderInit") << "GL_VERSION: " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL;
if (gHeadlessClient)
{
LL_INFOS("RenderInit") << "GL_VENDOR: " << HEADLESS_VENDOR_STRING << LL_ENDL;
LL_INFOS("RenderInit") << "GL_RENDERER: " << HEADLESS_RENDERER_STRING << LL_ENDL;
LL_INFOS("RenderInit") << "GL_VERSION: " << HEADLESS_VERSION_STRING << LL_ENDL;
}
else
{
LL_INFOS("RenderInit") << "GL_VENDOR: " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
LL_INFOS("RenderInit") << "GL_RENDERER: " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
LL_INFOS("RenderInit") << "GL_VERSION: " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL;
}
#if !LL_MESA_HEADLESS
all_exts = std::string(gGLHExts.mSysExts);
std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts));
LLStringUtil::replaceChar(all_exts, ' ', '\n');
LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL;
#endif
......@@ -590,7 +617,14 @@ void LLGLManager::printGLInfoString()
std::string LLGLManager::getRawGLString()
{
std::string gl_string;
gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER));
if (gHeadlessClient)
{
gl_string = HEADLESS_VENDOR_STRING + " " + HEADLESS_RENDERER_STRING;
}
else
{
gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER));
}
return gl_string;
}
......@@ -614,47 +648,47 @@ void LLGLManager::initExtensions()
mHasMultitexture = TRUE;
# else
mHasMultitexture = FALSE;
# endif
# endif // GL_ARB_multitexture
# ifdef GL_ARB_texture_env_combine
mHasARBEnvCombine = TRUE;
# else
mHasARBEnvCombine = FALSE;
# endif
# endif // GL_ARB_texture_env_combine
# ifdef GL_ARB_texture_compression
mHasCompressedTextures = TRUE;
# else
mHasCompressedTextures = FALSE;
# endif
# endif // GL_ARB_texture_compression
# ifdef GL_ARB_vertex_buffer_object
mHasVertexBufferObject = TRUE;
# else
mHasVertexBufferObject = FALSE;
# endif
# endif // GL_ARB_vertex_buffer_object
# ifdef GL_EXT_framebuffer_object
mHasFramebufferObject = TRUE;
# else
mHasFramebufferObject = FALSE;
# endif
# endif // GL_EXT_framebuffer_object
# ifdef GL_EXT_framebuffer_multisample
mHasFramebufferMultisample = TRUE;
# else
mHasFramebufferMultisample = FALSE;
# endif
# endif // GL_EXT_framebuffer_multisample
# ifdef GL_ARB_draw_buffers
mHasDrawBuffers = TRUE;
#else
mHasDrawBuffers = FALSE;
# endif
# endif // GL_ARB_draw_buffers
# if defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
mHasDepthClamp = TRUE;
#else
mHasDepthClamp = FALSE;
#endif
#endif // defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
# if GL_EXT_blend_func_separate
mHasBlendFuncSeparate = TRUE;
#else
mHasBlendFuncSeparate = FALSE;
# endif
# endif // GL_EXT_blend_func_separate
mHasMipMapGeneration = FALSE;
mHasSeparateSpecularColor = FALSE;
mHasAnisotropic = FALSE;
......@@ -1145,7 +1179,7 @@ void assert_glerror()
}
}
if (!gNoRender && gDebugGL)
if (gDebugGL)
{
do_assert_glerror();
}
......
......@@ -415,7 +415,7 @@ void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
extern BOOL gClothRipple;
extern BOOL gNoRender;
extern BOOL gHeadlessClient;
extern BOOL gGLActive;
#endif // LL_LLGL_H
......@@ -967,12 +967,14 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
}
if (mTexName == 0)
{
llwarns << "Setting subimage on image without GL texture" << llendl;
// *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18
//llwarns << "Setting subimage on image without GL texture" << llendl;
return FALSE;
}
if (datap == NULL)
{
llwarns << "Setting subimage on image with NULL datap" << llendl;
// *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18
//llwarns << "Setting subimage on image with NULL datap" << llendl;
return FALSE;
}
......@@ -1100,6 +1102,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
//the texture is assiciate with some image by calling glTexImage outside LLImageGL
BOOL LLImageGL::createGLTexture()
{
if (gHeadlessClient) return FALSE;
if (gGLManager.mIsDisabled)
{
llwarns << "Trying to create a texture while GL is disabled!" << llendl;
......@@ -1128,6 +1131,7 @@ BOOL LLImageGL::createGLTexture()
BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
{
if (gHeadlessClient) return FALSE;
if (gGLManager.mIsDisabled)
{
llwarns << "Trying to create a texture while GL is disabled!" << llendl;
......
......@@ -60,6 +60,11 @@ LLFloaterRegListener::LLFloaterRegListener():
"Ask to toggle the state of the floater specified in [\"name\"]",
&LLFloaterRegListener::toggleInstance,
requiredName);
add("instanceVisible",
"Return on [\"reply\"] an event whose [\"visible\"] indicates the visibility "
"of the floater specified in [\"name\"]",
&LLFloaterRegListener::instanceVisible,
requiredName);
LLSD requiredNameButton;
requiredNameButton["name"] = LLSD();
requiredNameButton["button"] = LLSD();
......@@ -71,9 +76,7 @@ LLFloaterRegListener::LLFloaterRegListener():
void LLFloaterRegListener::getBuildMap(const LLSD& event) const
{
// Honor the "reqid" convention by echoing event["reqid"] in our reply packet.
LLReqID reqID(event);
LLSD reply(reqID.makeResponse());
LLSD reply;
// Build an LLSD map that mirrors sBuildMap. Since we have no good way to
// represent a C++ callable in LLSD, the only part of BuildData we can
// store is the filename. For each LLSD map entry, it would be more
......@@ -86,7 +89,7 @@ void LLFloaterRegListener::getBuildMap(const LLSD& event) const
reply[mi->first] = mi->second.mFile;
}
// Send the reply to the LLEventPump named in event["reply"].
LLEventPumps::instance().obtain(event["reply"]).post(reply);
sendReply(reply, event);
}
void LLFloaterRegListener::showInstance(const LLSD& event) const
......@@ -104,6 +107,12 @@ void LLFloaterRegListener::toggleInstance(const LLSD& event) const
LLFloaterReg::toggleInstance(event["name"], event["key"]);
}
void LLFloaterRegListener::instanceVisible(const LLSD& event) const
{
sendReply(LLSDMap("visible", LLFloaterReg::instanceVisible(event["name"], event["key"])),
event);
}
void LLFloaterRegListener::clickButton(const LLSD& event) const
{
// If the caller requests a reply, build the reply.
......
......@@ -47,6 +47,7 @@ class LLFloaterRegListener: public LLEventAPI
void showInstance(const LLSD& event) const;
void hideInstance(const LLSD& event) const;
void toggleInstance(const LLSD& event) const;
void instanceVisible(const LLSD& event) const;
void clickButton(const LLSD& event) const;
};
......
......@@ -61,6 +61,8 @@
// for XUIParse
#include "llquaternion.h"
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/algorithm/string/finder.hpp>
//
// Globals
......@@ -2020,6 +2022,53 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect, FALSE );
}
LLView* LLUI::resolvePath(LLView* context, const std::string& path)
{
// Nothing about resolvePath() should require non-const LLView*. If caller
// wants non-const, call the const flavor and then cast away const-ness.
return const_cast<LLView*>(resolvePath(const_cast<const LLView*>(context), path));
}
const LLView* LLUI::resolvePath(const LLView* context, const std::string& path)
{
// Create an iterator over slash-separated parts of 'path'. Dereferencing
// this iterator returns an iterator_range over the substring. Unlike
// LLStringUtil::getTokens(), this split_iterator doesn't combine adjacent
// delimiters: leading/trailing slash produces an empty substring, double
// slash produces an empty substring. That's what we need.
boost::split_iterator<std::string::const_iterator> ti(path, boost::first_finder("/")), tend;
if (ti == tend)
{
// 'path' is completely empty, no navigation
return context;
}
// leading / means "start at root"
if (ti->empty())
{
context = getRootView();
++ti;
}
bool recurse = false;
for (; ti != tend && context; ++ti)
{
if (ti->empty())
{
recurse = true;
}
else
{
std::string part(ti->begin(), ti->end());
context = context->findChildView(part, recurse);
recurse = false;
}
}
return context;
}
// LLLocalClipRect and LLScreenClipRect moved to lllocalcliprect.h/cpp
......
......@@ -185,6 +185,33 @@ class LLUI
//helper functions (should probably move free standing rendering helper functions here)
static LLView* getRootView() { return sRootView; }
static void setRootView(LLView* view) { sRootView = view; }
/**
* Walk the LLView tree to resolve a path
* Paths can be discovered using Develop > XUI > Show XUI Paths
*
* A leading "/" indicates the root of the tree is the starting
* position of the search, (otherwise the context node is used)
*
* Adjacent "//" mean that the next level of the search is done
* recursively ("descendant" rather than "child").
*
* Return values: If no match is found, NULL is returned,
* otherwise the matching LLView* is returned.
*
* Examples:
*
* "/" -> return the root view
* "/foo" -> find "foo" as a direct child of the root
* "foo" -> find "foo" as a direct child of the context node
* "//foo" -> find the first "foo" child anywhere in the tree
* "/foo/bar" -> find "foo" as direct child of the root, and
* "bar" as a direct child of "foo"
* "//foo//bar/baz" -> find the first "foo" anywhere in the
* tree, the first "bar" anywhere under it, and "baz"
* as a direct child of that
*/
static const LLView* resolvePath(const LLView* context, const std::string& path);
static LLView* resolvePath(LLView* context, const std::string& path);
static std::string locateSkin(const std::string& filename);
static void setMousePositionScreen(S32 x, S32 y);
static void getMousePositionScreen(S32 *x, S32 *y);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment