diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index ef5b14b80..30fc121ee 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -297,6 +297,7 @@ endif (STANDALONE)
if(1 EQUAL 1)
add_definitions(-DOPENSIM_RULES=1)
+ add_definitions(-DMESH_ENABLED=1)
endif(1 EQUAL 1)
if(SERVER)
diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp
index 25fbc03fa..16600a227 100644
--- a/indra/llcharacter/lljoint.cpp
+++ b/indra/llcharacter/lljoint.cpp
@@ -56,6 +56,9 @@ LLJoint::LLJoint()
mUpdateXform = TRUE;
mJointNum = -1;
touch();
+#if MESH_ENABLED
+ mResetAfterRestoreOldXform = false;
+#endif //MESH_ENABLED
}
@@ -239,6 +242,43 @@ void LLJoint::setPosition( const LLVector3& pos )
}
}
+#if MESH_ENABLED
+//--------------------------------------------------------------------
+// setPosition()
+//--------------------------------------------------------------------
+void LLJoint::setDefaultFromCurrentXform( void )
+{
+ mDefaultXform = mXform;
+ touch(MATRIX_DIRTY | POSITION_DIRTY);
+
+}
+
+//--------------------------------------------------------------------
+// storeCurrentXform()
+//--------------------------------------------------------------------
+void LLJoint::storeCurrentXform( const LLVector3& pos )
+{
+ mOldXform = mXform;
+ mResetAfterRestoreOldXform = true;
+ setPosition( pos );
+}
+//--------------------------------------------------------------------
+// restoreOldXform()
+//--------------------------------------------------------------------
+void LLJoint::restoreOldXform( void )
+{
+ mResetAfterRestoreOldXform = false;
+ mXform = mOldXform;
+}
+//--------------------------------------------------------------------
+// restoreOldXform()
+//--------------------------------------------------------------------
+void LLJoint::restoreToDefaultXform( void )
+{
+ mXform = mDefaultXform;
+ setPosition( mXform.getPosition() );
+}
+#endif //MESH_ENABLED
//--------------------------------------------------------------------
// getWorldPosition()
diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h
index 37ae44998..852f04e05 100644
--- a/indra/llcharacter/lljoint.h
+++ b/indra/llcharacter/lljoint.h
@@ -86,10 +86,19 @@ protected:
// explicit transformation members
LLXformMatrix mXform;
+#if MESH_ENABLED
+ LLXformMatrix mOldXform;
+ LLXformMatrix mDefaultXform;
+ LLUUID mId;
+#endif //MESH_ENABLED
public:
U32 mDirtyFlags;
BOOL mUpdateXform;
+
+#if MESH_ENABLED
+ BOOL mResetAfterRestoreOldXform;
+#endif //MESH_ENABLED
// describes the skin binding pose
LLVector3 mSkinOffset;
@@ -179,6 +188,24 @@ public:
S32 getJointNum() const { return mJointNum; }
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
+#if MESH_ENABLED
+
+ void restoreOldXform( void );
+ void restoreToDefaultXform( void );
+ void setDefaultFromCurrentXform( void );
+ void storeCurrentXform( const LLVector3& pos );
+
+ //Accessor for the joint id
+ LLUUID getId( void ) { return mId; }
+ //Setter for the joints id
+ void setId( const LLUUID& id ) { mId = id;}
+
+ //If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it
+ const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
+ //Setter for joint reset flag
+ void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
+#endif //MESH_ENABLED
+
//
std::string exportString(U32 tabs = 0);
//
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index d88013fc4..c2b3779db 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -105,6 +105,9 @@ LLAssetDictionary::LLAssetDictionary()
//addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("FOLDER_LINK", "current", "current outfit", false, false, false));
//addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", false, false, false));
//addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false));
+#if MESH_ENABLED
+ addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
+#endif //MESH_ENABLED
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
};
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 554fc0c02..4590fc831 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -138,13 +138,19 @@ public:
// Inventory folder link
AT_LINK_FOLDER = 25,
-
+
//AT_CURRENT_OUTFIT = 46,
//AT_OUTFIT = 47,
//AT_MY_OUTFITS = 48,
+#if MESH_ENABLED
+ AT_MESH = 49,
+ // Mesh data in our proprietary SLM format
+
+ AT_COUNT = 50,
+#endif //MESH_ENABLED
// +*********************************************+
// | TO ADD AN ELEMENT TO THIS ENUM: |
// +*********************************************+
@@ -155,8 +161,9 @@ public:
// +*********************************************+
//AT_COUNT = 49,
-
+#if !MESH_ENABLED
AT_COUNT = 26,
+#endif //!MESH_ENABLED
AT_NONE = -1
};
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 3a7f30511..7f3dac2cf 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -72,7 +72,12 @@ public:
FTM_UPDATE_GRASS,
FTM_UPDATE_TREE,
FTM_UPDATE_AVATAR,
-
+#if MESH_ENABLED
+ FTM_UPDATE_RIGGED_VOLUME,
+ FTM_SKIN_RIGGED,
+ FTM_RIGGED_OCTREE,
+#endif //MESH_ENABLED
+
// common render components
FTM_SHADOW_GEOMETRY,
FTM_SHADOW_RENDER,
@@ -131,6 +136,12 @@ public:
FTM_STATESORT,
FTM_STATESORT_DRAWABLE,
FTM_STATESORT_POSTSORT,
+#if MESH_ENABLED
+ FTM_MESH_UPDATE,
+ FTM_MESH_LOCK1,
+ FTM_MESH_LOCK2,
+ FTM_LOAD_MESH_LOD,
+#endif //MESH_ENABLED
FTM_REBUILD_VBO,
FTM_REBUILD_VOLUME_VB,
FTM_REBUILD_BRIDGE_VB,
diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp
index 5be0414f9..c88909eb2 100644
--- a/indra/llcommon/llqueuedthread.cpp
+++ b/indra/llcommon/llqueuedthread.cpp
@@ -41,7 +41,8 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
LLThread(name),
mThreaded(threaded),
mIdleThread(TRUE),
- mNextHandle(0)
+ mNextHandle(0),
+ mStarted(FALSE)
{
if (mThreaded)
{
@@ -52,6 +53,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
// MAIN THREAD
LLQueuedThread::~LLQueuedThread()
{
+ if (!mThreaded)
+ {
+ endThread();
+ }
shutdown();
// ~LLThread() will be called here
}
@@ -90,6 +95,7 @@ void LLQueuedThread::shutdown()
if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
{
++active_count;
+ req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest
}
req->deleteRequest();
}
@@ -105,6 +111,14 @@ void LLQueuedThread::shutdown()
// virtual
S32 LLQueuedThread::update(U32 max_time_ms)
{
+ if (!mStarted)
+ {
+ if (!mThreaded)
+ {
+ startThread();
+ mStarted = TRUE;
+ }
+ }
return updateQueue(max_time_ms);
}
@@ -118,8 +132,11 @@ S32 LLQueuedThread::updateQueue(U32 max_time_ms)
if (mThreaded)
{
pending = getPending();
+ if(pending > 0)
+ {
unpause();
}
+ }
else
{
while (pending > 0)
@@ -349,9 +366,9 @@ bool LLQueuedThread::completeRequest(handle_t handle)
#if _DEBUG
// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
#endif
- //re insert to the queue to schedule for a delete later
- req->setStatus(STATUS_DELETE);
- mRequestQueue.insert(req);
+ mRequestHash.erase(handle);
+ req->deleteRequest();
+// check();
res = true;
}
unlockData();
@@ -395,19 +412,11 @@ S32 LLQueuedThread::processNextRequest()
}
req = *mRequestQueue.begin();
mRequestQueue.erase(mRequestQueue.begin());
-
- if(req->getStatus() == STATUS_DELETE)
- {
- mRequestHash.erase(req);
- req->deleteRequest();
- continue;
- }
-
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
{
req->setStatus(STATUS_ABORTED);
req->finishRequest(false);
- if ((req->getFlags() & FLAG_AUTO_COMPLETE))
+ if (req->getFlags() & FLAG_AUTO_COMPLETE)
{
mRequestHash.erase(req);
req->deleteRequest();
@@ -418,9 +427,11 @@ S32 LLQueuedThread::processNextRequest()
llassert_always(req->getStatus() == STATUS_QUEUED);
break;
}
+ U32 start_priority = 0 ;
if (req)
{
req->setStatus(STATUS_INPROGRESS);
+ start_priority = req->getPriority();
}
unlockData();
@@ -436,13 +447,12 @@ S32 LLQueuedThread::processNextRequest()
{
lockData();
req->setStatus(STATUS_COMPLETE);
-
req->finishRequest(true);
-
- if ((req->getFlags() & FLAG_AUTO_COMPLETE))
+ if (req->getFlags() & FLAG_AUTO_COMPLETE)
{
mRequestHash.erase(req);
req->deleteRequest();
+// check();
}
unlockData();
}
@@ -451,9 +461,8 @@ S32 LLQueuedThread::processNextRequest()
lockData();
req->setStatus(STATUS_QUEUED);
mRequestQueue.insert(req);
- U32 priority = req->getPriority();
unlockData();
- if (priority < PRIORITY_NORMAL)
+ if (mThreaded && start_priority < PRIORITY_NORMAL)
{
ms_sleep(1); // sleep the thread a little
}
@@ -481,6 +490,7 @@ void LLQueuedThread::run()
// call checPause() immediately so we don't try to do anything before the class is fully constructed
checkPause();
startThread();
+ mStarted = TRUE;
while (1)
{
diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index e0e0f1bfe..f0c36896c 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -184,7 +184,7 @@ public:
void waitOnPending();
void printQueueStats();
- S32 getPending();
+ virtual S32 getPending();
bool getThreaded() { return mThreaded ? true : false; }
// Request accessors
@@ -202,6 +202,7 @@ public:
protected:
BOOL mThreaded; // if false, run on main thread and do updates during update()
+ BOOL mStarted; // required when mThreaded is false to call startThread() from update()
LLAtomic32 mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
typedef std::set request_queue_t;
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index b7f28d365..cc0307a7a 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -39,6 +39,13 @@
#include
#include "apr_base64.h"
+#if MESH_ENABLED
+#ifdef LL_STANDALONE
+# include
+#else
+# include "zlib/zlib.h" // for davep's dirty little zip functions
+#endif
+#endif //MESH_ENABLED
#if !LL_WINDOWS
#include // htonl & ntohl
@@ -1990,3 +1997,181 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
return s;
}
+#if MESH_ENABLED
+
+//dirty little zippers -- yell at davep if these are horrid
+
+//return a string containing gzipped bytes of binary serialized LLSD
+// VERY inefficient -- creates several copies of LLSD block in memory
+std::string zip_llsd(LLSD& data)
+{
+ std::stringstream llsd_strm;
+
+ LLSDSerialize::toBinary(data, llsd_strm);
+
+ const U32 CHUNK = 65536;
+
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+
+ S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION);
+ if (ret != Z_OK)
+ {
+ llwarns << "Failed to compress LLSD block." << llendl;
+ return std::string();
+ }
+
+ std::string source = llsd_strm.str();
+
+ U8 out[CHUNK];
+
+ strm.avail_in = source.size();
+ strm.next_in = (U8*) source.data();
+ U8* output = NULL;
+
+ U32 cur_size = 0;
+
+ U32 have = 0;
+
+ do
+ {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+
+ ret = deflate(&strm, Z_FINISH);
+ if (ret == Z_OK || ret == Z_STREAM_END)
+ { //copy result into output
+ if (strm.avail_out >= CHUNK)
+ {
+ free(output);
+ llwarns << "Failed to compress LLSD block." << llendl;
+ return std::string();
+ }
+
+ have = CHUNK-strm.avail_out;
+ output = (U8*) realloc(output, cur_size+have);
+ memcpy(output+cur_size, out, have);
+ cur_size += have;
+ }
+ else
+ {
+ free(output);
+ llwarns << "Failed to compress LLSD block." << llendl;
+ return std::string();
+ }
+ }
+ while (ret == Z_OK);
+
+ std::string::size_type size = cur_size;
+
+ std::string result((char*) output, size);
+ deflateEnd(&strm);
+ free(output);
+
+#if 0 //verify results work with unzip_llsd
+ std::istringstream test(result);
+ LLSD test_sd;
+ if (!unzip_llsd(test_sd, test, result.size()))
+ {
+ llerrs << "Invalid compression result!" << llendl;
+ }
+#endif
+
+ return result;
+}
+
+//decompress a block of LLSD from provided istream
+// not very efficient -- creats a copy of decompressed LLSD block in memory
+// and deserializes from that copy using LLSDSerialize
+bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
+{
+ U8* result = NULL;
+ U32 cur_size = 0;
+ z_stream strm;
+
+ const U32 CHUNK = 65536;
+
+ U8 *in = new U8[size];
+ is.read((char*) in, size);
+
+ U8 out[CHUNK];
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = size;
+ strm.next_in = in;
+
+ S32 ret = inflateInit(&strm);
+
+ do
+ {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ if (ret == Z_STREAM_ERROR)
+ {
+ inflateEnd(&strm);
+ free(result);
+ delete [] in;
+ return false;
+ }
+
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ inflateEnd(&strm);
+ free(result);
+ delete [] in;
+ return false;
+ break;
+ }
+
+ U32 have = CHUNK-strm.avail_out;
+
+ result = (U8*) realloc(result, cur_size + have);
+ memcpy(result+cur_size, out, have);
+ cur_size += have;
+
+ } while (ret == Z_OK);
+
+ inflateEnd(&strm);
+ delete [] in;
+
+ if (ret != Z_STREAM_END)
+ {
+ free(result);
+ return false;
+ }
+
+ //result now points to the decompressed LLSD block
+ {
+ std::string res_str((char*) result, cur_size);
+
+ std::string deprecated_header(" LLSD/Binary ?>");
+
+ if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
+ {
+ res_str = res_str.substr(deprecated_header.size()+1, cur_size);
+ }
+ cur_size = res_str.size();
+
+ std::istringstream istr(res_str);
+
+ if (!LLSDSerialize::fromBinary(data, istr, cur_size))
+ {
+ llwarns << "Failed to unzip LLSD block" << llendl;
+ free(result);
+ return false;
+ }
+ }
+
+ free(result);
+ return true;
+}
+#endif //MESH_ENABLED
\ No newline at end of file
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 7dd2603eb..aed844fee 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -787,4 +787,9 @@ public:
}
};
+#if MESH_ENABLED
+//dirty little zip functions -- yell at davep
+LL_COMMON_API std::string zip_llsd(LLSD& data);
+LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
+#endif //MESH_ENABLED
#endif // LL_LLSDSERIALIZE_H
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index a3636a868..d7a0d77a3 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2138,6 +2138,13 @@ LLVolume::~LLVolume()
mPathp = NULL;
mProfilep = NULL;
mVolumeFaces.clear();
+
+#if MESH_ENABLED
+ ll_aligned_free_16(mHullPoints);
+ mHullPoints = NULL;
+ ll_aligned_free_16(mHullIndices);
+ mHullIndices = NULL;
+#endif //MESH_ENABLED
}
BOOL LLVolume::generate()
@@ -2378,11 +2385,16 @@ bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)co
bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const
{
bool retval = false;
- if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord)
+
+ const F32 epsilon = 0.00001f;
+
+ if (rhs.mData[POSITION].equals3(mData[POSITION], epsilon) &&
+ fabs(rhs.mTexCoord[0]-mTexCoord[0]) < epsilon &&
+ fabs(rhs.mTexCoord[1]-mTexCoord[1]) < epsilon)
{
if (angle_cutoff > 1.f)
{
- retval = (mData[NORMAL].equals3(rhs.mData[NORMAL]));
+ retval = (mData[NORMAL].equals3(rhs.mData[NORMAL], epsilon));
}
else
{
@@ -2499,9 +2511,9 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
}
{
- U16* n = (U16*) &(norm[0]);
- if(n)
+ if (!norm.empty())
{
+ U16* n = (U16*) &(norm[0]);
for (U32 j = 0; j < num_verts; ++j)
{
norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]);
@@ -2512,12 +2524,16 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
n += 3;
}
}
+ else
+ {
+ memset(norm_out, 0, sizeof(LLVector4a)*num_verts);
+ }
}
{
- U16* t = (U16*) &(tc[0]);
- if(t)
+ if (!tc.empty())
{
+ U16* t = (U16*) &(tc[0]);
for (U32 j = 0; j < num_verts; j+=2)
{
if (j < num_verts-1)
@@ -2538,6 +2554,10 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
tc_out++;
}
}
+ else
+ {
+ memset(tc_out, 0, sizeof(LLVector2)*num_verts);
+ }
}
if (mdl[i].has("Weights"))
@@ -2635,7 +2655,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
if (do_reverse_triangles)
{
- for (U32 j = 0; j < face.mNumIndices; j += 3)
+ for (U32 j = 0; j < (U32)face.mNumIndices; j += 3)
{
// swap the 2nd and 3rd index
S32 swap = face.mIndices[j+1];
@@ -2662,6 +2682,25 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
min.setMin(min, face.mPositions[i]);
max.setMax(max, face.mPositions[i]);
}
+
+ if (face.mTexCoords)
+ {
+ LLVector2& min_tc = face.mTexCoordExtents[0];
+ LLVector2& max_tc = face.mTexCoordExtents[1];
+
+ min_tc = face.mTexCoords[0];
+ max_tc = face.mTexCoords[0];
+
+ for (U32 j = 1; j < (U32)face.mNumVertices; ++j)
+ {
+ update_min_max(min_tc, max_tc, face.mTexCoords[j]);
+ }
+ }
+ else
+ {
+ face.mTexCoordExtents[0].set(0,0);
+ face.mTexCoordExtents[1].set(1,1);
+ }
}
}
}
@@ -2741,11 +2780,13 @@ void LLVolume::makeTetrahedron()
n[2] = cv[2].getNormal();
n += 3;
- tc[0] = cv[0].mTexCoord;
- tc[1] = cv[1].mTexCoord;
- tc[2] = cv[2].mTexCoord;
- tc += 3;
-
+ if(tc)
+ {
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+ }
//side 2
cv[0].setPosition(p[3]);
@@ -2764,11 +2805,14 @@ void LLVolume::makeTetrahedron()
n[2] = cv[2].getNormal();
n += 3;
- tc[0] = cv[0].mTexCoord;
- tc[1] = cv[1].mTexCoord;
- tc[2] = cv[2].mTexCoord;
- tc += 3;
-
+ if(tc)
+ {
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+ }
+
//side 3
cv[0].setPosition(p[3]);
cv[1].setPosition(p[1]);
@@ -2786,10 +2830,13 @@ void LLVolume::makeTetrahedron()
n[2] = cv[2].getNormal();
n += 3;
- tc[0] = cv[0].mTexCoord;
- tc[1] = cv[1].mTexCoord;
- tc[2] = cv[2].mTexCoord;
- tc += 3;
+ if(tc)
+ {
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+ }
//side 4
cv[0].setPosition(p[2]);
@@ -2808,10 +2855,13 @@ void LLVolume::makeTetrahedron()
n[2] = cv[2].getNormal();
n += 3;
- tc[0] = cv[0].mTexCoord;
- tc[1] = cv[1].mTexCoord;
- tc[2] = cv[2].mTexCoord;
- tc += 3;
+ if(tc)
+ {
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+ }
//set index buffer
for (U16 i = 0; i < 12; i++)
@@ -2833,7 +2883,7 @@ void LLVolume::copyVolumeFaces(const LLVolume* volume)
void LLVolume::cacheOptimize()
{
- for (S32 i = 0; i < mVolumeFaces.size(); ++i)
+ for (S32 i = 0; i < (S32)mVolumeFaces.size(); ++i)
{
mVolumeFaces[i].cacheOptimize();
}
@@ -5523,6 +5573,9 @@ LLVolumeFace::LLVolumeFace() :
mBinormals(NULL),
mTexCoords(NULL),
mIndices(NULL),
+#if MESH_ENABLED
+ mWeights(NULL),
+#endif //MESH_ENABLED
mOctree(NULL)
{
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
@@ -5590,7 +5643,16 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
- LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
+
+ if(src.mTexCoords)
+ {
+ LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
+ }
+ else
+ {
+ ll_aligned_free_16(mTexCoords) ;
+ mTexCoords = NULL ;
+ }
if (src.mBinormals)
@@ -5715,8 +5777,23 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv)
{
cv.setPosition(mPositions[index]);
- cv.setNormal(mNormals[index]);
- cv.mTexCoord = mTexCoords[index];
+ if (mNormals)
+ {
+ cv.setNormal(mNormals[index]);
+ }
+ else
+ {
+ cv.getNormal().clear();
+ }
+
+ if (mTexCoords)
+ {
+ cv.mTexCoord = mTexCoords[index];
+ }
+ else
+ {
+ cv.mTexCoord.clear();
+ }
}
bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const
@@ -5746,7 +5823,10 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
LLVolumeFace new_face;
//map of points to vector of vertices at that point
- VertexMapData::PointMap point_map;
+ std::map > point_map;
+
+ LLVector4a range;
+ range.setSub(mExtents[1],mExtents[0]);
//remove redundant vertices
for (U32 i = 0; i < (U32)mNumIndices; ++i)
@@ -5757,7 +5837,19 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
getVertexData(index, cv);
BOOL found = FALSE;
- VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr()));
+
+ LLVector4a pos;
+ pos.setSub(mPositions[index], mExtents[0]);
+ pos.div(range);
+
+ U64 pos64 = 0;
+
+ pos64 = (U16) (pos[0]*65535);
+ pos64 = pos64 | (((U64) (pos[1]*65535)) << 16);
+ pos64 = pos64 | (((U64) (pos[2]*65535)) << 32);
+
+ std::map >::iterator point_iter = point_map.find(pos64);
+
if (point_iter != point_map.end())
{ //duplicate point might exist
for (U32 j = 0; j < point_iter->second.size(); ++j)
@@ -5789,11 +5881,26 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
}
else
{
- point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d);
+ point_map[pos64].push_back(d);
}
}
}
+ llassert(new_face.mNumIndices == mNumIndices);
+ llassert(new_face.mNumVertices <= mNumVertices);
+
+ if (angle_cutoff > 1.f && !mNormals)
+ {
+ ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!mTexCoords)
+ {
+ ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+
swapData(new_face);
}
@@ -7026,6 +7133,7 @@ void LLVolumeFace::allocateBinormals(S32 num_verts)
#if MESH_ENABLED
void LLVolumeFace::allocateWeights(S32 num_verts)
{
+
ll_aligned_free_16(mWeights);
mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
}
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index a4f9f34b7..c85e43e1f 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -958,7 +958,12 @@ class LLVolume : public LLRefCount
{
friend class LLVolumeLODGroup;
+#if MESH_ENABLED
+protected:
+#endif //MESH_ENABLED
+#if !MESH_ENABLED
private:
+#endif //!MESH_ENABLED
LLVolume(const LLVolume&); // Don't implement
~LLVolume(); // use unref
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index f140d7910..c6c68e3a6 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -154,7 +154,7 @@ void LLVolumeMgr::unrefVolume(LLVolume *volumep)
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
if( iter == mVolumeLODGroups.end() )
{
- llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
+ llwarns << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
if (mDataMutex)
{
mDataMutex->unlock();
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 88a9ef11d..2f385d944 100644
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -17,7 +17,7 @@ include_directories(
set(llprimitive_SOURCE_FILES
llmaterialtable.cpp
- #llmodel.cpp
+ llmodel.cpp
llprimitive.cpp
llprimtexturelist.cpp
lltextureanim.cpp
@@ -33,7 +33,7 @@ set(llprimitive_HEADER_FILES
legacy_object_types.h
llmaterialtable.h
- #llmodel.h
+ llmodel.h
llprimitive.h
llprimtexturelist.h
lltextureanim.h
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 0463d5364..a7563f17c 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -26,15 +26,20 @@
#include "linden_common.h"
+#if MESH_ENABLED
#include "llmodel.h"
+#if MESH_IMPORT
#include "llconvexdecomposition.h"
+#endif //MESH_IMPORT
#include "llsdserialize.h"
#include "llvector4a.h"
+#if MESH_IMPORT
#include "dae.h"
#include "dae/daeErrorHandler.h"
#include "dom/domConstants.h"
#include "dom/domMesh.h"
+#endif //MESH_IMPORT
#ifdef LL_STANDALONE
# include
@@ -67,87 +72,13 @@ LLModel::~LLModel()
{
if (mDecompID >= 0)
{
+#if MESH_IMPORT
LLConvexDecomposition::getInstance()->deleteDecomposition(mDecompID);
+#endif //MESH_IMPORT
}
}
-void load_face_from_dom_inputs(LLVolumeFace& face, const domInputLocalOffset_Array& inputs, U32 min_idx, U32 max_idx)
-{
- for (U32 j = 0; j < inputs.getCount(); ++j)
- {
- if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0)
- { //found vertex array
- const domURIFragmentType& uri = inputs[j]->getSource();
- daeElementRef elem = uri.getElement();
- domVertices* vertices = (domVertices*) elem.cast();
-
- domInputLocal_Array& v_inp = vertices->getInput_array();
- if (inputs[j]->getOffset() != 0)
- {
- llerrs << "Vertex array offset MUST be zero." << llendl;
- }
-
- for (U32 k = 0; k < v_inp.getCount(); ++k)
- {
- if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0)
- {
- const domURIFragmentType& uri = v_inp[k]->getSource();
-
- daeElementRef elem = uri.getElement();
- domSource* src = (domSource*) elem.cast();
-
- if (src->getTechnique_common()->getAccessor()->getStride() != 3)
- {
- llerrs << "Vertex array stride MUST be three." << llendl;
- }
-
- domListOfFloats& v = src->getFloat_array()->getValue();
-
- LLVector4a min;
- min.set(v[min_idx], v[min_idx+1], v[min_idx+2]);
- LLVector4a max = min;
-
- for (U32 j = min_idx; j <= max_idx; ++j)
- { //copy vertex array
- face.mPositions[j-min_idx].set(v[j*3+0], v[j*3+1], v[j*3+2]);
- update_min_max(min, max, face.mPositions[j-min_idx]);
- }
-
- face.mExtents[0] = min;
- face.mExtents[1] = max;
- }
- }
- }
-
- if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0)
- {
- //found normal array for this triangle list
- const domURIFragmentType& uri = inputs[j]->getSource();
- daeElementRef elem = uri.getElement();
- domSource* src = (domSource*) elem.cast();
- domListOfFloats& n = src->getFloat_array()->getValue();
-
- for (U32 j = min_idx; j <= max_idx; ++j)
- {
- LLVector4a* norm = (LLVector4a*) face.mNormals + (j-min_idx);
- norm->set(n[j*3+0], n[j*3+1], n[j*3+2]);
- norm->normalize3();
- }
- }
- else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0)
- { //found texCoords
- const domURIFragmentType& uri = inputs[j]->getSource();
- daeElementRef elem = uri.getElement();
- domSource* src = (domSource*) elem.cast();
- domListOfFloats& u = src->getFloat_array()->getValue();
-
- for (U32 j = min_idx; j <= max_idx; ++j)
- {
- face.mTexCoords[j-min_idx].setVec(u[j*2+0], u[j*2+1]);
- }
- }
- }
-}
+#if MESH_IMPORT
bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride,
domSource* &pos_source, domSource* &tc_source, domSource* &norm_source)
@@ -329,6 +260,19 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector& fa
{
face_list.push_back(face);
face_list.rbegin()->fillFromLegacyData(verts, indices);
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!norm_source)
+ {
+ ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!tc_source)
+ {
+ ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+
face = LLVolumeFace();
point_map.clear();
}
@@ -348,6 +292,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector& fa
face_list.push_back(face);
face_list.rbegin()->fillFromLegacyData(verts, indices);
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!norm_source)
+ {
+ ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!tc_source)
+ {
+ ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
}
return LLModel::NO_ERRORS ;
@@ -524,6 +480,19 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector& fac
{
face_list.push_back(face);
face_list.rbegin()->fillFromLegacyData(verts, indices);
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!norm_source)
+ {
+ ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!tc_source)
+ {
+ ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+
face = LLVolumeFace();
verts.clear();
indices.clear();
@@ -544,6 +513,19 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector& fac
materials.push_back(material);
face_list.push_back(face);
face_list.rbegin()->fillFromLegacyData(verts, indices);
+
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!norm_source)
+ {
+ ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!tc_source)
+ {
+ ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
}
return LLModel::NO_ERRORS ;
@@ -733,6 +715,19 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector& fac
materials.push_back(material);
face_list.push_back(face);
face_list.rbegin()->fillFromLegacyData(new_verts, indices);
+
+ LLVolumeFace& new_face = *face_list.rbegin();
+ if (!n)
+ {
+ ll_aligned_free_16(new_face.mNormals);
+ new_face.mNormals = NULL;
+ }
+
+ if (!t)
+ {
+ ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
}
return LLModel::NO_ERRORS ;
@@ -817,9 +812,9 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
if (getNumVolumeFaces() > 0)
{
- optimizeVolumeFaces();
normalizeVolumeFaces();
-
+ optimizeVolumeFaces();
+
if (getNumVolumeFaces() > 0)
{
return TRUE;
@@ -833,6 +828,7 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
return FALSE;
}
+#endif //MESH_IMPORT
void LLModel::offsetMesh( const LLVector3& pivotPoint )
{
@@ -844,7 +840,7 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint )
LLVolumeFace& face = *currentFaceIt;
LLVector4a *pos = (LLVector4a*) face.mPositions;
- for (U32 i=0; i::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); )
+ for (U32 i = 0; i < (U32)getNumVolumeFaces(); ++i)
{
- std::vector::iterator cur_iter = iter++;
- LLVolumeFace& face = *cur_iter;
-
- for (S32 i = 0; i < (S32) face.mNumIndices; i += 3)
- { //remove zero area triangles
- U16 i0 = face.mIndices[i+0];
- U16 i1 = face.mIndices[i+1];
- U16 i2 = face.mIndices[i+2];
-
- if (i0 == i1 ||
- i1 == i2 ||
- i0 == i2)
- { //duplicate index in triangle, remove triangle
- face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3);
- i -= 3;
- }
- else
- {
- LLVolumeFace::VertexData& v0 = face.mVertices[i0];
- LLVolumeFace::VertexData& v1 = face.mVertices[i1];
- LLVolumeFace::VertexData& v2 = face.mVertices[i2];
-
- if (v0.mPosition == v1.mPosition ||
- v1.mPosition == v2.mPosition ||
- v2.mPosition == v0.mPosition)
- { //zero area triangle, delete
- face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3);
- i-=3;
- }
- }
- }
-
- //remove unreference vertices
- std::vector ref;
- ref.resize(face.mNumVertices);
-
- for (U32 i = 0; i < ref.size(); ++i)
- {
- ref[i] = false;
- }
-
- for (U32 i = 0; i < face.mNumIndices; ++i)
- {
- ref[face.mIndices[i]] = true;
- }
-
- U32 unref_count = 0;
- for (U32 i = 0; i < ref.size(); ++i)
- {
- if (!ref[i])
- {
- //vertex is unreferenced
- face.mVertices.erase(face.mVertices.begin()+(i-unref_count));
- U16 idx = (U16) (i-unref_count);
-
- for (U32 j = 0; j < face.mNumIndices; ++j)
- { //decrement every index array value greater than idx
- if (face.mIndices[j] > idx)
- {
- --face.mIndices[j];
- }
- }
- ++unref_count;
- }
- }
-
- if (face.mVertices.empty() || face.mIndices.empty())
- { //face is empty, remove it
- iter = mVolumeFaces.erase(cur_iter);
- }
+ mVolumeFaces[i].optimize();
}
-#endif
}
// Shrink the model to fit
@@ -962,6 +887,25 @@ void LLModel::normalizeVolumeFaces()
update_min_max(min, max, face.mExtents[0]);
update_min_max(min, max, face.mExtents[1]);
+
+ if (face.mTexCoords)
+ {
+ LLVector2& min_tc = face.mTexCoordExtents[0];
+ LLVector2& max_tc = face.mTexCoordExtents[1];
+
+ min_tc = face.mTexCoords[0];
+ max_tc = face.mTexCoords[0];
+
+ for (U32 j = 1; j < (U32)face.mNumVertices; ++j)
+ {
+ update_min_max(min_tc, max_tc, face.mTexCoords[j]);
+ }
+ }
+ else
+ {
+ face.mTexCoordExtents[0].set(0,0);
+ face.mTexCoordExtents[1].set(1,1);
+ }
}
// Now that we have the extents of the model
@@ -1025,12 +969,15 @@ void LLModel::normalizeVolumeFaces()
LLVector4a* pos = (LLVector4a*) face.mPositions;
LLVector4a* norm = (LLVector4a*) face.mNormals;
- for (U32 j = 0; j < face.mNumVertices; ++j)
+ for (U32 j = 0; j < (U32)face.mNumVertices; ++j)
{
pos[j].add(trans);
pos[j].mul(scale);
- norm[j].mul(inv_scale);
- norm[j].normalize3();
+ if (norm && !norm[j].equals3(LLVector4a::getZero()))
+ {
+ norm[j].mul(inv_scale);
+ norm[j].normalize3();
+ }
}
}
@@ -1073,8 +1020,26 @@ void LLModel::setVolumeFaceData(
face.resizeIndices(num_indices);
LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32));
- LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
- LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
+ if (norm.get())
+ {
+ LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32));
+ }
+ else
+ {
+ ll_aligned_free_16(face.mNormals);
+ face.mNormals = NULL;
+ }
+
+ if (tc.get())
+ {
+ LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
+ }
+ else
+ {
+ ll_aligned_free_16(face.mTexCoords);
+ face.mTexCoords = NULL;
+ }
+
U32 size = (num_indices*2+0xF)&~0xF;
LLVector4a::memcpyNonAliased16((F32*) face.mIndices, (F32*) ind.get(), size);
}
@@ -1160,7 +1125,7 @@ void LLModel::generateNormals(F32 angle_cutoff)
faceted.resizeVertices(vol_face.mNumIndices);
faceted.resizeIndices(vol_face.mNumIndices);
//bake out triangles into temporary face, clearing texture coordinates
- for (U32 i = 0; i < vol_face.mNumIndices; ++i)
+ for (U32 i = 0; i < (U32)vol_face.mNumIndices; ++i)
{
U32 idx = vol_face.mIndices[i];
@@ -1170,7 +1135,7 @@ void LLModel::generateNormals(F32 angle_cutoff)
}
//generate normals for temporary face
- for (U32 i = 0; i < faceted.mNumIndices; i += 3)
+ for (U32 i = 0; i < (U32)faceted.mNumIndices; i += 3)
{ //for each triangle
U16 i0 = faceted.mIndices[i+0];
U16 i1 = faceted.mIndices[i+1];
@@ -1199,12 +1164,12 @@ void LLModel::generateNormals(F32 angle_cutoff)
//generate normals for welded face based on new topology (step 3)
- for (U32 i = 0; i < faceted.mNumVertices; i++)
+ for (U32 i = 0; i < (U32)faceted.mNumVertices; i++)
{
faceted.mNormals[i].clear();
}
- for (U32 i = 0; i < faceted.mNumIndices; i += 3)
+ for (U32 i = 0; i < (U32)faceted.mNumIndices; i += 3)
{ //for each triangle
U16 i0 = faceted.mIndices[i+0];
U16 i1 = faceted.mIndices[i+1];
@@ -1233,7 +1198,7 @@ void LLModel::generateNormals(F32 angle_cutoff)
//normalize normals and build point map
LLVolumeFace::VertexMapData::PointMap point_map;
- for (U32 i = 0; i < faceted.mNumVertices; ++i)
+ for (U32 i = 0; i < (U32)faceted.mNumVertices; ++i)
{
faceted.mNormals[i].normalize3();
@@ -1251,18 +1216,31 @@ void LLModel::generateNormals(F32 angle_cutoff)
new_face.resizeIndices(vol_face.mNumIndices);
new_face.resizeVertices(vol_face.mNumIndices);
- for (U32 i = 0; i < vol_face.mNumIndices; ++i)
+ for (U32 i = 0; i < (U32)vol_face.mNumIndices; ++i)
{
U32 idx = vol_face.mIndices[i];
LLVolumeFace::VertexData v;
new_face.mPositions[i] = vol_face.mPositions[idx];
new_face.mNormals[i].clear();
- new_face.mTexCoords[i] = vol_face.mTexCoords[idx];
new_face.mIndices[i] = i;
}
+ if (vol_face.mTexCoords)
+ {
+ for (U32 i = 0; i < (U32)vol_face.mNumIndices; i++)
+ {
+ U32 idx = vol_face.mIndices[i];
+ new_face.mTexCoords[i] = vol_face.mTexCoords[idx];
+ }
+ }
+ else
+ {
+ ll_aligned_free_16(new_face.mTexCoords);
+ new_face.mTexCoords = NULL;
+ }
+
//generate normals for new face
- for (U32 i = 0; i < new_face.mNumIndices; i += 3)
+ for (U32 i = 0; i < (U32)new_face.mNumIndices; i += 3)
{ //for each triangle
U16 i0 = new_face.mIndices[i+0];
U16 i1 = new_face.mIndices[i+1];
@@ -1287,7 +1265,7 @@ void LLModel::generateNormals(F32 angle_cutoff)
}
//swap out normals in new_face with best match from point map (step 5)
- for (U32 i = 0; i < new_face.mNumVertices; ++i)
+ for (U32 i = 0; i < (U32)new_face.mNumVertices; ++i)
{
//LLVolumeFace::VertexData v = new_face.mVertices[i];
@@ -1320,6 +1298,8 @@ void LLModel::generateNormals(F32 angle_cutoff)
}
}
+#if MESH_IMPORT
+
//static
std::string LLModel::getElementLabel(daeElement *element)
{ // try to get a decent label for this element
@@ -1375,6 +1355,7 @@ LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh)
ret->mLabel = getElementLabel(mesh);
return ret;
}
+#endif MESH_IMPORT
std::string LLModel::getName() const
{
@@ -1395,7 +1376,8 @@ LLSD LLModel::writeModel(
const LLModel::Decomposition& decomp,
BOOL upload_skin,
BOOL upload_joints,
- BOOL nowrite)
+ BOOL nowrite,
+ BOOL as_slm)
{
LLSD mdl;
@@ -1419,12 +1401,20 @@ LLSD LLModel::writeModel(
!decomp.mHull.empty())
{
mdl["physics_convex"] = decomp.asLLSD();
- if (!decomp.mHull.empty())
- { //convex decomposition exists, physics mesh will not be used
+ if (!decomp.mHull.empty() && !as_slm)
+ { //convex decomposition exists, physics mesh will not be used (unless this is an slm file)
model[LLModel::LOD_PHYSICS] = NULL;
}
}
+ if (as_slm)
+ { //save material list names
+ for (U32 i = 0; i < high->mMaterialList.size(); ++i)
+ {
+ mdl["material_list"][i] = high->mMaterialList[i];
+ }
+ }
+
for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx)
{
if (model[idx] && model[idx]->getNumVolumeFaces() > 0)
@@ -1436,7 +1426,7 @@ LLSD LLModel::writeModel(
for (S32 i = 0; i < model[idx]->getNumVolumeFaces(); ++i)
{ //for each face
const LLVolumeFace& face = model[idx]->getVolumeFace(i);
- for (U32 j = 0; j < face.mNumVertices; ++j)
+ for (U32 j = 0; j < (U32)face.mNumVertices; ++j)
{
update_min_max(min_pos, max_pos, face.mPositions[j].getF32ptr());
}
@@ -1462,24 +1452,30 @@ LLSD LLModel::writeModel(
U32 tc_idx = 0;
LLVector2* ftc = (LLVector2*) face.mTexCoords;
- LLVector2 min_tc = ftc[0];
- LLVector2 max_tc = min_tc;
-
- //get texture coordinate domain
- for (U32 j = 0; j < face.mNumVertices; ++j)
+ LLVector2 min_tc;
+ LLVector2 max_tc;
+
+ if (ftc)
{
- update_min_max(min_tc, max_tc, ftc[j]);
+ min_tc = ftc[0];
+ max_tc = min_tc;
+
+ //get texture coordinate domain
+ for (U32 j = 0; j < (U32)face.mNumVertices; ++j)
+ {
+ update_min_max(min_tc, max_tc, ftc[j]);
+ }
}
+
LLVector2 tc_range = max_tc - min_tc;
- for (U32 j = 0; j < face.mNumVertices; ++j)
+ for (U32 j = 0; j < (U32)face.mNumVertices; ++j)
{ //for each vert
F32* pos = face.mPositions[j].getF32ptr();
- F32* norm = face.mNormals[j].getF32ptr();
-
- //position + normal
+
+ //position
for (U32 k = 0; k < 3; ++k)
{ //for each component
//convert to 16-bit normalized across domain
@@ -1489,33 +1485,44 @@ LLSD LLModel::writeModel(
//write to binary buffer
verts[vert_idx++] = buff[0];
verts[vert_idx++] = buff[1];
-
- //convert to 16-bit normalized
- val = (U16) ((norm[k]+1.f)*0.5f*65535);
-
- //write to binary buffer
- normals[norm_idx++] = buff[0];
- normals[norm_idx++] = buff[1];
}
+ if (face.mNormals)
+ { //normals
+ F32* norm = face.mNormals[j].getF32ptr();
+
+ for (U32 k = 0; k < 3; ++k)
+ { //for each component
+ //convert to 16-bit normalized
+ U16 val = (U16) ((norm[k]+1.f)*0.5f*65535);
+ U8* buff = (U8*) &val;
+
+ //write to binary buffer
+ normals[norm_idx++] = buff[0];
+ normals[norm_idx++] = buff[1];
+ }
+ }
+
F32* src_tc = (F32*) face.mTexCoords[j].mV;
//texcoord
- for (U32 k = 0; k < 2; ++k)
- { //for each component
- //convert to 16-bit normalized
- U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535);
+ if (face.mTexCoords)
+ {
+ for (U32 k = 0; k < 2; ++k)
+ { //for each component
+ //convert to 16-bit normalized
+ U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535);
- U8* buff = (U8*) &val;
- //write to binary buffer
- tc[tc_idx++] = buff[0];
- tc[tc_idx++] = buff[1];
+ U8* buff = (U8*) &val;
+ //write to binary buffer
+ tc[tc_idx++] = buff[0];
+ tc[tc_idx++] = buff[1];
+ }
}
-
}
U32 idx_idx = 0;
- for (U32 j = 0; j < face.mNumIndices; ++j)
+ for (U32 j = 0; j < (U32)face.mNumIndices; ++j)
{
U8* buff = (U8*) &(face.mIndices[j]);
indices[idx_idx++] = buff[0];
@@ -1525,12 +1532,19 @@ LLSD LLModel::writeModel(
//write out face data
mdl[model_names[idx]][i]["PositionDomain"]["Min"] = min_pos.getValue();
mdl[model_names[idx]][i]["PositionDomain"]["Max"] = max_pos.getValue();
- mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue();
- mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue();
-
mdl[model_names[idx]][i]["Position"] = verts;
- mdl[model_names[idx]][i]["Normal"] = normals;
- mdl[model_names[idx]][i]["TexCoord0"] = tc;
+
+ if (face.mNormals)
+ {
+ mdl[model_names[idx]][i]["Normal"] = normals;
+ }
+
+ if (face.mTexCoords)
+ {
+ mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue();
+ mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue();
+ mdl[model_names[idx]][i]["TexCoord0"] = tc;
+ }
mdl[model_names[idx]][i]["TriangleList"] = indices;
if (skinning)
@@ -1544,7 +1558,7 @@ LLSD LLModel::writeModel(
std::stringstream ostr;
- for (U32 j = 0; j < face.mNumVertices; ++j)
+ for (U32 j = 0; j < (U32)face.mNumVertices; ++j)
{
LLVector3 pos(face.mPositions[j].getF32ptr());
@@ -1588,10 +1602,10 @@ LLSD LLModel::writeModel(
}
}
- return writeModelToStream(ostr, mdl, nowrite);
+ return writeModelToStream(ostr, mdl, nowrite, as_slm);
}
-LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
+LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BOOL as_slm)
{
U32 bytes = 0;
@@ -1599,6 +1613,11 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
LLSD header;
+ if (as_slm && mdl.has("material_list"))
+ { //save material binding names to header
+ header["material_list"] = mdl["material_list"];
+ }
+
std::string skin;
if (mdl.has("skin"))
@@ -1689,13 +1708,13 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
}
else
{ //no exact match found, get closest point
- const F32 epsilon = 2.f/65536;
+ const F32 epsilon = 1e-5f;
weight_map::iterator iter_up = mSkinWeights.lower_bound(pos);
weight_map::iterator iter_down = ++iter_up;
weight_map::iterator best = iter_up;
- F32 min_dist = (iter->first - pos).magVecSquared();
+ F32 min_dist = (iter->first - pos).magVec();
bool done = false;
while (!done)
@@ -1706,7 +1725,7 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
if (iter_up != mSkinWeights.end() && ++iter_up != mSkinWeights.end())
{
done = false;
- F32 dist = (iter_up->first - pos).magVecSquared();
+ F32 dist = (iter_up->first - pos).magVec();
if (dist < epsilon)
{
@@ -1724,7 +1743,7 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
{
done = false;
- F32 dist = (iter_down->first - pos).magVecSquared();
+ F32 dist = (iter_down->first - pos).magVec();
if (dist < epsilon)
{
@@ -1792,6 +1811,15 @@ bool LLModel::loadModel(std::istream& is)
}
}
+ if (header.has("material_list"))
+ { //load material list names
+ mMaterialList.clear();
+ for (U32 i = 0; i < (U32)header["material_list"].size(); ++i)
+ {
+ mMaterialList.push_back(header["material_list"][i].asString());
+ }
+ }
+
std::string nm[] =
{
"lowest_lod",
@@ -1808,6 +1836,7 @@ bool LLModel::loadModel(std::istream& is)
if (header[nm[lod]]["offset"].asInteger() == -1 ||
header[nm[lod]]["size"].asInteger() == 0 )
{ //cannot load requested LOD
+ llwarns << "LoD data is invalid!" << llendl;
return false;
}
@@ -1821,7 +1850,7 @@ bool LLModel::loadModel(std::istream& is)
is.seekg(cur_pos);
}
- if (lod == LLModel::LOD_PHYSICS)
+ if (lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS)
{
std::ios::pos_type cur_pos = is.tellg();
loadDecomposition(header, is);
@@ -1868,11 +1897,66 @@ bool LLModel::loadModel(std::istream& is)
}
return true;
}
+ else
+ {
+ llwarns << "unpackVolumeFaces failed!" << llendl;
+ }
return false;
}
+void LLModel::matchMaterialOrder(LLModel* ref)
+{
+ llassert(ref->mMaterialList.size() == mMaterialList.size());
+
+ std::map index_map;
+
+ //build a map of material slot names to face indexes
+ bool reorder = false;
+ std::set base_mat;
+ std::set cur_mat;
+
+ for (U32 i = 0; i < mMaterialList.size(); i++)
+ {
+ index_map[ref->mMaterialList[i]] = i;
+ if (!reorder)
+ { //if any material name does not match reference, we need to reorder
+ reorder = ref->mMaterialList[i] != mMaterialList[i];
+ }
+ base_mat.insert(ref->mMaterialList[i]);
+ cur_mat.insert(mMaterialList[i]);
+ }
+
+
+ if (reorder &&
+ base_mat == cur_mat) //don't reorder if material name sets don't match
+ {
+ std::vector new_face_list;
+ new_face_list.resize(mVolumeFaces.size());
+
+ std::vector new_material_list;
+ new_material_list.resize(mVolumeFaces.size());
+
+ //rebuild face list so materials have the same order
+ //as the reference model
+ for (U32 i = 0; i < mMaterialList.size(); ++i)
+ {
+ U32 ref_idx = index_map[mMaterialList[i]];
+ new_face_list[ref_idx] = mVolumeFaces[i];
+
+ new_material_list[ref_idx] = mMaterialList[i];
+ }
+
+ llassert(new_material_list == ref->mMaterialList);
+
+ mVolumeFaces = new_face_list;
+ }
+
+ //override material list with reference model ordering
+ mMaterialList = ref->mMaterialList;
+}
+
bool LLModel::loadSkinInfo(LLSD& header, std::istream &is)
{
@@ -1926,7 +2010,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
{
if (skin.has("joint_names"))
{
- for (U32 i = 0; i < skin["joint_names"].size(); ++i)
+ for (U32 i = 0; i < (U32)skin["joint_names"].size(); ++i)
{
mJointNames.push_back(skin["joint_names"][i]);
}
@@ -1934,7 +2018,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
if (skin.has("inverse_bind_matrix"))
{
- for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i)
+ for (U32 i = 0; i < (U32)skin["inverse_bind_matrix"].size(); ++i)
{
LLMatrix4 mat;
for (U32 j = 0; j < 4; j++)
@@ -1962,7 +2046,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
if (skin.has("alt_inverse_bind_matrix"))
{
- for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i)
+ for (U32 i = 0; i < (U32)skin["alt_inverse_bind_matrix"].size(); ++i)
{
LLMatrix4 mat;
for (U32 j = 0; j < 4; j++)
@@ -2034,7 +2118,7 @@ LLModel::Decomposition::Decomposition(LLSD& data)
void LLModel::Decomposition::fromLLSD(LLSD& decomp)
{
- if (decomp.has("HullList"))
+ if (decomp.has("HullList") && decomp.has("Positions"))
{
// updated for const-correctness. gcc is picky about this type of thing - Nyx
const LLSD::Binary& hulls = decomp["HullList"].asBinary();
@@ -2190,6 +2274,8 @@ LLSD LLModel::Decomposition::asLLSD() const
ret["Min"] = min.getValue();
ret["Max"] = max.getValue();
+ LLVector3 range = max-min;
+
if (!hulls.empty())
{
ret["HullList"] = hulls;
@@ -2199,10 +2285,6 @@ LLSD LLModel::Decomposition::asLLSD() const
{
LLSD::Binary p(total*3*2);
- LLVector3 min(-0.5f, -0.5f, -0.5f);
- LLVector3 max(0.5f, 0.5f, 0.5f);
- LLVector3 range = max-min;
-
U32 vert_idx = 0;
for (U32 i = 0; i < mHull.size(); ++i)
@@ -2214,12 +2296,10 @@ LLSD LLModel::Decomposition::asLLSD() const
for (U32 j = 0; j < mHull[i].size(); ++j)
{
U64 test = 0;
+ const F32* src = mHull[i][j].mV;
+
for (U32 k = 0; k < 3; k++)
{
- F32* src = (F32*) (mHull[i][j].mV);
-
- llassert(src[k] <= 0.501f && src[k] >= -0.501f);
-
//convert to 16-bit normalized across domain
U16 val = (U16) (((src[k]-min.mV[k])/range.mV[k])*65535);
@@ -2258,19 +2338,15 @@ LLSD LLModel::Decomposition::asLLSD() const
{
LLSD::Binary p(mBaseHull.size()*3*2);
- LLVector3 min(-0.5f, -0.5f, -0.5f);
- LLVector3 max(0.5f, 0.5f, 0.5f);
- LLVector3 range = max-min;
-
U32 vert_idx = 0;
for (U32 j = 0; j < mBaseHull.size(); ++j)
{
+ const F32* v = mBaseHull[j].mV;
+
for (U32 k = 0; k < 3; k++)
{
- llassert(mBaseHull[j].mV[k] <= 0.51f && mBaseHull[j].mV[k] >= -0.51f);
-
//convert to 16-bit normalized across domain
- U16 val = (U16) (((mBaseHull[j].mV[k]-min.mV[k])/range.mV[k])*65535);
+ U16 val = (U16) (((v[k]-min.mV[k])/range.mV[k])*65535);
U8* buff = (U8*) &val;
//write to binary buffer
@@ -2315,4 +2391,4 @@ void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs)
mPhysicsShapeMesh = rhs->mPhysicsShapeMesh;
}
}
-
+#endif //MESH_ENABLED
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index cd9f76fcb..fe37d3420 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -32,8 +32,10 @@
#include "v4math.h"
#include "m4math.h"
+#if MESH_IMPORT
class daeElement;
class domMesh;
+#endif //MESH_IMPORT
#define MAX_MODEL_FACES 8
@@ -137,16 +139,20 @@ public:
const LLModel::Decomposition& decomp,
BOOL upload_skin,
BOOL upload_joints,
- BOOL nowrite = FALSE);
+ BOOL nowrite = FALSE,
+ BOOL as_slm = FALSE);
static LLSD writeModelToStream(
std::ostream& ostr,
LLSD& mdl,
- BOOL nowrite = FALSE);
+ BOOL nowrite = FALSE, BOOL as_slm = FALSE);
+#if MESH_IMPORT
static LLModel* loadModelFromDomMesh(domMesh* mesh);
static std::string getElementLabel(daeElement* element);
+#endif //MESH_IMPORT
std::string getName() const;
+ std::string getMetric() const {return mMetric;}
EModelStatus getStatus() const {return mStatus;}
static std::string getStatusString(U32 status) ;
@@ -171,6 +177,11 @@ public:
void optimizeVolumeFaces();
void offsetMesh( const LLVector3& pivotPoint );
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
+
+ //reorder face list based on mMaterialList in this and reference so
+ //order matches that of reference (material ordering touchup)
+ void matchMaterialOrder(LLModel* reference);
+
std::vector mMaterialList;
//data used for skin weights
@@ -211,6 +222,22 @@ public:
}
};
+
+ struct JointPositionalCompare
+ {
+ //Are the doubles the same w/in epsilon specified tolerance
+ bool areEqual( double a, double b )
+ {
+ const float epsilon = 1e-5f;
+ return (abs((int)(a - b)) < epsilon) && (a < b);
+ }
+ //Make sure that we return false for any values that are within the tolerance for equivalence
+ bool operator() ( const LLVector3& a, const LLVector3& b )
+ {
+ return ( areEqual( a[0],b[0]) && areEqual( a[1],b[1] ) && areEqual( a[2],b[2]) ) ? false : true;
+ }
+ };
+
//copy of position array for this model -- mPosition[idx].mV[X,Y,Z]
std::vector mPosition;
@@ -228,6 +255,8 @@ public:
std::string mRequestedLabel; // name requested in UI, if any.
std::string mLabel; // name computed from dae.
+ std::string mMetric; // user-supplied metric data for upload
+
LLVector3 mNormalizedScale;
LLVector3 mNormalizedTranslation;
@@ -250,8 +279,10 @@ public:
EModelStatus mStatus ;
protected:
+#if MESH_IMPORT
void addVolumeFacesFromDomMesh(domMesh* mesh);
virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
+#endif //MESH_IMPORT
};
#endif //LL_LLMODEL_H
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index c9b035db3..c255655de 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -109,6 +109,10 @@ public:
PARAMS_LIGHT = 0x20,
PARAMS_SCULPT = 0x30,
PARAMS_LIGHT_IMAGE = 0x40,
+#if MESH_ENABLED
+ PARAMS_RESERVED = 0x50, // Used on server-side
+ PARAMS_MESH = 0x60,
+#endif MESH_ENABLED
};
public:
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 5eb5ffd10..ec306ba26 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -63,6 +63,9 @@ LLShaderFeatures::LLShaderFeatures()
: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
+#if MESH_ENABLED
+, hasObjectSkinning(false)
+#endif //MESH_ENABLED
{
}
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 3c47e7504..3f8a6cb96 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -48,6 +48,9 @@ public:
bool hasWaterFog; // implies no gamma
bool hasTransport; // implies no lighting (it's possible to have neither though)
bool hasSkinning;
+#if MESH_ENABLED
+ bool hasObjectSkinning;
+#endif //MESH_ENABLED
bool hasAtmospherics;
bool hasGamma;
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 2dc3dae91..255643dc8 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -152,6 +152,16 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
return FALSE;
}
}
+
+#if MESH_ENABLED
+ if (features->hasObjectSkinning)
+ {
+ if (!shader->attachObject("avatar/objectSkinV.glsl"))
+ {
+ return FALSE;
+ }
+ }
+#endif //MESH_ENABLED
///////////////////////////////////////
// Attach Fragment Shader Features Next
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 21f321452..7a5c71729 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -293,6 +293,7 @@ set(viewer_SOURCE_FILES
llmediaremotectrl.cpp
llmemoryview.cpp
llmenucommands.cpp
+ llmeshrepository.cpp
llmimetypes.cpp
llmorphview.cpp
llmoveview.cpp
@@ -771,6 +772,7 @@ set(viewer_HEADER_FILES
llmediaremotectrl.h
llmemoryview.h
llmenucommands.h
+ llmeshrepository.h
llmimetypes.h
llmorphview.h
llmoveview.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 31440e213..ef738031e 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7885,6 +7885,51 @@
Value
410
+ MeshEnabled
+
+ MeshImportUseSLM
+
+ MeshUploadLogXML
+
+ MeshUploadFakeErrors
+
+
MigrateCacheDirectory
+ MeshStreamingCostScaler
+
+ MeshThreadCount
+
+ MeshMaxConcurrentRequests
+
RunBtnState