V3 mesh, texture, and hover merge.
This commit is contained in:
@@ -576,8 +576,6 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
|
||||
info->mRot.mV[VZ], LLQuaternion::XYZ));
|
||||
joint->setScale(info->mScale);
|
||||
|
||||
joint->setDefaultFromCurrentXform();
|
||||
|
||||
if (info->mIsJoint)
|
||||
{
|
||||
joint->setSkinOffset( info->mPivot );
|
||||
@@ -677,6 +675,42 @@ void LLAvatarAppearance::clearSkeleton()
|
||||
mSkeleton.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// addPelvisFixup
|
||||
//------------------------------------------------------------------------
|
||||
void LLAvatarAppearance::addPelvisFixup( F32 fixup, const LLUUID& mesh_id )
|
||||
{
|
||||
LLVector3 pos(0.0,0.0,fixup);
|
||||
mPelvisFixups.add(mesh_id,pos);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// addPelvisFixup
|
||||
//------------------------------------------------------------------------
|
||||
void LLAvatarAppearance::removePelvisFixup( const LLUUID& mesh_id )
|
||||
{
|
||||
mPelvisFixups.remove(mesh_id);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// hasPelvisFixup
|
||||
//------------------------------------------------------------------------
|
||||
bool LLAvatarAppearance::hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const
|
||||
{
|
||||
LLVector3 pos;
|
||||
if (mPelvisFixups.findActiveOverride(mesh_id,pos))
|
||||
{
|
||||
fixup = pos[2];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLAvatarAppearance::hasPelvisFixup( F32& fixup ) const
|
||||
{
|
||||
LLUUID mesh_id;
|
||||
return hasPelvisFixup( fixup, mesh_id );
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarAppearance::buildCharacter()
|
||||
// Deferred initialization and rebuild of the avatar.
|
||||
|
||||
@@ -159,11 +159,17 @@ protected:
|
||||
BOOL mIsBuilt; // state of deferred character building
|
||||
typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
|
||||
avatar_joint_list_t mSkeleton;
|
||||
|
||||
LLPosOverrideMap mPelvisFixups;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Pelvis height adjustment members.
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void addPelvisFixup( F32 fixup, const LLUUID& mesh_id );
|
||||
void removePelvisFixup( const LLUUID& mesh_id );
|
||||
bool hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const;
|
||||
bool hasPelvisFixup( F32& fixup ) const;
|
||||
|
||||
LLVector3 mBodySize;
|
||||
LLVector3 mAvatarOffset;
|
||||
protected:
|
||||
|
||||
@@ -85,8 +85,6 @@ LLSkinJoint::~LLSkinJoint()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLSkinJoint::setupSkinJoint( LLJoint *joint)
|
||||
{
|
||||
mRootToJointSkinOffset.clearVec();
|
||||
mRootToParentJointSkinOffset.clearVec();
|
||||
|
||||
// find the named joint
|
||||
if (!(mJoint = joint))
|
||||
@@ -96,6 +94,9 @@ void LLSkinJoint::setupSkinJoint( LLJoint *joint)
|
||||
}
|
||||
|
||||
// compute the inverse root skin matrix
|
||||
mRootToJointSkinOffset.clearVec();
|
||||
mRootToParentJointSkinOffset.clearVec();
|
||||
|
||||
do
|
||||
{
|
||||
mRootToJointSkinOffset -= joint->getSkinOffset();
|
||||
|
||||
@@ -16,6 +16,10 @@ include_directories(
|
||||
${LLVFS_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
)
|
||||
include_directories(SYSTEM
|
||||
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
|
||||
${LLXML_SYSTEM_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(llcharacter_SOURCE_FILES
|
||||
llanimationstates.cpp
|
||||
|
||||
@@ -36,6 +36,63 @@
|
||||
S32 LLJoint::sNumUpdates = 0;
|
||||
S32 LLJoint::sNumTouches = 0;
|
||||
|
||||
template <class T>
|
||||
bool attachment_map_iter_compare_key(const T& a, const T& b)
|
||||
{
|
||||
return a.first < b.first;
|
||||
}
|
||||
|
||||
bool LLPosOverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const
|
||||
{
|
||||
pos = LLVector3(0,0,0);
|
||||
mesh_id = LLUUID();
|
||||
bool found = false;
|
||||
|
||||
map_type::const_iterator it = std::max_element(m_map.begin(),
|
||||
m_map.end(),
|
||||
attachment_map_iter_compare_key<map_type::value_type>);
|
||||
if (it != m_map.end())
|
||||
{
|
||||
found = true;
|
||||
pos = it->second;
|
||||
mesh_id = it->first;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void LLPosOverrideMap::showJointPosOverrides( std::ostringstream& os ) const
|
||||
{
|
||||
map_type::const_iterator max_it = std::max_element(m_map.begin(),
|
||||
m_map.end(),
|
||||
attachment_map_iter_compare_key<map_type::value_type>);
|
||||
for (map_type::const_iterator it = m_map.begin();
|
||||
it != m_map.end(); ++it)
|
||||
{
|
||||
const LLVector3& pos = it->second;
|
||||
os << " " << "[" << it->first <<": " << pos << "]" << ((it==max_it) ? "*" : "");
|
||||
}
|
||||
}
|
||||
|
||||
U32 LLPosOverrideMap::count() const
|
||||
{
|
||||
return m_map.size();
|
||||
}
|
||||
|
||||
void LLPosOverrideMap::add(const LLUUID& mesh_id, const LLVector3& pos)
|
||||
{
|
||||
m_map[mesh_id] = pos;
|
||||
}
|
||||
|
||||
bool LLPosOverrideMap::remove(const LLUUID& mesh_id)
|
||||
{
|
||||
U32 remove_count = m_map.erase(mesh_id);
|
||||
return (remove_count > 0);
|
||||
}
|
||||
|
||||
void LLPosOverrideMap::clear()
|
||||
{
|
||||
m_map.clear();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLJoint()
|
||||
// Class Constructor
|
||||
@@ -57,7 +114,6 @@ LLJoint::LLJoint() :
|
||||
{
|
||||
init();
|
||||
touch();
|
||||
mResetAfterRestoreOldXform = false;
|
||||
}
|
||||
|
||||
LLJoint::LLJoint(S32 joint_num) :
|
||||
@@ -65,7 +121,6 @@ LLJoint::LLJoint(S32 joint_num) :
|
||||
{
|
||||
init();
|
||||
touch();
|
||||
mResetAfterRestoreOldXform = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -233,54 +288,120 @@ const LLVector3& LLJoint::getPosition()
|
||||
return mXform.getPosition();
|
||||
}
|
||||
|
||||
bool do_debug_joint(const std::string& name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// setPosition()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::setPosition( const LLVector3& pos )
|
||||
{
|
||||
// if (mXform.getPosition() != pos)
|
||||
if (pos != getPosition())
|
||||
{
|
||||
mXform.setPosition(pos);
|
||||
touch(MATRIX_DIRTY | POSITION_DIRTY);
|
||||
if (do_debug_joint(getName()))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL;
|
||||
}
|
||||
}
|
||||
mXform.setPosition(pos);
|
||||
touch(MATRIX_DIRTY | POSITION_DIRTY);
|
||||
}
|
||||
|
||||
void showJointPosOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info )
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << joint.m_posBeforeOverrides;
|
||||
joint.m_attachmentOverrides.showJointPosOverrides(os);
|
||||
LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// addAttachmentPosOverride()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info )
|
||||
{
|
||||
if (mesh_id.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!m_attachmentOverrides.count())
|
||||
{
|
||||
if (do_debug_joint(getName()))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_posBeforeOverrides " << getPosition() << LL_ENDL;
|
||||
}
|
||||
m_posBeforeOverrides = getPosition();
|
||||
}
|
||||
m_attachmentOverrides.add(mesh_id,pos);
|
||||
if (do_debug_joint(getName()))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL;
|
||||
}
|
||||
updatePos(av_info);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// removeAttachmentPosOverride()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info )
|
||||
{
|
||||
if (mesh_id.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (m_attachmentOverrides.remove(mesh_id))
|
||||
{
|
||||
if (do_debug_joint(getName()))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName()
|
||||
<< " removeAttachmentPosOverride for " << mesh_id << LL_ENDL;
|
||||
showJointPosOverrides(*this, "remove", av_info);
|
||||
}
|
||||
updatePos(av_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// setPosition()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::setDefaultFromCurrentXform( void )
|
||||
// hasAttachmentPosOverride()
|
||||
//--------------------------------------------------------------------
|
||||
bool LLJoint::hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const
|
||||
{
|
||||
mDefaultXform = mXform;
|
||||
touch(MATRIX_DIRTY | POSITION_DIRTY);
|
||||
|
||||
return m_attachmentOverrides.findActiveOverride(mesh_id,pos);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// storeCurrentXform()
|
||||
// clearAttachmentPosOverrides()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::storeCurrentXform( const LLVector3& pos )
|
||||
void LLJoint::clearAttachmentPosOverrides()
|
||||
{
|
||||
mOldXform = mXform;
|
||||
mResetAfterRestoreOldXform = true;
|
||||
setPosition( pos );
|
||||
if (m_attachmentOverrides.count())
|
||||
{
|
||||
m_attachmentOverrides.clear();
|
||||
setPosition(m_posBeforeOverrides);
|
||||
setId( LLUUID::null );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// restoreOldXform()
|
||||
// updatePos()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::restoreOldXform( void )
|
||||
void LLJoint::updatePos(const std::string& av_info)
|
||||
{
|
||||
mResetAfterRestoreOldXform = false;
|
||||
mXform = mOldXform;
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
// restoreOldXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::restoreToDefaultXform( void )
|
||||
{
|
||||
mXform = mDefaultXform;
|
||||
setPosition( mXform.getPosition() );
|
||||
LLVector3 pos, found_pos;
|
||||
LLUUID mesh_id;
|
||||
if (m_attachmentOverrides.findActiveOverride(mesh_id,found_pos))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner of " << m_attachmentOverrides.count() << " is mesh " << mesh_id << " pos " << found_pos << LL_ENDL;
|
||||
pos = found_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner is posBeforeOverrides " << m_posBeforeOverrides << LL_ENDL;
|
||||
pos = m_posBeforeOverrides;
|
||||
}
|
||||
setPosition(pos);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
@@ -46,6 +46,20 @@ const U32 LL_FACE_JOINT_NUM = 30;
|
||||
const S32 LL_CHARACTER_MAX_PRIORITY = 7;
|
||||
const F32 LL_MAX_PELVIS_OFFSET = 5.f;
|
||||
|
||||
class LLPosOverrideMap
|
||||
{
|
||||
public:
|
||||
LLPosOverrideMap() {}
|
||||
bool findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const;
|
||||
void showJointPosOverrides(std::ostringstream& os) const;
|
||||
U32 count() const;
|
||||
void add(const LLUUID& mesh_id, const LLVector3& pos);
|
||||
bool remove(const LLUUID& mesh_id);
|
||||
void clear();
|
||||
private:
|
||||
typedef std::map<LLUUID,LLVector3> map_type;
|
||||
map_type m_map;
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLJoint
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -79,8 +93,6 @@ protected:
|
||||
|
||||
// explicit transformation members
|
||||
LLXformMatrix mXform;
|
||||
LLXformMatrix mOldXform;
|
||||
LLXformMatrix mDefaultXform;
|
||||
|
||||
LLUUID mId;
|
||||
|
||||
@@ -88,8 +100,6 @@ public:
|
||||
U32 mDirtyFlags;
|
||||
BOOL mUpdateXform;
|
||||
|
||||
BOOL mResetAfterRestoreOldXform;
|
||||
|
||||
// describes the skin binding pose
|
||||
LLVector3 mSkinOffset;
|
||||
|
||||
@@ -103,6 +113,11 @@ public:
|
||||
static S32 sNumTouches;
|
||||
static S32 sNumUpdates;
|
||||
|
||||
LLPosOverrideMap m_attachmentOverrides;
|
||||
LLVector3 m_posBeforeOverrides;
|
||||
|
||||
void updatePos(const std::string& av_info);
|
||||
|
||||
public:
|
||||
LLJoint();
|
||||
LLJoint(S32 joint_num);
|
||||
@@ -183,22 +198,17 @@ public:
|
||||
virtual BOOL isAnimatable() const { return TRUE; }
|
||||
|
||||
S32 getJointNum() const { return mJointNum; }
|
||||
|
||||
void restoreOldXform( void );
|
||||
void restoreToDefaultXform( void );
|
||||
void setDefaultFromCurrentXform( void );
|
||||
void storeCurrentXform( const LLVector3& pos );
|
||||
|
||||
void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info );
|
||||
void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info );
|
||||
bool hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const;
|
||||
void clearAttachmentPosOverrides();
|
||||
|
||||
//Accessor for the joint id
|
||||
LLUUID getId( void ) { return mId; }
|
||||
//Setter for the joints id
|
||||
void setId( const LLUUID& id ) { mId = id;}
|
||||
|
||||
//If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it
|
||||
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
|
||||
//Setter for joint reset flag
|
||||
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
|
||||
|
||||
// <edit>
|
||||
std::string exportString(U32 tabs = 0);
|
||||
// </edit>
|
||||
|
||||
@@ -36,6 +36,7 @@ set(llcommon_SOURCE_FILES
|
||||
llassettype.cpp
|
||||
llbase32.cpp
|
||||
llbase64.cpp
|
||||
llcallbacklist.cpp
|
||||
llcommon.cpp
|
||||
llcommonutils.cpp
|
||||
llcoros.cpp
|
||||
@@ -138,6 +139,7 @@ set(llcommon_HEADER_FILES
|
||||
llbase32.h
|
||||
llbase64.h
|
||||
llboost.h
|
||||
llcallbacklist.h
|
||||
llchat.h
|
||||
llclickaction.h
|
||||
llcommon.h
|
||||
|
||||
230
indra/llcommon/llcallbacklist.cpp
Normal file
230
indra/llcommon/llcallbacklist.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* @file llcallbacklist.cpp
|
||||
* @brief A simple list of callback functions to call.
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#include "llcallbacklist.h"
|
||||
#include "lleventtimer.h"
|
||||
#include "llerrorlegacy.h"
|
||||
|
||||
// Globals
|
||||
//
|
||||
LLCallbackList gIdleCallbacks;
|
||||
|
||||
//
|
||||
// Member functions
|
||||
//
|
||||
|
||||
LLCallbackList::LLCallbackList()
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
LLCallbackList::~LLCallbackList()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void LLCallbackList::addFunction( callback_t func, void *data)
|
||||
{
|
||||
if (!func)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// only add one callback per func/data pair
|
||||
//
|
||||
if (containsFunction(func))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
callback_pair_t t(func, data);
|
||||
mCallbackList.push_back(t);
|
||||
}
|
||||
|
||||
bool LLCallbackList::containsFunction( callback_t func, void *data)
|
||||
{
|
||||
callback_pair_t t(func, data);
|
||||
callback_list_t::iterator iter = find(func,data);
|
||||
if (iter != mCallbackList.end())
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLCallbackList::deleteFunction( callback_t func, void *data)
|
||||
{
|
||||
callback_list_t::iterator iter = find(func,data);
|
||||
if (iter != mCallbackList.end())
|
||||
{
|
||||
mCallbackList.erase(iter);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
LLCallbackList::callback_list_t::iterator
|
||||
LLCallbackList::find(callback_t func, void *data)
|
||||
{
|
||||
callback_pair_t t(func, data);
|
||||
return std::find(mCallbackList.begin(), mCallbackList.end(), t);
|
||||
}
|
||||
|
||||
void LLCallbackList::deleteAllFunctions()
|
||||
{
|
||||
mCallbackList.clear();
|
||||
}
|
||||
|
||||
|
||||
void LLCallbackList::callFunctions()
|
||||
{
|
||||
for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); )
|
||||
{
|
||||
callback_list_t::iterator curiter = iter++;
|
||||
curiter->first(curiter->second);
|
||||
}
|
||||
}
|
||||
|
||||
// Shim class to allow arbitrary boost::bind
|
||||
// expressions to be run as one-time idle callbacks.
|
||||
class OnIdleCallbackOneTime
|
||||
{
|
||||
public:
|
||||
OnIdleCallbackOneTime(nullary_func_t callable):
|
||||
mCallable(callable)
|
||||
{
|
||||
}
|
||||
static void onIdle(void *data)
|
||||
{
|
||||
gIdleCallbacks.deleteFunction(onIdle, data);
|
||||
OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data);
|
||||
self->call();
|
||||
delete self;
|
||||
}
|
||||
void call()
|
||||
{
|
||||
mCallable();
|
||||
}
|
||||
private:
|
||||
nullary_func_t mCallable;
|
||||
};
|
||||
|
||||
void doOnIdleOneTime(nullary_func_t callable)
|
||||
{
|
||||
OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable);
|
||||
gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor);
|
||||
}
|
||||
|
||||
// Shim class to allow generic boost functions to be run as
|
||||
// recurring idle callbacks. Callable should return true when done,
|
||||
// false to continue getting called.
|
||||
class OnIdleCallbackRepeating
|
||||
{
|
||||
public:
|
||||
OnIdleCallbackRepeating(bool_func_t callable):
|
||||
mCallable(callable)
|
||||
{
|
||||
}
|
||||
// Will keep getting called until the callable returns true.
|
||||
static void onIdle(void *data)
|
||||
{
|
||||
OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data);
|
||||
bool done = self->call();
|
||||
if (done)
|
||||
{
|
||||
gIdleCallbacks.deleteFunction(onIdle, data);
|
||||
delete self;
|
||||
}
|
||||
}
|
||||
bool call()
|
||||
{
|
||||
return mCallable();
|
||||
}
|
||||
private:
|
||||
bool_func_t mCallable;
|
||||
};
|
||||
|
||||
void doOnIdleRepeating(bool_func_t callable)
|
||||
{
|
||||
OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable);
|
||||
gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
|
||||
}
|
||||
|
||||
class NullaryFuncEventTimer: public LLEventTimer
|
||||
{
|
||||
public:
|
||||
NullaryFuncEventTimer(nullary_func_t callable, F32 seconds):
|
||||
LLEventTimer(seconds),
|
||||
mCallable(callable)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
BOOL tick()
|
||||
{
|
||||
mCallable();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
nullary_func_t mCallable;
|
||||
};
|
||||
|
||||
// Call a given callable once after specified interval.
|
||||
void doAfterInterval(nullary_func_t callable, F32 seconds)
|
||||
{
|
||||
new NullaryFuncEventTimer(callable, seconds);
|
||||
}
|
||||
|
||||
class BoolFuncEventTimer: public LLEventTimer
|
||||
{
|
||||
public:
|
||||
BoolFuncEventTimer(bool_func_t callable, F32 seconds):
|
||||
LLEventTimer(seconds),
|
||||
mCallable(callable)
|
||||
{
|
||||
}
|
||||
private:
|
||||
BOOL tick()
|
||||
{
|
||||
return mCallable();
|
||||
}
|
||||
|
||||
bool_func_t mCallable;
|
||||
};
|
||||
|
||||
// Call a given callable every specified number of seconds, until it returns true.
|
||||
void doPeriodically(bool_func_t callable, F32 seconds)
|
||||
{
|
||||
new BoolFuncEventTimer(callable, seconds);
|
||||
}
|
||||
@@ -28,27 +28,35 @@
|
||||
#define LL_LLCALLBACKLIST_H
|
||||
|
||||
#include "llstl.h"
|
||||
#include <boost/function.hpp>
|
||||
#include <list>
|
||||
#include "stdtypes.h"
|
||||
|
||||
class LLCallbackList
|
||||
{
|
||||
public:
|
||||
typedef void (*callback_t)(void*);
|
||||
|
||||
typedef std::pair< callback_t,void* > callback_pair_t;
|
||||
// NOTE: It is confirmed that we DEPEND on the order provided by using a list :(
|
||||
//
|
||||
typedef std::list< callback_pair_t > callback_list_t;
|
||||
|
||||
LLCallbackList();
|
||||
~LLCallbackList();
|
||||
|
||||
void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data)
|
||||
BOOL containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair
|
||||
BOOL deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found
|
||||
void callFunctions(); // calls all functions
|
||||
void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data)
|
||||
bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair
|
||||
bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found
|
||||
void callFunctions(); // calls all functions
|
||||
void deleteAllFunctions();
|
||||
|
||||
static void test();
|
||||
|
||||
protected:
|
||||
// Use a list so that the callbacks are ordered in case that matters
|
||||
typedef std::pair<callback_t,void*> callback_pair_t;
|
||||
typedef std::list<callback_pair_t > callback_list_t;
|
||||
|
||||
inline callback_list_t::iterator find(callback_t func, void *data);
|
||||
|
||||
callback_list_t mCallbackList;
|
||||
};
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
*/
|
||||
|
||||
// Specific error codes
|
||||
const int LL_ERR_NOERR = 0;
|
||||
const int LL_ERR_ASSET_REQUEST_FAILED = -1;
|
||||
//const int LL_ERR_ASSET_REQUEST_INVALID = -2;
|
||||
const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3;
|
||||
@@ -108,7 +107,7 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
|
||||
: liru_slashpos2 == std::string::npos ? std::string(__FILE__)/*Apparently, we're in / or perhaps the top of the drive, print as is*/\
|
||||
: std::string(__FILE__).substr(1+liru_slashpos2))/*print foo/bar.cpp or perhaps foo\bar.cpp*/
|
||||
|
||||
#define llassert_always(func) do { if (LL_UNLIKELY(!(func))) LL_ERRS() << "\nASSERT(" #func ")\nfile:" << liru_assert_strip << " line:" << std::dec << __LINE__ << LL_ENDL; } while(0)
|
||||
//#define llassert_always(func) do { if (LL_UNLIKELY(!(func))) LL_ERRS() << "\nASSERT(" #func ")\nfile:" << liru_assert_strip << " line:" << std::dec << __LINE__ << LL_ENDL; } while(0)
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
#define llassert(func) llassert_always(func)
|
||||
|
||||
@@ -37,7 +37,11 @@
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <typeinfo>
|
||||
#include "stdtypes.h"
|
||||
|
||||
// Use to compare the first element only of a pair
|
||||
// e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t;
|
||||
|
||||
@@ -2691,6 +2691,17 @@ void LLVolume::setMeshAssetLoaded(BOOL loaded)
|
||||
mIsMeshAssetLoaded = loaded;
|
||||
}
|
||||
|
||||
void LLVolume::copyFacesTo(std::vector<LLVolumeFace> &faces) const
|
||||
{
|
||||
faces = mVolumeFaces;
|
||||
}
|
||||
|
||||
void LLVolume::copyFacesFrom(const std::vector<LLVolumeFace> &faces)
|
||||
{
|
||||
mVolumeFaces = faces;
|
||||
mSculptLevel = 0;
|
||||
}
|
||||
|
||||
void LLVolume::copyVolumeFaces(const LLVolume* volume)
|
||||
{
|
||||
mVolumeFaces = volume->mVolumeFaces;
|
||||
@@ -4657,7 +4668,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
||||
|
||||
if (src.mNormals)
|
||||
{
|
||||
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
|
||||
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
|
||||
}
|
||||
|
||||
if(src.mTexCoords)
|
||||
@@ -4665,27 +4676,17 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
||||
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
|
||||
}
|
||||
|
||||
allocateTangents(src.mTangents ? src.mNumVertices : 0);
|
||||
if (src.mTangents)
|
||||
{
|
||||
allocateTangents(src.mNumVertices);
|
||||
LLVector4a::memcpyNonAliased16((F32*) mTangents, (F32*) src.mTangents, vert_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
ll_aligned_free_16(mTangents);
|
||||
mTangents = NULL;
|
||||
LLVector4a::memcpyNonAliased16((F32*)mTangents, (F32*)src.mTangents, vert_size);
|
||||
}
|
||||
|
||||
allocateWeights(src.mWeights ? src.mNumVertices : 0);
|
||||
if (src.mWeights)
|
||||
{
|
||||
allocateWeights(src.mNumVertices);
|
||||
LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mNumIndices)
|
||||
@@ -4711,19 +4712,10 @@ LLVolumeFace::~LLVolumeFace()
|
||||
|
||||
void LLVolumeFace::freeData()
|
||||
{
|
||||
ll_aligned_free<64>(mPositions);
|
||||
mPositions = NULL;
|
||||
|
||||
//normals and texture coordinates are part of the same buffer as mPositions, do not free them separately
|
||||
mNormals = NULL;
|
||||
mTexCoords = NULL;
|
||||
|
||||
ll_aligned_free_16(mIndices);
|
||||
mIndices = NULL;
|
||||
ll_aligned_free_16(mTangents);
|
||||
mTangents = NULL;
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = NULL;
|
||||
allocateVertices(0);
|
||||
allocateTangents(0);
|
||||
allocateWeights(0);
|
||||
allocateIndices(0);
|
||||
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
@@ -4883,7 +4875,7 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
|
||||
//
|
||||
if (new_face.mNumVertices <= mNumVertices)
|
||||
{
|
||||
llassert(new_face.mNumIndices == mNumIndices);
|
||||
llassert(new_face.mNumIndices == mNumIndices);
|
||||
swapData(new_face);
|
||||
}
|
||||
}
|
||||
@@ -5158,12 +5150,12 @@ public:
|
||||
void LLVolumeFace::cacheOptimize()
|
||||
{ //optimize for vertex cache according to Forsyth method:
|
||||
// http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
|
||||
|
||||
|
||||
llassert(!mOptimized);
|
||||
mOptimized = TRUE;
|
||||
|
||||
LLVCacheLRU cache;
|
||||
|
||||
|
||||
if (mNumVertices < 3)
|
||||
{ //nothing to do
|
||||
return;
|
||||
@@ -5175,17 +5167,17 @@ void LLVolumeFace::cacheOptimize()
|
||||
//mapping of triangles do vertices
|
||||
std::vector<LLVCacheTriangleData> triangle_data;
|
||||
|
||||
triangle_data.resize(mNumIndices/3);
|
||||
triangle_data.resize(mNumIndices / 3);
|
||||
vertex_data.resize(mNumVertices);
|
||||
|
||||
for (U32 i = 0; i < (U32)mNumIndices; i++)
|
||||
{ //populate vertex data and triangle data arrays
|
||||
U16 idx = mIndices[i];
|
||||
U32 tri_idx = i/3;
|
||||
U32 tri_idx = i / 3;
|
||||
|
||||
vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
|
||||
vertex_data[idx].mIdx = idx;
|
||||
triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]);
|
||||
triangle_data[tri_idx].mVertex[i % 3] = &(vertex_data[idx]);
|
||||
}
|
||||
|
||||
/*F32 pre_acmr = 1.f;
|
||||
@@ -5234,7 +5226,7 @@ void LLVolumeFace::cacheOptimize()
|
||||
tri->complete();
|
||||
|
||||
U32 breaks = 0;
|
||||
for (U32 i = 1; i < (U32)mNumIndices/3; ++i)
|
||||
for (U32 i = 1; i < (U32)mNumIndices / 3; ++i)
|
||||
{
|
||||
cache.updateScores();
|
||||
tri = cache.mBestTriangle;
|
||||
@@ -5249,8 +5241,8 @@ void LLVolumeFace::cacheOptimize()
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cache.addTriangle(tri);
|
||||
new_indices.push_back(tri->mVertex[0]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[1]->mIdx);
|
||||
@@ -5276,29 +5268,36 @@ void LLVolumeFace::cacheOptimize()
|
||||
{
|
||||
test_cache.addVertex(&vertex_data[mIndices[i]]);
|
||||
}
|
||||
|
||||
|
||||
post_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
|
||||
}*/
|
||||
|
||||
//optimize for pre-TnL cache
|
||||
|
||||
|
||||
//allocate space for new buffer
|
||||
S32 num_verts = mNumVertices;
|
||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
LLVector4a* pos = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size);
|
||||
LLVector4a* norm = pos + num_verts;
|
||||
LLVector2* tc = (LLVector2*) (norm + num_verts);
|
||||
|
||||
LLVector4a* wght = NULL;
|
||||
if (mWeights)
|
||||
LLVector4a* old_pos = mPositions;
|
||||
LLVector4a* old_norm = old_pos + num_verts;
|
||||
LLVector2* old_tc = (LLVector2*)(old_norm + num_verts);
|
||||
mPositions = NULL;
|
||||
if (old_pos)
|
||||
{
|
||||
wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
allocateVertices(num_verts);
|
||||
}
|
||||
|
||||
LLVector4a* binorm = NULL;
|
||||
if (mTangents)
|
||||
LLVector4a* old_wght = mWeights;
|
||||
mWeights = NULL;
|
||||
if (old_wght)
|
||||
{
|
||||
binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
allocateWeights(num_verts);
|
||||
}
|
||||
|
||||
LLVector4a* old_binorm = mTangents;
|
||||
mTangents = NULL;
|
||||
if (old_binorm)
|
||||
{
|
||||
allocateTangents(num_verts);
|
||||
}
|
||||
|
||||
//allocate mapping of old indices to new indices
|
||||
@@ -5314,16 +5313,16 @@ void LLVolumeFace::cacheOptimize()
|
||||
new_idx[idx] = cur_idx;
|
||||
|
||||
//copy vertex data
|
||||
pos[cur_idx] = mPositions[idx];
|
||||
norm[cur_idx] = mNormals[idx];
|
||||
tc[cur_idx] = mTexCoords[idx];
|
||||
mPositions[cur_idx] = old_pos[idx];
|
||||
mNormals[cur_idx] = old_norm[idx];
|
||||
mTexCoords[cur_idx] = old_tc[idx];
|
||||
if (mWeights)
|
||||
{
|
||||
wght[cur_idx] = mWeights[idx];
|
||||
mWeights[cur_idx] = old_wght[idx];
|
||||
}
|
||||
if (mTangents)
|
||||
{
|
||||
binorm[cur_idx] = mTangents[idx];
|
||||
mTangents[cur_idx] = old_binorm[idx];
|
||||
}
|
||||
|
||||
cur_idx++;
|
||||
@@ -5335,16 +5334,11 @@ void LLVolumeFace::cacheOptimize()
|
||||
mIndices[i] = new_idx[mIndices[i]];
|
||||
}
|
||||
|
||||
ll_aligned_free<64>(mPositions);
|
||||
// DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
|
||||
ll_aligned_free_16(mWeights);
|
||||
ll_aligned_free_16(mTangents);
|
||||
ll_aligned_free<64>(old_pos);
|
||||
ll_aligned_free_16(old_binorm);
|
||||
ll_aligned_free_16(old_wght);
|
||||
|
||||
mPositions = pos;
|
||||
mNormals = norm;
|
||||
mTexCoords = tc;
|
||||
mWeights = wght;
|
||||
mTangents = binorm;
|
||||
// DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
|
||||
|
||||
//std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
|
||||
//LL_INFOS() << result << LL_ENDL;
|
||||
@@ -6053,32 +6047,9 @@ void LLVolumeFace::createTangents()
|
||||
|
||||
void LLVolumeFace::resizeVertices(S32 num_verts)
|
||||
{
|
||||
ll_aligned_free<64>(mPositions);
|
||||
//DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
|
||||
ll_aligned_free_16(mTangents);
|
||||
|
||||
mTangents = NULL;
|
||||
|
||||
if (num_verts)
|
||||
{
|
||||
//pad texture coordinate block end to allow for QWORD reads
|
||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
|
||||
mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size);
|
||||
mNormals = mPositions+num_verts;
|
||||
mTexCoords = (LLVector2*) (mNormals+num_verts);
|
||||
|
||||
ll_assert_aligned(mPositions, 64);
|
||||
}
|
||||
else
|
||||
{
|
||||
mPositions = NULL;
|
||||
mNormals = NULL;
|
||||
mTexCoords = NULL;
|
||||
}
|
||||
|
||||
allocateTangents(0);
|
||||
allocateVertices(num_verts);
|
||||
mNumVertices = num_verts;
|
||||
mNumAllocatedVertices = num_verts;
|
||||
}
|
||||
|
||||
void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
|
||||
@@ -6093,49 +6064,10 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
|
||||
if (new_verts > mNumAllocatedVertices)
|
||||
{
|
||||
//double buffer size on expansion
|
||||
new_verts *= 2;
|
||||
|
||||
S32 new_tc_size = ((new_verts*8)+0xF) & ~0xF;
|
||||
S32 old_tc_size = ((mNumVertices*8)+0xF) & ~0xF;
|
||||
|
||||
S32 old_vsize = mNumVertices*16;
|
||||
|
||||
S32 new_size = new_verts*16*2+new_tc_size;
|
||||
|
||||
LLVector4a* old_buf = mPositions;
|
||||
|
||||
mPositions = (LLVector4a*) ll_aligned_malloc<64>(new_size);
|
||||
mNormals = mPositions+new_verts;
|
||||
mTexCoords = (LLVector2*) (mNormals+new_verts);
|
||||
|
||||
//<singu>
|
||||
llassert(mNumVertices || (old_buf == NULL && mTangents == NULL));
|
||||
if (mNumVertices) // It turns out this can be zero, in which case old_buf (and mTangents) is NULL.
|
||||
{
|
||||
//</singu>
|
||||
|
||||
//positions
|
||||
LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize);
|
||||
|
||||
//normals
|
||||
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
|
||||
|
||||
//tex coords
|
||||
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tc_size);
|
||||
|
||||
ll_aligned_free<64>(old_buf);
|
||||
|
||||
//<singu>
|
||||
}
|
||||
//</singu>
|
||||
allocateVertices(new_verts * 2, true);
|
||||
|
||||
//just clear tangents
|
||||
ll_aligned_free_16(mTangents);
|
||||
mTangents = NULL;
|
||||
ll_aligned_free<64>(old_buf);
|
||||
|
||||
mNumAllocatedVertices = new_verts;
|
||||
|
||||
allocateTangents(0);
|
||||
}
|
||||
|
||||
mPositions[mNumVertices] = pos;
|
||||
@@ -6148,47 +6080,101 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
|
||||
void LLVolumeFace::allocateTangents(S32 num_verts)
|
||||
{
|
||||
ll_aligned_free_16(mTangents);
|
||||
mTangents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
mTangents = NULL;
|
||||
if (num_verts)
|
||||
{
|
||||
mTangents = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVolumeFace::allocateWeights(S32 num_verts)
|
||||
{
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
mWeights = NULL;
|
||||
if (num_verts)
|
||||
{
|
||||
mWeights = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
}
|
||||
|
||||
void LLVolumeFace::resizeIndices(S32 num_indices)
|
||||
void LLVolumeFace::allocateVertices(S32 num_verts, bool copy)
|
||||
{
|
||||
if (!copy || !num_verts)
|
||||
{
|
||||
ll_aligned_free<64>(mPositions);
|
||||
mPositions = NULL;
|
||||
mNormals = NULL;
|
||||
mTexCoords = NULL;
|
||||
}
|
||||
|
||||
if (num_verts)
|
||||
{
|
||||
const U32 new_vsize = num_verts * sizeof(LLVector4a);
|
||||
const U32 new_nsize = new_vsize;
|
||||
const U32 new_tcsize = (num_verts * sizeof(LLVector2) + 0xF) & ~0xF;
|
||||
const U32 new_size = new_vsize + new_nsize + new_tcsize;
|
||||
|
||||
//allocate new buffer space
|
||||
LLVector4a* old_buf = mPositions;
|
||||
mPositions = (LLVector4a*)ll_aligned_malloc<64>(new_size);
|
||||
mNormals = mPositions + num_verts;
|
||||
mTexCoords = (LLVector2*)(mNormals + num_verts);
|
||||
|
||||
if (copy && old_buf)
|
||||
{
|
||||
U32 verts_to_copy = std::min(mNumVertices, num_verts);
|
||||
if (verts_to_copy)
|
||||
{
|
||||
const U32 old_vsize = verts_to_copy * sizeof(LLVector4a);
|
||||
const U32 old_nsize = old_vsize;
|
||||
const U32 old_tcsize = (verts_to_copy * sizeof(LLVector2) + 0xF) & ~0xF;
|
||||
|
||||
LLVector4a::memcpyNonAliased16((F32*)mPositions, (F32*)old_buf, old_vsize);
|
||||
LLVector4a::memcpyNonAliased16((F32*)mNormals, (F32*)(old_buf + mNumVertices), old_nsize);
|
||||
LLVector4a::memcpyNonAliased16((F32*)mTexCoords, (F32*)(old_buf + mNumVertices * 2), old_tcsize);
|
||||
}
|
||||
ll_aligned_free<64>(old_buf);
|
||||
}
|
||||
}
|
||||
mNumAllocatedVertices = num_verts;
|
||||
}
|
||||
|
||||
void LLVolumeFace::allocateIndices(S32 num_indices, bool copy)
|
||||
{
|
||||
if (num_indices == mNumIndices)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
S32 new_size = ((num_indices * sizeof(U16)) + 0xF) & ~0xF;
|
||||
if (copy && num_indices && mIndices && mNumIndices)
|
||||
{
|
||||
S32 old_size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF;
|
||||
|
||||
mIndices = (U16*)ll_aligned_realloc_16(mIndices, new_size, old_size);
|
||||
|
||||
mNumIndices = num_indices;
|
||||
return;
|
||||
}
|
||||
ll_aligned_free_16(mIndices);
|
||||
|
||||
mIndices = NULL;
|
||||
if (num_indices)
|
||||
{
|
||||
//pad index block end to allow for QWORD reads
|
||||
S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF;
|
||||
|
||||
mIndices = (U16*) ll_aligned_malloc_16(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
mIndices = NULL;
|
||||
mIndices = (U16*)ll_aligned_malloc_16(new_size);
|
||||
}
|
||||
|
||||
mNumIndices = num_indices;
|
||||
}
|
||||
void LLVolumeFace::resizeIndices(S32 num_indices)
|
||||
{
|
||||
allocateIndices(num_indices);
|
||||
}
|
||||
|
||||
void LLVolumeFace::pushIndex(const U16& idx)
|
||||
{
|
||||
S32 new_count = mNumIndices + 1;
|
||||
S32 new_size = ((new_count*2)+0xF) & ~0xF;
|
||||
allocateIndices(mNumIndices + 1, true);
|
||||
|
||||
S32 old_size = ((mNumIndices*2)+0xF) & ~0xF;
|
||||
if (new_size != old_size)
|
||||
{
|
||||
mIndices = (U16*) ll_aligned_realloc_16(mIndices, new_size, old_size);
|
||||
ll_assert_aligned(mIndices,16);
|
||||
}
|
||||
|
||||
mIndices[mNumIndices++] = idx;
|
||||
mIndices[mNumIndices-1] = idx;
|
||||
}
|
||||
|
||||
void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx)
|
||||
@@ -6225,24 +6211,7 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
|
||||
LL_ERRS() << "Cannot append empty face." << LL_ENDL;
|
||||
}
|
||||
|
||||
U32 old_vsize = mNumVertices*16;
|
||||
U32 new_vsize = new_count * 16;
|
||||
U32 old_tcsize = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF;
|
||||
U32 new_tcsize = (new_count*sizeof(LLVector2)+0xF) & ~0xF;
|
||||
U32 new_size = new_vsize * 2 + new_tcsize;
|
||||
|
||||
//allocate new buffer space
|
||||
LLVector4a* old_buf = mPositions;
|
||||
mPositions = (LLVector4a*) ll_aligned_malloc<64>(new_size);
|
||||
mNormals = mPositions + new_count;
|
||||
mTexCoords = (LLVector2*) (mNormals+new_count);
|
||||
|
||||
mNumAllocatedVertices = new_count;
|
||||
|
||||
LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize);
|
||||
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
|
||||
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tcsize);
|
||||
|
||||
allocateVertices(new_count, true);
|
||||
mNumVertices = new_count;
|
||||
|
||||
//get destination address of appended face
|
||||
@@ -6286,9 +6255,8 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
|
||||
|
||||
new_count = mNumIndices + face.mNumIndices;
|
||||
|
||||
//allocate new index buffer
|
||||
mIndices = (U16*) ll_aligned_realloc_16(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF, (mNumIndices*sizeof(U16)+0xF) & ~0xF);
|
||||
|
||||
allocateIndices(mNumIndices + face.mNumIndices, true);
|
||||
|
||||
//get destination address into new index buffer
|
||||
U16* dst_idx = mIndices+mNumIndices;
|
||||
mNumIndices = new_count;
|
||||
|
||||
@@ -876,6 +876,8 @@ public:
|
||||
void resizeVertices(S32 num_verts);
|
||||
void allocateTangents(S32 num_verts);
|
||||
void allocateWeights(S32 num_verts);
|
||||
void allocateVertices(S32 num_verts, bool copy = false);
|
||||
void allocateIndices(S32 num_indices, bool copy = false);
|
||||
void resizeIndices(S32 num_indices);
|
||||
void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
|
||||
|
||||
@@ -976,6 +978,7 @@ protected:
|
||||
~LLVolume(); // use unref
|
||||
|
||||
public:
|
||||
typedef std::vector<LLVolumeFace> face_list_t;
|
||||
|
||||
struct FaceParams
|
||||
{
|
||||
@@ -1048,11 +1051,16 @@ public:
|
||||
// conversion if *(LLVolume*) to LLVolume&
|
||||
const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE
|
||||
|
||||
LLVolumeFace &getVolumeFace(const S32 f) {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE
|
||||
|
||||
face_list_t& getVolumeFaces() { return mVolumeFaces; }
|
||||
U32 mFaceMask; // bit array of which faces exist in this volume
|
||||
LLVector3 mLODScaleBias; // vector for biasing LOD based on scale
|
||||
|
||||
void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level);
|
||||
void copyVolumeFaces(const LLVolume* volume);
|
||||
void copyFacesTo(std::vector<LLVolumeFace> &faces) const;
|
||||
void copyFacesFrom(const std::vector<LLVolumeFace> &faces);
|
||||
void cacheOptimize();
|
||||
|
||||
private:
|
||||
|
||||
@@ -9,22 +9,30 @@ include(LLMessage)
|
||||
include(LLXML)
|
||||
include(LLPhysicsExtensions)
|
||||
include(Colladadom)
|
||||
include(LLCharacter)
|
||||
|
||||
include_directories(
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLMESSAGE_INCLUDE_DIRS}
|
||||
${LLXML_INCLUDE_DIRS}
|
||||
${LLPHYSICSEXTENSIONS_INCLUDE_DIRS}
|
||||
${COLLADADOM_INCLUDE_DIRS}
|
||||
${LLCHARACTER_INCLUDE_DIRS}
|
||||
)
|
||||
include_directories(SYSTEM
|
||||
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
|
||||
${LLXML_SYSTEM_INCLUDE_DIRS}
|
||||
${LLPHYSICSEXTENSIONS_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(llprimitive_SOURCE_FILES
|
||||
lldaeloader.cpp
|
||||
llmaterialid.cpp
|
||||
llmaterial.cpp
|
||||
llmaterialtable.cpp
|
||||
llmediaentry.cpp
|
||||
llmodel.cpp
|
||||
llmodelloader.cpp
|
||||
llprimitive.cpp
|
||||
llprimtexturelist.cpp
|
||||
lltextureanim.cpp
|
||||
@@ -37,13 +45,14 @@ set(llprimitive_SOURCE_FILES
|
||||
|
||||
set(llprimitive_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
lldaeloader.h
|
||||
legacy_object_types.h
|
||||
llmaterial.h
|
||||
llmaterialid.h
|
||||
llmaterialtable.h
|
||||
llmediaentry.h
|
||||
llmodel.h
|
||||
llmodelloader.h
|
||||
llprimitive.h
|
||||
llprimtexturelist.h
|
||||
lltextureanim.h
|
||||
|
||||
2605
indra/llprimitive/lldaeloader.cpp
Normal file
2605
indra/llprimitive/lldaeloader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
111
indra/llprimitive/lldaeloader.h
Normal file
111
indra/llprimitive/lldaeloader.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file lldaeloader.h
|
||||
* @brief LLDAELoader class definition
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLDAELOADER_H
|
||||
#define LL_LLDAELOADER_H
|
||||
|
||||
#include "llmodelloader.h"
|
||||
|
||||
class DAE;
|
||||
class daeElement;
|
||||
class domProfile_COMMON;
|
||||
class domInstance_geometry;
|
||||
class domNode;
|
||||
class domTranslate;
|
||||
class domController;
|
||||
class domSkin;
|
||||
class domMesh;
|
||||
|
||||
class LLDAELoader : public LLModelLoader
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, LLImportMaterial> material_map;
|
||||
typedef std::map<daeElement*, std::vector<LLPointer<LLModel> > > dae_model_map;
|
||||
dae_model_map mModelsMap;
|
||||
|
||||
LLDAELoader(
|
||||
std::string filename,
|
||||
S32 lod,
|
||||
LLModelLoader::load_callback_t load_cb,
|
||||
LLModelLoader::joint_lookup_func_t joint_lookup_func,
|
||||
LLModelLoader::texture_load_func_t texture_load_func,
|
||||
LLModelLoader::state_callback_t state_cb,
|
||||
void* opaque_userdata,
|
||||
JointTransformMap& jointMap,
|
||||
JointSet& jointsFromNodes,
|
||||
U32 modelLimit,
|
||||
bool preprocess);
|
||||
virtual ~LLDAELoader() ;
|
||||
|
||||
virtual bool OpenFile(const std::string& filename);
|
||||
|
||||
protected:
|
||||
|
||||
void processElement(daeElement* element, bool& badElement, DAE* dae);
|
||||
void processDomModel(LLModel* model, DAE* dae, daeElement* pRoot, domMesh* mesh, domSkin* skin);
|
||||
|
||||
material_map getMaterials(LLModel* model, domInstance_geometry* instance_geo, DAE* dae);
|
||||
LLImportMaterial profileToMaterial(domProfile_COMMON* material, DAE* dae);
|
||||
LLColor4 getDaeColor(daeElement* element);
|
||||
|
||||
daeElement* getChildFromElement( daeElement* pElement, std::string const & name );
|
||||
|
||||
bool isNodeAJoint( domNode* pNode );
|
||||
void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms );
|
||||
void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform );
|
||||
void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform );
|
||||
void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform );
|
||||
void buildJointToNodeMappingFromScene( daeElement* pRoot );
|
||||
void processJointToNodeMapping( domNode* pNode );
|
||||
void processChildJoints( domNode* pParentNode );
|
||||
|
||||
bool verifyCount( int expected, int result );
|
||||
|
||||
//Verify that a controller matches vertex counts
|
||||
bool verifyController( domController* pController );
|
||||
|
||||
static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh);
|
||||
static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh);
|
||||
|
||||
static LLModel* loadModelFromDomMesh(domMesh* mesh);
|
||||
|
||||
// Loads a mesh breaking it into one or more models as necessary
|
||||
// to get around volume face limitations while retaining >8 materials
|
||||
//
|
||||
bool loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& models_out, U32 submodel_limit);
|
||||
|
||||
static std::string getElementLabel(daeElement *element);
|
||||
static size_t getSuffixPosition(std::string label);
|
||||
static std::string getLodlessLabel(daeElement *element);
|
||||
|
||||
static std::string preprocessDAE(std::string filename);
|
||||
|
||||
private:
|
||||
U32 mGeneratedModelLimit; // Attempt to limit amount of generated submodels
|
||||
bool mPreprocessDAE;
|
||||
|
||||
};
|
||||
#endif // LL_LLDAELLOADER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@
|
||||
#include "llvolume.h"
|
||||
#include "v4math.h"
|
||||
#include "m4math.h"
|
||||
#include <queue>
|
||||
|
||||
class daeElement;
|
||||
class domMesh;
|
||||
@@ -138,15 +139,16 @@ public:
|
||||
BOOL upload_skin,
|
||||
BOOL upload_joints,
|
||||
BOOL nowrite = FALSE,
|
||||
BOOL as_slm = FALSE);
|
||||
BOOL as_slm = FALSE,
|
||||
int submodel_id = 0);
|
||||
|
||||
static LLSD writeModelToStream(
|
||||
std::ostream& ostr,
|
||||
LLSD& mdl,
|
||||
BOOL nowrite = FALSE, BOOL as_slm = FALSE);
|
||||
|
||||
void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); }
|
||||
|
||||
static LLModel* loadModelFromDomMesh(domMesh* mesh);
|
||||
static std::string getElementLabel(daeElement* element);
|
||||
std::string getName() const;
|
||||
std::string getMetric() const {return mMetric;}
|
||||
EModelStatus getStatus() const {return mStatus;}
|
||||
@@ -169,7 +171,9 @@ public:
|
||||
|
||||
void addFace(const LLVolumeFace& face);
|
||||
|
||||
void sortVolumeFacesByMaterialName();
|
||||
void normalizeVolumeFaces();
|
||||
void trimVolumeFacesToSize(S32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
|
||||
void optimizeVolumeFaces();
|
||||
void offsetMesh( const LLVector3& pivotPoint );
|
||||
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
|
||||
@@ -280,9 +284,113 @@ public:
|
||||
EModelStatus mStatus ;
|
||||
|
||||
int mSubmodelID;
|
||||
protected:
|
||||
void addVolumeFacesFromDomMesh(domMesh* mesh);
|
||||
virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
|
||||
};
|
||||
|
||||
typedef std::vector<LLPointer<LLModel> > model_list;
|
||||
typedef std::queue<LLPointer<LLModel> > model_queue;
|
||||
|
||||
class LLModelMaterialBase
|
||||
{
|
||||
public:
|
||||
std::string mDiffuseMapFilename;
|
||||
std::string mDiffuseMapLabel;
|
||||
std::string mBinding;
|
||||
LLColor4 mDiffuseColor;
|
||||
bool mFullbright;
|
||||
|
||||
LLModelMaterialBase()
|
||||
: mFullbright(false)
|
||||
{
|
||||
mDiffuseColor.set(1,1,1,1);
|
||||
}
|
||||
};
|
||||
|
||||
class LLImportMaterial : public LLModelMaterialBase
|
||||
{
|
||||
public:
|
||||
friend class LLMeshUploadThread;
|
||||
friend class LLModelPreview;
|
||||
|
||||
bool operator<(const LLImportMaterial ¶ms) const;
|
||||
|
||||
LLImportMaterial() : LLModelMaterialBase()
|
||||
{
|
||||
mDiffuseColor.set(1,1,1,1);
|
||||
}
|
||||
|
||||
LLImportMaterial(LLSD& data);
|
||||
virtual ~LLImportMaterial();
|
||||
|
||||
LLSD asLLSD();
|
||||
|
||||
const LLUUID& getDiffuseMap() const { return mDiffuseMapID; }
|
||||
void setDiffuseMap(const LLUUID& texId) { mDiffuseMapID = texId; }
|
||||
|
||||
protected:
|
||||
|
||||
LLUUID mDiffuseMapID;
|
||||
void* mOpaqueData; // allow refs to viewer/platform-specific structs for each material
|
||||
// currently only stores an LLPointer< LLViewerFetchedTexture > > to
|
||||
// maintain refs to textures associated with each material for free
|
||||
// ref counting.
|
||||
};
|
||||
|
||||
typedef std::map<std::string, LLImportMaterial> material_map;
|
||||
|
||||
class LLModelInstanceBase
|
||||
{
|
||||
public:
|
||||
LLPointer<LLModel> mModel;
|
||||
LLPointer<LLModel> mLOD[5];
|
||||
LLUUID mMeshID;
|
||||
|
||||
LLMatrix4 mTransform;
|
||||
material_map mMaterial;
|
||||
|
||||
LLModelInstanceBase(LLModel* model, LLMatrix4& transform, material_map& materials)
|
||||
: mModel(model), mTransform(transform), mMaterial(materials)
|
||||
{
|
||||
}
|
||||
|
||||
LLModelInstanceBase()
|
||||
: mModel(NULL)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<LLModelInstanceBase> model_instance_list;
|
||||
|
||||
class LLModelInstance : public LLModelInstanceBase
|
||||
{
|
||||
public:
|
||||
std::string mLabel;
|
||||
LLUUID mMeshID;
|
||||
S32 mLocalMeshID;
|
||||
|
||||
LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, material_map& materials)
|
||||
: LLModelInstanceBase(model, transform, materials), mLabel(label)
|
||||
{
|
||||
mLocalMeshID = -1;
|
||||
}
|
||||
|
||||
LLModelInstance(LLSD& data);
|
||||
|
||||
LLSD asLLSD();
|
||||
};
|
||||
|
||||
#define LL_DEGENERACY_TOLERANCE 1e-7f
|
||||
|
||||
inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
|
||||
{
|
||||
volatile F32 p0 = a[0] * b[0];
|
||||
volatile F32 p1 = a[1] * b[1];
|
||||
volatile F32 p2 = a[2] * b[2];
|
||||
return p0 + p1 + p2;
|
||||
}
|
||||
|
||||
bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE);
|
||||
|
||||
bool validate_face(const LLVolumeFace& face);
|
||||
bool validate_model(const LLModel* mdl);
|
||||
|
||||
#endif //LL_LLMODEL_H
|
||||
|
||||
644
indra/llprimitive/llmodelloader.cpp
Normal file
644
indra/llprimitive/llmodelloader.cpp
Normal file
@@ -0,0 +1,644 @@
|
||||
/**
|
||||
* @file llmodelloader.cpp
|
||||
* @brief LLModelLoader class implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&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 "llmodelloader.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "lljoint.h"
|
||||
#include "llcallbacklist.h"
|
||||
|
||||
#include "llmatrix4a.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
|
||||
|
||||
void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
|
||||
{
|
||||
LLVector4a box[] =
|
||||
{
|
||||
LLVector4a(-1, 1,-1),
|
||||
LLVector4a(-1, 1, 1),
|
||||
LLVector4a(-1,-1,-1),
|
||||
LLVector4a(-1,-1, 1),
|
||||
LLVector4a( 1, 1,-1),
|
||||
LLVector4a( 1, 1, 1),
|
||||
LLVector4a( 1,-1,-1),
|
||||
LLVector4a( 1,-1, 1),
|
||||
};
|
||||
|
||||
for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
|
||||
{
|
||||
const LLVolumeFace& face = model->getVolumeFace(j);
|
||||
|
||||
LLVector4a center;
|
||||
center.setAdd(face.mExtents[0], face.mExtents[1]);
|
||||
center.mul(0.5f);
|
||||
LLVector4a size;
|
||||
size.setSub(face.mExtents[1],face.mExtents[0]);
|
||||
size.mul(0.5f);
|
||||
|
||||
for (U32 i = 0; i < 8; i++)
|
||||
{
|
||||
LLVector4a t;
|
||||
t.setMul(size, box[i]);
|
||||
t.add(center);
|
||||
|
||||
LLVector4a v;
|
||||
|
||||
mat.affineTransform(t, v);
|
||||
|
||||
if (first_transform)
|
||||
{
|
||||
first_transform = FALSE;
|
||||
min = max = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
update_min_max(min, max, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform)
|
||||
{
|
||||
LLVector4a mina, maxa;
|
||||
LLMatrix4a mata;
|
||||
|
||||
mata.loadu(mat);
|
||||
mina.load3(min.mV);
|
||||
maxa.load3(max.mV);
|
||||
|
||||
stretch_extents(model, mata, mina, maxa, first_transform);
|
||||
|
||||
min.set(mina.getF32ptr());
|
||||
max.set(maxa.getF32ptr());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLModelLoader
|
||||
//-----------------------------------------------------------------------------
|
||||
LLModelLoader::LLModelLoader(
|
||||
std::string filename,
|
||||
S32 lod,
|
||||
load_callback_t load_cb,
|
||||
joint_lookup_func_t joint_lookup_func,
|
||||
texture_load_func_t texture_load_func,
|
||||
state_callback_t state_cb,
|
||||
void* opaque_userdata,
|
||||
JointTransformMap& jointMap,
|
||||
JointSet& jointsFromNodes )
|
||||
: mJointList( jointMap )
|
||||
, mJointsFromNode( jointsFromNodes )
|
||||
, LLThread("Model Loader")
|
||||
, mFilename(filename)
|
||||
, mLod(lod)
|
||||
, mTrySLM(false)
|
||||
, mFirstTransform(TRUE)
|
||||
, mNumOfFetchingTextures(0)
|
||||
, mLoadCallback(load_cb)
|
||||
, mJointLookupFunc(joint_lookup_func)
|
||||
, mTextureLoadFunc(texture_load_func)
|
||||
, mStateCallback(state_cb)
|
||||
, mOpaqueData(opaque_userdata)
|
||||
, mRigParityWithScene(false)
|
||||
, mRigValidJointUpload(false)
|
||||
, mLegacyRigValid(false)
|
||||
, mNoNormalize(false)
|
||||
, mNoOptimize(false)
|
||||
, mCacheOnlyHitIfRigged(false)
|
||||
{
|
||||
mJointMap["mPelvis"] = "mPelvis";
|
||||
mJointMap["mTorso"] = "mTorso";
|
||||
mJointMap["mChest"] = "mChest";
|
||||
mJointMap["mNeck"] = "mNeck";
|
||||
mJointMap["mHead"] = "mHead";
|
||||
mJointMap["mSkull"] = "mSkull";
|
||||
mJointMap["mEyeRight"] = "mEyeRight";
|
||||
mJointMap["mEyeLeft"] = "mEyeLeft";
|
||||
mJointMap["mCollarLeft"] = "mCollarLeft";
|
||||
mJointMap["mShoulderLeft"] = "mShoulderLeft";
|
||||
mJointMap["mElbowLeft"] = "mElbowLeft";
|
||||
mJointMap["mWristLeft"] = "mWristLeft";
|
||||
mJointMap["mCollarRight"] = "mCollarRight";
|
||||
mJointMap["mShoulderRight"] = "mShoulderRight";
|
||||
mJointMap["mElbowRight"] = "mElbowRight";
|
||||
mJointMap["mWristRight"] = "mWristRight";
|
||||
mJointMap["mHipRight"] = "mHipRight";
|
||||
mJointMap["mKneeRight"] = "mKneeRight";
|
||||
mJointMap["mAnkleRight"] = "mAnkleRight";
|
||||
mJointMap["mFootRight"] = "mFootRight";
|
||||
mJointMap["mToeRight"] = "mToeRight";
|
||||
mJointMap["mHipLeft"] = "mHipLeft";
|
||||
mJointMap["mKneeLeft"] = "mKneeLeft";
|
||||
mJointMap["mAnkleLeft"] = "mAnkleLeft";
|
||||
mJointMap["mFootLeft"] = "mFootLeft";
|
||||
mJointMap["mToeLeft"] = "mToeLeft";
|
||||
|
||||
mJointMap["avatar_mPelvis"] = "mPelvis";
|
||||
mJointMap["avatar_mTorso"] = "mTorso";
|
||||
mJointMap["avatar_mChest"] = "mChest";
|
||||
mJointMap["avatar_mNeck"] = "mNeck";
|
||||
mJointMap["avatar_mHead"] = "mHead";
|
||||
mJointMap["avatar_mSkull"] = "mSkull";
|
||||
mJointMap["avatar_mEyeRight"] = "mEyeRight";
|
||||
mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
|
||||
mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
|
||||
mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
|
||||
mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
|
||||
mJointMap["avatar_mWristLeft"] = "mWristLeft";
|
||||
mJointMap["avatar_mCollarRight"] = "mCollarRight";
|
||||
mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
|
||||
mJointMap["avatar_mElbowRight"] = "mElbowRight";
|
||||
mJointMap["avatar_mWristRight"] = "mWristRight";
|
||||
mJointMap["avatar_mHipRight"] = "mHipRight";
|
||||
mJointMap["avatar_mKneeRight"] = "mKneeRight";
|
||||
mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
|
||||
mJointMap["avatar_mFootRight"] = "mFootRight";
|
||||
mJointMap["avatar_mToeRight"] = "mToeRight";
|
||||
mJointMap["avatar_mHipLeft"] = "mHipLeft";
|
||||
mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
|
||||
mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
|
||||
mJointMap["avatar_mFootLeft"] = "mFootLeft";
|
||||
mJointMap["avatar_mToeLeft"] = "mToeLeft";
|
||||
|
||||
|
||||
mJointMap["hip"] = "mPelvis";
|
||||
mJointMap["abdomen"] = "mTorso";
|
||||
mJointMap["chest"] = "mChest";
|
||||
mJointMap["neck"] = "mNeck";
|
||||
mJointMap["head"] = "mHead";
|
||||
mJointMap["figureHair"] = "mSkull";
|
||||
mJointMap["lCollar"] = "mCollarLeft";
|
||||
mJointMap["lShldr"] = "mShoulderLeft";
|
||||
mJointMap["lForeArm"] = "mElbowLeft";
|
||||
mJointMap["lHand"] = "mWristLeft";
|
||||
mJointMap["rCollar"] = "mCollarRight";
|
||||
mJointMap["rShldr"] = "mShoulderRight";
|
||||
mJointMap["rForeArm"] = "mElbowRight";
|
||||
mJointMap["rHand"] = "mWristRight";
|
||||
mJointMap["rThigh"] = "mHipRight";
|
||||
mJointMap["rShin"] = "mKneeRight";
|
||||
mJointMap["rFoot"] = "mFootRight";
|
||||
mJointMap["lThigh"] = "mHipLeft";
|
||||
mJointMap["lShin"] = "mKneeLeft";
|
||||
mJointMap["lFoot"] = "mFootLeft";
|
||||
|
||||
//move into joint mapper class
|
||||
//1. joints for joint offset verification
|
||||
mMasterJointList.push_front("mPelvis");
|
||||
mMasterJointList.push_front("mTorso");
|
||||
mMasterJointList.push_front("mChest");
|
||||
mMasterJointList.push_front("mNeck");
|
||||
mMasterJointList.push_front("mHead");
|
||||
mMasterJointList.push_front("mCollarLeft");
|
||||
mMasterJointList.push_front("mShoulderLeft");
|
||||
mMasterJointList.push_front("mElbowLeft");
|
||||
mMasterJointList.push_front("mWristLeft");
|
||||
mMasterJointList.push_front("mCollarRight");
|
||||
mMasterJointList.push_front("mShoulderRight");
|
||||
mMasterJointList.push_front("mElbowRight");
|
||||
mMasterJointList.push_front("mWristRight");
|
||||
mMasterJointList.push_front("mHipRight");
|
||||
mMasterJointList.push_front("mKneeRight");
|
||||
mMasterJointList.push_front("mFootRight");
|
||||
mMasterJointList.push_front("mHipLeft");
|
||||
mMasterJointList.push_front("mKneeLeft");
|
||||
mMasterJointList.push_front("mFootLeft");
|
||||
|
||||
//2. legacy joint list - used to verify rigs that will not be using joint offsets
|
||||
mMasterLegacyJointList.push_front("mPelvis");
|
||||
mMasterLegacyJointList.push_front("mTorso");
|
||||
mMasterLegacyJointList.push_front("mChest");
|
||||
mMasterLegacyJointList.push_front("mNeck");
|
||||
mMasterLegacyJointList.push_front("mHead");
|
||||
mMasterLegacyJointList.push_front("mHipRight");
|
||||
mMasterLegacyJointList.push_front("mKneeRight");
|
||||
mMasterLegacyJointList.push_front("mFootRight");
|
||||
mMasterLegacyJointList.push_front("mHipLeft");
|
||||
mMasterLegacyJointList.push_front("mKneeLeft");
|
||||
mMasterLegacyJointList.push_front("mFootLeft");
|
||||
|
||||
assert_main_thread();
|
||||
sActiveLoaderList.push_back(this) ;
|
||||
}
|
||||
|
||||
LLModelLoader::~LLModelLoader()
|
||||
{
|
||||
assert_main_thread();
|
||||
sActiveLoaderList.remove(this);
|
||||
}
|
||||
|
||||
void LLModelLoader::run()
|
||||
{
|
||||
doLoadModel();
|
||||
doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
|
||||
}
|
||||
|
||||
bool LLModelLoader::doLoadModel()
|
||||
{
|
||||
//first, look for a .slm file of the same name that was modified later
|
||||
//than the .dae
|
||||
|
||||
if (mTrySLM)
|
||||
{
|
||||
std::string filename = mFilename;
|
||||
|
||||
std::string::size_type i = filename.rfind(".");
|
||||
if (i != std::string::npos)
|
||||
{
|
||||
filename.replace(i, filename.size()-1, ".slm");
|
||||
llstat slm_status;
|
||||
if (LLFile::stat(filename, &slm_status) == 0)
|
||||
{ //slm file exists
|
||||
llstat dae_status;
|
||||
if (LLFile::stat(mFilename, &dae_status) != 0 ||
|
||||
dae_status.st_mtime < slm_status.st_mtime)
|
||||
{
|
||||
if (loadFromSLM(filename))
|
||||
{ //slm successfully loaded, if this fails, fall through and
|
||||
//try loading from dae
|
||||
|
||||
mLod = -1; //successfully loading from an slm implicitly sets all
|
||||
//LoDs
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OpenFile(mFilename);
|
||||
}
|
||||
|
||||
void LLModelLoader::setLoadState(U32 state)
|
||||
{
|
||||
mStateCallback(state, mOpaqueData);
|
||||
}
|
||||
|
||||
bool LLModelLoader::loadFromSLM(const std::string& filename)
|
||||
{
|
||||
//only need to populate mScene with data from slm
|
||||
llstat stat;
|
||||
|
||||
if (LLFile::stat(filename, &stat))
|
||||
{ //file does not exist
|
||||
return false;
|
||||
}
|
||||
|
||||
S32 file_size = (S32) stat.st_size;
|
||||
|
||||
llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary);
|
||||
LLSD data;
|
||||
LLSDSerialize::fromBinary(data, ifstream, file_size);
|
||||
ifstream.close();
|
||||
|
||||
//build model list for each LoD
|
||||
model_list model[LLModel::NUM_LODS];
|
||||
|
||||
if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
|
||||
{ //unsupported version
|
||||
return false;
|
||||
}
|
||||
|
||||
LLSD& mesh = data["mesh"];
|
||||
|
||||
LLVolumeParams volume_params;
|
||||
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
|
||||
|
||||
for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
|
||||
{
|
||||
for (U32 i = 0; i < (U32)mesh.size(); ++i)
|
||||
{
|
||||
std::stringstream str(mesh[i].asString());
|
||||
LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
|
||||
if (loaded_model->loadModel(str))
|
||||
{
|
||||
loaded_model->mLocalID = i;
|
||||
model[lod].push_back(loaded_model);
|
||||
|
||||
if (lod == LLModel::LOD_HIGH)
|
||||
{
|
||||
if (!loaded_model->mSkinInfo.mJointNames.empty())
|
||||
{
|
||||
//check to see if rig is valid
|
||||
critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
|
||||
}
|
||||
else if (mCacheOnlyHitIfRigged)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (model[LLModel::LOD_HIGH].empty())
|
||||
{ //failed to load high lod
|
||||
return false;
|
||||
}
|
||||
|
||||
//load instance list
|
||||
model_instance_list instance_list;
|
||||
|
||||
LLSD& instance = data["instance"];
|
||||
|
||||
for (U32 i = 0; i < (U32)instance.size(); ++i)
|
||||
{
|
||||
//deserialize instance list
|
||||
instance_list.push_back(LLModelInstance(instance[i]));
|
||||
|
||||
//match up model instance pointers
|
||||
S32 idx = instance_list[i].mLocalMeshID;
|
||||
std::string instance_label = instance_list[i].mLabel;
|
||||
|
||||
for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
|
||||
{
|
||||
if (!model[lod].empty())
|
||||
{
|
||||
if (idx >= model[lod].size())
|
||||
{
|
||||
if (model[lod].size())
|
||||
{
|
||||
instance_list[i].mLOD[lod] = model[lod][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
instance_list[i].mLOD[lod] = NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (model[lod][idx]
|
||||
&& model[lod][idx]->mLabel.empty()
|
||||
&& !instance_label.empty())
|
||||
{
|
||||
// restore model names
|
||||
std::string name = instance_label;
|
||||
switch (lod)
|
||||
{
|
||||
case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
|
||||
case LLModel::LOD_LOW: name += "_LOD1"; break;
|
||||
case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
|
||||
case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
|
||||
case LLModel::LOD_HIGH: break;
|
||||
}
|
||||
model[lod][idx]->mLabel = name;
|
||||
}
|
||||
|
||||
instance_list[i].mLOD[lod] = model[lod][idx];
|
||||
}
|
||||
}
|
||||
|
||||
if (!instance_list[i].mModel)
|
||||
instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
|
||||
}
|
||||
|
||||
// Set name for UI to use
|
||||
std::string name = data["name"];
|
||||
if (!name.empty())
|
||||
{
|
||||
model[LLModel::LOD_HIGH][0]->mRequestedLabel = name;
|
||||
}
|
||||
|
||||
|
||||
//convert instance_list to mScene
|
||||
mFirstTransform = TRUE;
|
||||
for (U32 i = 0; i < instance_list.size(); ++i)
|
||||
{
|
||||
LLModelInstance& cur_instance = instance_list[i];
|
||||
mScene[cur_instance.mTransform].push_back(cur_instance);
|
||||
stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
|
||||
}
|
||||
|
||||
setLoadState( DONE );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//static
|
||||
bool LLModelLoader::isAlive(LLModelLoader* loader)
|
||||
{
|
||||
if(!loader)
|
||||
{
|
||||
return false ;
|
||||
}
|
||||
|
||||
std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
|
||||
for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
|
||||
|
||||
return *iter == loader ;
|
||||
}
|
||||
|
||||
void LLModelLoader::loadModelCallback()
|
||||
{
|
||||
mLoadCallback(mScene,mModelList,mLod, mOpaqueData);
|
||||
|
||||
while (!isStopped())
|
||||
{ //wait until this thread is stopped before deleting self
|
||||
boost::this_thread::sleep_for(boost::chrono::microseconds(100));
|
||||
}
|
||||
|
||||
//double check if "this" is valid before deleting it, in case it is aborted during running.
|
||||
if(!isAlive(this))
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// critiqueRigForUploadApplicability()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
|
||||
{
|
||||
critiqueJointToNodeMappingFromScene();
|
||||
|
||||
//Determines the following use cases for a rig:
|
||||
//1. It is suitable for upload with skin weights & joint positions, or
|
||||
//2. It is suitable for upload as standard av with just skin weights
|
||||
|
||||
bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
|
||||
bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
|
||||
|
||||
//It's OK that both could end up being true, both default to false
|
||||
if ( isJointPositionUploadOK )
|
||||
{
|
||||
setRigValidForJointPositionUpload( true );
|
||||
}
|
||||
|
||||
if ( isRigLegacyOK)
|
||||
{
|
||||
setLegacyRigValid( true );
|
||||
}
|
||||
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// critiqueJointToNodeMappingFromScene()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLModelLoader::critiqueJointToNodeMappingFromScene( void )
|
||||
{
|
||||
//Do the actual nodes back the joint listing from the dae?
|
||||
//if yes then this is a fully rigged asset, otherwise it's just a partial rig
|
||||
|
||||
JointSet::iterator jointsFromNodeIt = mJointsFromNode.begin();
|
||||
JointSet::iterator jointsFromNodeEndIt = mJointsFromNode.end();
|
||||
bool result = true;
|
||||
|
||||
if ( !mJointsFromNode.empty() )
|
||||
{
|
||||
for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt )
|
||||
{
|
||||
std::string name = *jointsFromNodeIt;
|
||||
if ( mJointTransformMap.find( name ) != mJointTransformMap.end() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() <<"critiqueJointToNodeMappingFromScene is missing a: " << name << LL_ENDL;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
//Determines the following use cases for a rig:
|
||||
//1. Full av rig w/1-1 mapping from the scene and joint array
|
||||
//2. Partial rig but w/o parity between the scene and joint array
|
||||
if ( result )
|
||||
{
|
||||
setRigWithSceneParity( true );
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// isRigLegacy()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
|
||||
{
|
||||
//No joints in asset
|
||||
if ( jointListFromAsset.size() == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
JointSet :: const_iterator masterJointIt = mMasterLegacyJointList.begin();
|
||||
JointSet :: const_iterator masterJointEndIt = mMasterLegacyJointList.end();
|
||||
|
||||
std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
|
||||
std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
|
||||
|
||||
for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
|
||||
{
|
||||
result = false;
|
||||
modelJointIt = jointListFromAsset.begin();
|
||||
|
||||
for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
|
||||
{
|
||||
if ( *masterJointIt == *modelJointIt )
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !result )
|
||||
{
|
||||
LL_INFOS() <<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// isRigSuitableForJointPositionUpload()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
JointSet :: const_iterator masterJointIt = mMasterJointList.begin();
|
||||
JointSet :: const_iterator masterJointEndIt = mMasterJointList.end();
|
||||
|
||||
std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
|
||||
std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
|
||||
|
||||
for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
|
||||
{
|
||||
result = false;
|
||||
modelJointIt = jointListFromAsset.begin();
|
||||
|
||||
for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
|
||||
{
|
||||
if ( *masterJointIt == *modelJointIt )
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !result )
|
||||
{
|
||||
LL_INFOS() <<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//called in the main thread
|
||||
void LLModelLoader::loadTextures()
|
||||
{
|
||||
BOOL is_paused = isPaused() ;
|
||||
pause() ; //pause the loader
|
||||
|
||||
for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
|
||||
{
|
||||
for(U32 i = 0 ; i < iter->second.size(); i++)
|
||||
{
|
||||
for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
|
||||
j != iter->second[i].mMaterial.end(); ++j)
|
||||
{
|
||||
LLImportMaterial& material = j->second;
|
||||
|
||||
if(!material.mDiffuseMapFilename.empty())
|
||||
{
|
||||
mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_paused)
|
||||
{
|
||||
unpause() ;
|
||||
}
|
||||
}
|
||||
212
indra/llprimitive/llmodelloader.h
Normal file
212
indra/llprimitive/llmodelloader.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @file llmodelloader.h
|
||||
* @brief LLModelLoader class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&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_LLMODELLOADER_H
|
||||
#define LL_LLMODELLOADER_H
|
||||
|
||||
#include "llmodel.h"
|
||||
#include "llthread.h"
|
||||
#include <boost/function.hpp>
|
||||
#include <list>
|
||||
|
||||
class LLJoint;
|
||||
|
||||
typedef std::map<std::string, LLMatrix4> JointTransformMap;
|
||||
typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
|
||||
typedef std::map<std::string, std::string> JointMap;
|
||||
typedef std::deque<std::string> JointSet;
|
||||
|
||||
const S32 SLM_SUPPORTED_VERSION = 3;
|
||||
const S32 NUM_LOD = 4;
|
||||
|
||||
class LLModelLoader : public LLThread
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::map<std::string, LLImportMaterial> material_map;
|
||||
typedef std::vector<LLPointer<LLModel > > model_list;
|
||||
typedef std::vector<LLModelInstance> model_instance_list;
|
||||
typedef std::map<LLMatrix4, model_instance_list > scene;
|
||||
|
||||
// Callback with loaded model data and loaded LoD
|
||||
//
|
||||
typedef boost::function<void (scene&,model_list&,S32,void*) > load_callback_t;
|
||||
|
||||
// Function to provide joint lookup by name
|
||||
// (within preview avi skeleton, for example)
|
||||
//
|
||||
typedef boost::function<LLJoint* (const std::string&,void*) > joint_lookup_func_t;
|
||||
|
||||
// Func to load and associate material with all it's textures,
|
||||
// returned value is the number of textures loaded
|
||||
// intentionally non-const so func can modify material to
|
||||
// store platform-specific data
|
||||
//
|
||||
typedef boost::function<U32 (LLImportMaterial&,void*) > texture_load_func_t;
|
||||
|
||||
// Callback to inform client of state changes
|
||||
// during loading process (errors will be reported
|
||||
// as state changes here as well)
|
||||
//
|
||||
typedef boost::function<void (U32,void*) > state_callback_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STARTING = 0,
|
||||
READING_FILE,
|
||||
CREATING_FACES,
|
||||
GENERATING_VERTEX_BUFFERS,
|
||||
GENERATING_LOD,
|
||||
DONE,
|
||||
ERROR_PARSING, //basically loading failed
|
||||
ERROR_MATERIALS,
|
||||
ERROR_PASSWORD_REQUIRED,
|
||||
ERROR_NEED_MORE_MEMORY,
|
||||
ERROR_INVALID_FILE,
|
||||
ERROR_LOADER_SETUP,
|
||||
ERROR_INVALID_PARAMETERS,
|
||||
ERROR_OUT_OF_RANGE,
|
||||
ERROR_FILE_VERSION_INVALID,
|
||||
ERROR_MODEL // this error should always be last in this list, error code is passed as ERROR_MODEL+error_code
|
||||
} eLoadState;
|
||||
|
||||
U32 mState;
|
||||
std::string mFilename;
|
||||
|
||||
S32 mLod;
|
||||
|
||||
LLMatrix4 mTransform;
|
||||
BOOL mFirstTransform;
|
||||
LLVector3 mExtents[2];
|
||||
|
||||
bool mTrySLM;
|
||||
bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info)
|
||||
|
||||
model_list mModelList;
|
||||
scene mScene;
|
||||
|
||||
typedef std::queue<LLPointer<LLModel> > model_queue;
|
||||
|
||||
//queue of models that need a physics rep
|
||||
model_queue mPhysicsQ;
|
||||
|
||||
//map of avatar joints as named in COLLADA assets to internal joint names
|
||||
JointMap mJointMap;
|
||||
JointTransformMap& mJointList;
|
||||
JointSet& mJointsFromNode;
|
||||
|
||||
LLModelLoader(
|
||||
std::string filename,
|
||||
S32 lod,
|
||||
LLModelLoader::load_callback_t load_cb,
|
||||
LLModelLoader::joint_lookup_func_t joint_lookup_func,
|
||||
LLModelLoader::texture_load_func_t texture_load_func,
|
||||
LLModelLoader::state_callback_t state_cb,
|
||||
void* opaque_userdata,
|
||||
JointTransformMap& jointMap,
|
||||
JointSet& jointsFromNodes);
|
||||
virtual ~LLModelLoader() ;
|
||||
|
||||
virtual void setNoNormalize() { mNoNormalize = true; }
|
||||
virtual void setNoOptimize() { mNoOptimize = true; }
|
||||
|
||||
virtual void run();
|
||||
|
||||
// Will try SLM or derived class OpenFile as appropriate
|
||||
//
|
||||
virtual bool doLoadModel();
|
||||
|
||||
// Derived classes need to provide their parsing of files here
|
||||
//
|
||||
virtual bool OpenFile(const std::string& filename) = 0;
|
||||
|
||||
bool loadFromSLM(const std::string& filename);
|
||||
|
||||
void loadModelCallback();
|
||||
void loadTextures() ; //called in the main thread.
|
||||
void setLoadState(U32 state);
|
||||
|
||||
|
||||
|
||||
S32 mNumOfFetchingTextures ; //updated in the main thread
|
||||
bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
|
||||
|
||||
bool verifyCount( int expected, int result );
|
||||
|
||||
//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
|
||||
void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
|
||||
void critiqueJointToNodeMappingFromScene( void );
|
||||
|
||||
//Determines if a rig is a legacy from the joint list
|
||||
bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
|
||||
|
||||
//Determines if a rig is suitable for upload
|
||||
bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
|
||||
|
||||
void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; }
|
||||
const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; }
|
||||
|
||||
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
|
||||
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
|
||||
|
||||
const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
|
||||
void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// isNodeAJoint()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool isNodeAJoint(const char* name)
|
||||
{
|
||||
return mJointMap.find(name) != mJointMap.end();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
LLModelLoader::load_callback_t mLoadCallback;
|
||||
LLModelLoader::joint_lookup_func_t mJointLookupFunc;
|
||||
LLModelLoader::texture_load_func_t mTextureLoadFunc;
|
||||
LLModelLoader::state_callback_t mStateCallback;
|
||||
void* mOpaqueData;
|
||||
|
||||
bool mRigParityWithScene;
|
||||
bool mRigValidJointUpload;
|
||||
bool mLegacyRigValid;
|
||||
|
||||
bool mNoNormalize;
|
||||
bool mNoOptimize;
|
||||
|
||||
JointSet mMasterJointList;
|
||||
JointSet mMasterLegacyJointList;
|
||||
JointTransformMap mJointTransformMap;
|
||||
|
||||
static std::list<LLModelLoader*> sActiveLoaderList;
|
||||
static bool isAlive(LLModelLoader* loader) ;
|
||||
};
|
||||
class LLMatrix4a;
|
||||
void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform);
|
||||
void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform);
|
||||
|
||||
#endif // LL_LLMODELLOADER_H
|
||||
@@ -655,7 +655,6 @@ set(viewer_HEADER_FILES
|
||||
llavataractions.h
|
||||
llavatarpropertiesprocessor.h
|
||||
llbox.h
|
||||
llcallbacklist.h
|
||||
llcallingcard.h
|
||||
llcapabilitylistener.h
|
||||
llcaphttpsender.h
|
||||
|
||||
@@ -70,7 +70,7 @@ void LLCallbackList::addFunction( callback_t func, void *data)
|
||||
}
|
||||
|
||||
|
||||
BOOL LLCallbackList::containsFunction( callback_t func, void *data)
|
||||
bool LLCallbackList::containsFunction( callback_t func, void *data)
|
||||
{
|
||||
callback_pair_t t(func, data);
|
||||
callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t);
|
||||
@@ -85,7 +85,7 @@ BOOL LLCallbackList::containsFunction( callback_t func, void *data)
|
||||
}
|
||||
|
||||
|
||||
BOOL LLCallbackList::deleteFunction( callback_t func, void *data)
|
||||
bool LLCallbackList::deleteFunction( callback_t func, void *data)
|
||||
{
|
||||
callback_pair_t t(func, data);
|
||||
callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t);
|
||||
|
||||
@@ -339,6 +339,34 @@ void LLFace::dirtyTexture()
|
||||
gPipeline.markTextured(drawablep);
|
||||
}
|
||||
|
||||
void LLFace::notifyAboutCreatingTexture(LLViewerTexture *texture)
|
||||
{
|
||||
LLDrawable* drawablep = getDrawable();
|
||||
if(mVObjp.notNull() && mVObjp->getVolume())
|
||||
{
|
||||
LLVOVolume *vobj = drawablep->getVOVolume();
|
||||
if(vobj && vobj->notifyAboutCreatingTexture(texture))
|
||||
{
|
||||
gPipeline.markTextured(drawablep);
|
||||
gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFace::notifyAboutMissingAsset(LLViewerTexture *texture)
|
||||
{
|
||||
LLDrawable* drawablep = getDrawable();
|
||||
if(mVObjp.notNull() && mVObjp->getVolume())
|
||||
{
|
||||
LLVOVolume *vobj = drawablep->getVOVolume();
|
||||
if(vobj && vobj->notifyAboutMissingAsset(texture))
|
||||
{
|
||||
gPipeline.markTextured(drawablep);
|
||||
gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFace::switchTexture(U32 ch, LLViewerTexture* new_texture)
|
||||
{
|
||||
llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
|
||||
@@ -989,6 +1017,10 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po
|
||||
const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset);
|
||||
const LLVector4a& normal = vf.mNormals[0];
|
||||
const LLVector4a& tangent = vf.mTangents[0];
|
||||
if (!&tangent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLVector4a binormal;
|
||||
binormal.setCross3(normal, tangent);
|
||||
@@ -1648,7 +1680,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
||||
do_xform = false;
|
||||
}
|
||||
|
||||
if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
|
||||
if (getVirtualSize() >= MIN_TEX_ANIM_SIZE || isState(LLFace::RIGGED))
|
||||
{ //don't override texture transform during tc bake
|
||||
tex_mode = 0;
|
||||
}
|
||||
|
||||
@@ -237,6 +237,9 @@ public:
|
||||
|
||||
static U32 getRiggedDataMask(U32 type);
|
||||
|
||||
void notifyAboutCreatingTexture(LLViewerTexture *texture);
|
||||
void notifyAboutMissingAsset(LLViewerTexture *texture);
|
||||
|
||||
public: //aligned members
|
||||
LL_ALIGN_16(LLVector4a mExtents[2]);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,31 +2,25 @@
|
||||
* @file llfloatermodelpreview.h
|
||||
* @brief LLFloaterModelPreview class definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2010, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* 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.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* 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.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* 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$
|
||||
*/
|
||||
|
||||
@@ -42,105 +36,24 @@
|
||||
#include "llviewermenufile.h"
|
||||
#include "llfloatermodeluploadbase.h"
|
||||
|
||||
#include "lldaeloader.h"
|
||||
|
||||
class LLComboBox;
|
||||
class LLJoint;
|
||||
class LLViewerJointMesh;
|
||||
class LLVOAvatar;
|
||||
class LLVertexBuffer;
|
||||
class LLModelPreview;
|
||||
class LLFloaterModelPreview;
|
||||
class DAE;
|
||||
class daeElement;
|
||||
class domProfile_COMMON;
|
||||
class domInstance_geometry;
|
||||
class domNode;
|
||||
class domTranslate;
|
||||
class domController;
|
||||
|
||||
typedef std::map<std::string, LLMatrix4> JointTransformMap;
|
||||
typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
|
||||
|
||||
const S32 NUM_LOD = 4;
|
||||
|
||||
class LLModelLoader : public LLThread
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
STARTING = 0,
|
||||
READING_FILE,
|
||||
CREATING_FACES,
|
||||
GENERATING_VERTEX_BUFFERS,
|
||||
GENERATING_LOD,
|
||||
DONE,
|
||||
ERROR_PARSING, //basically loading failed
|
||||
ERROR_MATERIALS,
|
||||
} eLoadState;
|
||||
|
||||
U32 mState;
|
||||
std::string mFilename;
|
||||
S32 mLod;
|
||||
LLModelPreview* mPreview;
|
||||
LLMatrix4 mTransform;
|
||||
BOOL mFirstTransform;
|
||||
LLVector3 mExtents[2];
|
||||
bool mTrySLM;
|
||||
|
||||
std::map<daeElement*, LLPointer<LLModel> > mModel;
|
||||
|
||||
typedef std::vector<LLPointer<LLModel> > model_list;
|
||||
model_list mModelList;
|
||||
|
||||
typedef std::vector<LLModelInstance> model_instance_list;
|
||||
|
||||
typedef std::map<LLMatrix4, model_instance_list > scene;
|
||||
|
||||
scene mScene;
|
||||
|
||||
typedef std::queue<LLPointer<LLModel> > model_queue;
|
||||
|
||||
//queue of models that need a physics rep
|
||||
model_queue mPhysicsQ;
|
||||
|
||||
LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,
|
||||
std::deque<std::string>& jointsFromNodes);
|
||||
~LLModelLoader() ;
|
||||
|
||||
virtual void run();
|
||||
bool doLoadModel();
|
||||
bool loadFromSLM(const std::string& filename);
|
||||
void loadModelCallback();
|
||||
|
||||
void loadTextures() ; //called in the main thread.
|
||||
void processElement(daeElement* element, bool& badElement);
|
||||
std::map<std::string, LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo);
|
||||
LLImportMaterial profileToMaterial(domProfile_COMMON* material);
|
||||
std::string getElementLabel(daeElement *element);
|
||||
LLColor4 getDaeColor(daeElement* element);
|
||||
|
||||
daeElement* getChildFromElement(daeElement* pElement, std::string const & name);
|
||||
|
||||
bool isNodeAJoint(domNode* pNode);
|
||||
void processJointNode(domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms);
|
||||
void extractTranslation(domTranslate* pTranslate, LLMatrix4& transform);
|
||||
void extractTranslationViaElement(daeElement* pTranslateElement, LLMatrix4& transform);
|
||||
void extractTranslationViaSID(daeElement* pElement, LLMatrix4& transform);
|
||||
|
||||
void setLoadState(U32 state);
|
||||
|
||||
void buildJointToNodeMappingFromScene(daeElement* pRoot);
|
||||
void processJointToNodeMapping(domNode* pNode);
|
||||
void processChildJoints(domNode* pParentNode);
|
||||
|
||||
//map of avatar joints as named in COLLADA assets to internal joint names
|
||||
std::map<std::string, std::string> mJointMap;
|
||||
JointTransformMap& mJointList;
|
||||
std::deque<std::string>& mJointsFromNode;
|
||||
|
||||
S32 mNumOfFetchingTextures ; //updated in the main thread
|
||||
bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
|
||||
|
||||
private:
|
||||
static std::list<LLModelLoader*> sActiveLoaderList;
|
||||
static bool isAlive(LLModelLoader* loader) ;
|
||||
};
|
||||
class domSkin;
|
||||
class domMesh;
|
||||
|
||||
class LLFloaterModelPreview : public LLFloaterModelUploadBase
|
||||
{
|
||||
@@ -171,7 +84,8 @@ public:
|
||||
BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
|
||||
|
||||
/*virtual*/ void onOpen(/*const LLSD& key*/);
|
||||
/*virtual*/ void onOpen();
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
|
||||
static void onMouseCaptureLostModelPreview(LLMouseHandler*);
|
||||
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
|
||||
@@ -211,6 +125,8 @@ public:
|
||||
|
||||
/*virtual*/ void onModelUploadFailure();
|
||||
|
||||
bool isModelUploadAllowed();
|
||||
|
||||
protected:
|
||||
friend class LLModelPreview;
|
||||
friend class LLPhysicsDecomp;
|
||||
@@ -339,8 +255,12 @@ public:
|
||||
void clearModel(S32 lod);
|
||||
void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);
|
||||
void loadModelCallback(S32 lod);
|
||||
bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
|
||||
void queryLODs() { mGenLOD = true; };
|
||||
void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
|
||||
void genModelBBox(); // Generate just a model BBox if we can't generate proper LOD
|
||||
void generateNormals();
|
||||
void restoreNormals();
|
||||
U32 calcResourceCost();
|
||||
void rebuildUploadData();
|
||||
void saveUploadData(bool save_skinweights, bool save_joint_poisitions);
|
||||
@@ -354,44 +274,51 @@ public:
|
||||
|
||||
const bool getModelPivot(void) const { return mHasPivot; }
|
||||
void setHasPivot(bool val) { mHasPivot = val; }
|
||||
void setModelPivot(const LLVector3& pivot) { mModelPivot = pivot; }
|
||||
void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; }
|
||||
|
||||
//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
|
||||
void critiqueRigForUploadApplicability(const std::vector<std::string> &jointListFromAsset);
|
||||
void critiqueJointToNodeMappingFromScene(void);
|
||||
//Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions
|
||||
//Accessors for joint position upload friendly rigs
|
||||
const bool isRigValidForJointPositionUpload(void) const { return mRigValidJointUpload; }
|
||||
void setRigValidForJointPositionUpload(bool rigValid) { mRigValidJointUpload = rigValid; }
|
||||
bool isRigSuitableForJointPositionUpload(const std::vector<std::string> &jointListFromAsset);
|
||||
//Determines if a rig is a legacy from the joint list
|
||||
bool isRigLegacy(const std::vector<std::string> &jointListFromAsset);
|
||||
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
|
||||
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
|
||||
|
||||
//Accessors for the legacy rigs
|
||||
const bool isLegacyRigValid(void) const { return mLegacyRigValid; }
|
||||
void setLegacyRigValid(bool rigValid) { mLegacyRigValid = rigValid; }
|
||||
//Verify that a controller matches vertex counts
|
||||
bool verifyController(domController* pController);
|
||||
const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
|
||||
void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
|
||||
|
||||
static void textureLoadedCallback(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata);
|
||||
|
||||
boost::signals2::connection setDetailsCallback(const details_signal_t::slot_type& cb){ return mDetailsSignal.connect(cb); }
|
||||
boost::signals2::connection setModelLoadedCallback(const model_loaded_signal_t::slot_type& cb){ return mModelLoadedSignal.connect(cb); }
|
||||
boost::signals2::connection setModelUpdatedCallback(const model_updated_signal_t::slot_type& cb){ return mModelUpdatedSignal.connect(cb); }
|
||||
|
||||
void setLoadState(U32 state) { mLoadState = state; }
|
||||
static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
|
||||
static bool lodQueryCallback();
|
||||
|
||||
boost::signals2::connection setDetailsCallback( const details_signal_t::slot_type& cb ){ return mDetailsSignal.connect(cb); }
|
||||
boost::signals2::connection setModelLoadedCallback( const model_loaded_signal_t::slot_type& cb ){ return mModelLoadedSignal.connect(cb); }
|
||||
boost::signals2::connection setModelUpdatedCallback( const model_updated_signal_t::slot_type& cb ){ return mModelUpdatedSignal.connect(cb); }
|
||||
|
||||
void setLoadState( U32 state ) { mLoadState = state; }
|
||||
U32 getLoadState() { return mLoadState; }
|
||||
void setRigWithSceneParity(bool state) { mRigParityWithScene = state; }
|
||||
const bool getRigWithSceneParity(void) const { return mRigParityWithScene; }
|
||||
void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; }
|
||||
const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; }
|
||||
|
||||
LLVector3 getTranslationForJointOffset( std::string joint );
|
||||
|
||||
LLVector3 getTranslationForJointOffset(std::string joint);
|
||||
static bool sIgnoreLoadedCallback;
|
||||
std::vector<S32> mLodsQuery;
|
||||
|
||||
protected:
|
||||
|
||||
static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque);
|
||||
static void stateChangedCallback(U32 state, void* opaque);
|
||||
|
||||
static LLJoint* lookupJointByName(const std::string&, void* opaque);
|
||||
static U32 loadTextures(LLImportMaterial& material, void* opaque);
|
||||
|
||||
private:
|
||||
//Utility function for controller vertex compare
|
||||
bool verifyCount(int expected, int result);
|
||||
bool verifyCount( int expected, int result );
|
||||
//Creates the dummy avatar for the preview window
|
||||
void createPreviewAvatar(void);
|
||||
void createPreviewAvatar( void );
|
||||
//Accessor for the dummy avatar
|
||||
LLVOAvatar* getPreviewAvatar(void) { return mPreviewAvatar; }
|
||||
LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; }
|
||||
// Count amount of original models, excluding sub-models
|
||||
static U32 countRootModels(LLModelLoader::model_list models);
|
||||
|
||||
protected:
|
||||
friend class LLModelLoader;
|
||||
@@ -413,12 +340,14 @@ private:
|
||||
LLVector3 mPreviewTarget;
|
||||
LLVector3 mPreviewScale;
|
||||
S32 mPreviewLOD;
|
||||
S32 mPhysicsSearchLOD;
|
||||
U32 mResourceCost;
|
||||
std::string mLODFile[LLModel::NUM_LODS];
|
||||
bool mLoading;
|
||||
U32 mLoadState;
|
||||
bool mResetJoints;
|
||||
bool mRigParityWithScene;
|
||||
bool mModelNoErrors;
|
||||
|
||||
std::map<std::string, bool> mViewOption;
|
||||
|
||||
@@ -445,6 +374,12 @@ private:
|
||||
LLModelLoader::model_list mModel[LLModel::NUM_LODS];
|
||||
LLModelLoader::model_list mBaseModel;
|
||||
|
||||
typedef std::vector<LLVolumeFace> v_LLVolumeFace_t;
|
||||
typedef std::vector<v_LLVolumeFace_t> vv_LLVolumeFace_t;
|
||||
|
||||
vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS];
|
||||
vv_LLVolumeFace_t mBaseModelFacesCopy;
|
||||
|
||||
U32 mGroup;
|
||||
std::map<LLPointer<LLModel>, U32> mObject;
|
||||
U32 mMaxTriangleLimit;
|
||||
@@ -463,16 +398,15 @@ private:
|
||||
bool mHasPivot;
|
||||
|
||||
float mPelvisZOffset;
|
||||
|
||||
|
||||
bool mRigValidJointUpload;
|
||||
bool mLegacyRigValid;
|
||||
|
||||
bool mLastJointUpdate;
|
||||
|
||||
std::deque<std::string> mMasterJointList;
|
||||
std::deque<std::string> mMasterLegacyJointList;
|
||||
std::deque<std::string> mJointsFromNode;
|
||||
JointTransformMap mJointTransformMap;
|
||||
JointSet mJointsFromNode;
|
||||
JointTransformMap mJointTransformMap;
|
||||
|
||||
LLPointer<LLVOAvatar> mPreviewAvatar;
|
||||
};
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ std::string header_lod[] =
|
||||
"medium_lod",
|
||||
"high_lod"
|
||||
};
|
||||
const char * const LOG_MESH = "Mesh";
|
||||
|
||||
|
||||
//get the number of bytes resident in memory for given volume
|
||||
@@ -206,6 +207,12 @@ void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res,
|
||||
}
|
||||
}
|
||||
|
||||
LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material)
|
||||
{
|
||||
LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData);
|
||||
return ppTex ? (*ppTex).get() : NULL;
|
||||
}
|
||||
|
||||
S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
|
||||
S32 LLMeshRepoThread::sActiveLODRequests = 0;
|
||||
U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
|
||||
@@ -1429,6 +1436,13 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
|
||||
{
|
||||
LLMeshUploadData data;
|
||||
data.mBaseModel = iter->first;
|
||||
|
||||
if (data.mBaseModel->mSubmodelID)
|
||||
{
|
||||
// These are handled below to insure correct parenting order on creation
|
||||
// due to map walking being based on model address (aka random)
|
||||
continue;
|
||||
}
|
||||
LLModelInstance& first_instance = *(iter->second.begin());
|
||||
for (S32 i = 0; i < 5; i++)
|
||||
{
|
||||
@@ -1466,7 +1480,10 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
|
||||
data.mModel[LLModel::LOD_IMPOSTOR],
|
||||
decomp,
|
||||
mUploadSkin,
|
||||
mUploadJoints);
|
||||
mUploadJoints,
|
||||
FALSE,
|
||||
FALSE,
|
||||
data.mBaseModel->mSubmodelID);
|
||||
|
||||
data.mAssetData = ostr.str();
|
||||
std::string str = ostr.str();
|
||||
@@ -1500,17 +1517,26 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
|
||||
instance_entry["scale"] = ll_sd_from_vector3(scale);
|
||||
|
||||
instance_entry["material"] = LL_MCODE_WOOD;
|
||||
instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
|
||||
instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
|
||||
instance_entry["mesh"] = mesh_index[data.mBaseModel];
|
||||
|
||||
instance_entry["face_list"] = LLSD::emptyArray();
|
||||
|
||||
S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ;
|
||||
// We want to be able to allow more than 8 materials...
|
||||
//
|
||||
S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ;
|
||||
|
||||
for (S32 face_num = 0; face_num < end; face_num++)
|
||||
{
|
||||
LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
|
||||
LLSD face_entry = LLSD::emptyMap();
|
||||
LLViewerFetchedTexture *texture = material.mDiffuseMap.get();
|
||||
|
||||
LLViewerFetchedTexture *texture = NULL;
|
||||
|
||||
if (material.mDiffuseMapFilename.size())
|
||||
{
|
||||
texture = FindViewerTexture(material);
|
||||
}
|
||||
|
||||
if ((texture != NULL) &&
|
||||
(textures.find(texture) == textures.end()))
|
||||
@@ -1525,9 +1551,171 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
|
||||
{
|
||||
LLPointer<LLImageJ2C> upload_file =
|
||||
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
|
||||
|
||||
if (!upload_file.isNull() && upload_file->getDataSize())
|
||||
{
|
||||
texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (texture != NULL &&
|
||||
mUploadTextures &&
|
||||
texture_index.find(texture) == texture_index.end())
|
||||
{
|
||||
texture_index[texture] = texture_num;
|
||||
std::string str = texture_str.str();
|
||||
res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
|
||||
texture_num++;
|
||||
}
|
||||
|
||||
// Subset of TextureEntry fields.
|
||||
if (texture != NULL && mUploadTextures)
|
||||
{
|
||||
face_entry["image"] = texture_index[texture];
|
||||
face_entry["scales"] = 1.0;
|
||||
face_entry["scalet"] = 1.0;
|
||||
face_entry["offsets"] = 0.0;
|
||||
face_entry["offsett"] = 0.0;
|
||||
face_entry["imagerot"] = 0.0;
|
||||
}
|
||||
face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor);
|
||||
face_entry["fullbright"] = material.mFullbright;
|
||||
instance_entry["face_list"][face_num] = face_entry;
|
||||
}
|
||||
|
||||
res["instance_list"][instance_num] = instance_entry;
|
||||
instance_num++;
|
||||
}
|
||||
}
|
||||
|
||||
for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
|
||||
{
|
||||
LLMeshUploadData data;
|
||||
data.mBaseModel = iter->first;
|
||||
|
||||
if (!data.mBaseModel->mSubmodelID)
|
||||
{
|
||||
// These were handled above already...
|
||||
//
|
||||
continue;
|
||||
}
|
||||
|
||||
LLModelInstance& first_instance = *(iter->second.begin());
|
||||
for (S32 i = 0; i < 5; i++)
|
||||
{
|
||||
data.mModel[i] = first_instance.mLOD[i];
|
||||
}
|
||||
|
||||
if (mesh_index.find(data.mBaseModel) == mesh_index.end())
|
||||
{
|
||||
// Have not seen this model before - create a new mesh_list entry for it.
|
||||
if (model_name.empty())
|
||||
{
|
||||
model_name = data.mBaseModel->getName();
|
||||
}
|
||||
|
||||
if (model_metric.empty())
|
||||
{
|
||||
model_metric = data.mBaseModel->getMetric();
|
||||
}
|
||||
|
||||
std::stringstream ostr;
|
||||
|
||||
LLModel::Decomposition& decomp =
|
||||
data.mModel[LLModel::LOD_PHYSICS].notNull() ?
|
||||
data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
|
||||
data.mBaseModel->mPhysics;
|
||||
|
||||
decomp.mBaseHull = mHullMap[data.mBaseModel];
|
||||
|
||||
LLSD mesh_header = LLModel::writeModel(
|
||||
ostr,
|
||||
data.mModel[LLModel::LOD_PHYSICS],
|
||||
data.mModel[LLModel::LOD_HIGH],
|
||||
data.mModel[LLModel::LOD_MEDIUM],
|
||||
data.mModel[LLModel::LOD_LOW],
|
||||
data.mModel[LLModel::LOD_IMPOSTOR],
|
||||
decomp,
|
||||
mUploadSkin,
|
||||
mUploadJoints,
|
||||
FALSE,
|
||||
FALSE,
|
||||
data.mBaseModel->mSubmodelID);
|
||||
|
||||
data.mAssetData = ostr.str();
|
||||
std::string str = ostr.str();
|
||||
|
||||
res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end());
|
||||
mesh_index[data.mBaseModel] = mesh_num;
|
||||
mesh_num++;
|
||||
}
|
||||
|
||||
// For all instances that use this model
|
||||
for (instance_list::iterator instance_iter = iter->second.begin();
|
||||
instance_iter != iter->second.end();
|
||||
++instance_iter)
|
||||
{
|
||||
|
||||
LLModelInstance& instance = *instance_iter;
|
||||
|
||||
LLSD instance_entry;
|
||||
|
||||
for (S32 i = 0; i < 5; i++)
|
||||
{
|
||||
data.mModel[i] = instance.mLOD[i];
|
||||
}
|
||||
|
||||
LLVector3 pos, scale;
|
||||
LLQuaternion rot;
|
||||
LLMatrix4 transformation = instance.mTransform;
|
||||
decomposeMeshMatrix(transformation,pos,rot,scale);
|
||||
instance_entry["position"] = ll_sd_from_vector3(pos);
|
||||
instance_entry["rotation"] = ll_sd_from_quaternion(rot);
|
||||
instance_entry["scale"] = ll_sd_from_vector3(scale);
|
||||
|
||||
instance_entry["material"] = LL_MCODE_WOOD;
|
||||
instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_NONE);
|
||||
instance_entry["mesh"] = mesh_index[data.mBaseModel];
|
||||
|
||||
instance_entry["face_list"] = LLSD::emptyArray();
|
||||
|
||||
// We want to be able to allow more than 8 materials...
|
||||
//
|
||||
S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ;
|
||||
|
||||
for (S32 face_num = 0; face_num < end; face_num++)
|
||||
{
|
||||
LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
|
||||
LLSD face_entry = LLSD::emptyMap();
|
||||
|
||||
LLViewerFetchedTexture *texture = NULL;
|
||||
|
||||
if (material.mDiffuseMapFilename.size())
|
||||
{
|
||||
texture = FindViewerTexture(material);
|
||||
}
|
||||
|
||||
if ((texture != NULL) &&
|
||||
(textures.find(texture) == textures.end()))
|
||||
{
|
||||
textures.insert(texture);
|
||||
}
|
||||
|
||||
std::stringstream texture_str;
|
||||
if (texture != NULL && include_textures && mUploadTextures)
|
||||
{
|
||||
if(texture->hasSavedRawImage())
|
||||
{
|
||||
LLPointer<LLImageJ2C> upload_file =
|
||||
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
|
||||
|
||||
if (!upload_file.isNull() && upload_file->getDataSize())
|
||||
{
|
||||
texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (texture != NULL &&
|
||||
mUploadTextures &&
|
||||
@@ -2165,7 +2353,7 @@ void LLMeshRepository::init()
|
||||
|
||||
void LLMeshRepository::shutdown()
|
||||
{
|
||||
LL_INFOS() << "Shutting down mesh repository." << LL_ENDL;
|
||||
LL_INFOS(LOG_MESH) << "Shutting down mesh repository." << LL_ENDL;
|
||||
|
||||
mThread->mSignal->signal();
|
||||
|
||||
@@ -2179,7 +2367,7 @@ void LLMeshRepository::shutdown()
|
||||
delete mMeshMutex;
|
||||
mMeshMutex = NULL;
|
||||
|
||||
LL_INFOS() << "Shutting down decomposition system." << LL_ENDL;
|
||||
LL_INFOS(LOG_MESH) << "Shutting down decomposition system." << LL_ENDL;
|
||||
|
||||
if (mDecompThread)
|
||||
{
|
||||
@@ -2407,7 +2595,8 @@ void LLMeshRepository::notifyLoadedMeshes()
|
||||
}
|
||||
|
||||
//sort by "score"
|
||||
std::sort(mPendingRequests.begin(), mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater());
|
||||
std::partial_sort(mPendingRequests.begin(), mPendingRequests.begin() + push_count,
|
||||
mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater());
|
||||
|
||||
while (!mPendingRequests.empty() && push_count > 0)
|
||||
{
|
||||
@@ -2461,9 +2650,8 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
|
||||
vobj->notifyMeshLoaded();
|
||||
}
|
||||
}
|
||||
mLoadingSkins.erase(info.mMeshID);
|
||||
}
|
||||
|
||||
mLoadingSkins.erase(info.mMeshID);
|
||||
}
|
||||
|
||||
void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp)
|
||||
@@ -2472,18 +2660,18 @@ void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decom
|
||||
if (iter == mDecompositionMap.end())
|
||||
{ //just insert decomp into map
|
||||
mDecompositionMap[decomp->mMeshID] = decomp;
|
||||
mLoadingDecompositions.erase(decomp->mMeshID);
|
||||
}
|
||||
else
|
||||
{ //merge decomp with existing entry
|
||||
{ //merge decomp with existing entry
|
||||
iter->second->merge(decomp);
|
||||
mLoadingDecompositions.erase(decomp->mMeshID);
|
||||
delete decomp;
|
||||
}
|
||||
|
||||
mLoadingDecompositions.erase(decomp->mMeshID);
|
||||
}
|
||||
|
||||
void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume)
|
||||
{ //called from main thread
|
||||
{ //called from main thread
|
||||
S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail());
|
||||
|
||||
//get list of objects waiting to be notified this mesh is loaded
|
||||
@@ -2494,7 +2682,8 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol
|
||||
//make sure target volume is still valid
|
||||
if (volume->getNumVolumeFaces() <= 0)
|
||||
{
|
||||
LL_WARNS() << "Mesh loading returned empty volume." << LL_ENDL;
|
||||
LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume. ID: " << mesh_params.getSculptID()
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
{ //update system volume
|
||||
@@ -2507,7 +2696,8 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Couldn't find system volume for given mesh." << LL_ENDL;
|
||||
LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_params.getSculptID()
|
||||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2774,37 +2964,6 @@ void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation,
|
||||
result_rot = quat_rotation;
|
||||
}
|
||||
|
||||
bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
|
||||
{
|
||||
if (mDiffuseMap != rhs.mDiffuseMap)
|
||||
{
|
||||
return mDiffuseMap < rhs.mDiffuseMap;
|
||||
}
|
||||
|
||||
if (mDiffuseMapFilename != rhs.mDiffuseMapFilename)
|
||||
{
|
||||
return mDiffuseMapFilename < rhs.mDiffuseMapFilename;
|
||||
}
|
||||
|
||||
if (mDiffuseMapLabel != rhs.mDiffuseMapLabel)
|
||||
{
|
||||
return mDiffuseMapLabel < rhs.mDiffuseMapLabel;
|
||||
}
|
||||
|
||||
if (mDiffuseColor != rhs.mDiffuseColor)
|
||||
{
|
||||
return mDiffuseColor < rhs.mDiffuseColor;
|
||||
}
|
||||
|
||||
if (mBinding != rhs.mBinding)
|
||||
{
|
||||
return mBinding < rhs.mBinding;
|
||||
}
|
||||
|
||||
return mFullbright < rhs.mFullbright;
|
||||
}
|
||||
|
||||
|
||||
void LLMeshRepository::updateInventory(inventory_data data)
|
||||
{
|
||||
LLMutexLock lock(mMeshMutex);
|
||||
@@ -3036,7 +3195,7 @@ void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh, bool vertex_based)
|
||||
|
||||
if (ret)
|
||||
{
|
||||
LL_ERRS() << "Convex Decomposition thread valid but could not set mesh data" << LL_ENDL;
|
||||
LL_ERRS(LOG_MESH) << "Convex Decomposition thread valid but could not set mesh data." << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3112,7 +3271,8 @@ void LLPhysicsDecomp::doDecomposition()
|
||||
|
||||
if (ret)
|
||||
{
|
||||
LL_WARNS() << "Convex Decomposition thread valid but could not execute stage " << stage << LL_ENDL;
|
||||
LL_WARNS(LOG_MESH) << "Convex Decomposition thread valid but could not execute stage " << stage << "."
|
||||
<< LL_ENDL;
|
||||
LLMutexLock lock(mMutex);
|
||||
|
||||
mCurRequest->mHull.clear();
|
||||
@@ -3243,7 +3403,7 @@ void LLPhysicsDecomp::doDecompositionSingleHull()
|
||||
LLCDResult ret = decomp->buildSingleHull() ;
|
||||
if(ret)
|
||||
{
|
||||
LL_WARNS() << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL;
|
||||
LL_WARNS(LOG_MESH) << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL;
|
||||
make_box(mCurRequest);
|
||||
}
|
||||
else
|
||||
@@ -3491,60 +3651,6 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg)
|
||||
mStatusMessage = msg;
|
||||
}
|
||||
|
||||
LLModelInstance::LLModelInstance(LLSD& data)
|
||||
{
|
||||
mLocalMeshID = data["mesh_id"].asInteger();
|
||||
mLabel = data["label"].asString();
|
||||
mTransform.setValue(data["transform"]);
|
||||
|
||||
for (U32 i = 0; i < (U32)data["material"].size(); ++i)
|
||||
{
|
||||
LLImportMaterial mat(data["material"][i]);
|
||||
mMaterial[mat.mBinding] = mat;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LLSD LLModelInstance::asLLSD()
|
||||
{
|
||||
LLSD ret;
|
||||
|
||||
ret["mesh_id"] = mModel->mLocalID;
|
||||
ret["label"] = mLabel;
|
||||
ret["transform"] = mTransform.getValue();
|
||||
|
||||
U32 i = 0;
|
||||
for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter)
|
||||
{
|
||||
ret["material"][i++] = iter->second.asLLSD();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LLImportMaterial::LLImportMaterial(LLSD& data)
|
||||
{
|
||||
mDiffuseMapFilename = data["diffuse"]["filename"].asString();
|
||||
mDiffuseMapLabel = data["diffuse"]["label"].asString();
|
||||
mDiffuseColor.setValue(data["diffuse"]["color"]);
|
||||
mFullbright = data["fullbright"].asBoolean();
|
||||
mBinding = data["binding"].asString();
|
||||
}
|
||||
|
||||
|
||||
LLSD LLImportMaterial::asLLSD()
|
||||
{
|
||||
LLSD ret;
|
||||
|
||||
ret["diffuse"]["filename"] = mDiffuseMapFilename;
|
||||
ret["diffuse"]["label"] = mDiffuseMapLabel;
|
||||
ret["diffuse"]["color"] = mDiffuseColor.getValue();
|
||||
ret["fullbright"] = mFullbright;
|
||||
ret["binding"] = mBinding;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp)
|
||||
{
|
||||
decomp.mMesh.resize(decomp.mHull.size());
|
||||
|
||||
@@ -92,54 +92,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class LLImportMaterial
|
||||
{
|
||||
public:
|
||||
LLPointer<LLViewerFetchedTexture> mDiffuseMap;
|
||||
std::string mDiffuseMapFilename;
|
||||
std::string mDiffuseMapLabel;
|
||||
std::string mBinding;
|
||||
LLColor4 mDiffuseColor;
|
||||
bool mFullbright;
|
||||
|
||||
bool operator<(const LLImportMaterial ¶ms) const;
|
||||
|
||||
LLImportMaterial()
|
||||
: mFullbright(false)
|
||||
{
|
||||
mDiffuseColor.set(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
LLImportMaterial(LLSD& data);
|
||||
|
||||
LLSD asLLSD();
|
||||
};
|
||||
|
||||
class LLModelInstance
|
||||
{
|
||||
public:
|
||||
LLPointer<LLModel> mModel;
|
||||
LLPointer<LLModel> mLOD[5];
|
||||
|
||||
std::string mLabel;
|
||||
|
||||
LLUUID mMeshID;
|
||||
S32 mLocalMeshID;
|
||||
|
||||
LLMatrix4 mTransform;
|
||||
std::map<std::string, LLImportMaterial> mMaterial;
|
||||
|
||||
LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials)
|
||||
: mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
|
||||
{
|
||||
mLocalMeshID = -1;
|
||||
}
|
||||
|
||||
LLModelInstance(LLSD& data);
|
||||
|
||||
LLSD asLLSD();
|
||||
};
|
||||
|
||||
class LLPhysicsDecomp : public LLThread
|
||||
{
|
||||
public:
|
||||
@@ -441,6 +393,7 @@ public:
|
||||
void setFeeObserverHandle(LLHandle<LLWholeModelFeeObserver> observer_handle) { mFeeObserverHandle = observer_handle; }
|
||||
void setUploadObserverHandle(LLHandle<LLWholeModelUploadObserver> observer_handle) { mUploadObserverHandle = observer_handle; }
|
||||
|
||||
LLViewerFetchedTexture* FindViewerTexture(const LLImportMaterial& material);
|
||||
private:
|
||||
LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;
|
||||
LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle;
|
||||
|
||||
@@ -372,10 +372,17 @@ void LLViewerObject::markDead()
|
||||
//</singu>
|
||||
|
||||
// Root object of this hierarchy unlinks itself.
|
||||
LLVOAvatar *av = getAvatarAncestor();
|
||||
if (getParent())
|
||||
{
|
||||
((LLViewerObject *)getParent())->removeChild(this);
|
||||
}
|
||||
LLUUID mesh_id;
|
||||
if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id))
|
||||
{
|
||||
// This case is needed for indirectly attached mesh objects.
|
||||
av->resetJointPositionsOnDetach(mesh_id);
|
||||
}
|
||||
|
||||
// Mark itself as dead
|
||||
mDead = TRUE;
|
||||
@@ -4798,6 +4805,22 @@ LLVOAvatar* LLViewerObject::asAvatar()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If this object is directly or indirectly parented by an avatar, return it.
|
||||
LLVOAvatar* LLViewerObject::getAvatarAncestor()
|
||||
{
|
||||
LLViewerObject *pobj = (LLViewerObject*) getParent();
|
||||
while (pobj)
|
||||
{
|
||||
LLVOAvatar *av = pobj->asAvatar();
|
||||
if (av)
|
||||
{
|
||||
return av;
|
||||
}
|
||||
pobj = (LLViewerObject*) pobj->getParent();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL LLViewerObject::isParticleSource() const
|
||||
{
|
||||
return !mPartSourcep.isNull() && !mPartSourcep->isDead();
|
||||
|
||||
@@ -141,6 +141,8 @@ public:
|
||||
|
||||
virtual LLVOAvatar* asAvatar();
|
||||
|
||||
LLVOAvatar* getAvatarAncestor();
|
||||
|
||||
static void initVOClasses();
|
||||
static void cleanupVOClasses();
|
||||
|
||||
|
||||
@@ -536,7 +536,6 @@ void output_statistics(void*)
|
||||
LL_INFOS() << "--------------------------------" << LL_ENDL;
|
||||
LL_INFOS() << "Avatar Memory (partly overlaps with above stats):" << LL_ENDL;
|
||||
LLTexLayerStaticImageList::getInstance()->dumpByteCount();
|
||||
LLVOAvatarSelf::dumpScratchTextureByteCount();
|
||||
LLViewerTexLayerSetBuffer::dumpTotalByteCount();
|
||||
LLVOAvatarSelf::dumpTotalLocalTextureByteCount();
|
||||
LLTexLayerParamAlpha::dumpCacheByteCount();
|
||||
|
||||
@@ -614,6 +614,7 @@ LLViewerTexture::~LLViewerTexture()
|
||||
// virtual
|
||||
void LLViewerTexture::init(bool firstinit)
|
||||
{
|
||||
mSelectedTime = 0.f;
|
||||
mMaxVirtualSize = 0.f;
|
||||
mNeedsGLTexture = FALSE ;
|
||||
mMaxVirtualSizeResetInterval = 1;
|
||||
@@ -639,12 +640,37 @@ S8 LLViewerTexture::getType() const
|
||||
|
||||
void LLViewerTexture::cleanup()
|
||||
{
|
||||
mFaceList[LLRender::DIFFUSE_MAP].clear() ;
|
||||
mFaceList[LLRender::NORMAL_MAP].clear() ;
|
||||
notifyAboutMissingAsset();
|
||||
|
||||
mFaceList[LLRender::DIFFUSE_MAP].clear();
|
||||
mFaceList[LLRender::NORMAL_MAP].clear();
|
||||
mFaceList[LLRender::SPECULAR_MAP].clear() ;
|
||||
mVolumeList.clear();
|
||||
}
|
||||
|
||||
void LLViewerTexture::notifyAboutCreatingTexture()
|
||||
{
|
||||
for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
|
||||
{
|
||||
for(U32 f = 0; f < mNumFaces[ch]; f++)
|
||||
{
|
||||
mFaceList[ch][f]->notifyAboutCreatingTexture(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLViewerTexture::notifyAboutMissingAsset()
|
||||
{
|
||||
for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
|
||||
{
|
||||
for(U32 f = 0; f < mNumFaces[ch]; f++)
|
||||
{
|
||||
mFaceList[ch][f]->notifyAboutMissingAsset(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLViewerTexture::dump()
|
||||
{
|
||||
LLGLTexture::dump();
|
||||
@@ -654,6 +680,30 @@ void LLViewerTexture::dump()
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
void LLViewerTexture::setBoostLevel(S32 level)
|
||||
{
|
||||
if(mBoostLevel != level)
|
||||
{
|
||||
mBoostLevel = level;
|
||||
if(mBoostLevel != LLViewerTexture::BOOST_NONE &&
|
||||
mBoostLevel != LLViewerTexture::BOOST_SELECTED)
|
||||
{
|
||||
setNoDelete();
|
||||
}
|
||||
}
|
||||
|
||||
if (mBoostLevel == LLViewerTexture::BOOST_SELECTED)
|
||||
{
|
||||
mSelectedTime = gFrameTimeSeconds;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool LLViewerTexture::isActiveFetching()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLViewerTexture::bindDefaultImage(S32 stage)
|
||||
{
|
||||
if (stage < 0) return false;
|
||||
@@ -945,6 +995,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
|
||||
{
|
||||
mOrigWidth = 0;
|
||||
mOrigHeight = 0;
|
||||
mHasAux = FALSE;
|
||||
mNeedsAux = FALSE;
|
||||
mRequestedDiscardLevel = -1;
|
||||
mRequestedDownloadPriority = 0.f;
|
||||
@@ -1002,6 +1053,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
|
||||
mLastReferencedSavedRawImageTime = 0.0f ;
|
||||
mKeptSavedRawImageTime = 0.f ;
|
||||
mLastCallBackActiveTime = 0.f;
|
||||
mForceCallbackFetch = FALSE;
|
||||
}
|
||||
|
||||
LLViewerFetchedTexture::~LLViewerFetchedTexture()
|
||||
@@ -1348,6 +1400,7 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
|
||||
//{
|
||||
res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
|
||||
//resetFaceAtlas() ;
|
||||
notifyAboutCreatingTexture();
|
||||
//}
|
||||
setActive() ;
|
||||
}
|
||||
@@ -1666,6 +1719,14 @@ void LLViewerFetchedTexture::updateVirtualSize()
|
||||
}
|
||||
}
|
||||
}
|
||||
//reset whether or not a face was selected after 10 seconds
|
||||
const F32 SELECTION_RESET_TIME = 10.f;
|
||||
|
||||
if (getBoostLevel() == LLViewerTexture::BOOST_SELECTED &&
|
||||
gFrameTimeSeconds - mSelectedTime > SELECTION_RESET_TIME)
|
||||
{
|
||||
setBoostLevel(LLViewerTexture::BOOST_NONE);
|
||||
}
|
||||
|
||||
if(mMaxVirtualSizeResetCounter > 0)
|
||||
{
|
||||
@@ -1693,6 +1754,27 @@ S32 LLViewerFetchedTexture::getCurrentDiscardLevelForFetching()
|
||||
return current_discard ;
|
||||
}
|
||||
|
||||
bool LLViewerFetchedTexture::setDebugFetching(S32 debug_level)
|
||||
{
|
||||
if(debug_level < 0)
|
||||
{
|
||||
mInDebug = FALSE;
|
||||
return false;
|
||||
}
|
||||
mInDebug = TRUE;
|
||||
|
||||
mDesiredDiscardLevel = debug_level;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLViewerFetchedTexture::isActiveFetching()
|
||||
{
|
||||
static LLCachedControl<bool> monitor_enabled(gSavedSettings,"DebugShowTextureInfo");
|
||||
|
||||
return mFetchState > 7 && mFetchState < 10 && monitor_enabled; //in state of WAIT_HTTP_REQ or DECODE_IMAGE.
|
||||
}
|
||||
|
||||
bool LLViewerFetchedTexture::updateFetch()
|
||||
{
|
||||
static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled");
|
||||
@@ -1745,7 +1827,11 @@ bool LLViewerFetchedTexture::updateFetch()
|
||||
if (mAuxRawImage.notNull()) sAuxCount--;
|
||||
bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage);
|
||||
if (mRawImage.notNull()) sRawCount++;
|
||||
if (mAuxRawImage.notNull()) sAuxCount++;
|
||||
if (mAuxRawImage.notNull())
|
||||
{
|
||||
mHasAux = TRUE;
|
||||
sAuxCount++;
|
||||
}
|
||||
if (finished)
|
||||
{
|
||||
mIsFetching = FALSE;
|
||||
@@ -1808,7 +1894,7 @@ bool LLViewerFetchedTexture::updateFetch()
|
||||
if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL))
|
||||
{
|
||||
// We finished but received no data
|
||||
if (current_discard < 0)
|
||||
if (getDiscardLevel() < 0)
|
||||
{
|
||||
LL_WARNS() << "!mIsFetching, setting as missing, decode_priority " << decode_priority
|
||||
<< " mRawDiscardLevel " << mRawDiscardLevel
|
||||
@@ -1820,8 +1906,17 @@ bool LLViewerFetchedTexture::updateFetch()
|
||||
else
|
||||
{
|
||||
//LL_WARNS() << mID << ": Setting min discard to " << current_discard << LL_ENDL;
|
||||
mMinDiscardLevel = current_discard;
|
||||
desired_discard = current_discard;
|
||||
if(current_discard >= 0)
|
||||
{
|
||||
mMinDiscardLevel = current_discard;
|
||||
desired_discard = current_discard;
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 dis_level = getDiscardLevel();
|
||||
mMinDiscardLevel = dis_level;
|
||||
desired_discard = dis_level;
|
||||
}
|
||||
}
|
||||
destroyRawImage();
|
||||
}
|
||||
@@ -1959,6 +2054,22 @@ bool LLViewerFetchedTexture::updateFetch()
|
||||
return mIsFetching ? true : false;
|
||||
}
|
||||
|
||||
void LLViewerFetchedTexture::clearFetchedResults()
|
||||
{
|
||||
if(mNeedsCreateTexture || mIsFetching)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cleanup();
|
||||
destroyGLTexture();
|
||||
|
||||
if(getDiscardLevel() >= 0) //sculpty texture, force to invalidate
|
||||
{
|
||||
mGLTexturep->forceToInvalidateGLTexture();
|
||||
}
|
||||
}
|
||||
|
||||
void LLViewerFetchedTexture::forceToDeleteRequest()
|
||||
{
|
||||
if (mHasFetcher)
|
||||
@@ -1973,26 +2084,42 @@ void LLViewerFetchedTexture::forceToDeleteRequest()
|
||||
mDesiredDiscardLevel = getMaxDiscardLevel() + 1; //defer LLAppViewer::getTextureFetch()->deleteRequest to updateFetch?
|
||||
}
|
||||
|
||||
void LLViewerFetchedTexture::setIsMissingAsset()
|
||||
void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing)
|
||||
{
|
||||
if (mUrl.empty())
|
||||
if (is_missing == mIsMissingAsset)
|
||||
{
|
||||
LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
if (is_missing)
|
||||
{
|
||||
notifyAboutMissingAsset();
|
||||
|
||||
if (mUrl.empty())
|
||||
{
|
||||
LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This may or may not be an error - it is normal to have no
|
||||
// map tile on an empty region, but bad if we're failing on a
|
||||
// server bake texture.
|
||||
LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL;
|
||||
}
|
||||
if (mHasFetcher)
|
||||
{
|
||||
LLAppViewer::getTextureFetch()->deleteRequest(getID(), true);
|
||||
mHasFetcher = FALSE;
|
||||
mIsFetching = FALSE;
|
||||
mLastPacketTimer.reset();
|
||||
mFetchState = 0;
|
||||
mFetchPriority = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL;
|
||||
LL_INFOS() << mID << ": un-flagging missing asset" << LL_ENDL;
|
||||
}
|
||||
if (mHasFetcher)
|
||||
{
|
||||
LLAppViewer::getTextureFetch()->deleteRequest(getID(), true);
|
||||
mHasFetcher = FALSE;
|
||||
mIsFetching = FALSE;
|
||||
mLastPacketTimer.reset();
|
||||
mFetchState = 0;
|
||||
mFetchPriority = 0;
|
||||
}
|
||||
mIsMissingAsset = TRUE;
|
||||
mIsMissingAsset = is_missing;
|
||||
}
|
||||
|
||||
void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback,
|
||||
@@ -2035,10 +2162,19 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call
|
||||
}
|
||||
if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0)
|
||||
{
|
||||
// We need aux data, but we've already loaded the image, and it didn't have any
|
||||
LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL;
|
||||
if(mHasAux)
|
||||
{
|
||||
//trigger a refetch
|
||||
forceToRefetchTexture();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need aux data, but we've already loaded the image, and it didn't have any
|
||||
LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
mLastCallBackActiveTime = sCurrentTime ;
|
||||
mLastReferencedSavedRawImageTime = sCurrentTime;
|
||||
}
|
||||
|
||||
void LLViewerFetchedTexture::clearCallbackEntryList()
|
||||
@@ -2151,6 +2287,7 @@ void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry:
|
||||
}
|
||||
mPauseLoadedCallBacks = FALSE ;
|
||||
mLastCallBackActiveTime = sCurrentTime ;
|
||||
mForceCallbackFetch = TRUE;
|
||||
if(need_raw)
|
||||
{
|
||||
mSaveRawImage = TRUE ;
|
||||
@@ -2191,6 +2328,7 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s
|
||||
bool LLViewerFetchedTexture::doLoadedCallbacks()
|
||||
{
|
||||
static const F32 MAX_INACTIVE_TIME = 120.f ; //seconds
|
||||
static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds
|
||||
|
||||
if (mNeedsCreateTexture)
|
||||
{
|
||||
@@ -2395,6 +2533,9 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
|
||||
}
|
||||
}
|
||||
|
||||
// Done with any raw image data at this point (will be re-created if we still have callbacks)
|
||||
destroyRawImage();
|
||||
|
||||
//
|
||||
// If we have no callbacks, take us off of the image callback list.
|
||||
//
|
||||
@@ -2402,10 +2543,12 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
|
||||
{
|
||||
gTextureList.mCallbackList.erase(this);
|
||||
}
|
||||
|
||||
// Done with any raw image data at this point (will be re-created if we still have callbacks)
|
||||
destroyRawImage();
|
||||
|
||||
else if(!res && mForceCallbackFetch && sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME && !mIsFetching)
|
||||
{
|
||||
//wait for long enough but no fetching request issued, force one.
|
||||
forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f);
|
||||
mForceCallbackFetch = FALSE; //fire once.
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2487,7 +2630,7 @@ bool LLViewerFetchedTexture::needsToSaveRawImage()
|
||||
|
||||
void LLViewerFetchedTexture::destroyRawImage()
|
||||
{
|
||||
if (mAuxRawImage.notNull())
|
||||
if (mAuxRawImage.notNull() && !needsToSaveRawImage())
|
||||
{
|
||||
sAuxCount--;
|
||||
mAuxRawImage = NULL;
|
||||
@@ -2660,7 +2803,25 @@ void LLViewerFetchedTexture::saveRawImage()
|
||||
mForceToSaveRawImage = FALSE ;
|
||||
}
|
||||
|
||||
mLastReferencedSavedRawImageTime = sCurrentTime;
|
||||
}
|
||||
|
||||
//force to refetch the texture to the discard level
|
||||
void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept_time)
|
||||
{
|
||||
if(mForceToSaveRawImage)
|
||||
{
|
||||
desired_discard = llmin(desired_discard, mDesiredSavedRawDiscardLevel);
|
||||
kept_time = llmax(kept_time, mKeptSavedRawImageTime);
|
||||
}
|
||||
|
||||
//trigger a new fetch.
|
||||
mForceToSaveRawImage = TRUE ;
|
||||
mDesiredSavedRawDiscardLevel = desired_discard ;
|
||||
mKeptSavedRawImageTime = kept_time ;
|
||||
mLastReferencedSavedRawImageTime = sCurrentTime ;
|
||||
mSavedRawImage = NULL ;
|
||||
mSavedRawDiscardLevel = -1 ;
|
||||
}
|
||||
|
||||
void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time)
|
||||
@@ -2710,6 +2871,12 @@ void LLViewerFetchedTexture::destroySavedRawImage()
|
||||
mDesiredSavedRawDiscardLevel = -1 ;
|
||||
mLastReferencedSavedRawImageTime = 0.0f ;
|
||||
mKeptSavedRawImageTime = 0.f ;
|
||||
|
||||
if(mAuxRawImage.notNull())
|
||||
{
|
||||
sAuxCount--;
|
||||
mAuxRawImage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LLImageRaw* LLViewerFetchedTexture::getSavedRawImage()
|
||||
|
||||
@@ -132,9 +132,10 @@ public:
|
||||
|
||||
/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
|
||||
/*virtual*/ void forceImmediateUpdate() ;
|
||||
/*virtual*/ bool isActiveFetching();
|
||||
|
||||
/*virtual*/ const LLUUID& getID() const { return mID; }
|
||||
//void setBoostLevel(S32 level);
|
||||
void setBoostLevel(S32 level);
|
||||
S32 getBoostLevel() { return mBoostLevel; }
|
||||
|
||||
void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
|
||||
@@ -147,6 +148,8 @@ public:
|
||||
|
||||
LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;}
|
||||
|
||||
S32 getFullWidth() const { return mFullWidth; }
|
||||
S32 getFullHeight() const { return mFullHeight; }
|
||||
/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
|
||||
|
||||
virtual void addFace(U32 channel, LLFace* facep) ;
|
||||
@@ -174,6 +177,10 @@ protected:
|
||||
void init(bool firstinit) ;
|
||||
void reorganizeFaceList() ;
|
||||
void reorganizeVolumeList() ;
|
||||
|
||||
void notifyAboutMissingAsset();
|
||||
void notifyAboutCreatingTexture();
|
||||
|
||||
private:
|
||||
friend class LLBumpImageList;
|
||||
friend class LLUIImageList;
|
||||
@@ -184,7 +191,7 @@ private:
|
||||
static bool isMemoryForTextureLow() ;
|
||||
protected:
|
||||
LLUUID mID;
|
||||
|
||||
F32 mSelectedTime; // time texture was last selected
|
||||
mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need?
|
||||
mutable S32 mMaxVirtualSizeResetCounter ;
|
||||
mutable S32 mMaxVirtualSizeResetInterval;
|
||||
@@ -325,13 +332,17 @@ public:
|
||||
void setMinDiscardLevel(S32 discard) { mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); }
|
||||
|
||||
bool updateFetch();
|
||||
bool setDebugFetching(S32 debug_level);
|
||||
bool isInDebug() {return mInDebug;}
|
||||
|
||||
void clearFetchedResults(); //clear all fetched results, for debug use.
|
||||
|
||||
// Override the computation of discard levels if we know the exact output
|
||||
// size of the image. Used for UI textures to not decode, even if we have
|
||||
// more data.
|
||||
/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
|
||||
|
||||
void setIsMissingAsset();
|
||||
void setIsMissingAsset(BOOL is_missing = true);
|
||||
/*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; }
|
||||
|
||||
// returns dimensions of original image for local files (before power of two scaling)
|
||||
@@ -374,6 +385,7 @@ public:
|
||||
BOOL isCachedRawImageReady() const {return mCachedRawImageReady ;}
|
||||
BOOL isRawImageValid()const { return mIsRawImageValid ; }
|
||||
void forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ;
|
||||
void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);
|
||||
/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
|
||||
void destroySavedRawImage() ;
|
||||
LLImageRaw* getSavedRawImage() ;
|
||||
@@ -386,6 +398,7 @@ public:
|
||||
|
||||
void forceToDeleteRequest();
|
||||
void forceRefetch();
|
||||
/*virtual*/bool isActiveFetching(); //is actively in fetching by the fetching pipeline.
|
||||
|
||||
protected:
|
||||
/*virtual*/ void switchToCachedImage();
|
||||
@@ -406,6 +419,8 @@ private:
|
||||
|
||||
private:
|
||||
BOOL mFullyLoaded;
|
||||
BOOL mInDebug;
|
||||
BOOL mForceCallbackFetch;
|
||||
|
||||
protected:
|
||||
std::string mLocalFileName;
|
||||
@@ -433,6 +448,7 @@ protected:
|
||||
S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have
|
||||
|
||||
S8 mNeedsAux; // We need to decode the auxiliary channels
|
||||
S8 mHasAux; // We have aux channels
|
||||
S8 mDecodingAux; // Are we decoding high components
|
||||
S8 mIsRawImageValid;
|
||||
S8 mHasFetcher; // We've made a fecth request
|
||||
|
||||
@@ -139,6 +139,8 @@ size_t strnlen(const char *s, size_t n)
|
||||
}
|
||||
#endif
|
||||
|
||||
extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG;
|
||||
|
||||
const F32 MAX_HOVER_Z = 2.0;
|
||||
const F32 MIN_HOVER_Z = -2.0;
|
||||
|
||||
@@ -290,6 +292,9 @@ const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f;
|
||||
|
||||
const S32 MORPH_MASK_REQUESTED_DISCARD = 0;
|
||||
|
||||
const F32 MAX_STANDOFF_FROM_ORIGIN = 3;
|
||||
const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32;
|
||||
|
||||
// Discard level at which to switch to baked textures
|
||||
// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB
|
||||
const S32 SWITCH_TO_BAKED_DISCARD = 5;
|
||||
@@ -1092,7 +1097,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
|
||||
mFullyLoadedInitialized(FALSE),
|
||||
mSupportsAlphaLayers(FALSE),
|
||||
mLoadedCallbacksPaused(FALSE),
|
||||
mHasPelvisOffset( FALSE ),
|
||||
mLastRezzedStatus(-1),
|
||||
mIsEditingAppearance(FALSE),
|
||||
mUseLocalAppearance(FALSE),
|
||||
@@ -1166,10 +1170,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
|
||||
mRuthDebugTimer.reset();
|
||||
mDebugExistenceTimer.reset();
|
||||
mLastAppearanceMessageTimer.reset();
|
||||
mPelvisOffset = LLVector3(0.0f,0.0f,0.0f);
|
||||
mLastPelvisToFoot = 0.0f;
|
||||
mPelvisFixup = 0.0f;
|
||||
mLastPelvisFixup = 0.0f;
|
||||
}
|
||||
|
||||
std::string LLVOAvatar::avString() const
|
||||
@@ -1524,7 +1524,6 @@ void LLVOAvatar::deleteCachedImages(bool clearAll)
|
||||
}
|
||||
LLViewerTexLayerSet::sHasCaches = FALSE;
|
||||
}
|
||||
LLVOAvatarSelf::deleteScratchTextures();
|
||||
LLTexLayerStaticImageList::getInstance()->deleteCachedImages();
|
||||
}
|
||||
|
||||
@@ -1659,23 +1658,25 @@ LLTexLayerSet* LLVOAvatar::createTexLayerSet()
|
||||
|
||||
const LLVector3 LLVOAvatar::getRenderPosition() const
|
||||
{
|
||||
|
||||
if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
|
||||
{
|
||||
return getPositionAgent();
|
||||
}
|
||||
else if (isRoot() || !mDrawable->getParent())
|
||||
{
|
||||
if ( !mHasPelvisOffset )
|
||||
{
|
||||
return mDrawable->getPositionAgent();
|
||||
}
|
||||
else
|
||||
F32 fixup;
|
||||
if ( hasPelvisFixup( fixup) )
|
||||
{
|
||||
//Apply a pelvis fixup (as defined by the avs skin)
|
||||
LLVector3 pos = mDrawable->getPositionAgent();
|
||||
pos[VZ] += mPelvisFixup;
|
||||
pos[VZ] += fixup;
|
||||
return pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mDrawable->getPositionAgent();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2420,11 +2421,16 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU
|
||||
if (!result)
|
||||
{
|
||||
const std::string url = getImageURL(te,uuid);
|
||||
|
||||
if (!url.empty())
|
||||
{
|
||||
LL_DEBUGS("Avatar") << avString() << "from URL " << url << LL_ENDL;
|
||||
result = LLViewerTextureManager::getFetchedTextureFromUrl(
|
||||
url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
|
||||
if (result->isMissingAsset())
|
||||
{
|
||||
result->setIsMissingAsset(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2569,7 +2575,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
|
||||
|
||||
// animate the character
|
||||
// store off last frame's root position to be consistent with camera position
|
||||
LLVector3 root_pos_last = mRoot->getWorldPosition();
|
||||
mLastRootPos = mRoot->getWorldPosition();
|
||||
bool detailed_update;
|
||||
{
|
||||
LLFastTimer t(FTM_CHARACTER_UPDATE);
|
||||
@@ -2598,7 +2604,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
|
||||
idleUpdateWindEffect();
|
||||
}
|
||||
|
||||
idleUpdateNameTag(root_pos_last);
|
||||
idleUpdateNameTag( mLastRootPos );
|
||||
idleUpdateRenderCost();
|
||||
}
|
||||
}
|
||||
@@ -3845,18 +3851,8 @@ void LLVOAvatar::resetFreezeTime()
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// updateCharacter()
|
||||
// called on both your avatar and other avatars
|
||||
//------------------------------------------------------------------------
|
||||
BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
|
||||
void LLVOAvatar::updateDebugText()
|
||||
{
|
||||
// Frozen!
|
||||
if (areAnimationsPaused())
|
||||
{
|
||||
updateMotions(LLCharacter::NORMAL_UPDATE); // This is necessary to get unpaused again.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
|
||||
{
|
||||
@@ -3947,6 +3943,34 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDebugText.size() && mText.notNull())
|
||||
{
|
||||
mText->markDead();
|
||||
mText = NULL;
|
||||
}
|
||||
else if (mDebugText.size())
|
||||
{
|
||||
setDebugText(mDebugText);
|
||||
}
|
||||
mDebugText.clear();
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// updateCharacter()
|
||||
// called on both your avatar and other avatars
|
||||
//------------------------------------------------------------------------
|
||||
BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
|
||||
{
|
||||
// Frozen!
|
||||
if (areAnimationsPaused())
|
||||
{
|
||||
updateMotions(LLCharacter::NORMAL_UPDATE); // This is necessary to get unpaused again.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
updateDebugText();
|
||||
|
||||
if (gNoRender)
|
||||
{
|
||||
// Hack if we're running drones...
|
||||
@@ -3957,9 +3981,6 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
LLVector3d root_pos_global;
|
||||
|
||||
if (!mIsBuilt)
|
||||
{
|
||||
return FALSE;
|
||||
@@ -4444,17 +4465,6 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
|
||||
|
||||
mRoot->updateWorldMatrixChildren();
|
||||
|
||||
if (!mDebugText.size() && mText.notNull())
|
||||
{
|
||||
mText->markDead();
|
||||
mText = NULL;
|
||||
}
|
||||
else if (mDebugText.size())
|
||||
{
|
||||
setDebugText(mDebugText);
|
||||
}
|
||||
mDebugText.clear();
|
||||
|
||||
//mesh vertices need to be reskinned
|
||||
mNeedsSkin = TRUE;
|
||||
|
||||
@@ -4485,39 +4495,13 @@ void LLVOAvatar::updateHeadOffset()
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// setPelvisOffset
|
||||
//------------------------------------------------------------------------
|
||||
void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount, F32 pelvisFixup )
|
||||
{
|
||||
mHasPelvisOffset = hasOffset;
|
||||
if ( mHasPelvisOffset )
|
||||
{
|
||||
//Store off last pelvis to foot value
|
||||
mLastPelvisToFoot = mPelvisToFoot;
|
||||
mPelvisOffset = offsetAmount;
|
||||
mLastPelvisFixup = mPelvisFixup;
|
||||
mPelvisFixup = pelvisFixup;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// postPelvisSetRecalc
|
||||
//------------------------------------------------------------------------
|
||||
void LLVOAvatar::postPelvisSetRecalc( void )
|
||||
{
|
||||
computeBodySize();
|
||||
mRoot->touch();
|
||||
mRoot->updateWorldMatrixChildren();
|
||||
dirtyMesh();
|
||||
updateHeadOffset();
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// pelisPoke
|
||||
//------------------------------------------------------------------------
|
||||
void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount )
|
||||
{
|
||||
mHasPelvisOffset = true;
|
||||
mLastPelvisFixup = mPelvisFixup;
|
||||
mPelvisFixup = pelvisFixupAmount;
|
||||
{
|
||||
mRoot->updateWorldMatrixChildren();
|
||||
computeBodySize();
|
||||
dirtyMesh(2);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// updateVisibility()
|
||||
@@ -5773,6 +5757,12 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL
|
||||
{
|
||||
sitDown(FALSE);
|
||||
}
|
||||
if ((anim_id == ANIM_AGENT_BUSY) && gAgent.isDoNotDisturb())
|
||||
{
|
||||
// re-assert DND tag animation
|
||||
gAgent.sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_START);
|
||||
return result;
|
||||
}
|
||||
stopMotion(anim_id);
|
||||
result = TRUE;
|
||||
}
|
||||
@@ -5985,11 +5975,163 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )
|
||||
|
||||
return jointp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// resetJointPositionsToDefault
|
||||
// getRiggedMeshID
|
||||
//
|
||||
// If viewer object is a rigged mesh, set the mesh id and return true.
|
||||
// Otherwise, null out the id and return false.
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatar::resetJointPositionsToDefault( void )
|
||||
// static
|
||||
bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id)
|
||||
{
|
||||
mesh_id.setNull();
|
||||
|
||||
//If a VO has a skin that we'll reset the joint positions to their default
|
||||
if ( pVO && pVO->mDrawable )
|
||||
{
|
||||
LLVOVolume* pVObj = pVO->mDrawable->getVOVolume();
|
||||
if ( pVObj )
|
||||
{
|
||||
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj );
|
||||
if (pSkinData
|
||||
&& pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG // full rig
|
||||
&& pSkinData->mAlternateBindMatrix.size() > 0 )
|
||||
{
|
||||
mesh_id = pSkinData->mMeshID;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLVOAvatar::clearAttachmentPosOverrides()
|
||||
{
|
||||
//Subsequent joints are relative to pelvis
|
||||
avatar_joint_list_t::iterator iter = mSkeleton.begin();
|
||||
avatar_joint_list_t::iterator end = mSkeleton.end();
|
||||
|
||||
for (; iter != end; ++iter)
|
||||
{
|
||||
LLJoint* pJoint = (*iter);
|
||||
pJoint->clearAttachmentPosOverrides();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// addAttachmentPosOverridesForObject
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo)
|
||||
{
|
||||
LLVOAvatar *av = vo->getAvatarAncestor();
|
||||
if (!av || (av != this))
|
||||
{
|
||||
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
|
||||
}
|
||||
|
||||
// Process all children
|
||||
LLViewerObject::const_child_list_t& children = vo->getChildren();
|
||||
for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
|
||||
it != children.end(); ++it)
|
||||
{
|
||||
LLViewerObject *childp = *it;
|
||||
addAttachmentPosOverridesForObject(childp);
|
||||
}
|
||||
|
||||
LLVOVolume *vobj = dynamic_cast<LLVOVolume*>(vo);
|
||||
bool pelvisGotSet = false;
|
||||
|
||||
if (!vobj)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (vobj->isMesh() &&
|
||||
((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
|
||||
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
|
||||
|
||||
if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )
|
||||
{
|
||||
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
|
||||
if ( bindCnt > 0 )
|
||||
{
|
||||
const U32 jointCnt = pSkinData->mJointNames.size();
|
||||
const F32 pelvisZOffset = pSkinData->mPelvisOffset;
|
||||
const LLUUID& mesh_id = pSkinData->mMeshID;
|
||||
bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false;
|
||||
if ( fullRig )
|
||||
{
|
||||
for ( U32 i=0; i<jointCnt; ++i )
|
||||
{
|
||||
std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
|
||||
LLJoint* pJoint = getJoint( lookingForJoint );
|
||||
if ( pJoint && pJoint->getId() != currentId )
|
||||
{
|
||||
pJoint->setId( currentId );
|
||||
const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
|
||||
//Set the joint position
|
||||
pJoint->addAttachmentPosOverride( jointPos, mesh_id, avString() );
|
||||
|
||||
//If joint is a pelvis then handle old/new pelvis to foot values
|
||||
if ( lookingForJoint == "mPelvis" )
|
||||
{
|
||||
pelvisGotSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pelvisZOffset != 0.0F)
|
||||
{
|
||||
addPelvisFixup( pelvisZOffset, mesh_id );
|
||||
pelvisGotSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Rebuild body data if we altered joints/pelvis
|
||||
if ( pelvisGotSet )
|
||||
{
|
||||
postPelvisSetRecalc();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// resetJointPositionsOnDetach
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatar::resetJointPositionsOnDetach(LLViewerObject *vo)
|
||||
{
|
||||
LLVOAvatar *av = vo->getAvatarAncestor();
|
||||
if (!av || (av != this))
|
||||
{
|
||||
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
|
||||
}
|
||||
|
||||
// Process all children
|
||||
LLViewerObject::const_child_list_t& children = vo->getChildren();
|
||||
for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
|
||||
it != children.end(); ++it)
|
||||
{
|
||||
LLViewerObject *childp = *it;
|
||||
resetJointPositionsOnDetach(childp);
|
||||
}
|
||||
|
||||
// Process self.
|
||||
LLUUID mesh_id;
|
||||
if (getRiggedMeshID(vo,mesh_id))
|
||||
{
|
||||
resetJointPositionsOnDetach(mesh_id);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// resetJointPositionsOnDetach
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatar::resetJointPositionsOnDetach(const LLUUID& mesh_id)
|
||||
{
|
||||
//Subsequent joints are relative to pelvis
|
||||
avatar_joint_list_t::iterator iter = mSkeleton.begin();
|
||||
avatar_joint_list_t::iterator end = mSkeleton.end();
|
||||
@@ -6000,24 +6142,19 @@ void LLVOAvatar::resetJointPositionsToDefault( void )
|
||||
{
|
||||
LLJoint* pJoint = (*iter);
|
||||
//Reset joints except for pelvis
|
||||
if ( pJoint && pJoint != pJointPelvis && pJoint->doesJointNeedToBeReset() )
|
||||
{
|
||||
if ( pJoint )
|
||||
{
|
||||
pJoint->setId( LLUUID::null );
|
||||
pJoint->restoreOldXform();
|
||||
}
|
||||
else
|
||||
if ( pJoint && pJoint == pJointPelvis && pJoint->doesJointNeedToBeReset() )
|
||||
pJoint->removeAttachmentPosOverride(mesh_id, avString());
|
||||
}
|
||||
if ( pJoint && pJoint == pJointPelvis)
|
||||
{
|
||||
pJoint->setId( LLUUID::null );
|
||||
removePelvisFixup( mesh_id );
|
||||
pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) );
|
||||
//pJoint->setJointResetFlag( false ); // Singu TODO
|
||||
}
|
||||
}
|
||||
|
||||
//make sure we don't apply the joint offset
|
||||
mHasPelvisOffset = false;
|
||||
mPelvisFixup = mLastPelvisFixup;
|
||||
postPelvisSetRecalc();
|
||||
}
|
||||
}
|
||||
|
||||
postPelvisSetRecalc();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// getCharacterPosition()
|
||||
@@ -6461,12 +6598,20 @@ BOOL LLVOAvatar::setParent(LLViewerObject* parent)
|
||||
void LLVOAvatar::addChild(LLViewerObject *childp)
|
||||
{
|
||||
childp->extractAttachmentItemID(); // find the inventory item this object is associated with.
|
||||
if (isSelf())
|
||||
{
|
||||
const LLUUID& item_id = childp->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT attachment child added " << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
|
||||
}
|
||||
|
||||
LLViewerObject::addChild(childp);
|
||||
if (childp->mDrawable)
|
||||
{
|
||||
if (!attachObject(childp))
|
||||
{
|
||||
LL_WARNS() << "addChild() failed for "
|
||||
LL_WARNS() << "ATT addChild() failed for "
|
||||
<< childp->getID()
|
||||
<< " item " << childp->getAttachmentItemID()
|
||||
<< LL_ENDL;
|
||||
@@ -6552,10 +6697,21 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi
|
||||
//-----------------------------------------------------------------------------
|
||||
const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object)
|
||||
{
|
||||
if (isSelf())
|
||||
{
|
||||
const LLUUID& item_id = viewer_object->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT attaching object "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
}
|
||||
LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object);
|
||||
|
||||
if (!attachment || !attachment->addObject(viewer_object))
|
||||
{
|
||||
const LLUUID& item_id = viewer_object->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_WARNS("Avatar") << "ATT attach failed "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6620,7 +6776,14 @@ void LLVOAvatar::lazyAttach()
|
||||
LLPointer<LLViewerObject> cur_attachment = mPendingAttachment[i];
|
||||
if (cur_attachment->mDrawable)
|
||||
{
|
||||
if(!attachObject(cur_attachment))
|
||||
if (isSelf())
|
||||
{
|
||||
const LLUUID& item_id = cur_attachment->getAttachmentItemID();
|
||||
LLViewerInventoryItem *item = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Avatar") << "ATT attaching object "
|
||||
<< (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
|
||||
}
|
||||
if (!attachObject(cur_attachment))
|
||||
{ // Drop it
|
||||
LL_WARNS() << "attachObject() failed for "
|
||||
<< cur_attachment->getID()
|
||||
@@ -6686,27 +6849,15 @@ void LLVOAvatar::rebuildRiggedAttachments( void )
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
|
||||
{
|
||||
//If a VO has a skin that we'll reset the joint positions to their default
|
||||
if ( pVO && pVO->mDrawable )
|
||||
LLUUID mesh_id;
|
||||
if (getRiggedMeshID(pVO, mesh_id))
|
||||
{
|
||||
LLVOVolume* pVObj = pVO->mDrawable->getVOVolume();
|
||||
if ( pVObj )
|
||||
resetJointPositionsOnDetach(mesh_id);
|
||||
if ( gAgentCamera.cameraCustomizeAvatar() )
|
||||
{
|
||||
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj );
|
||||
if ( pSkinData
|
||||
&& pSkinData->mJointNames.size() > 20 // full rig
|
||||
&& pSkinData->mAlternateBindMatrix.size() > 0 )
|
||||
{
|
||||
LLVOAvatar::resetJointPositionsToDefault();
|
||||
//Need to handle the repositioning of the cam, updating rig data etc during outfit editing
|
||||
//This handles the case where we detach a replacement rig.
|
||||
if ( gAgentCamera.cameraCustomizeAvatar() )
|
||||
{
|
||||
gAgent.unpauseAnimation();
|
||||
//Still want to refocus on head bone
|
||||
gAgentCamera.changeCameraToCustomizeAvatar();
|
||||
}
|
||||
}
|
||||
gAgent.unpauseAnimation();
|
||||
//Still want to refocus on head bone
|
||||
gAgentCamera.changeCameraToCustomizeAvatar();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6845,9 +6996,18 @@ void LLVOAvatar::getOffObject()
|
||||
LLVector3 cur_position_world = mDrawable->getWorldPosition();
|
||||
LLQuaternion cur_rotation_world = mDrawable->getWorldRotation();
|
||||
|
||||
if (mLastRootPos.length() >= MAX_STANDOFF_FROM_ORIGIN
|
||||
&& (cur_position_world.length() < MAX_STANDOFF_FROM_ORIGIN
|
||||
|| dist_vec(cur_position_world, mLastRootPos) > MAX_STANDOFF_DISTANCE_CHANGE))
|
||||
{
|
||||
// Most likely drawable got updated too early or some updates were missed - we got relative position to non-existing parent
|
||||
// restore coordinates from cache
|
||||
cur_position_world = mLastRootPos;
|
||||
}
|
||||
|
||||
// set *local* position based on last *world* position, since we're unparenting the avatar
|
||||
mDrawable->mXform.setPosition(cur_position_world);
|
||||
mDrawable->mXform.setRotation(cur_rotation_world);
|
||||
mDrawable->mXform.setRotation(cur_rotation_world);
|
||||
|
||||
gPipeline.markMoved(mDrawable, TRUE);
|
||||
|
||||
@@ -7065,6 +7225,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, bool
|
||||
BOOL LLVOAvatar::isVisible() const
|
||||
{
|
||||
return mDrawable.notNull()
|
||||
&& (!mOrphaned || isSelf())
|
||||
&& (mDrawable->isVisible() || mIsDummy);
|
||||
}
|
||||
|
||||
@@ -7109,6 +7270,7 @@ void LLVOAvatar::updateRezzedStatusTimers()
|
||||
for (S32 i = 1; i < 4; i++)
|
||||
{
|
||||
startPhase("load_" + LLVOAvatar::rezStatusToString(i));
|
||||
startPhase("first_load_" + LLVOAvatar::rezStatusToString(i));
|
||||
}
|
||||
}
|
||||
if (rez_status < mLastRezzedStatus)
|
||||
@@ -7125,6 +7287,7 @@ void LLVOAvatar::updateRezzedStatusTimers()
|
||||
for (S32 i = llmax(mLastRezzedStatus+1,1); i <= rez_status; i++)
|
||||
{
|
||||
stopPhase("load_" + LLVOAvatar::rezStatusToString(i));
|
||||
stopPhase("first_load_" + LLVOAvatar::rezStatusToString(i), false);
|
||||
}
|
||||
if (rez_status == 3)
|
||||
{
|
||||
@@ -7254,14 +7417,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
|
||||
record["grid_y"] = LLSD::Integer(grid_y);
|
||||
record["is_using_server_bakes"] = ((bool) isUsingServerBakes());
|
||||
record["is_self"] = isSelf();
|
||||
|
||||
|
||||
#if 0 // verbose logging
|
||||
std::ostringstream ostr;
|
||||
ostr << LLSDNotationStreamer(record);
|
||||
LL_DEBUGS("Avatar") << "record\n" << ostr.str() << LL_ENDL;
|
||||
#endif
|
||||
|
||||
|
||||
if (isAgentAvatarValid())
|
||||
{
|
||||
gAgentAvatarp->addMetricsTimerRecord(record);
|
||||
@@ -7535,6 +7691,8 @@ void LLVOAvatar::updateMeshTextures()
|
||||
// we'll consider it loaded and use it (rather than
|
||||
// doing compositing).
|
||||
useBakedTexture( baked_img->getID() );
|
||||
mLoadedCallbacksPaused |= !isVisible();
|
||||
checkTextureLoading();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -7547,6 +7705,10 @@ void LLVOAvatar::updateMeshTextures()
|
||||
}
|
||||
baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ),
|
||||
src_callback_list, paused );
|
||||
|
||||
// this could add paused texture callbacks
|
||||
mLoadedCallbacksPaused |= paused;
|
||||
checkTextureLoading();
|
||||
}
|
||||
}
|
||||
else if (layerset && isUsingLocalAppearance())
|
||||
@@ -7615,7 +7777,15 @@ void LLVOAvatar::updateMeshTextures()
|
||||
}
|
||||
}
|
||||
}
|
||||
removeMissingBakedTextures();
|
||||
|
||||
// removeMissingBakedTextures() will call back into this rountine if something is removed, and can blow up the stack
|
||||
static bool call_remove_missing = true;
|
||||
if (call_remove_missing)
|
||||
{
|
||||
call_remove_missing = false;
|
||||
removeMissingBakedTextures(); // May call back into this function if anything is removed
|
||||
call_remove_missing = true;
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
@@ -7916,6 +8086,9 @@ void LLVOAvatar::onFirstTEMessageReceived()
|
||||
LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL;
|
||||
image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ),
|
||||
src_callback_list, paused );
|
||||
|
||||
// this could add paused texture callbacks
|
||||
mLoadedCallbacksPaused |= paused;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8494,7 +8667,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture
|
||||
}
|
||||
if (!found_texture_id)
|
||||
{
|
||||
LL_INFOS() << "onBakedTextureMasksLoaded(): unexpected image id: " << id << LL_ENDL;
|
||||
LL_INFOS() << "unexpected image id: " << id << LL_ENDL;
|
||||
}
|
||||
self->dirtyMesh();
|
||||
}
|
||||
|
||||
@@ -249,7 +249,10 @@ public:
|
||||
|
||||
virtual LLJoint* getJoint(const std::string &name);
|
||||
|
||||
void resetJointPositionsToDefault( void );
|
||||
void addAttachmentPosOverridesForObject(LLViewerObject *vo);
|
||||
void resetJointPositionsOnDetach(const LLUUID& mesh_id);
|
||||
void resetJointPositionsOnDetach(LLViewerObject *vo);
|
||||
void clearAttachmentPosOverrides();
|
||||
|
||||
/*virtual*/ const LLUUID& getID() const;
|
||||
/*virtual*/ void addDebugText(const std::string& text);
|
||||
@@ -283,6 +286,7 @@ private:
|
||||
// Updates
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
void updateDebugText();
|
||||
virtual BOOL updateCharacter(LLAgent &agent);
|
||||
void idleUpdateVoiceVisualizer(bool voice_enabled);
|
||||
void idleUpdateMisc(bool detailed_update);
|
||||
@@ -393,19 +397,13 @@ protected:
|
||||
/*virtual*/ LLAvatarJointMesh* createAvatarJointMesh(); // Returns LLViewerJointMesh
|
||||
public:
|
||||
void updateHeadOffset();
|
||||
void setPelvisOffset( bool hasOffset, const LLVector3& translation, F32 offset ) ;
|
||||
bool hasPelvisOffset( void ) { return mHasPelvisOffset; }
|
||||
void postPelvisSetRecalc( void );
|
||||
void setPelvisOffset( F32 pelvixFixupAmount );
|
||||
|
||||
/*virtual*/ BOOL loadSkeletonNode();
|
||||
/*virtual*/ void buildCharacter();
|
||||
|
||||
bool mHasPelvisOffset;
|
||||
LLVector3 mPelvisOffset;
|
||||
F32 mLastPelvisToFoot;
|
||||
F32 mPelvisFixup;
|
||||
F32 mLastPelvisFixup;
|
||||
LLVector3 mCurRootToHeadOffset;
|
||||
LLVector3 mTargetRootToHeadOffset;
|
||||
|
||||
S32 mLastSkeletonSerialNum;
|
||||
|
||||
@@ -744,6 +742,7 @@ public:
|
||||
void clampAttachmentPositions();
|
||||
virtual const LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object);
|
||||
virtual BOOL detachObject(LLViewerObject *viewer_object);
|
||||
static bool getRiggedMeshID( LLViewerObject* pVO, LLUUID& mesh_id );
|
||||
void cleanupAttachedMesh( LLViewerObject* pVO );
|
||||
static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj);
|
||||
/*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const;
|
||||
@@ -905,6 +904,8 @@ public:
|
||||
private:
|
||||
// set this property only with LLVOAvatar::sitDown method
|
||||
BOOL mIsSitting;
|
||||
// position backup in case of missing data
|
||||
LLVector3 mLastRootPos;
|
||||
|
||||
/** Hierarchy
|
||||
** **
|
||||
|
||||
@@ -153,15 +153,6 @@ typedef LLHTTPClient::ResponderIgnore LLHoverHeightResponder;
|
||||
** **
|
||||
*********************************************************************************/
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Static Data
|
||||
//-----------------------------------------------------------------------------
|
||||
S32Bytes LLVOAvatarSelf::sScratchTexBytes(0);
|
||||
LLMap< LLGLenum, LLGLuint*> LLVOAvatarSelf::sScratchTexNames;
|
||||
LLMap< LLGLenum, F32*> LLVOAvatarSelf::sScratchTexLastBindTime;
|
||||
|
||||
|
||||
/*********************************************************************************
|
||||
** **
|
||||
** Begin LLVOAvatarSelf Constructor routines
|
||||
@@ -2685,13 +2676,9 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
|
||||
{
|
||||
F32 desired_pixels;
|
||||
desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
|
||||
|
||||
// DRANO what priority should wearable-based textures have?
|
||||
if (isUsingLocalAppearance())
|
||||
{
|
||||
imagep->setBoostLevel(getAvatarBoostLevel());
|
||||
imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
|
||||
}
|
||||
|
||||
imagep->setBoostLevel(getAvatarBoostLevel());
|
||||
imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
|
||||
imagep->resetTextureStats();
|
||||
imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);
|
||||
imagep->addTextureStats( desired_pixels / texel_area_ratio );
|
||||
@@ -3210,77 +3197,6 @@ BOOL LLVOAvatarSelf::needsRenderBeam()
|
||||
return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
|
||||
}
|
||||
|
||||
// static
|
||||
void LLVOAvatarSelf::deleteScratchTextures()
|
||||
{
|
||||
if(gAuditTexture)
|
||||
{
|
||||
S32Bytes total_tex_size = sScratchTexBytes ;
|
||||
S32Bytes tex_size(SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT) ;
|
||||
|
||||
if( sScratchTexNames.checkData( GL_LUMINANCE ) )
|
||||
{
|
||||
LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
|
||||
total_tex_size -= tex_size ;
|
||||
}
|
||||
if( sScratchTexNames.checkData( GL_ALPHA ) )
|
||||
{
|
||||
LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
|
||||
total_tex_size -= tex_size ;
|
||||
}
|
||||
if( sScratchTexNames.checkData( GL_COLOR_INDEX ) )
|
||||
{
|
||||
LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
|
||||
total_tex_size -= tex_size ;
|
||||
}
|
||||
if( sScratchTexNames.checkData( LLRender::sGLCoreProfile ? GL_RG : GL_LUMINANCE_ALPHA ) )
|
||||
{
|
||||
LLImageGL::decTextureCounter(tex_size, 2, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
|
||||
total_tex_size -= 2 * tex_size ;
|
||||
}
|
||||
if( sScratchTexNames.checkData( GL_RGB ) )
|
||||
{
|
||||
LLImageGL::decTextureCounter(tex_size, 3, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
|
||||
total_tex_size -= 3 * tex_size ;
|
||||
}
|
||||
if( sScratchTexNames.checkData( GL_RGBA ) )
|
||||
{
|
||||
LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
|
||||
total_tex_size -= 4 * tex_size ;
|
||||
}
|
||||
//others
|
||||
while(total_tex_size > S32Bytes(0))
|
||||
{
|
||||
LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
|
||||
total_tex_size -= 4 * tex_size ;
|
||||
}
|
||||
}
|
||||
|
||||
for( LLGLuint* namep = sScratchTexNames.getFirstData();
|
||||
namep;
|
||||
namep = sScratchTexNames.getNextData() )
|
||||
{
|
||||
LLImageGL::deleteTextures(1, (U32 *)namep );
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
if( sScratchTexBytes.value() )
|
||||
{
|
||||
LL_DEBUGS() << "Clearing Scratch Textures " << (S32Kilobytes)sScratchTexBytes << "KB" << LL_ENDL;
|
||||
|
||||
sScratchTexNames.deleteAllData();
|
||||
sScratchTexLastBindTime.deleteAllData();
|
||||
LLImageGL::sGlobalTextureMemory -= sScratchTexBytes;
|
||||
sScratchTexBytes = S32Bytes(0);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLVOAvatarSelf::dumpScratchTextureByteCount()
|
||||
{
|
||||
LL_INFOS() << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << LL_ENDL;
|
||||
}
|
||||
|
||||
void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value);
|
||||
|
||||
void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "llviewertexture.h"
|
||||
#include "llvoavatar.h"
|
||||
#include <map>
|
||||
|
||||
struct LocalTextureData;
|
||||
class LLInventoryCallback;
|
||||
@@ -266,17 +267,6 @@ public:
|
||||
const LLUUID& grabBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
|
||||
BOOL canGrabBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Scratch textures (used for compositing)
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
static void deleteScratchTextures();
|
||||
private:
|
||||
static S32Bytes sScratchTexBytes;
|
||||
static LLMap< LLGLenum, LLGLuint*> sScratchTexNames;
|
||||
static LLMap< LLGLenum, F32*> sScratchTexLastBindTime;
|
||||
|
||||
/** Textures
|
||||
** **
|
||||
*******************************************************************************/
|
||||
@@ -383,7 +373,6 @@ public:
|
||||
public:
|
||||
static void dumpTotalLocalTextureByteCount();
|
||||
void dumpLocalTextures() const;
|
||||
static void dumpScratchTextureByteCount();
|
||||
void dumpWearableInfo(LLAPRFile& outfile);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
const S32 MIN_QUIET_FRAMES_COALESCE = 30;
|
||||
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
|
||||
const F32 FORCE_CULL_AREA = 8.f;
|
||||
U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 20;
|
||||
|
||||
BOOL gAnimateTextures = TRUE;
|
||||
//extern BOOL gHideSelectedObjects;
|
||||
@@ -1564,6 +1565,65 @@ static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies");
|
||||
static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives");
|
||||
static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
|
||||
|
||||
bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable)
|
||||
{
|
||||
bool regen_faces = false;
|
||||
|
||||
LLVolume *old_volumep, *new_volumep;
|
||||
F32 old_lod, new_lod;
|
||||
S32 old_num_faces, new_num_faces ;
|
||||
|
||||
old_volumep = getVolume();
|
||||
old_lod = old_volumep->getDetail();
|
||||
old_num_faces = old_volumep->getNumFaces() ;
|
||||
old_volumep = NULL ;
|
||||
|
||||
{
|
||||
LLFastTimer ftm(FTM_GEN_VOLUME);
|
||||
const LLVolumeParams &volume_params = getVolume()->getParams();
|
||||
setVolume(volume_params, 0);
|
||||
}
|
||||
|
||||
new_volumep = getVolume();
|
||||
new_lod = new_volumep->getDetail();
|
||||
new_num_faces = new_volumep->getNumFaces() ;
|
||||
new_volumep = NULL ;
|
||||
|
||||
if ((new_lod != old_lod) || mSculptChanged)
|
||||
{
|
||||
sNumLODChanges += new_num_faces ;
|
||||
|
||||
if((S32)getNumTEs() != getVolume()->getNumFaces())
|
||||
{
|
||||
setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
|
||||
}
|
||||
|
||||
drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
|
||||
|
||||
{
|
||||
LLFastTimer t(FTM_GEN_TRIANGLES);
|
||||
regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs();
|
||||
if (regen_faces)
|
||||
{
|
||||
regenFaces();
|
||||
}
|
||||
|
||||
if (mSculptChanged)
|
||||
{ //changes in sculpt maps can thrash an object bounding box without
|
||||
//triggering a spatial group bounding box update -- force spatial group
|
||||
//to update bounding boxes
|
||||
LLSpatialGroup* group = mDrawable->getSpatialGroup();
|
||||
if (group)
|
||||
{
|
||||
group->unbound();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return regen_faces;
|
||||
}
|
||||
|
||||
BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
|
||||
{
|
||||
LLFastTimer t(FTM_UPDATE_PRIMITIVES);
|
||||
@@ -1595,8 +1655,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
|
||||
group->dirtyMesh();
|
||||
}
|
||||
|
||||
BOOL compiled = FALSE;
|
||||
|
||||
updateRelativeXform();
|
||||
|
||||
if (mDrawable.isNull()) // Not sure why this is happening, but it is...
|
||||
@@ -1608,83 +1666,35 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
|
||||
{
|
||||
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
|
||||
|
||||
compiled = TRUE;
|
||||
bool was_regen_faces = false;
|
||||
|
||||
if (mVolumeChanged)
|
||||
{
|
||||
LLFastTimer ftm(FTM_GEN_VOLUME);
|
||||
LLVolumeParams volume_params = getVolume()->getParams();
|
||||
setVolume(volume_params, 0);
|
||||
was_regen_faces = lodOrSculptChanged(drawable);
|
||||
drawable->setState(LLDrawable::REBUILD_VOLUME);
|
||||
}
|
||||
|
||||
else if (mSculptChanged || mLODChanged)
|
||||
{
|
||||
was_regen_faces = lodOrSculptChanged(drawable);
|
||||
}
|
||||
|
||||
if (!was_regen_faces) {
|
||||
LLFastTimer t(FTM_GEN_TRIANGLES);
|
||||
regenFaces();
|
||||
genBBoxes(FALSE);
|
||||
}
|
||||
|
||||
genBBoxes(FALSE);
|
||||
}
|
||||
else if ((mLODChanged) || (mSculptChanged))
|
||||
else if (mLODChanged || mSculptChanged)
|
||||
{
|
||||
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
|
||||
lodOrSculptChanged(drawable);
|
||||
genBBoxes(FALSE);
|
||||
|
||||
LLVolume *old_volumep, *new_volumep;
|
||||
F32 old_lod, new_lod;
|
||||
S32 old_num_faces, new_num_faces ;
|
||||
|
||||
old_volumep = getVolume();
|
||||
old_lod = old_volumep->getDetail();
|
||||
old_num_faces = old_volumep->getNumFaces() ;
|
||||
old_volumep = NULL ;
|
||||
|
||||
{
|
||||
LLFastTimer ftm(FTM_GEN_VOLUME);
|
||||
LLVolumeParams volume_params = getVolume()->getParams();
|
||||
setVolume(volume_params, 0);
|
||||
}
|
||||
|
||||
new_volumep = getVolume();
|
||||
new_lod = new_volumep->getDetail();
|
||||
new_num_faces = new_volumep->getNumFaces() ;
|
||||
new_volumep = NULL ;
|
||||
|
||||
if ((new_lod != old_lod) || mSculptChanged)
|
||||
{
|
||||
compiled = TRUE;
|
||||
sNumLODChanges += new_num_faces ;
|
||||
|
||||
if((S32)getNumTEs() != getVolume()->getNumFaces())
|
||||
{
|
||||
setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces.
|
||||
}
|
||||
|
||||
drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
|
||||
|
||||
{
|
||||
LLFastTimer t(FTM_GEN_TRIANGLES);
|
||||
if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs())
|
||||
{
|
||||
regenFaces();
|
||||
}
|
||||
genBBoxes(FALSE);
|
||||
|
||||
if (mSculptChanged)
|
||||
{ //changes in sculpt maps can thrash an object bounding box without
|
||||
//triggering a spatial group bounding box update -- force spatial group
|
||||
//to update bounding boxes
|
||||
LLSpatialGroup* group = mDrawable->getSpatialGroup();
|
||||
if (group)
|
||||
{
|
||||
group->unbound();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
|
||||
else
|
||||
{
|
||||
compiled = TRUE;
|
||||
// All it did was move or we changed the texture coordinate offset
|
||||
LLFastTimer t(FTM_GEN_TRIANGLES);
|
||||
genBBoxes(FALSE);
|
||||
@@ -1692,7 +1702,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
|
||||
|
||||
// Update face flags
|
||||
updateFaceFlags();
|
||||
|
||||
|
||||
mVolumeChanged = FALSE;
|
||||
mLODChanged = FALSE;
|
||||
mSculptChanged = FALSE;
|
||||
@@ -1819,7 +1829,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
|
||||
const LLTextureEntry *tep = getTE(te);
|
||||
if (!tep)
|
||||
{
|
||||
LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL;
|
||||
LL_WARNS("MaterialTEs") << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL;
|
||||
}
|
||||
else if (color != tep->getColor())
|
||||
{
|
||||
@@ -1971,10 +1981,237 @@ S32 LLVOVolume::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID)
|
||||
return res;
|
||||
}
|
||||
|
||||
bool LLVOVolume::notifyAboutCreatingTexture(LLViewerTexture *texture)
|
||||
{ //Ok, here we have confirmation about texture creation, check our wait-list
|
||||
//and make changes, or return false
|
||||
|
||||
std::pair<mmap_UUID_MAP_t::iterator, mmap_UUID_MAP_t::iterator> range = mWaitingTextureInfo.equal_range(texture->getID());
|
||||
|
||||
typedef std::map<U8, LLMaterialPtr> map_te_material;
|
||||
map_te_material new_material;
|
||||
|
||||
for(mmap_UUID_MAP_t::iterator range_it = range.first; range_it != range.second; ++range_it)
|
||||
{
|
||||
LLMaterialPtr cur_material = getTEMaterialParams(range_it->second.te);
|
||||
|
||||
//here we just interesting in DIFFUSE_MAP only!
|
||||
if(cur_material.notNull() && LLRender::DIFFUSE_MAP == range_it->second.map && GL_RGBA != texture->getPrimaryFormat())
|
||||
{ //ok let's check the diffuse mode
|
||||
switch(cur_material->getDiffuseAlphaMode())
|
||||
{
|
||||
case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND:
|
||||
case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE:
|
||||
case LLMaterial::DIFFUSE_ALPHA_MODE_MASK:
|
||||
{ //uups... we have non 32 bit texture with LLMaterial::DIFFUSE_ALPHA_MODE_* => LLMaterial::DIFFUSE_ALPHA_MODE_NONE
|
||||
|
||||
LLMaterialPtr mat = NULL;
|
||||
map_te_material::iterator it = new_material.find(range_it->second.te);
|
||||
if(new_material.end() == it) {
|
||||
mat = new LLMaterial(cur_material->asLLSD());
|
||||
new_material.insert(map_te_material::value_type(range_it->second.te, mat));
|
||||
} else {
|
||||
mat = it->second;
|
||||
}
|
||||
|
||||
mat->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
|
||||
|
||||
} break;
|
||||
} //switch
|
||||
} //if
|
||||
} //for
|
||||
|
||||
//setup new materials
|
||||
for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)
|
||||
{
|
||||
LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second);
|
||||
LLViewerObject::setTEMaterialParams(it->first, it->second);
|
||||
}
|
||||
|
||||
//clear wait-list
|
||||
mWaitingTextureInfo.erase(range.first, range.second);
|
||||
|
||||
return 0 != new_material.size();
|
||||
}
|
||||
|
||||
bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture)
|
||||
{ //Ok, here if we wait information about texture and it's missing
|
||||
//then depending from the texture map (diffuse, normal, or specular)
|
||||
//make changes in material and confirm it. If not return false.
|
||||
std::pair<mmap_UUID_MAP_t::iterator, mmap_UUID_MAP_t::iterator> range = mWaitingTextureInfo.equal_range(texture->getID());
|
||||
if(range.first == range.second) return false;
|
||||
|
||||
typedef std::map<U8, LLMaterialPtr> map_te_material;
|
||||
map_te_material new_material;
|
||||
|
||||
for(mmap_UUID_MAP_t::iterator range_it = range.first; range_it != range.second; ++range_it)
|
||||
{
|
||||
LLMaterialPtr cur_material = getTEMaterialParams(range_it->second.te);
|
||||
if (cur_material.isNull())
|
||||
continue;
|
||||
|
||||
switch(range_it->second.map)
|
||||
{
|
||||
case LLRender::DIFFUSE_MAP:
|
||||
{
|
||||
if(LLMaterial::DIFFUSE_ALPHA_MODE_NONE != cur_material->getDiffuseAlphaMode())
|
||||
{ //missing texture + !LLMaterial::DIFFUSE_ALPHA_MODE_NONE => LLMaterial::DIFFUSE_ALPHA_MODE_NONE
|
||||
LLMaterialPtr mat = NULL;
|
||||
map_te_material::iterator it = new_material.find(range_it->second.te);
|
||||
if(new_material.end() == it) {
|
||||
mat = new LLMaterial(cur_material->asLLSD());
|
||||
new_material.insert(map_te_material::value_type(range_it->second.te, mat));
|
||||
} else {
|
||||
mat = it->second;
|
||||
}
|
||||
|
||||
mat->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
|
||||
}
|
||||
} break;
|
||||
case LLRender::NORMAL_MAP:
|
||||
{ //missing texture => reset material texture id
|
||||
LLMaterialPtr mat = NULL;
|
||||
map_te_material::iterator it = new_material.find(range_it->second.te);
|
||||
if(new_material.end() == it) {
|
||||
mat = new LLMaterial(cur_material->asLLSD());
|
||||
new_material.insert(map_te_material::value_type(range_it->second.te, mat));
|
||||
} else {
|
||||
mat = it->second;
|
||||
}
|
||||
|
||||
mat->setNormalID(LLUUID::null);
|
||||
} break;
|
||||
case LLRender::SPECULAR_MAP:
|
||||
{ //missing texture => reset material texture id
|
||||
LLMaterialPtr mat = NULL;
|
||||
map_te_material::iterator it = new_material.find(range_it->second.te);
|
||||
if(new_material.end() == it) {
|
||||
mat = new LLMaterial(cur_material->asLLSD());
|
||||
new_material.insert(map_te_material::value_type(range_it->second.te, mat));
|
||||
} else {
|
||||
mat = it->second;
|
||||
}
|
||||
|
||||
mat->setSpecularID(LLUUID::null);
|
||||
} break;
|
||||
case LLRender::NUM_TEXTURE_CHANNELS:
|
||||
//nothing to do, make compiler happy
|
||||
break;
|
||||
} //switch
|
||||
} //for
|
||||
|
||||
//setup new materials
|
||||
for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it)
|
||||
{
|
||||
LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second);
|
||||
LLViewerObject::setTEMaterialParams(it->first, it->second);
|
||||
}
|
||||
|
||||
//clear wait-list
|
||||
mWaitingTextureInfo.erase(range.first, range.second);
|
||||
|
||||
return 0 != new_material.size();
|
||||
}
|
||||
|
||||
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
|
||||
LLMaterialPtr pMaterial = const_cast<LLMaterialPtr&>(pMaterialParams);
|
||||
|
||||
if(pMaterialParams)
|
||||
{ //check all of them according to material settings
|
||||
|
||||
LLViewerTexture *img_diffuse = getTEImage(te);
|
||||
LLViewerTexture *img_normal = getTENormalMap(te);
|
||||
LLViewerTexture *img_specular = getTESpecularMap(te);
|
||||
|
||||
llassert(NULL != img_diffuse);
|
||||
|
||||
LLMaterialPtr new_material = NULL;
|
||||
|
||||
//diffuse
|
||||
if(NULL != img_diffuse)
|
||||
{ //guard
|
||||
if(0 == img_diffuse->getPrimaryFormat() && !img_diffuse->isMissingAsset())
|
||||
{ //ok here we don't have information about texture, let's belief and leave material settings
|
||||
//but we remember this case
|
||||
mWaitingTextureInfo.insert(mmap_UUID_MAP_t::value_type(img_diffuse->getID(), material_info(LLRender::DIFFUSE_MAP, te)));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bSetDiffuseNone = false;
|
||||
if(img_diffuse->isMissingAsset())
|
||||
{
|
||||
bSetDiffuseNone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(pMaterialParams->getDiffuseAlphaMode())
|
||||
{
|
||||
case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND:
|
||||
case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE:
|
||||
case LLMaterial::DIFFUSE_ALPHA_MODE_MASK:
|
||||
{ //all of them modes available only for 32 bit textures
|
||||
if(GL_RGBA != img_diffuse->getPrimaryFormat())
|
||||
{
|
||||
bSetDiffuseNone = true;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} //else
|
||||
|
||||
|
||||
if(bSetDiffuseNone)
|
||||
{ //upps... we should substitute this material with LLMaterial::DIFFUSE_ALPHA_MODE_NONE
|
||||
new_material = new LLMaterial(pMaterialParams->asLLSD());
|
||||
new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//normal
|
||||
if(LLUUID::null != pMaterialParams->getNormalID())
|
||||
{
|
||||
if(img_normal && img_normal->isMissingAsset() && img_normal->getID() == pMaterialParams->getNormalID())
|
||||
{
|
||||
if(!new_material) {
|
||||
new_material = new LLMaterial(pMaterialParams->asLLSD());
|
||||
}
|
||||
new_material->setNormalID(LLUUID::null);
|
||||
}
|
||||
else if(NULL == img_normal || 0 == img_normal->getPrimaryFormat())
|
||||
{ //ok here we don't have information about texture, let's belief and leave material settings
|
||||
//but we remember this case
|
||||
mWaitingTextureInfo.insert(mmap_UUID_MAP_t::value_type(pMaterialParams->getNormalID(), material_info(LLRender::NORMAL_MAP,te)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//specular
|
||||
if(LLUUID::null != pMaterialParams->getSpecularID())
|
||||
{
|
||||
if(img_specular && img_specular->isMissingAsset() && img_specular->getID() == pMaterialParams->getSpecularID())
|
||||
{
|
||||
if(!new_material) {
|
||||
new_material = new LLMaterial(pMaterialParams->asLLSD());
|
||||
}
|
||||
new_material->setSpecularID(LLUUID::null);
|
||||
}
|
||||
else if(NULL == img_specular || 0 == img_specular->getPrimaryFormat())
|
||||
{ //ok here we don't have information about texture, let's belief and leave material settings
|
||||
//but we remember this case
|
||||
mWaitingTextureInfo.insert(mmap_UUID_MAP_t::value_type(pMaterialParams->getSpecularID(), material_info(LLRender::SPECULAR_MAP, te)));
|
||||
}
|
||||
}
|
||||
|
||||
if(new_material) {
|
||||
pMaterial = new_material;
|
||||
LLMaterialMgr::getInstance()->put(getID(),te,*pMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial);
|
||||
|
||||
LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterial) ? pMaterial->asLLSD() : LLSD("null")) << " res " << res
|
||||
<< ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" )
|
||||
<< LL_ENDL;
|
||||
setChanged(ALL_CHANGED);
|
||||
@@ -4597,60 +4834,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
||||
|
||||
//get drawpool of avatar with rigged face
|
||||
LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
|
||||
|
||||
//Determine if we've received skininfo that contains an
|
||||
//alternate bind matrix - if it does then apply the translational component
|
||||
//to the joints of the avatar.
|
||||
bool pelvisGotSet = false;
|
||||
|
||||
|
||||
// FIXME should this be inside the face loop?
|
||||
// doesn't seem to depend on any per-face state.
|
||||
if ( pAvatarVO )
|
||||
{
|
||||
LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
|
||||
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
|
||||
|
||||
if ( pSkinData )
|
||||
{
|
||||
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
|
||||
if ( bindCnt > 0 )
|
||||
{
|
||||
const int jointCnt = pSkinData->mJointNames.size();
|
||||
const F32 pelvisZOffset = pSkinData->mPelvisOffset;
|
||||
bool fullRig = (jointCnt>=20) ? true : false;
|
||||
if ( fullRig )
|
||||
{
|
||||
for ( int i=0; i<jointCnt; ++i )
|
||||
{
|
||||
std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
|
||||
//LL_INFOS() <<"joint name "<<lookingForJoint.c_str()<<LL_ENDL;
|
||||
LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
|
||||
if ( pJoint && pJoint->getId() != currentId )
|
||||
{
|
||||
pJoint->setId( currentId );
|
||||
const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
|
||||
//Set the joint position
|
||||
pJoint->storeCurrentXform( jointPos );
|
||||
//If joint is a pelvis then handle old/new pelvis to foot values
|
||||
if ( lookingForJoint == "mPelvis" )
|
||||
{
|
||||
pJoint->storeCurrentXform( jointPos );
|
||||
if ( !pAvatarVO->hasPelvisOffset() )
|
||||
{
|
||||
pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
|
||||
//Trigger to rebuild viewer AV
|
||||
pelvisGotSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//If we've set the pelvis to a new position we need to also rebuild some information that the
|
||||
//viewer does at launch (e.g. body size etc.)
|
||||
if ( pelvisGotSet )
|
||||
{
|
||||
pAvatarVO->postPelvisSetRecalc();
|
||||
pAvatarVO->addAttachmentPosOverridesForObject(vobj);
|
||||
}
|
||||
|
||||
if (pool)
|
||||
@@ -5407,6 +5596,10 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
|
||||
for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
|
||||
{
|
||||
LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
|
||||
if(!drawablep)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
|
||||
{
|
||||
LLFace* face = drawablep->getFace(i);
|
||||
|
||||
@@ -358,6 +358,10 @@ protected:
|
||||
void cleanUpMediaImpls();
|
||||
void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;
|
||||
void removeMediaImpl(S32 texture_index) ;
|
||||
|
||||
private:
|
||||
bool lodOrSculptChanged(LLDrawable *drawable);
|
||||
|
||||
public:
|
||||
|
||||
static S32 getRenderComplexityMax() {return mRenderComplexity_last;}
|
||||
@@ -402,6 +406,26 @@ protected:
|
||||
static S32 sNumLODChanges;
|
||||
|
||||
friend class LLVolumeImplFlexible;
|
||||
|
||||
public:
|
||||
bool notifyAboutCreatingTexture(LLViewerTexture *texture);
|
||||
bool notifyAboutMissingAsset(LLViewerTexture *texture);
|
||||
|
||||
private:
|
||||
struct material_info
|
||||
{
|
||||
LLRender::eTexIndex map;
|
||||
U8 te;
|
||||
|
||||
material_info(LLRender::eTexIndex map_, U8 te_)
|
||||
: map(map_)
|
||||
, te(te_)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::multimap<LLUUID, material_info> mmap_UUID_MAP_t;
|
||||
mmap_UUID_MAP_t mWaitingTextureInfo;
|
||||
|
||||
};
|
||||
|
||||
#endif // LL_LLVOVOLUME_H
|
||||
|
||||
Reference in New Issue
Block a user