V3 mesh, texture, and hover merge.

This commit is contained in:
Shyotl
2016-04-26 13:36:39 -05:00
parent be5d2f20bc
commit 55b5f60b68
39 changed files with 6860 additions and 4126 deletions

View File

@@ -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.

View File

@@ -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:

View File

@@ -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();

View File

@@ -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

View File

@@ -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);
}
//--------------------------------------------------------------------

View File

@@ -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>

View File

@@ -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

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

View File

@@ -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;
};

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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:

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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

View File

@@ -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 &params) 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

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

View 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

View File

@@ -655,7 +655,6 @@ set(viewer_HEADER_FILES
llavataractions.h
llavatarpropertiesprocessor.h
llbox.h
llcallbacklist.h
llcallingcard.h
llcapabilitylistener.h
llcaphttpsender.h

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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());

View File

@@ -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 &params) 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;

View File

@@ -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();

View File

@@ -141,6 +141,8 @@ public:
virtual LLVOAvatar* asAvatar();
LLVOAvatar* getAvatarAncestor();
static void initVOClasses();
static void cleanupVOClasses();

View File

@@ -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();

View File

@@ -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()

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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
** **

View File

@@ -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)

View File

@@ -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);
//--------------------------------------------------------------------

View File

@@ -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);

View File

@@ -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