Merge remote-tracking branch 'shyotl/master'
This commit is contained in:
@@ -319,6 +319,7 @@ set(viewer_SOURCE_FILES
|
||||
llmapresponders.cpp
|
||||
llmarketplacefunctions.cpp
|
||||
llmarketplacenotifications.cpp
|
||||
llmaterialmgr.cpp
|
||||
llmediactrl.cpp
|
||||
llmediadataclient.cpp
|
||||
llmediaremotectrl.cpp
|
||||
@@ -832,6 +833,7 @@ set(viewer_HEADER_FILES
|
||||
llmapresponders.h
|
||||
llmarketplacefunctions.h
|
||||
llmarketplacenotifications.h
|
||||
llmaterialmgr.h
|
||||
llmediactrl.h
|
||||
llmediadataclient.h
|
||||
llmediaremotectrl.h
|
||||
|
||||
@@ -1072,6 +1072,12 @@ bool LLFace::canRenderAsMask()
|
||||
return false;
|
||||
}
|
||||
|
||||
LLMaterial* mat = te->getMaterialParams();
|
||||
if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static const LLCachedControl<bool> use_rmse_auto_mask("SHUseRMSEAutoMask",false);
|
||||
static const LLCachedControl<F32> auto_mask_max_rmse("SHAutoMaskMaxRMSE",.09f);
|
||||
if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha
|
||||
|
||||
793
indra/newview/llmaterialmgr.cpp
Normal file
793
indra/newview/llmaterialmgr.cpp
Normal file
@@ -0,0 +1,793 @@
|
||||
/**
|
||||
* @file llmaterialmgr.cpp
|
||||
* @brief Material manager
|
||||
*
|
||||
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2013, 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 "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llsdserialize.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llcallbacklist.h"
|
||||
#include "llmaterialmgr.h"
|
||||
#include "llviewerobject.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llworld.h"
|
||||
|
||||
/**
|
||||
* Materials cap parameters
|
||||
*/
|
||||
|
||||
#define MATERIALS_CAPABILITY_NAME "RenderMaterials"
|
||||
|
||||
#define MATERIALS_CAP_ZIP_FIELD "Zipped"
|
||||
|
||||
#define MATERIALS_CAP_FULL_PER_FACE_FIELD "FullMaterialsPerFace"
|
||||
#define MATERIALS_CAP_FACE_FIELD "Face"
|
||||
#define MATERIALS_CAP_MATERIAL_FIELD "Material"
|
||||
#define MATERIALS_CAP_OBJECT_ID_FIELD "ID"
|
||||
#define MATERIALS_CAP_MATERIAL_ID_FIELD "MaterialID"
|
||||
|
||||
#define MATERIALS_GET_MAX_ENTRIES 50
|
||||
#define MATERIALS_GET_TIMEOUT (60.f * 20)
|
||||
#define MATERIALS_POST_MAX_ENTRIES 50
|
||||
#define MATERIALS_POST_TIMEOUT (60.f * 5)
|
||||
#define MATERIALS_PUT_THROTTLE_SECS 1.f
|
||||
#define MATERIALS_PUT_MAX_ENTRIES 50
|
||||
|
||||
/**
|
||||
* LLMaterialsResponder helper class
|
||||
*/
|
||||
|
||||
extern AIHTTPTimeoutPolicy materialsResponder_timeout;
|
||||
|
||||
class LLMaterialsResponder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
typedef boost::function<void (bool, const LLSD&)> CallbackFunction;
|
||||
|
||||
LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback);
|
||||
virtual ~LLMaterialsResponder();
|
||||
|
||||
virtual void result(const LLSD& pContent);
|
||||
virtual void error(U32 pStatus, const std::string& pReason);
|
||||
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return materialsResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "LLMaterialsResponder"; }
|
||||
private:
|
||||
std::string mMethod;
|
||||
std::string mCapabilityURL;
|
||||
CallbackFunction mCallback;
|
||||
};
|
||||
|
||||
LLMaterialsResponder::LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback)
|
||||
: LLHTTPClient::ResponderWithResult()
|
||||
, mMethod(pMethod)
|
||||
, mCapabilityURL(pCapabilityURL)
|
||||
, mCallback(pCallback)
|
||||
{
|
||||
}
|
||||
|
||||
LLMaterialsResponder::~LLMaterialsResponder()
|
||||
{
|
||||
}
|
||||
|
||||
void LLMaterialsResponder::result(const LLSD& pContent)
|
||||
{
|
||||
LL_DEBUGS("Materials") << LL_ENDL;
|
||||
mCallback(true, pContent);
|
||||
}
|
||||
|
||||
void LLMaterialsResponder::error(U32 pStatus, const std::string& pReason)
|
||||
{
|
||||
LL_WARNS("Materials")
|
||||
<< "\n--------------------------------------------------------------------------\n"
|
||||
<< mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME
|
||||
<< "'\n with url '" << mCapabilityURL << "' because " << pReason
|
||||
<< "\n--------------------------------------------------------------------------"
|
||||
<< LL_ENDL;
|
||||
|
||||
LLSD emptyResult;
|
||||
mCallback(false, emptyResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* LLMaterialMgr class
|
||||
*/
|
||||
|
||||
LLMaterialMgr::LLMaterialMgr()
|
||||
{
|
||||
mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(LLMaterialID::null, LLMaterialPtr(NULL)));
|
||||
gIdleCallbacks.addFunction(&LLMaterialMgr::onIdle, NULL);
|
||||
LLWorld::instance().setRegionRemovedCallback(boost::bind(&LLMaterialMgr::onRegionRemoved, this, _1));
|
||||
}
|
||||
|
||||
LLMaterialMgr::~LLMaterialMgr()
|
||||
{
|
||||
gIdleCallbacks.deleteFunction(&LLMaterialMgr::onIdle, NULL);
|
||||
}
|
||||
|
||||
bool LLMaterialMgr::isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const
|
||||
{
|
||||
get_pending_map_t::const_iterator itPending = mGetPending.find(pending_material_t(region_id, material_id));
|
||||
return (mGetPending.end() != itPending) && (LLFrameTimer::getTotalSeconds() < itPending->second + MATERIALS_POST_TIMEOUT);
|
||||
}
|
||||
|
||||
void LLMaterialMgr::markGetPending(const LLUUID& region_id, const LLMaterialID& material_id)
|
||||
{
|
||||
get_pending_map_t::iterator itPending = mGetPending.find(pending_material_t(region_id, material_id));
|
||||
if (mGetPending.end() == itPending)
|
||||
{
|
||||
mGetPending.insert(std::pair<pending_material_t, F64>(pending_material_t(region_id, material_id), LLFrameTimer::getTotalSeconds()));
|
||||
}
|
||||
else
|
||||
{
|
||||
itPending->second = LLFrameTimer::getTotalSeconds();
|
||||
}
|
||||
}
|
||||
|
||||
const LLMaterialPtr LLMaterialMgr::get(const LLUUID& region_id, const LLMaterialID& material_id)
|
||||
{
|
||||
LL_DEBUGS("Materials") << "region " << region_id << " material id " << material_id << LL_ENDL;
|
||||
LLMaterialPtr material;
|
||||
material_map_t::const_iterator itMaterial = mMaterials.find(material_id);
|
||||
if (mMaterials.end() != itMaterial)
|
||||
{
|
||||
material = itMaterial->second;
|
||||
LL_DEBUGS("Materials") << " found material " << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isGetPending(region_id, material_id))
|
||||
{
|
||||
LL_DEBUGS("Materials") << " material pending " << material_id << LL_ENDL;
|
||||
get_queue_t::iterator itQueue = mGetQueue.find(region_id);
|
||||
if (mGetQueue.end() == itQueue)
|
||||
{
|
||||
LL_DEBUGS("Materials") << "mGetQueue add region " << region_id << " pending " << material_id << LL_ENDL;
|
||||
std::pair<get_queue_t::iterator, bool> ret = mGetQueue.insert(std::pair<LLUUID, material_queue_t>(region_id, material_queue_t()));
|
||||
itQueue = ret.first;
|
||||
}
|
||||
itQueue->second.insert(material_id);
|
||||
markGetPending(region_id, material_id);
|
||||
}
|
||||
LL_DEBUGS("Materials") << " returning empty material " << LL_ENDL;
|
||||
material = LLMaterialPtr();
|
||||
}
|
||||
return material;
|
||||
}
|
||||
|
||||
boost::signals2::connection LLMaterialMgr::get(const LLUUID& region_id, const LLMaterialID& material_id, LLMaterialMgr::get_callback_t::slot_type cb)
|
||||
{
|
||||
boost::signals2::connection connection;
|
||||
|
||||
material_map_t::const_iterator itMaterial = mMaterials.find(material_id);
|
||||
if (itMaterial != mMaterials.end())
|
||||
{
|
||||
LL_DEBUGS("Materials") << "region " << region_id << " found materialid " << material_id << LL_ENDL;
|
||||
get_callback_t signal;
|
||||
signal.connect(cb);
|
||||
signal(material_id, itMaterial->second);
|
||||
connection = boost::signals2::connection();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isGetPending(region_id, material_id))
|
||||
{
|
||||
get_queue_t::iterator itQueue = mGetQueue.find(region_id);
|
||||
if (mGetQueue.end() == itQueue)
|
||||
{
|
||||
LL_DEBUGS("Materials") << "mGetQueue inserting region "<<region_id << LL_ENDL;
|
||||
std::pair<get_queue_t::iterator, bool> ret = mGetQueue.insert(std::pair<LLUUID, material_queue_t>(region_id, material_queue_t()));
|
||||
itQueue = ret.first;
|
||||
}
|
||||
LL_DEBUGS("Materials") << "adding material id " << material_id << LL_ENDL;
|
||||
itQueue->second.insert(material_id);
|
||||
markGetPending(region_id, material_id);
|
||||
}
|
||||
|
||||
get_callback_map_t::iterator itCallback = mGetCallbacks.find(material_id);
|
||||
if (itCallback == mGetCallbacks.end())
|
||||
{
|
||||
std::pair<get_callback_map_t::iterator, bool> ret = mGetCallbacks.insert(std::pair<LLMaterialID, get_callback_t*>(material_id, new get_callback_t()));
|
||||
itCallback = ret.first;
|
||||
}
|
||||
connection = itCallback->second->connect(cb);;
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
boost::signals2::connection LLMaterialMgr::getTE(const LLUUID& region_id, const LLMaterialID& material_id, U32 te, LLMaterialMgr::get_callback_te_t::slot_type cb)
|
||||
{
|
||||
boost::signals2::connection connection;
|
||||
|
||||
material_map_t::const_iterator itMaterial = mMaterials.find(material_id);
|
||||
if (itMaterial != mMaterials.end())
|
||||
{
|
||||
LL_DEBUGS("Materials") << "region " << region_id << " found materialid " << material_id << LL_ENDL;
|
||||
get_callback_te_t signal;
|
||||
signal.connect(cb);
|
||||
signal(material_id, itMaterial->second, te);
|
||||
connection = boost::signals2::connection();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isGetPending(region_id, material_id))
|
||||
{
|
||||
get_queue_t::iterator itQueue = mGetQueue.find(region_id);
|
||||
if (mGetQueue.end() == itQueue)
|
||||
{
|
||||
LL_DEBUGS("Materials") << "mGetQueue inserting region "<<region_id << LL_ENDL;
|
||||
std::pair<get_queue_t::iterator, bool> ret = mGetQueue.insert(std::pair<LLUUID, material_queue_t>(region_id, material_queue_t()));
|
||||
itQueue = ret.first;
|
||||
}
|
||||
LL_DEBUGS("Materials") << "adding material id " << material_id << LL_ENDL;
|
||||
itQueue->second.insert(material_id);
|
||||
markGetPending(region_id, material_id);
|
||||
}
|
||||
|
||||
TEMaterialPair te_mat_pair;
|
||||
te_mat_pair.te = te;
|
||||
te_mat_pair.materialID = material_id;
|
||||
|
||||
get_callback_te_map_t::iterator itCallback = mGetTECallbacks.find(te_mat_pair);
|
||||
if (itCallback == mGetTECallbacks.end())
|
||||
{
|
||||
std::pair<get_callback_te_map_t::iterator, bool> ret = mGetTECallbacks.insert(std::pair<TEMaterialPair, get_callback_te_t*>(te_mat_pair, new get_callback_te_t()));
|
||||
itCallback = ret.first;
|
||||
}
|
||||
connection = itCallback->second->connect(cb);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
bool LLMaterialMgr::isGetAllPending(const LLUUID& region_id) const
|
||||
{
|
||||
getall_pending_map_t::const_iterator itPending = mGetAllPending.find(region_id);
|
||||
return (mGetAllPending.end() != itPending) && (LLFrameTimer::getTotalSeconds() < itPending->second + MATERIALS_GET_TIMEOUT);
|
||||
}
|
||||
|
||||
void LLMaterialMgr::getAll(const LLUUID& region_id)
|
||||
{
|
||||
if (!isGetAllPending(region_id))
|
||||
{
|
||||
LL_DEBUGS("Materials") << "queuing for region " << region_id << LL_ENDL;
|
||||
mGetAllQueue.insert(region_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Materials") << "already pending for region " << region_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
boost::signals2::connection LLMaterialMgr::getAll(const LLUUID& region_id, LLMaterialMgr::getall_callback_t::slot_type cb)
|
||||
{
|
||||
if (!isGetAllPending(region_id))
|
||||
{
|
||||
mGetAllQueue.insert(region_id);
|
||||
}
|
||||
|
||||
getall_callback_map_t::iterator itCallback = mGetAllCallbacks.find(region_id);
|
||||
if (mGetAllCallbacks.end() == itCallback)
|
||||
{
|
||||
std::pair<getall_callback_map_t::iterator, bool> ret = mGetAllCallbacks.insert(std::pair<LLUUID, getall_callback_t*>(region_id, new getall_callback_t()));
|
||||
itCallback = ret.first;
|
||||
}
|
||||
return itCallback->second->connect(cb);;
|
||||
}
|
||||
|
||||
void LLMaterialMgr::put(const LLUUID& object_id, const U8 te, const LLMaterial& material)
|
||||
{
|
||||
put_queue_t::iterator itQueue = mPutQueue.find(object_id);
|
||||
if (mPutQueue.end() == itQueue)
|
||||
{
|
||||
LL_DEBUGS("Materials") << "mPutQueue insert object " << object_id << LL_ENDL;
|
||||
mPutQueue.insert(std::pair<LLUUID, facematerial_map_t>(object_id, facematerial_map_t()));
|
||||
itQueue = mPutQueue.find(object_id);
|
||||
}
|
||||
|
||||
facematerial_map_t::iterator itFace = itQueue->second.find(te);
|
||||
if (itQueue->second.end() == itFace)
|
||||
{
|
||||
itQueue->second.insert(std::pair<U8, LLMaterial>(te, material));
|
||||
}
|
||||
else
|
||||
{
|
||||
itFace->second = material;
|
||||
}
|
||||
}
|
||||
|
||||
void LLMaterialMgr::remove(const LLUUID& object_id, const U8 te)
|
||||
{
|
||||
put(object_id, te, LLMaterial::null);
|
||||
}
|
||||
|
||||
const LLMaterialPtr LLMaterialMgr::setMaterial(const LLUUID& region_id, const LLMaterialID& material_id, const LLSD& material_data)
|
||||
{
|
||||
LL_DEBUGS("Materials") << "region " << region_id << " material id " << material_id << LL_ENDL;
|
||||
material_map_t::const_iterator itMaterial = mMaterials.find(material_id);
|
||||
if (mMaterials.end() == itMaterial)
|
||||
{
|
||||
LL_DEBUGS("Materials") << "new material" << LL_ENDL;
|
||||
LLMaterialPtr newMaterial(new LLMaterial(material_data));
|
||||
std::pair<material_map_t::const_iterator, bool> ret = mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(material_id, newMaterial));
|
||||
itMaterial = ret.first;
|
||||
}
|
||||
|
||||
// we may have cleared our queues on leaving a region before we recv'd our
|
||||
// update for this material...too late now!
|
||||
//
|
||||
if (isGetPending(region_id, material_id))
|
||||
{
|
||||
|
||||
TEMaterialPair te_mat_pair;
|
||||
te_mat_pair.materialID = material_id;
|
||||
|
||||
U32 i = 0;
|
||||
while (i < LLTEContents::MAX_TES)
|
||||
{
|
||||
te_mat_pair.te = i++;
|
||||
get_callback_te_map_t::iterator itCallbackTE = mGetTECallbacks.find(te_mat_pair);
|
||||
if (itCallbackTE != mGetTECallbacks.end())
|
||||
{
|
||||
(*itCallbackTE->second)(material_id, itMaterial->second, te_mat_pair.te);
|
||||
delete itCallbackTE->second;
|
||||
mGetTECallbacks.erase(itCallbackTE);
|
||||
}
|
||||
}
|
||||
|
||||
get_callback_map_t::iterator itCallback = mGetCallbacks.find(material_id);
|
||||
if (itCallback != mGetCallbacks.end())
|
||||
{
|
||||
(*itCallback->second)(material_id, itMaterial->second);
|
||||
|
||||
delete itCallback->second;
|
||||
mGetCallbacks.erase(itCallback);
|
||||
}
|
||||
}
|
||||
|
||||
mGetPending.erase(pending_material_t(region_id, material_id));
|
||||
|
||||
return itMaterial->second;
|
||||
}
|
||||
|
||||
void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUID& region_id)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
// *TODO: is there any kind of error handling we can do here?
|
||||
LL_WARNS("Materials")<< "failed"<<LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
llassert(content.isMap());
|
||||
llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
|
||||
llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
|
||||
|
||||
LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
|
||||
std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
|
||||
std::istringstream content_stream(content_string);
|
||||
|
||||
LLSD response_data;
|
||||
if (!unzip_llsd(response_data, content_stream, content_binary.size()))
|
||||
{
|
||||
LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
llassert(response_data.isArray());
|
||||
LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
|
||||
for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial)
|
||||
{
|
||||
const LLSD& material_data = *itMaterial;
|
||||
llassert(material_data.isMap());
|
||||
|
||||
llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
|
||||
llassert(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].isBinary());
|
||||
LLMaterialID material_id(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].asBinary());
|
||||
|
||||
llassert(material_data.has(MATERIALS_CAP_MATERIAL_FIELD));
|
||||
llassert(material_data[MATERIALS_CAP_MATERIAL_FIELD].isMap());
|
||||
|
||||
setMaterial(region_id, material_id, material_data[MATERIALS_CAP_MATERIAL_FIELD]);
|
||||
}
|
||||
}
|
||||
|
||||
void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LLUUID& region_id)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
// *TODO: is there any kind of error handling we can do here?
|
||||
LL_WARNS("Materials")<< "failed"<<LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
llassert(content.isMap());
|
||||
llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
|
||||
llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
|
||||
|
||||
LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
|
||||
std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
|
||||
std::istringstream content_stream(content_string);
|
||||
|
||||
LLSD response_data;
|
||||
if (!unzip_llsd(response_data, content_stream, content_binary.size()))
|
||||
{
|
||||
LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
get_queue_t::iterator itQueue = mGetQueue.find(region_id);
|
||||
material_map_t materials;
|
||||
|
||||
llassert(response_data.isArray());
|
||||
LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
|
||||
for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial)
|
||||
{
|
||||
const LLSD& material_data = *itMaterial;
|
||||
llassert(material_data.isMap());
|
||||
|
||||
llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
|
||||
llassert(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].isBinary());
|
||||
LLMaterialID material_id(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].asBinary());
|
||||
if (mGetQueue.end() != itQueue)
|
||||
{
|
||||
itQueue->second.erase(material_id);
|
||||
}
|
||||
|
||||
llassert(material_data.has(MATERIALS_CAP_MATERIAL_FIELD));
|
||||
llassert(material_data[MATERIALS_CAP_MATERIAL_FIELD].isMap());
|
||||
LLMaterialPtr material = setMaterial(region_id, material_id, material_data[MATERIALS_CAP_MATERIAL_FIELD]);
|
||||
|
||||
materials[material_id] = material;
|
||||
}
|
||||
|
||||
getall_callback_map_t::iterator itCallback = mGetAllCallbacks.find(region_id);
|
||||
if (itCallback != mGetAllCallbacks.end())
|
||||
{
|
||||
(*itCallback->second)(region_id, materials);
|
||||
|
||||
delete itCallback->second;
|
||||
mGetAllCallbacks.erase(itCallback);
|
||||
}
|
||||
|
||||
if ( (mGetQueue.end() != itQueue) && (itQueue->second.empty()) )
|
||||
{
|
||||
mGetQueue.erase(itQueue);
|
||||
}
|
||||
|
||||
LL_DEBUGS("Materials")<< "recording that getAll has been done for region id " << region_id << LL_ENDL;
|
||||
mGetAllRequested.insert(region_id); // prevents subsequent getAll requests for this region
|
||||
mGetAllPending.erase(region_id); // Invalidates region_id
|
||||
}
|
||||
|
||||
void LLMaterialMgr::onPutResponse(bool success, const LLSD& content)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
// *TODO: is there any kind of error handling we can do here?
|
||||
LL_WARNS("Materials")<< "failed"<<LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
llassert(content.isMap());
|
||||
llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
|
||||
llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
|
||||
|
||||
LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
|
||||
std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
|
||||
std::istringstream content_stream(content_string);
|
||||
|
||||
LLSD response_data;
|
||||
if (!unzip_llsd(response_data, content_stream, content_binary.size()))
|
||||
{
|
||||
LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
llassert(response_data.isArray());
|
||||
LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
|
||||
for (LLSD::array_const_iterator faceIter = response_data.beginArray(); faceIter != response_data.endArray(); ++faceIter)
|
||||
{
|
||||
# ifndef LL_RELEASE_FOR_DOWNLOAD
|
||||
const LLSD& face_data = *faceIter; // conditional to avoid unused variable warning
|
||||
# endif
|
||||
llassert(face_data.isMap());
|
||||
|
||||
llassert(face_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
|
||||
llassert(face_data[MATERIALS_CAP_OBJECT_ID_FIELD].isInteger());
|
||||
// U32 local_id = face_data[MATERIALS_CAP_OBJECT_ID_FIELD].asInteger();
|
||||
|
||||
llassert(face_data.has(MATERIALS_CAP_FACE_FIELD));
|
||||
llassert(face_data[MATERIALS_CAP_FACE_FIELD].isInteger());
|
||||
// S32 te = face_data[MATERIALS_CAP_FACE_FIELD].asInteger();
|
||||
|
||||
llassert(face_data.has(MATERIALS_CAP_MATERIAL_ID_FIELD));
|
||||
llassert(face_data[MATERIALS_CAP_MATERIAL_ID_FIELD].isBinary());
|
||||
// LLMaterialID material_id(face_data[MATERIALS_CAP_MATERIAL_ID_FIELD].asBinary());
|
||||
|
||||
// *TODO: do we really still need to process this?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_MATERIALS_IDLE("Materials");
|
||||
|
||||
void LLMaterialMgr::onIdle(void*)
|
||||
{
|
||||
LLFastTimer t(FTM_MATERIALS_IDLE);
|
||||
|
||||
LLMaterialMgr* instancep = LLMaterialMgr::getInstance();
|
||||
|
||||
if (!instancep->mGetQueue.empty())
|
||||
{
|
||||
instancep->processGetQueue();
|
||||
}
|
||||
|
||||
if (!instancep->mGetAllQueue.empty())
|
||||
{
|
||||
instancep->processGetAllQueue();
|
||||
}
|
||||
|
||||
static LLFrameTimer mPutTimer;
|
||||
if ( (!instancep->mPutQueue.empty()) && (mPutTimer.hasExpired()) )
|
||||
{
|
||||
instancep->processPutQueue();
|
||||
mPutTimer.reset(MATERIALS_PUT_THROTTLE_SECS);
|
||||
}
|
||||
}
|
||||
|
||||
void LLMaterialMgr::processGetQueue()
|
||||
{
|
||||
get_queue_t::iterator loopRegionQueue = mGetQueue.begin();
|
||||
while (mGetQueue.end() != loopRegionQueue)
|
||||
{
|
||||
get_queue_t::iterator itRegionQueue = loopRegionQueue++;
|
||||
|
||||
const LLUUID& region_id = itRegionQueue->first;
|
||||
if (isGetAllPending(region_id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
|
||||
if (!regionp)
|
||||
{
|
||||
LL_WARNS("Materials") << "Unknown region with id " << region_id.asString() << LL_ENDL;
|
||||
mGetQueue.erase(itRegionQueue);
|
||||
continue;
|
||||
}
|
||||
else if (!regionp->capabilitiesReceived())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (mGetAllRequested.end() == mGetAllRequested.find(region_id))
|
||||
{
|
||||
LL_DEBUGS("Materials") << "calling getAll for " << regionp->getName() << LL_ENDL;
|
||||
getAll(region_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
|
||||
if (capURL.empty())
|
||||
{
|
||||
LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
|
||||
<< "' is not defined on region '" << regionp->getName() << "'" << LL_ENDL;
|
||||
mGetQueue.erase(itRegionQueue);
|
||||
continue;
|
||||
}
|
||||
|
||||
LLSD materialsData = LLSD::emptyArray();
|
||||
|
||||
material_queue_t& materials = itRegionQueue->second;
|
||||
material_queue_t::iterator loopMaterial = materials.begin();
|
||||
while ( (materials.end() != loopMaterial) && (materialsData.size() <= MATERIALS_GET_MAX_ENTRIES) )
|
||||
{
|
||||
material_queue_t::iterator itMaterial = loopMaterial++;
|
||||
materialsData.append((*itMaterial).asLLSD());
|
||||
materials.erase(itMaterial);
|
||||
markGetPending(region_id, *itMaterial);
|
||||
}
|
||||
if (materials.empty())
|
||||
{
|
||||
mGetQueue.erase(itRegionQueue);
|
||||
}
|
||||
|
||||
std::string materialString = zip_llsd(materialsData);
|
||||
|
||||
S32 materialSize = materialString.size();
|
||||
if (materialSize <= 0)
|
||||
{
|
||||
LL_ERRS("Materials") << "cannot zip LLSD binary content" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LLSD::Binary materialBinary;
|
||||
materialBinary.resize(materialSize);
|
||||
memcpy(materialBinary.data(), materialString.data(), materialSize);
|
||||
|
||||
LLSD postData = LLSD::emptyMap();
|
||||
postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
|
||||
|
||||
LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id));
|
||||
LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials."
|
||||
<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL;
|
||||
LLHTTPClient::post(capURL, postData, materialsResponder);
|
||||
}
|
||||
}
|
||||
|
||||
void LLMaterialMgr::processGetAllQueue()
|
||||
{
|
||||
getall_queue_t::iterator loopRegion = mGetAllQueue.begin();
|
||||
while (mGetAllQueue.end() != loopRegion)
|
||||
{
|
||||
getall_queue_t::iterator itRegion = loopRegion++;
|
||||
|
||||
const LLUUID& region_id = *itRegion;
|
||||
LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
|
||||
if (regionp == NULL)
|
||||
{
|
||||
LL_WARNS("Materials") << "Unknown region with id " << region_id.asString() << LL_ENDL;
|
||||
clearGetQueues(region_id); // Invalidates region_id
|
||||
continue;
|
||||
}
|
||||
else if (!regionp->capabilitiesReceived())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
|
||||
if (capURL.empty())
|
||||
{
|
||||
LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
|
||||
<< "' is not defined on the current region '" << regionp->getName() << "'" << LL_ENDL;
|
||||
clearGetQueues(region_id); // Invalidates region_id
|
||||
continue;
|
||||
}
|
||||
|
||||
LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL;
|
||||
LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion));
|
||||
LLHTTPClient::get(capURL, materialsResponder);
|
||||
mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));
|
||||
mGetAllQueue.erase(itRegion); // Invalidates region_id
|
||||
}
|
||||
}
|
||||
|
||||
void LLMaterialMgr::processPutQueue()
|
||||
{
|
||||
typedef std::map<const LLViewerRegion*, LLSD> regionput_request_map;
|
||||
regionput_request_map requests;
|
||||
|
||||
put_queue_t::iterator loopQueue = mPutQueue.begin();
|
||||
while (mPutQueue.end() != loopQueue)
|
||||
{
|
||||
put_queue_t::iterator itQueue = loopQueue++;
|
||||
|
||||
const LLUUID& object_id = itQueue->first;
|
||||
const LLViewerObject* objectp = gObjectList.findObject(object_id);
|
||||
if ( (!objectp) || (!objectp->getRegion()) )
|
||||
{
|
||||
LL_WARNS("Materials") << "Object or object region is NULL" << LL_ENDL;
|
||||
|
||||
mPutQueue.erase(itQueue);
|
||||
continue;
|
||||
}
|
||||
|
||||
const LLViewerRegion* regionp = objectp->getRegion();
|
||||
if (!regionp->capabilitiesReceived())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LLSD& facesData = requests[regionp];
|
||||
|
||||
facematerial_map_t& face_map = itQueue->second;
|
||||
facematerial_map_t::iterator itFace = face_map.begin();
|
||||
while ( (face_map.end() != itFace) && (facesData.size() < MATERIALS_GET_MAX_ENTRIES) )
|
||||
{
|
||||
LLSD faceData = LLSD::emptyMap();
|
||||
faceData[MATERIALS_CAP_FACE_FIELD] = static_cast<LLSD::Integer>(itFace->first);
|
||||
faceData[MATERIALS_CAP_OBJECT_ID_FIELD] = static_cast<LLSD::Integer>(objectp->getLocalID());
|
||||
if (!itFace->second.isNull())
|
||||
{
|
||||
faceData[MATERIALS_CAP_MATERIAL_FIELD] = itFace->second.asLLSD();
|
||||
}
|
||||
facesData.append(faceData);
|
||||
face_map.erase(itFace++);
|
||||
}
|
||||
if (face_map.empty())
|
||||
{
|
||||
mPutQueue.erase(itQueue);
|
||||
}
|
||||
}
|
||||
|
||||
for (regionput_request_map::const_iterator itRequest = requests.begin(); itRequest != requests.end(); ++itRequest)
|
||||
{
|
||||
std::string capURL = itRequest->first->getCapability(MATERIALS_CAPABILITY_NAME);
|
||||
if (capURL.empty())
|
||||
{
|
||||
LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
|
||||
<< "' is not defined on region '" << itRequest->first->getName() << "'" << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
LLSD materialsData = LLSD::emptyMap();
|
||||
materialsData[MATERIALS_CAP_FULL_PER_FACE_FIELD] = itRequest->second;
|
||||
|
||||
std::string materialString = zip_llsd(materialsData);
|
||||
|
||||
S32 materialSize = materialString.size();
|
||||
|
||||
if (materialSize > 0)
|
||||
{
|
||||
LLSD::Binary materialBinary;
|
||||
materialBinary.resize(materialSize);
|
||||
memcpy(materialBinary.data(), materialString.data(), materialSize);
|
||||
|
||||
LLSD putData = LLSD::emptyMap();
|
||||
putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
|
||||
|
||||
LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL;
|
||||
LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2));
|
||||
LLHTTPClient::put(capURL, putData, materialsResponder);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("debugMaterials") << "cannot zip LLSD binary content" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMaterialMgr::clearGetQueues(const LLUUID& region_id)
|
||||
{
|
||||
mGetQueue.erase(region_id);
|
||||
for (get_pending_map_t::iterator itPending = mGetPending.begin(); itPending != mGetPending.end();)
|
||||
{
|
||||
if (region_id == itPending->first.first)
|
||||
{
|
||||
mGetPending.erase(itPending++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++itPending;
|
||||
}
|
||||
}
|
||||
|
||||
mGetAllQueue.erase(region_id);
|
||||
mGetAllRequested.erase(region_id);
|
||||
mGetAllPending.erase(region_id);
|
||||
mGetAllCallbacks.erase(region_id);
|
||||
}
|
||||
|
||||
void LLMaterialMgr::onRegionRemoved(LLViewerRegion* regionp)
|
||||
{
|
||||
clearGetQueues(regionp->getRegionID());
|
||||
// Put doesn't need clearing: objects that can't be found will clean up in processPutQueue()
|
||||
}
|
||||
|
||||
130
indra/newview/llmaterialmgr.h
Normal file
130
indra/newview/llmaterialmgr.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @file llmaterialmgr.h
|
||||
* @brief Material manager
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&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_LLMATERIALMGR_H
|
||||
#define LL_LLMATERIALMGR_H
|
||||
|
||||
#include "llmaterial.h"
|
||||
#include "llmaterialid.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
class LLViewerRegion;
|
||||
|
||||
class LLMaterialMgr : public LLSingleton<LLMaterialMgr>
|
||||
{
|
||||
friend class LLSingleton<LLMaterialMgr>;
|
||||
protected:
|
||||
LLMaterialMgr();
|
||||
virtual ~LLMaterialMgr();
|
||||
|
||||
public:
|
||||
typedef std::map<LLMaterialID, LLMaterialPtr> material_map_t;
|
||||
|
||||
typedef boost::signals2::signal<void (const LLMaterialID&, const LLMaterialPtr)> get_callback_t;
|
||||
const LLMaterialPtr get(const LLUUID& region_id, const LLMaterialID& material_id);
|
||||
boost::signals2::connection get(const LLUUID& region_id, const LLMaterialID& material_id, get_callback_t::slot_type cb);
|
||||
|
||||
typedef boost::signals2::signal<void (const LLMaterialID&, const LLMaterialPtr, U32 te)> get_callback_te_t;
|
||||
boost::signals2::connection getTE(const LLUUID& region_id, const LLMaterialID& material_id, U32 te, get_callback_te_t::slot_type cb);
|
||||
|
||||
typedef boost::signals2::signal<void (const LLUUID&, const material_map_t&)> getall_callback_t;
|
||||
void getAll(const LLUUID& region_id);
|
||||
boost::signals2::connection getAll(const LLUUID& region_id, getall_callback_t::slot_type cb);
|
||||
void put(const LLUUID& object_id, const U8 te, const LLMaterial& material);
|
||||
void remove(const LLUUID& object_id, const U8 te);
|
||||
|
||||
protected:
|
||||
void clearGetQueues(const LLUUID& region_id);
|
||||
bool isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const;
|
||||
bool isGetAllPending(const LLUUID& region_id) const;
|
||||
void markGetPending(const LLUUID& region_id, const LLMaterialID& material_id);
|
||||
const LLMaterialPtr setMaterial(const LLUUID& region_id, const LLMaterialID& material_id, const LLSD& material_data);
|
||||
|
||||
static void onIdle(void*);
|
||||
void processGetQueue();
|
||||
void onGetResponse(bool success, const LLSD& content, const LLUUID& region_id);
|
||||
void processGetAllQueue();
|
||||
void onGetAllResponse(bool success, const LLSD& content, const LLUUID& region_id);
|
||||
void processPutQueue();
|
||||
void onPutResponse(bool success, const LLSD& content);
|
||||
void onRegionRemoved(LLViewerRegion* regionp);
|
||||
|
||||
protected:
|
||||
typedef std::set<LLMaterialID> material_queue_t;
|
||||
typedef std::map<LLUUID, material_queue_t> get_queue_t;
|
||||
get_queue_t mGetQueue;
|
||||
typedef std::pair<const LLUUID, LLMaterialID> pending_material_t;
|
||||
typedef std::map<const pending_material_t, F64> get_pending_map_t;
|
||||
get_pending_map_t mGetPending;
|
||||
typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t;
|
||||
get_callback_map_t mGetCallbacks;
|
||||
|
||||
// struct for TE-specific material ID query
|
||||
class TEMaterialPair
|
||||
{
|
||||
public:
|
||||
|
||||
U32 te;
|
||||
LLMaterialID materialID;
|
||||
|
||||
bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); }
|
||||
};
|
||||
|
||||
friend inline bool operator<(
|
||||
const LLMaterialMgr::TEMaterialPair& lhs,
|
||||
const LLMaterialMgr::TEMaterialPair& rhs)
|
||||
{
|
||||
return (lhs.te < rhs.te) ? TRUE :
|
||||
(lhs.materialID < rhs.materialID);
|
||||
}
|
||||
|
||||
struct TEMaterialPairHasher
|
||||
{
|
||||
enum { bucket_size = 8 };
|
||||
size_t operator()(const TEMaterialPair& key_value) const { return *((size_t*)key_value.materialID.get()); } // cheesy, but effective
|
||||
bool operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; }
|
||||
};
|
||||
|
||||
typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t;
|
||||
get_callback_te_map_t mGetTECallbacks;
|
||||
|
||||
typedef std::set<LLUUID> getall_queue_t;
|
||||
getall_queue_t mGetAllQueue;
|
||||
getall_queue_t mGetAllRequested;
|
||||
typedef std::map<LLUUID, F64> getall_pending_map_t;
|
||||
getall_pending_map_t mGetAllPending;
|
||||
typedef std::map<LLUUID, getall_callback_t*> getall_callback_map_t;
|
||||
getall_callback_map_t mGetAllCallbacks;
|
||||
|
||||
typedef std::map<U8, LLMaterial> facematerial_map_t;
|
||||
typedef std::map<LLUUID, facematerial_map_t> put_queue_t;
|
||||
put_queue_t mPutQueue;
|
||||
|
||||
material_map_t mMaterials;
|
||||
};
|
||||
|
||||
#endif // LL_LLMATERIALMGR_H
|
||||
|
||||
@@ -840,6 +840,7 @@ void LLSelectMgr::addAsFamily(std::vector<LLViewerObject*>& objects, BOOL add_to
|
||||
if (objectp->getNumTEs() > 0)
|
||||
{
|
||||
nodep->selectAllTEs(TRUE);
|
||||
objectp->setAllTESelected(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -897,10 +898,12 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab
|
||||
else if (face == SELECT_ALL_TES)
|
||||
{
|
||||
nodep->selectAllTEs(TRUE);
|
||||
objectp->setAllTESelected(true);
|
||||
}
|
||||
else if (0 <= face && face < SELECT_MAX_TES)
|
||||
{
|
||||
nodep->selectTE(face, TRUE);
|
||||
objectp->setTESelected(face, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1124,6 +1127,7 @@ LLObjectSelectionHandle LLSelectMgr::selectHighlightedObjects()
|
||||
|
||||
// flag this object as selected
|
||||
objectp->setSelected(TRUE);
|
||||
objectp->setAllTESelected(true);
|
||||
|
||||
mSelectedObjects->mSelectType = getSelectTypeForObject(objectp);
|
||||
|
||||
@@ -1351,6 +1355,7 @@ void LLSelectMgr::remove(LLViewerObject *objectp, S32 te, BOOL undoable)
|
||||
if (nodep->isTESelected(te))
|
||||
{
|
||||
nodep->selectTE(te, FALSE);
|
||||
objectp->setTESelected(te, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1671,6 +1671,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
||||
capabilityNames.append("ProductInfoRequest");
|
||||
capabilityNames.append("ProvisionVoiceAccountRequest");
|
||||
capabilityNames.append("RemoteParcelRequest");
|
||||
capabilityNames.append("RenderMaterials");
|
||||
capabilityNames.append("RequestTextureDownload");
|
||||
//capabilityNames.append("ResourceCostSelected"); //Object weights (llfloaterobjectweights.cpp)
|
||||
capabilityNames.append("RetrieveNavMeshSrc");
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "lldir.h"
|
||||
#include "llflexibleobject.h"
|
||||
#include "llfloatertools.h"
|
||||
#include "llmaterialid.h"
|
||||
#include "llmaterialtable.h"
|
||||
#include "llprimitive.h"
|
||||
#include "llvolume.h"
|
||||
@@ -81,6 +82,7 @@
|
||||
#include "llviewershadermgr.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "llvocache.h"
|
||||
#include "llmaterialmgr.h"
|
||||
|
||||
// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d)
|
||||
#include "rlvhandler.h"
|
||||
@@ -1942,6 +1944,62 @@ S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow)
|
||||
return res;
|
||||
}
|
||||
|
||||
void LLVOVolume::setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID &pMaterialID, const LLMaterialPtr pMaterialParams, U32 te)
|
||||
{
|
||||
LLVOVolume* pVol = (LLVOVolume*)gObjectList.findObject(objectID);
|
||||
if (pVol)
|
||||
{
|
||||
LL_DEBUGS("MaterialTEs") << "materialid " << pMaterialID.asString() << " to TE " << te << LL_ENDL;
|
||||
if (te >= pVol->getNumTEs())
|
||||
return;
|
||||
|
||||
LLTextureEntry* texture_entry = pVol->getTE(te);
|
||||
if (texture_entry && (texture_entry->getMaterialID() == pMaterialID))
|
||||
{
|
||||
pVol->setTEMaterialParams(te, pMaterialParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLVOVolume::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID)
|
||||
{
|
||||
S32 res = LLViewerObject::setTEMaterialID(te, pMaterialID);
|
||||
LL_DEBUGS("MaterialTEs") << "te "<< (S32)te << " materialid " << pMaterialID.asString() << " res " << res
|
||||
<< ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" )
|
||||
<< LL_ENDL;
|
||||
|
||||
LL_DEBUGS("MaterialTEs") << " " << pMaterialID.asString() << LL_ENDL;
|
||||
if (res)
|
||||
{
|
||||
LLMaterialMgr::instance().getTE(getRegion()->getRegionID(), pMaterialID, te, boost::bind(&LLVOVolume::setTEMaterialParamsCallbackTE, getID(), _1, _2, _3));
|
||||
|
||||
setChanged(ALL_CHANGED);
|
||||
if (!mDrawable.isNull())
|
||||
{
|
||||
gPipeline.markTextured(mDrawable);
|
||||
gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL);
|
||||
}
|
||||
mFaceMappingChanged = TRUE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
|
||||
{
|
||||
S32 res = LLViewerObject::setTEMaterialParams(te, pMaterialParams);
|
||||
LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterialParams) ? pMaterialParams->asLLSD() : LLSD("null")) << " res " << res
|
||||
<< ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" )
|
||||
<< LL_ENDL;
|
||||
setChanged(ALL_CHANGED);
|
||||
if (!mDrawable.isNull())
|
||||
{
|
||||
gPipeline.markTextured(mDrawable);
|
||||
gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL);
|
||||
}
|
||||
mFaceMappingChanged = TRUE;
|
||||
return TEM_CHANGE_TEXTURE;
|
||||
}
|
||||
|
||||
S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t)
|
||||
{
|
||||
S32 res = LLViewerObject::setTEScale(te, s, t);
|
||||
@@ -3988,7 +4046,9 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
|
||||
|
||||
BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
|
||||
(type == LLRenderPass::PASS_INVISIBLE) ||
|
||||
(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT));
|
||||
(type == LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK) ||
|
||||
(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)) ||
|
||||
(facep->getTextureEntry()->getFullbright());
|
||||
|
||||
if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL))
|
||||
{
|
||||
@@ -4026,6 +4086,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
|
||||
LLViewerTexture* tex = facep->getTexture();
|
||||
|
||||
U8 index = facep->getTextureIndex();
|
||||
|
||||
LLMaterialID mat_id = facep->getTextureEntry()->getMaterialID();
|
||||
|
||||
bool batchable = false;
|
||||
|
||||
@@ -4371,66 +4433,104 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
||||
LLViewerTexture* tex = facep->getTexture();
|
||||
U32 type = gPipeline.getPoolTypeFromTE(te, tex);
|
||||
|
||||
if (type == LLDrawPool::POOL_ALPHA)
|
||||
{
|
||||
if (te->getColor().mV[3] > 0.f)
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (te->getShiny())
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
|
||||
}
|
||||
}
|
||||
|
||||
if (te->getGlow())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
|
||||
}
|
||||
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
LLMaterial* mat = te->getMaterialParams().get();
|
||||
|
||||
if (mat)
|
||||
{
|
||||
if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
|
||||
bool fullbright = te->getFullbright();
|
||||
bool is_alpha = type == LLDrawPool::POOL_ALPHA;
|
||||
U8 mode = mat->getDiffuseAlphaMode();
|
||||
bool can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE ||
|
||||
mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE;
|
||||
|
||||
if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK && te->getColor().mV[3] >= 0.999f)
|
||||
{
|
||||
if (te->getBumpmap())
|
||||
pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE);
|
||||
}
|
||||
else if (is_alpha || (te->getColor().mV[3] < 0.999f))
|
||||
{
|
||||
if (te->getColor().mV[3] > 0.f)
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
|
||||
pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA : LLDrawPoolAvatar::RIGGED_ALPHA);
|
||||
}
|
||||
}
|
||||
else if (gPipeline.canUseVertexShaders()
|
||||
&& LLPipeline::sRenderBump
|
||||
&& te->getShiny()
|
||||
&& can_be_shiny)
|
||||
{
|
||||
pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : LLDrawPoolAvatar::RIGGED_SHINY);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == LLDrawPool::POOL_ALPHA)
|
||||
{
|
||||
if (te->getColor().mV[3] > 0.f)
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (te->getShiny())
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
|
||||
{
|
||||
if (te->getBumpmap())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5058,7 +5158,6 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
|
||||
index_offset += facep->getGeomCount();
|
||||
indices_index += facep->getIndicesCount();
|
||||
|
||||
|
||||
//append face to appropriate render batch
|
||||
|
||||
BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA;
|
||||
@@ -5078,7 +5177,46 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
|
||||
|
||||
BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE;
|
||||
|
||||
if (is_alpha)
|
||||
LLMaterial* mat = te->getMaterialParams().get();
|
||||
|
||||
bool can_be_shiny = true;
|
||||
if (mat)
|
||||
{
|
||||
U8 mode = mat->getDiffuseAlphaMode();
|
||||
can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE ||
|
||||
mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE;
|
||||
}
|
||||
|
||||
bool use_legacy_bump = te->getBumpmap();
|
||||
if (mat)
|
||||
{
|
||||
U8 mode = mat->getDiffuseAlphaMode();
|
||||
if (te->getColor().mV[3] < 0.999f)
|
||||
{
|
||||
mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
|
||||
}
|
||||
|
||||
if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
|
||||
{
|
||||
registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK : LLRenderPass::PASS_ALPHA_MASK);
|
||||
}
|
||||
else if (is_alpha || (te->getColor().mV[3] < 0.999f))
|
||||
{
|
||||
registerFace(group, facep, LLRenderPass::PASS_ALPHA);
|
||||
}
|
||||
else if (gPipeline.canUseVertexShaders()
|
||||
&& LLPipeline::sRenderBump
|
||||
&& te->getShiny()
|
||||
&& can_be_shiny)
|
||||
{
|
||||
registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_SHINY);
|
||||
}
|
||||
else
|
||||
{
|
||||
registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT : LLRenderPass::PASS_SIMPLE);
|
||||
}
|
||||
}
|
||||
else if (is_alpha)
|
||||
{
|
||||
// can we safely treat this as an alpha mask?
|
||||
if (facep->getFaceColor().mV[3] <= 0.f)
|
||||
@@ -5103,7 +5241,8 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
|
||||
}
|
||||
else if (gPipeline.canUseVertexShaders()
|
||||
&& LLPipeline::sRenderBump
|
||||
&& te->getShiny())
|
||||
&& te->getShiny()
|
||||
&& can_be_shiny)
|
||||
{ //shiny
|
||||
if (tex->getPrimaryFormat() == GL_ALPHA)
|
||||
{ //invisiprim+shiny
|
||||
@@ -5120,7 +5259,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
|
||||
registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
|
||||
}
|
||||
}
|
||||
else if (te->getBumpmap())
|
||||
else if (use_legacy_bump)
|
||||
{ //register in deferred bump pass
|
||||
registerFace(group, facep, LLRenderPass::PASS_BUMP);
|
||||
}
|
||||
@@ -5147,25 +5286,40 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
|
||||
}
|
||||
else if (fullbright || bake_sunlight)
|
||||
{ //fullbright
|
||||
registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
|
||||
if (LLPipeline::sRenderDeferred && !hud_group && LLPipeline::sRenderBump && te->getBumpmap())
|
||||
if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
|
||||
{
|
||||
registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
|
||||
}
|
||||
if (LLPipeline::sRenderDeferred && !hud_group && LLPipeline::sRenderBump && use_legacy_bump)
|
||||
{ //if this is the deferred render and a bump map is present, register in post deferred bump
|
||||
registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
|
||||
if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && use_legacy_bump)
|
||||
{ //non-shiny or fullbright deferred bump
|
||||
registerFace(group, facep, LLRenderPass::PASS_BUMP);
|
||||
}
|
||||
else
|
||||
{ //all around simple
|
||||
llassert(mask & LLVertexBuffer::MAP_NORMAL);
|
||||
registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
|
||||
if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
|
||||
{ //material alpha mask can be respected in non-deferred
|
||||
registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!gPipeline.canUseVertexShaders() &&
|
||||
!is_alpha &&
|
||||
te->getShiny() &&
|
||||
@@ -5181,7 +5335,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
|
||||
llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright);
|
||||
facep->setPoolType((fullbright) ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE);
|
||||
|
||||
if (!force_simple && te->getBumpmap() && LLPipeline::sRenderBump)
|
||||
if (!force_simple && LLPipeline::sRenderBump && use_legacy_bump)
|
||||
{
|
||||
registerFace(group, facep, LLRenderPass::PASS_BUMP);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
class LLViewerTextureAnim;
|
||||
class LLDrawPool;
|
||||
class LLMaterialID;
|
||||
class LLSelectNode;
|
||||
class LLObjectMediaDataClient;
|
||||
class LLObjectMediaNavigateClient;
|
||||
@@ -191,6 +192,11 @@ public:
|
||||
/*virtual*/ S32 setTEBumpShinyFullbright(const U8 te, const U8 bump);
|
||||
/*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags);
|
||||
/*virtual*/ S32 setTEGlow(const U8 te, const F32 glow);
|
||||
/*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
|
||||
|
||||
static void setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID& pMaterialID, const LLMaterialPtr pMaterialParams, U32 te);
|
||||
|
||||
/*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
|
||||
/*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t);
|
||||
/*virtual*/ S32 setTEScaleS(const U8 te, const F32 s);
|
||||
/*virtual*/ S32 setTEScaleT(const U8 te, const F32 t);
|
||||
|
||||
@@ -293,6 +293,7 @@ void LLWorld::removeRegion(const LLHost &host)
|
||||
mCulledRegionList.remove(regionp);
|
||||
mVisibleRegionList.remove(regionp);
|
||||
|
||||
mRegionRemovedSignal(regionp);
|
||||
//double check all objects of this region are removed.
|
||||
gObjectList.clearAllMapObjectsInRegion(regionp) ;
|
||||
//llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ;
|
||||
@@ -420,6 +421,19 @@ LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLViewerRegion* LLWorld::getRegionFromID(const LLUUID& region_id)
|
||||
{
|
||||
for (region_list_t::iterator iter = mRegionList.begin();
|
||||
iter != mRegionList.end(); ++iter)
|
||||
{
|
||||
LLViewerRegion* regionp = *iter;
|
||||
if (regionp->getRegionID() == region_id)
|
||||
{
|
||||
return regionp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LLWorld::updateAgentOffset(const LLVector3d &offset_global)
|
||||
{
|
||||
@@ -1506,6 +1520,11 @@ bool LLWorld::isRegionListed(const LLViewerRegion* region) const
|
||||
return it != mRegionList.end();
|
||||
}
|
||||
|
||||
boost::signals2::connection LLWorld::setRegionRemovedCallback(const region_remove_signal_t::slot_type& cb)
|
||||
{
|
||||
return mRegionRemovedSignal.connect(cb);
|
||||
}
|
||||
|
||||
LLHTTPRegistration<LLEstablishAgentCommunication>
|
||||
gHTTPRegistrationEstablishAgentCommunication(
|
||||
"/message/EstablishAgentCommunication");
|
||||
|
||||
@@ -82,6 +82,7 @@ public:
|
||||
LLViewerRegion* getRegionFromPosGlobal(const LLVector3d &pos);
|
||||
LLViewerRegion* getRegionFromPosAgent(const LLVector3 &pos);
|
||||
LLViewerRegion* getRegionFromHandle(const U64 &handle);
|
||||
LLViewerRegion* getRegionFromID(const LLUUID& region_id);
|
||||
BOOL positionRegionValidGlobal(const LLVector3d& pos); // true if position is in valid region
|
||||
LLVector3d clipToVisibleRegions(const LLVector3d &start_pos, const LLVector3d &end_pos);
|
||||
|
||||
@@ -157,6 +158,8 @@ public:
|
||||
typedef std::list<LLViewerRegion*> region_list_t;
|
||||
const region_list_t& getRegionList() const { return mActiveRegionList; }
|
||||
|
||||
typedef boost::signals2::signal<void(LLViewerRegion*)> region_remove_signal_t;
|
||||
boost::signals2::connection setRegionRemovedCallback(const region_remove_signal_t::slot_type& cb);
|
||||
// Returns lists of avatar IDs and their world-space positions within a given distance of a point.
|
||||
// All arguments are optional. Given containers will be emptied and then filled.
|
||||
// Not supplying origin or radius input returns data on all avatars in the known regions.
|
||||
@@ -176,6 +179,8 @@ private:
|
||||
region_list_t mVisibleRegionList;
|
||||
region_list_t mCulledRegionList;
|
||||
|
||||
region_remove_signal_t mRegionRemovedSignal;
|
||||
|
||||
// Number of points on edge
|
||||
static const U32 mWidth;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user