merge changes for 3.8.4-release
commit
9757c3a7fa
1
.hgtags
1
.hgtags
|
|
@ -507,3 +507,4 @@ d07f76c5b9860fb87924d00ca729f7d4532534d6 3.7.29-release
|
|||
3f61ed662347dc7c6941b8266e72746a66d90e2a 3.8.1-release
|
||||
3a62616f3dd8bd512fcdfd29ef033b2505b11213 3.8.2-release
|
||||
60572f718879f786f6bc8b5c9373ebebf4693078 3.8.3-release
|
||||
27e3cf444c4cc645884960a61325a9ee0e9a2d0f 3.8.4-release
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ set(llcommon_SOURCE_FILES
|
|||
llbase32.cpp
|
||||
llbase64.cpp
|
||||
llbitpack.cpp
|
||||
llcallbacklist.cpp
|
||||
llcommon.cpp
|
||||
llcommonutils.cpp
|
||||
llcoros.cpp
|
||||
|
|
@ -129,6 +130,7 @@ set(llcommon_HEADER_FILES
|
|||
llbase64.h
|
||||
llbitpack.h
|
||||
llboost.h
|
||||
llcallbacklist.h
|
||||
llcommon.h
|
||||
llcommonutils.h
|
||||
llcoros.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,230 @@
|
|||
/**
|
||||
* @file llcallbacklist.cpp
|
||||
* @brief A simple list of callback functions to call.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llcallbacklist.h"
|
||||
#include "lleventtimer.h"
|
||||
#include "llerrorlegacy.h"
|
||||
|
||||
// Globals
|
||||
//
|
||||
LLCallbackList gIdleCallbacks;
|
||||
|
||||
//
|
||||
// Member functions
|
||||
//
|
||||
|
||||
LLCallbackList::LLCallbackList()
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
LLCallbackList::~LLCallbackList()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void LLCallbackList::addFunction( callback_t func, void *data)
|
||||
{
|
||||
if (!func)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// only add one callback per func/data pair
|
||||
//
|
||||
if (containsFunction(func))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
callback_pair_t t(func, data);
|
||||
mCallbackList.push_back(t);
|
||||
}
|
||||
|
||||
bool LLCallbackList::containsFunction( callback_t func, void *data)
|
||||
{
|
||||
callback_pair_t t(func, data);
|
||||
callback_list_t::iterator iter = find(func,data);
|
||||
if (iter != mCallbackList.end())
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLCallbackList::deleteFunction( callback_t func, void *data)
|
||||
{
|
||||
callback_list_t::iterator iter = find(func,data);
|
||||
if (iter != mCallbackList.end())
|
||||
{
|
||||
mCallbackList.erase(iter);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
LLCallbackList::callback_list_t::iterator
|
||||
LLCallbackList::find(callback_t func, void *data)
|
||||
{
|
||||
callback_pair_t t(func, data);
|
||||
return std::find(mCallbackList.begin(), mCallbackList.end(), t);
|
||||
}
|
||||
|
||||
void LLCallbackList::deleteAllFunctions()
|
||||
{
|
||||
mCallbackList.clear();
|
||||
}
|
||||
|
||||
|
||||
void LLCallbackList::callFunctions()
|
||||
{
|
||||
for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); )
|
||||
{
|
||||
callback_list_t::iterator curiter = iter++;
|
||||
curiter->first(curiter->second);
|
||||
}
|
||||
}
|
||||
|
||||
// Shim class to allow arbitrary boost::bind
|
||||
// expressions to be run as one-time idle callbacks.
|
||||
class OnIdleCallbackOneTime
|
||||
{
|
||||
public:
|
||||
OnIdleCallbackOneTime(nullary_func_t callable):
|
||||
mCallable(callable)
|
||||
{
|
||||
}
|
||||
static void onIdle(void *data)
|
||||
{
|
||||
gIdleCallbacks.deleteFunction(onIdle, data);
|
||||
OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data);
|
||||
self->call();
|
||||
delete self;
|
||||
}
|
||||
void call()
|
||||
{
|
||||
mCallable();
|
||||
}
|
||||
private:
|
||||
nullary_func_t mCallable;
|
||||
};
|
||||
|
||||
void doOnIdleOneTime(nullary_func_t callable)
|
||||
{
|
||||
OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable);
|
||||
gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor);
|
||||
}
|
||||
|
||||
// Shim class to allow generic boost functions to be run as
|
||||
// recurring idle callbacks. Callable should return true when done,
|
||||
// false to continue getting called.
|
||||
class OnIdleCallbackRepeating
|
||||
{
|
||||
public:
|
||||
OnIdleCallbackRepeating(bool_func_t callable):
|
||||
mCallable(callable)
|
||||
{
|
||||
}
|
||||
// Will keep getting called until the callable returns true.
|
||||
static void onIdle(void *data)
|
||||
{
|
||||
OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data);
|
||||
bool done = self->call();
|
||||
if (done)
|
||||
{
|
||||
gIdleCallbacks.deleteFunction(onIdle, data);
|
||||
delete self;
|
||||
}
|
||||
}
|
||||
bool call()
|
||||
{
|
||||
return mCallable();
|
||||
}
|
||||
private:
|
||||
bool_func_t mCallable;
|
||||
};
|
||||
|
||||
void doOnIdleRepeating(bool_func_t callable)
|
||||
{
|
||||
OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable);
|
||||
gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
|
||||
}
|
||||
|
||||
class NullaryFuncEventTimer: public LLEventTimer
|
||||
{
|
||||
public:
|
||||
NullaryFuncEventTimer(nullary_func_t callable, F32 seconds):
|
||||
LLEventTimer(seconds),
|
||||
mCallable(callable)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
BOOL tick()
|
||||
{
|
||||
mCallable();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
nullary_func_t mCallable;
|
||||
};
|
||||
|
||||
// Call a given callable once after specified interval.
|
||||
void doAfterInterval(nullary_func_t callable, F32 seconds)
|
||||
{
|
||||
new NullaryFuncEventTimer(callable, seconds);
|
||||
}
|
||||
|
||||
class BoolFuncEventTimer: public LLEventTimer
|
||||
{
|
||||
public:
|
||||
BoolFuncEventTimer(bool_func_t callable, F32 seconds):
|
||||
LLEventTimer(seconds),
|
||||
mCallable(callable)
|
||||
{
|
||||
}
|
||||
private:
|
||||
BOOL tick()
|
||||
{
|
||||
return mCallable();
|
||||
}
|
||||
|
||||
bool_func_t mCallable;
|
||||
};
|
||||
|
||||
// Call a given callable every specified number of seconds, until it returns true.
|
||||
void doPeriodically(bool_func_t callable, F32 seconds)
|
||||
{
|
||||
new BoolFuncEventTimer(callable, seconds);
|
||||
}
|
||||
|
|
@ -28,27 +28,34 @@
|
|||
#define LL_LLCALLBACKLIST_H
|
||||
|
||||
#include "llstl.h"
|
||||
#include <boost/function.hpp>
|
||||
#include <list>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "linden_common.h"
|
||||
#include "llunits.h"
|
||||
#include "stdtypes.h"
|
||||
#if !LL_WINDOWS
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
|
@ -59,7 +60,7 @@ class LLMutex ;
|
|||
LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(reinterpret_cast<uintptr_t>(ptr),((U32)alignment))
|
||||
#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(uintptr_t(ptr),((U32)alignment))
|
||||
#else
|
||||
#define ll_assert_aligned(ptr,alignment)
|
||||
#endif
|
||||
|
|
@ -69,13 +70,13 @@ LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
|
|||
template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address)
|
||||
{
|
||||
return reinterpret_cast<T*>(
|
||||
(reinterpret_cast<uintptr_t>(address) + 0xF) & ~0xF);
|
||||
(uintptr_t(address) + 0xF) & ~0xF);
|
||||
}
|
||||
|
||||
template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
|
||||
{
|
||||
return reinterpret_cast<T*>(
|
||||
(reinterpret_cast<uintptr_t>(address) + 0x3F) & ~0x3F);
|
||||
(uintptr_t(address) + 0x3F) & ~0x3F);
|
||||
}
|
||||
|
||||
#if LL_LINUX || LL_DARWIN
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@
|
|||
|
||||
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
struct apr_thread_mutex_t;
|
||||
struct apr_pool_t;
|
||||
struct apr_thread_cond_t;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#ifndef LL_LLSTL_H
|
||||
#define LL_LLSTL_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
|
@ -272,6 +273,7 @@ inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value)
|
|||
}
|
||||
};
|
||||
|
||||
// Useful for replacing the removeObj() functionality of LLDynamicArray
|
||||
// Example:
|
||||
// for (std::vector<T>::iterator iter = mList.begin(); iter != mList.end(); )
|
||||
// {
|
||||
|
|
@ -530,7 +532,7 @@ bool before(const std::type_info* lhs, const std::type_info* rhs)
|
|||
return strcmp(lhs->name(), rhs->name()) < 0;
|
||||
#else // not Linux, or gcc 4.4+
|
||||
// Just use before(), as we normally would
|
||||
return lhs->before(*rhs);
|
||||
return lhs->before(*rhs) ? true : false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6072,7 +6072,7 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
|
|||
|
||||
if (new_verts > mNumAllocatedVertices)
|
||||
{
|
||||
//double buffer size on expansion
|
||||
// double buffer size on expansion
|
||||
new_verts *= 2;
|
||||
|
||||
S32 new_tc_size = ((new_verts*8)+0xF) & ~0xF;
|
||||
|
|
@ -6088,18 +6088,21 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
|
|||
mNormals = mPositions+new_verts;
|
||||
mTexCoords = (LLVector2*) (mNormals+new_verts);
|
||||
|
||||
//positions
|
||||
LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize);
|
||||
|
||||
//normals
|
||||
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
|
||||
if (old_buf != NULL)
|
||||
{
|
||||
// copy old positions into new buffer
|
||||
LLVector4a::memcpyNonAliased16((F32*)mPositions, (F32*)old_buf, old_vsize);
|
||||
|
||||
//tex coords
|
||||
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tc_size);
|
||||
// normals
|
||||
LLVector4a::memcpyNonAliased16((F32*)mNormals, (F32*)(old_buf + mNumVertices), old_vsize);
|
||||
|
||||
//just clear tangents
|
||||
ll_aligned_free_16(mTangents);
|
||||
mTangents = NULL;
|
||||
// tex coords
|
||||
LLVector4a::memcpyNonAliased16((F32*)mTexCoords, (F32*)(old_buf + mNumVertices * 2), old_tc_size);
|
||||
}
|
||||
|
||||
// just clear tangents
|
||||
ll_aligned_free_16(mTangents);
|
||||
mTangents = NULL;
|
||||
ll_aligned_free<64>(old_buf);
|
||||
|
||||
mNumAllocatedVertices = new_verts;
|
||||
|
|
|
|||
|
|
@ -968,6 +968,7 @@ protected:
|
|||
~LLVolume(); // use unref
|
||||
|
||||
public:
|
||||
typedef std::vector<LLVolumeFace> face_list_t;
|
||||
|
||||
struct FaceParams
|
||||
{
|
||||
|
|
@ -1041,6 +1042,10 @@ 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
|
||||
|
||||
|
|
@ -1080,7 +1085,6 @@ public:
|
|||
|
||||
|
||||
BOOL mGenerateSingleFace;
|
||||
typedef std::vector<LLVolumeFace> face_list_t;
|
||||
face_list_t mVolumeFaces;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -274,6 +274,19 @@ const LLMatrix4& LLMatrix4::invert(void)
|
|||
return *this;
|
||||
}
|
||||
|
||||
// Convenience func for simplifying comparison-heavy code by
|
||||
// intentionally stomping values in [-FLT_EPS,FLT_EPS] to 0.0f
|
||||
//
|
||||
void LLMatrix4::condition(void)
|
||||
{
|
||||
U32 i;
|
||||
U32 j;
|
||||
for (i = 0; i < 3;i++)
|
||||
for (j = 0; j < 3;j++)
|
||||
mMatrix[i][j] = ((mMatrix[i][j] > -FLT_EPSILON)
|
||||
&& (mMatrix[i][j] < FLT_EPSILON)) ? 0.0f : mMatrix[i][j];
|
||||
}
|
||||
|
||||
LLVector4 LLMatrix4::getFwdRow4() const
|
||||
{
|
||||
return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]);
|
||||
|
|
|
|||
|
|
@ -180,6 +180,11 @@ public:
|
|||
const LLMatrix4& setTranslation(const LLVector4 &translation);
|
||||
const LLMatrix4& setTranslation(const LLVector3 &translation);
|
||||
|
||||
// Convenience func for simplifying comparison-heavy code by
|
||||
// intentionally stomping values [-FLT_EPS,FLT_EPS] to 0.0
|
||||
//
|
||||
void condition(void);
|
||||
|
||||
///////////////////////////
|
||||
//
|
||||
// Get properties of a matrix
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ include(LLMath)
|
|||
include(LLMessage)
|
||||
include(LLXML)
|
||||
include(LLPhysicsExtensions)
|
||||
include(LLCharacter)
|
||||
|
||||
include_directories(
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
|
|
@ -16,6 +17,7 @@ include_directories(
|
|||
${LLXML_INCLUDE_DIRS}
|
||||
${LIBS_PREBUILT_DIR}/include/collada
|
||||
${LIBS_PREBUILT_DIR}/include/collada/1.4
|
||||
${LLCHARACTER_INCLUDE_DIRS}
|
||||
)
|
||||
include_directories(SYSTEM
|
||||
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
|
||||
|
|
@ -24,11 +26,13 @@ include_directories(SYSTEM
|
|||
)
|
||||
|
||||
set(llprimitive_SOURCE_FILES
|
||||
lldaeloader.cpp
|
||||
llmaterialid.cpp
|
||||
llmaterial.cpp
|
||||
llmaterialtable.cpp
|
||||
llmediaentry.cpp
|
||||
llmodel.cpp
|
||||
llmodelloader.cpp
|
||||
llprimitive.cpp
|
||||
llprimtexturelist.cpp
|
||||
lltextureanim.cpp
|
||||
|
|
@ -40,16 +44,17 @@ set(llprimitive_SOURCE_FILES
|
|||
|
||||
set(llprimitive_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
lldaeloader.h
|
||||
legacy_object_types.h
|
||||
lllslconstants.h
|
||||
llmaterial.h
|
||||
llmaterialid.h
|
||||
llmaterialtable.h
|
||||
llmediaentry.h
|
||||
llmodel.h
|
||||
llmodelloader.h
|
||||
llprimitive.h
|
||||
llprimtexturelist.h
|
||||
lllslconstants.h
|
||||
lltextureanim.h
|
||||
lltextureentry.h
|
||||
lltreeparams.h
|
||||
|
|
@ -72,6 +77,7 @@ target_link_libraries(llprimitive
|
|||
${LLMESSAGE_LIBRARIES}
|
||||
${LLXML_LIBRARIES}
|
||||
${LLPHYSICSEXTENSIONS_LIBRARIES}
|
||||
${LLCHARACTER_LIBRARIES}
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* @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);
|
||||
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);
|
||||
|
||||
private:
|
||||
U32 mGeneratedModelLimit; // Attempt to limit amount of generated submodels
|
||||
|
||||
};
|
||||
#endif // LL_LLDAELLOADER_H
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -31,6 +31,7 @@
|
|||
#include "llvolume.h"
|
||||
#include "v4math.h"
|
||||
#include "m4math.h"
|
||||
#include <queue>
|
||||
|
||||
class daeElement;
|
||||
class domMesh;
|
||||
|
|
@ -138,15 +139,16 @@ public:
|
|||
BOOL upload_skin,
|
||||
BOOL upload_joints,
|
||||
BOOL nowrite = FALSE,
|
||||
BOOL as_slm = FALSE);
|
||||
BOOL as_slm = FALSE,
|
||||
int submodel_id = 0);
|
||||
|
||||
static LLSD writeModelToStream(
|
||||
std::ostream& ostr,
|
||||
LLSD& mdl,
|
||||
BOOL nowrite = FALSE, BOOL as_slm = FALSE);
|
||||
|
||||
void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); }
|
||||
|
||||
static LLModel* loadModelFromDomMesh(domMesh* mesh);
|
||||
static std::string getElementLabel(daeElement* element);
|
||||
std::string getName() const;
|
||||
std::string getMetric() const {return mMetric;}
|
||||
EModelStatus getStatus() const {return mStatus;}
|
||||
|
|
@ -169,20 +171,25 @@ public:
|
|||
|
||||
void addFace(const LLVolumeFace& face);
|
||||
|
||||
void sortVolumeFacesByMaterialName();
|
||||
void normalizeVolumeFaces();
|
||||
void trimVolumeFacesToSize(U32 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);
|
||||
LLVector3 getTransformedCenter(const LLMatrix4& mat);
|
||||
|
||||
|
||||
//reorder face list based on mMaterialList in this and reference so
|
||||
//order matches that of reference (material ordering touchup)
|
||||
bool matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCnt );
|
||||
bool isMaterialListSubset( LLModel* ref );
|
||||
bool needToAddFaces( LLModel* ref, int& refFaceCnt, int& modelFaceCnt );
|
||||
|
||||
|
||||
std::vector<std::string> mMaterialList;
|
||||
typedef std::vector<std::string> material_list;
|
||||
|
||||
material_list mMaterialList;
|
||||
|
||||
material_list& getMaterialList() { return mMaterialList; }
|
||||
|
||||
//data used for skin weights
|
||||
class JointWeight
|
||||
|
|
@ -275,9 +282,115 @@ public:
|
|||
Decomposition mPhysics;
|
||||
|
||||
EModelStatus mStatus ;
|
||||
protected:
|
||||
void addVolumeFacesFromDomMesh(domMesh* mesh);
|
||||
virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
|
||||
|
||||
int mSubmodelID;
|
||||
};
|
||||
|
||||
typedef std::vector<LLPointer<LLModel> > model_list;
|
||||
typedef std::queue<LLPointer<LLModel> > model_queue;
|
||||
|
||||
class LLModelMaterialBase
|
||||
{
|
||||
public:
|
||||
std::string mDiffuseMapFilename;
|
||||
std::string mDiffuseMapLabel;
|
||||
std::string mBinding;
|
||||
LLColor4 mDiffuseColor;
|
||||
bool mFullbright;
|
||||
|
||||
LLModelMaterialBase()
|
||||
: mFullbright(false)
|
||||
{
|
||||
mDiffuseColor.set(1,1,1,1);
|
||||
}
|
||||
};
|
||||
|
||||
class LLImportMaterial : public LLModelMaterialBase
|
||||
{
|
||||
public:
|
||||
friend class LLMeshUploadThread;
|
||||
friend class LLModelPreview;
|
||||
|
||||
bool operator<(const LLImportMaterial ¶ms) const;
|
||||
|
||||
LLImportMaterial() : LLModelMaterialBase()
|
||||
{
|
||||
mDiffuseColor.set(1,1,1,1);
|
||||
}
|
||||
|
||||
LLImportMaterial(LLSD& data);
|
||||
virtual ~LLImportMaterial();
|
||||
|
||||
LLSD asLLSD();
|
||||
|
||||
const LLUUID& getDiffuseMap() const { return mDiffuseMapID; }
|
||||
void setDiffuseMap(const LLUUID& texId) { mDiffuseMapID = texId; }
|
||||
|
||||
protected:
|
||||
|
||||
LLUUID mDiffuseMapID;
|
||||
void* mOpaqueData; // allow refs to viewer/platform-specific structs for each material
|
||||
// currently only stores an LLPointer< LLViewerFetchedTexture > > to
|
||||
// maintain refs to textures associated with each material for free
|
||||
// ref counting.
|
||||
};
|
||||
|
||||
typedef std::map<std::string, LLImportMaterial> material_map;
|
||||
|
||||
class LLModelInstanceBase
|
||||
{
|
||||
public:
|
||||
LLPointer<LLModel> mModel;
|
||||
LLPointer<LLModel> mLOD[5];
|
||||
LLUUID mMeshID;
|
||||
|
||||
LLMatrix4 mTransform;
|
||||
material_map mMaterial;
|
||||
|
||||
LLModelInstanceBase(LLModel* model, LLMatrix4& transform, material_map& materials)
|
||||
: mModel(model), mTransform(transform), mMaterial(materials)
|
||||
{
|
||||
}
|
||||
|
||||
LLModelInstanceBase()
|
||||
: mModel(NULL)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<LLModelInstanceBase> model_instance_list;
|
||||
|
||||
class LLModelInstance : public LLModelInstanceBase
|
||||
{
|
||||
public:
|
||||
std::string mLabel;
|
||||
LLUUID mMeshID;
|
||||
S32 mLocalMeshID;
|
||||
|
||||
LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, material_map& materials)
|
||||
: LLModelInstanceBase(model, transform, materials), mLabel(label)
|
||||
{
|
||||
mLocalMeshID = -1;
|
||||
}
|
||||
|
||||
LLModelInstance(LLSD& data);
|
||||
|
||||
LLSD asLLSD();
|
||||
};
|
||||
|
||||
#define LL_DEGENERACY_TOLERANCE 1e-7f
|
||||
|
||||
inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
|
||||
{
|
||||
volatile F32 p0 = a[0] * b[0];
|
||||
volatile F32 p1 = a[1] * b[1];
|
||||
volatile F32 p2 = a[2] * b[2];
|
||||
return p0 + p1 + p2;
|
||||
}
|
||||
|
||||
bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE);
|
||||
|
||||
bool validate_face(const LLVolumeFace& face);
|
||||
bool validate_model(const LLModel* mdl);
|
||||
|
||||
#endif //LL_LLMODEL_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,640 @@
|
|||
/**
|
||||
* @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 "glh/glh_linear.h"
|
||||
#include "llmatrix4a.h"
|
||||
#include <boost/bind.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)
|
||||
, mFirstTransform(TRUE)
|
||||
, mNumOfFetchingTextures(0)
|
||||
, mLoadCallback(load_cb)
|
||||
, mJointLookupFunc(joint_lookup_func)
|
||||
, mTextureLoadFunc(texture_load_func)
|
||||
, mStateCallback(state_cb)
|
||||
, mOpaqueData(opaque_userdata)
|
||||
, 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 < 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 < 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
|
||||
apr_sleep(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() ;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -89,6 +89,10 @@ public:
|
|||
|
||||
bool operator==(const LLTextureEntry &rhs) const;
|
||||
bool operator!=(const LLTextureEntry &rhs) const;
|
||||
|
||||
// Added to allow use with std::map
|
||||
//
|
||||
bool operator <(const LLTextureEntry &rhs) const;
|
||||
|
||||
LLSD asLLSD() const;
|
||||
void asLLSD(LLSD& sd) const;
|
||||
|
|
|
|||
|
|
@ -141,7 +141,6 @@ set(viewer_SOURCE_FILES
|
|||
llbreadcrumbview.cpp
|
||||
llbrowsernotification.cpp
|
||||
llbuycurrencyhtml.cpp
|
||||
llcallbacklist.cpp
|
||||
llcallingcard.cpp
|
||||
llcapabilitylistener.cpp
|
||||
llcaphttpsender.cpp
|
||||
|
|
@ -762,7 +761,6 @@ set(viewer_HEADER_FILES
|
|||
llbox.h
|
||||
llbreadcrumbview.h
|
||||
llbuycurrencyhtml.h
|
||||
llcallbacklist.h
|
||||
llcallingcard.h
|
||||
llcapabilitylistener.h
|
||||
llcapabilityprovider.h
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.8.4
|
||||
3.8.5
|
||||
|
|
|
|||
|
|
@ -2,6 +2,39 @@
|
|||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<map>
|
||||
<key>ImporterDebug</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable debug output to more precisely identify sources of import errors. Warning: the output can slow down import on many machines.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>ImporterLegacyMatching</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable index based model matching.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>ImporterModelLimit</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Limits amount of importer generated models for dae files</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>768</integer>
|
||||
</map>
|
||||
<key>IMShowTime</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "llcommandhandler.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llcommanddispatcherlistener.h"
|
||||
#include "llstartup.h"
|
||||
#include "stringize.h"
|
||||
|
||||
// system includes
|
||||
|
|
@ -116,7 +117,11 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
|
|||
LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL;
|
||||
if (! slurl_blocked)
|
||||
{
|
||||
LLNotificationsUtil::add("BlockedSLURL");
|
||||
if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
|
||||
{
|
||||
// Note: commands can arrive before we initialize everything we need for Notification.
|
||||
LLNotificationsUtil::add("BlockedSLURL");
|
||||
}
|
||||
slurl_blocked = true;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -138,7 +143,10 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
|
|||
LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL;
|
||||
if (! slurl_throttled)
|
||||
{
|
||||
LLNotificationsUtil::add("ThrottledSLURL");
|
||||
if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT)
|
||||
{
|
||||
LLNotificationsUtil::add("ThrottledSLURL");
|
||||
}
|
||||
slurl_throttled = true;
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1593,6 +1593,14 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
|
|||
for (U32 j = 0; j < count; ++j)
|
||||
{
|
||||
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
|
||||
if (!joint)
|
||||
{
|
||||
joint = avatar->getJoint("mPelvis");
|
||||
}
|
||||
if (!joint)
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "Failed to find " << skin->mJointNames[j] << LL_ENDL;
|
||||
}
|
||||
if (joint)
|
||||
{
|
||||
mat[j] = skin->mInvBindMatrix[j];
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -37,6 +37,8 @@
|
|||
#include "llviewermenufile.h"
|
||||
#include "llfloatermodeluploadbase.h"
|
||||
|
||||
#include "lldaeloader.h"
|
||||
|
||||
class LLComboBox;
|
||||
class LLJoint;
|
||||
class LLViewerJointMesh;
|
||||
|
|
@ -45,103 +47,18 @@ class LLTextBox;
|
|||
class LLVertexBuffer;
|
||||
class LLModelPreview;
|
||||
class LLFloaterModelPreview;
|
||||
class DAE;
|
||||
class daeElement;
|
||||
class domProfile_COMMON;
|
||||
class domInstance_geometry;
|
||||
class domNode;
|
||||
class domTranslate;
|
||||
class domController;
|
||||
class domSkin;
|
||||
class domMesh;
|
||||
class LLMenuButton;
|
||||
class LLToggleableMenu;
|
||||
|
||||
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 LLFloaterModelPreview : public LLFloaterModelUploadBase
|
||||
{
|
||||
public:
|
||||
|
|
@ -172,6 +89,7 @@ public:
|
|||
BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
|
||||
|
||||
/*virtual*/ void onOpen(const LLSD& key);
|
||||
/*virtual*/ void onClose(bool app_quitting);
|
||||
|
||||
static void onMouseCaptureLostModelPreview(LLMouseHandler*);
|
||||
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
|
||||
|
|
@ -210,6 +128,8 @@ public:
|
|||
|
||||
/*virtual*/ void onModelUploadFailure();
|
||||
|
||||
bool isModelUploadAllowed();
|
||||
|
||||
protected:
|
||||
friend class LLModelPreview;
|
||||
friend class LLMeshFilePicker;
|
||||
|
|
@ -359,21 +279,14 @@ public:
|
|||
void setHasPivot( bool val ) { mHasPivot = val; }
|
||||
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 );
|
||||
|
||||
//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 );
|
||||
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 );
|
||||
|
||||
|
|
@ -388,6 +301,16 @@ public:
|
|||
|
||||
LLVector3 getTranslationForJointOffset( std::string joint );
|
||||
|
||||
static bool sIgnoreLoadedCallback;
|
||||
|
||||
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 );
|
||||
|
|
@ -395,6 +318,8 @@ private:
|
|||
void createPreviewAvatar( void );
|
||||
//Accessor for the dummy avatar
|
||||
LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; }
|
||||
// Count amount of original models, excluding sub-models
|
||||
static U32 countRootModels(LLModelLoader::model_list models);
|
||||
|
||||
protected:
|
||||
friend class LLModelLoader;
|
||||
|
|
@ -416,13 +341,15 @@ 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;
|
||||
|
||||
//GLOD object parameters (must rebuild object if these change)
|
||||
|
|
@ -459,7 +386,7 @@ private:
|
|||
U32 mMaxTriangleLimit;
|
||||
|
||||
LLMeshUploadThread::instance_list mUploadData;
|
||||
std::set<LLViewerFetchedTexture* > mTextureSet;
|
||||
std::set<LLViewerFetchedTexture * > mTextureSet;
|
||||
|
||||
//map of vertex buffers to models (one vertex buffer in vector per face in model
|
||||
std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1];
|
||||
|
|
@ -478,10 +405,9 @@ private:
|
|||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -493,6 +493,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;
|
||||
}
|
||||
|
||||
volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
|
||||
volatile S32 LLMeshRepoThread::sActiveLODRequests = 0;
|
||||
U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
|
||||
|
|
@ -587,16 +593,16 @@ public:
|
|||
LLMeshLODHandler(const LLVolumeParams & mesh_params, S32 lod, U32 offset, U32 requested_bytes)
|
||||
: LLMeshHandlerBase(offset, requested_bytes),
|
||||
mLOD(lod)
|
||||
{
|
||||
{
|
||||
mMeshParams = mesh_params;
|
||||
LLMeshRepoThread::incActiveLODRequests();
|
||||
}
|
||||
virtual ~LLMeshLODHandler();
|
||||
|
||||
|
||||
protected:
|
||||
LLMeshLODHandler(const LLMeshLODHandler &); // Not defined
|
||||
void operator=(const LLMeshLODHandler &); // Not defined
|
||||
|
||||
|
||||
public:
|
||||
virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);
|
||||
virtual void processFailure(LLCore::HttpStatus status);
|
||||
|
|
@ -796,7 +802,7 @@ LLMeshRepoThread::LLMeshRepoThread()
|
|||
mHttpLargePolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LLMeshRepoThread::~LLMeshRepoThread()
|
||||
{
|
||||
LL_INFOS(LOG_MESH) << "Small GETs issued: " << LLMeshRepository::sHTTPRequestCount
|
||||
|
|
@ -865,16 +871,16 @@ void LLMeshRepoThread::run()
|
|||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (! mHttpRequestSet.empty())
|
||||
{
|
||||
// Dispatch all HttpHandler notifications
|
||||
mHttpRequest->update(0L);
|
||||
}
|
||||
sRequestWaterLevel = mHttpRequestSet.size(); // Stats data update
|
||||
|
||||
// NOTE: order of queue processing intentionally favors LOD requests over header requests
|
||||
|
||||
// NOTE: order of queue processing intentionally favors LOD requests over header requests
|
||||
|
||||
while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)
|
||||
{
|
||||
if (! mMutex)
|
||||
|
|
@ -938,7 +944,7 @@ void LLMeshRepoThread::run()
|
|||
mSkinRequests.erase(iter);
|
||||
mMutex->unlock();
|
||||
|
||||
if (!fetchMeshSkinInfo(mesh_id))
|
||||
if (! fetchMeshSkinInfo(mesh_id))
|
||||
{
|
||||
incomplete.insert(mesh_id);
|
||||
}
|
||||
|
|
@ -967,7 +973,7 @@ void LLMeshRepoThread::run()
|
|||
mDecompositionRequests.erase(iter);
|
||||
mMutex->unlock();
|
||||
|
||||
if (!fetchMeshDecomposition(mesh_id))
|
||||
if (! fetchMeshDecomposition(mesh_id))
|
||||
{
|
||||
incomplete.insert(mesh_id);
|
||||
}
|
||||
|
|
@ -993,7 +999,7 @@ void LLMeshRepoThread::run()
|
|||
mPhysicsShapeRequests.erase(iter);
|
||||
mMutex->unlock();
|
||||
|
||||
if (!fetchMeshPhysicsShape(mesh_id))
|
||||
if (! fetchMeshPhysicsShape(mesh_id))
|
||||
{
|
||||
incomplete.insert(mesh_id);
|
||||
}
|
||||
|
|
@ -1219,7 +1225,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
|
|||
}
|
||||
|
||||
++LLMeshRepository::sMeshRequestCount;
|
||||
bool ret = true ;
|
||||
bool ret = true;
|
||||
U32 header_size = mMeshHeaderSize[mesh_id];
|
||||
|
||||
if (header_size > 0)
|
||||
|
|
@ -1267,7 +1273,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
|
|||
constructUrl(mesh_id, &http_url, &cap_version);
|
||||
|
||||
if (!http_url.empty())
|
||||
{
|
||||
{
|
||||
LLMeshSkinInfoHandler * handler = new LLMeshSkinInfoHandler(mesh_id, offset, size);
|
||||
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
|
||||
if (LLCORE_HTTP_HANDLE_INVALID == handle)
|
||||
|
|
@ -1313,7 +1319,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
|
|||
|
||||
++LLMeshRepository::sMeshRequestCount;
|
||||
U32 header_size = mMeshHeaderSize[mesh_id];
|
||||
bool ret = true ;
|
||||
bool ret = true;
|
||||
|
||||
if (header_size > 0)
|
||||
{
|
||||
|
|
@ -1359,9 +1365,9 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
|
|||
int cap_version(2);
|
||||
std::string http_url;
|
||||
constructUrl(mesh_id, &http_url, &cap_version);
|
||||
|
||||
|
||||
if (!http_url.empty())
|
||||
{
|
||||
{
|
||||
LLMeshDecompositionHandler * handler = new LLMeshDecompositionHandler(mesh_id, offset, size);
|
||||
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
|
||||
if (LLCORE_HTTP_HANDLE_INVALID == handle)
|
||||
|
|
@ -1407,7 +1413,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
|
|||
|
||||
++LLMeshRepository::sMeshRequestCount;
|
||||
U32 header_size = mMeshHeaderSize[mesh_id];
|
||||
bool ret = true ;
|
||||
bool ret = true;
|
||||
|
||||
if (header_size > 0)
|
||||
{
|
||||
|
|
@ -1452,9 +1458,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
|
|||
int cap_version(2);
|
||||
std::string http_url;
|
||||
constructUrl(mesh_id, &http_url, &cap_version);
|
||||
|
||||
|
||||
if (!http_url.empty())
|
||||
{
|
||||
{
|
||||
LLMeshPhysicsShapeHandler * handler = new LLMeshPhysicsShapeHandler(mesh_id, offset, size);
|
||||
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
|
||||
if (LLCORE_HTTP_HANDLE_INVALID == handle)
|
||||
|
|
@ -1543,11 +1549,11 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)
|
|||
}
|
||||
|
||||
//either cache entry doesn't exist or is corrupt, request header from simulator
|
||||
bool retval = true ;
|
||||
bool retval = true;
|
||||
int cap_version(2);
|
||||
std::string http_url;
|
||||
constructUrl(mesh_params.getSculptID(), &http_url, &cap_version);
|
||||
|
||||
|
||||
if (!http_url.empty())
|
||||
{
|
||||
//grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits
|
||||
|
|
@ -1635,9 +1641,9 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
|
|||
int cap_version(2);
|
||||
std::string http_url;
|
||||
constructUrl(mesh_id, &http_url, &cap_version);
|
||||
|
||||
|
||||
if (!http_url.empty())
|
||||
{
|
||||
{
|
||||
LLMeshLODHandler * handler = new LLMeshLODHandler(mesh_params, lod, offset, size);
|
||||
LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
|
||||
if (LLCORE_HTTP_HANDLE_INVALID == handle)
|
||||
|
|
@ -1909,7 +1915,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
|
|||
|
||||
mOrigin += gAgent.getAtAxis() * scale.magVec();
|
||||
|
||||
mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ;
|
||||
mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut");
|
||||
|
||||
mHttpRequest = new LLCore::HttpRequest;
|
||||
mHttpOptions = new LLCore::HttpOptions;
|
||||
|
|
@ -1977,14 +1983,14 @@ void LLMeshUploadThread::preStart()
|
|||
|
||||
void LLMeshUploadThread::discard()
|
||||
{
|
||||
LLMutexLock lock(mMutex) ;
|
||||
LLMutexLock lock(mMutex);
|
||||
mDiscarded = true;
|
||||
}
|
||||
|
||||
bool LLMeshUploadThread::isDiscarded() const
|
||||
{
|
||||
LLMutexLock lock(mMutex) ;
|
||||
return mDiscarded ;
|
||||
LLMutexLock lock(mMutex);
|
||||
return mDiscarded;
|
||||
}
|
||||
|
||||
void LLMeshUploadThread::run()
|
||||
|
|
@ -2049,6 +2055,14 @@ 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++)
|
||||
{
|
||||
|
|
@ -2086,7 +2100,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();
|
||||
|
|
@ -2120,17 +2137,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()))
|
||||
|
|
@ -2145,9 +2171,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 &&
|
||||
|
|
@ -2235,7 +2423,7 @@ void LLMeshUploadThread::generateHulls()
|
|||
}
|
||||
}
|
||||
|
||||
if(has_valid_requests)
|
||||
if (has_valid_requests)
|
||||
{
|
||||
// *NOTE: Interesting livelock condition on shutdown. If there
|
||||
// is an upload request in generateHulls() when shutdown starts,
|
||||
|
|
@ -2340,7 +2528,7 @@ void LLMeshUploadThread::requestWholeModelFee()
|
|||
else
|
||||
{
|
||||
U32 sleep_time(10);
|
||||
|
||||
|
||||
mHttpRequest->update(0);
|
||||
while (! LLApp::isQuitting() && ! finished() && ! isDiscarded())
|
||||
{
|
||||
|
|
@ -2435,7 +2623,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
|
|||
// model fee case
|
||||
LLWholeModelFeeObserver* observer(mFeeObserverHandle.get());
|
||||
mWholeModelUploadURL.clear();
|
||||
|
||||
|
||||
if (! status)
|
||||
{
|
||||
LL_WARNS(LOG_MESH) << "Fee request failed. Reason: " << reason
|
||||
|
|
@ -2465,7 +2653,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
|
|||
LLCoreHttpUtil::responseToLLSD(response, true, body);
|
||||
}
|
||||
dump_llsd_to_file(body, make_dump_name("whole_model_fee_response_", dump_num));
|
||||
|
||||
|
||||
if (body["state"].asString() == "upload")
|
||||
{
|
||||
mWholeModelUploadURL = body["uploader"].asString();
|
||||
|
|
@ -2536,7 +2724,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
|
|||
LODRequest req = mUnavailableQ.front();
|
||||
mUnavailableQ.pop();
|
||||
mMutex->unlock();
|
||||
|
||||
|
||||
update_metrics = true;
|
||||
gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);
|
||||
}
|
||||
|
|
@ -2672,7 +2860,7 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
|
|||
void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
|
||||
{
|
||||
mProcessed = true;
|
||||
|
||||
|
||||
unsigned int retries(0U);
|
||||
response->getRetries(NULL, &retries);
|
||||
LLMeshRepository::sHTTPRetryCount += retries;
|
||||
|
|
@ -2728,7 +2916,7 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo
|
|||
// 200 case, typically
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
|
||||
// *DEBUG: To test validation below
|
||||
// offset += 1;
|
||||
|
||||
|
|
@ -2844,7 +3032,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
|
|||
const std::string & lod_name = header_lod[i];
|
||||
lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());
|
||||
}
|
||||
|
||||
|
||||
// just in case skin info or decomposition is at the end of the file (which it shouldn't be)
|
||||
lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
|
||||
lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger());
|
||||
|
|
@ -2852,7 +3040,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
|
|||
S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
|
||||
S32 bytes = lod_bytes + header_bytes;
|
||||
|
||||
|
||||
|
||||
// It's possible for the remote asset to have more data than is needed for the local cache
|
||||
// only allocate as much space in the VFS as is needed for the local cache
|
||||
data_size = llmin(data_size, bytes);
|
||||
|
|
@ -2864,11 +3052,11 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
|
|||
++LLMeshRepository::sCacheWrites;
|
||||
|
||||
file.write(data, data_size);
|
||||
|
||||
|
||||
// zero out the rest of the file
|
||||
U8 block[MESH_HEADER_SIZE];
|
||||
memset(block, 0, sizeof(block));
|
||||
|
||||
|
||||
while (bytes-file.tell() > sizeof(block))
|
||||
{
|
||||
file.write(block, sizeof(block));
|
||||
|
|
@ -2894,8 +3082,8 @@ LLMeshLODHandler::~LLMeshLODHandler()
|
|||
gMeshRepo.mThread->lockAndLoadMeshLOD(mMeshParams, mLOD);
|
||||
}
|
||||
LLMeshRepoThread::decActiveLODRequests();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)
|
||||
{
|
||||
|
|
@ -2913,7 +3101,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body
|
|||
{
|
||||
if ((! MESH_LOD_PROCESS_FAILED) && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
|
||||
{
|
||||
//good fetch from sim, write to VFS for caching
|
||||
// good fetch from sim, write to VFS for caching
|
||||
LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
|
||||
|
||||
S32 offset = mOffset;
|
||||
|
|
@ -2961,7 +3149,7 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /*
|
|||
{
|
||||
if ((! MESH_SKIN_INFO_PROCESS_FAILED) && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))
|
||||
{
|
||||
//good fetch from sim, write to VFS for caching
|
||||
// good fetch from sim, write to VFS for caching
|
||||
LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
|
||||
|
||||
S32 offset = mOffset;
|
||||
|
|
@ -3291,7 +3479,7 @@ void LLMeshRepository::notifyLoadedMeshes()
|
|||
REQUEST2_LOW_WATER_MIN,
|
||||
REQUEST2_LOW_WATER_MAX);
|
||||
}
|
||||
|
||||
|
||||
//clean up completed upload threads
|
||||
for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); )
|
||||
{
|
||||
|
|
@ -3368,7 +3556,7 @@ void LLMeshRepository::notifyLoadedMeshes()
|
|||
|
||||
//call completed callbacks on finished decompositions
|
||||
mDecompThread->notifyCompleted();
|
||||
|
||||
|
||||
// For major operations, attempt to get the required locks
|
||||
// without blocking and punt if they're not available. The
|
||||
// longest run of holdoffs is kept in sMaxLockHoldoffs just
|
||||
|
|
@ -3387,12 +3575,12 @@ void LLMeshRepository::notifyLoadedMeshes()
|
|||
return;
|
||||
}
|
||||
hold_offs = 0;
|
||||
|
||||
|
||||
if (gAgent.getRegion())
|
||||
{
|
||||
// Update capability urls
|
||||
static std::string region_name("never name a region this");
|
||||
|
||||
|
||||
if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())
|
||||
{
|
||||
region_name = gAgent.getRegion()->getName();
|
||||
|
|
@ -3408,7 +3596,7 @@ void LLMeshRepository::notifyLoadedMeshes()
|
|||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//popup queued error messages from background threads
|
||||
while (!mUploadErrorQ.empty())
|
||||
{
|
||||
|
|
@ -3763,7 +3951,7 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
|
|||
|
||||
|
||||
void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
|
||||
bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
|
||||
bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
|
||||
LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
|
||||
{
|
||||
LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url,
|
||||
|
|
@ -3834,37 +4022,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);
|
||||
|
|
@ -4262,7 +4419,7 @@ void LLPhysicsDecomp::doDecompositionSingleHull()
|
|||
setMeshData(mesh, true);
|
||||
|
||||
LLCDResult ret = decomp->buildSingleHull() ;
|
||||
if(ret)
|
||||
if (ret)
|
||||
{
|
||||
LL_WARNS(LOG_MESH) << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL;
|
||||
make_box(mCurRequest);
|
||||
|
|
@ -4450,60 +4607,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 < 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());
|
||||
|
|
|
|||
|
|
@ -90,54 +90,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class LLImportMaterial
|
||||
{
|
||||
public:
|
||||
LLPointer<LLViewerFetchedTexture> mDiffuseMap;
|
||||
std::string mDiffuseMapFilename;
|
||||
std::string mDiffuseMapLabel;
|
||||
std::string mBinding;
|
||||
LLColor4 mDiffuseColor;
|
||||
bool mFullbright;
|
||||
|
||||
bool operator<(const LLImportMaterial ¶ms) const;
|
||||
|
||||
LLImportMaterial()
|
||||
: mFullbright(false)
|
||||
{
|
||||
mDiffuseColor.set(1,1,1,1);
|
||||
}
|
||||
|
||||
LLImportMaterial(LLSD& data);
|
||||
|
||||
LLSD asLLSD();
|
||||
};
|
||||
|
||||
class LLModelInstance
|
||||
{
|
||||
public:
|
||||
LLPointer<LLModel> mModel;
|
||||
LLPointer<LLModel> mLOD[5];
|
||||
|
||||
std::string mLabel;
|
||||
|
||||
LLUUID mMeshID;
|
||||
S32 mLocalMeshID;
|
||||
|
||||
LLMatrix4 mTransform;
|
||||
std::map<std::string, LLImportMaterial> mMaterial;
|
||||
|
||||
LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials)
|
||||
: mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
|
||||
{
|
||||
mLocalMeshID = -1;
|
||||
}
|
||||
|
||||
LLModelInstance(LLSD& data);
|
||||
|
||||
LLSD asLLSD();
|
||||
};
|
||||
|
||||
class LLPhysicsDecomp : public LLThread
|
||||
{
|
||||
public:
|
||||
|
|
@ -483,6 +435,8 @@ public:
|
|||
// Inherited from LLCore::HttpHandler
|
||||
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
|
||||
|
||||
LLViewerFetchedTexture* FindViewerTexture(const LLImportMaterial& material);
|
||||
|
||||
private:
|
||||
LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;
|
||||
LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle;
|
||||
|
|
|
|||
|
|
@ -4179,6 +4179,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
|
|||
for (U32 j = 0; j < maxJoints; ++j)
|
||||
{
|
||||
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
|
||||
if (!joint)
|
||||
{
|
||||
joint = avatar->getJoint("mPelvis");
|
||||
}
|
||||
if (joint)
|
||||
{
|
||||
mat[j] = skin->mInvBindMatrix[j];
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
<string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string>
|
||||
<string name="mesh_status_missing_lod">Missing required level of detail.</string>
|
||||
<string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string>
|
||||
<string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string>
|
||||
<string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->
|
||||
<string name="decomposing">Analyzing...</string>
|
||||
<string name="simplifying">Simplifying...</string>
|
||||
|
|
@ -66,7 +67,7 @@
|
|||
follows="top|left"
|
||||
layout="topleft"
|
||||
height="19"
|
||||
max_length_bytes="64"
|
||||
max_length_bytes="63"
|
||||
name="description_form"
|
||||
prevalidate_callback="ascii"
|
||||
top_pad="5"
|
||||
|
|
@ -1046,19 +1047,19 @@
|
|||
bg_alpha_color="0 0 0 0"
|
||||
bg_opaque_color="0 0 0 0.3"
|
||||
follows="left|top"
|
||||
height="16"
|
||||
height="19"
|
||||
layout="topleft"
|
||||
left="18"
|
||||
name="physics info"
|
||||
top_pad="15"
|
||||
width="589">
|
||||
top_pad="12"
|
||||
width="319">
|
||||
<text
|
||||
follows="top|left"
|
||||
height="15"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
text_color="White"
|
||||
top_pad="0"
|
||||
top_pad="3"
|
||||
name="results_text"
|
||||
width="50">
|
||||
Results:
|
||||
|
|
@ -1096,6 +1097,33 @@
|
|||
Hulls: [HULLS]
|
||||
</text>
|
||||
</panel>
|
||||
<panel
|
||||
bg_alpha_color="0 0 0 0"
|
||||
bg_opaque_color="0 0 0 0.3"
|
||||
follows="left|top"
|
||||
height="19"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
top_delta="0"
|
||||
name="physics message"
|
||||
width="270">
|
||||
<icon
|
||||
follows="left|top"
|
||||
height="16"
|
||||
left="0"
|
||||
layout="topleft"
|
||||
name="physics_status_message_icon"
|
||||
top_pad="0"
|
||||
width="16" />
|
||||
<text
|
||||
follows="left|top"
|
||||
height="15"
|
||||
layout="topleft"
|
||||
left_pad="2"
|
||||
name="physics_status_message_text"
|
||||
width="252"
|
||||
top_delta="3"/>
|
||||
</panel>
|
||||
</panel>
|
||||
<!-- MODIFIERS PANEL -->
|
||||
<panel
|
||||
|
|
|
|||
Loading…
Reference in New Issue