diff options
Diffstat (limited to 'indra/newview/llmeshrepository.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/newview/llmeshrepository.cpp | 1437 |
1 files changed, 552 insertions, 885 deletions
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 6e0722bcf9..f461c7e46f 100644..100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -34,9 +34,9 @@ #include "llagent.h" #include "llappviewer.h" #include "llbufferstream.h" +#include "llcallbacklist.h" #include "llcurl.h" #include "lldatapacker.h" -#include "llfasttimer.h" #include "llfloatermodelpreview.h" #include "llfloaterperms.h" #include "lleconomy.h" @@ -49,6 +49,7 @@ #include "llthread.h" #include "llvfile.h" #include "llviewercontrol.h" +#include "llviewerinventory.h" #include "llviewermenufile.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" @@ -62,6 +63,7 @@ #include "llinventorymodel.h" #include "llfoldertype.h" #include "llviewerparcelmgr.h" +#include "lluploadfloaterobservers.h" #include "boost/lexical_cast.hpp" @@ -71,16 +73,24 @@ #include <queue> -LLFastTimer::DeclareTimer FTM_MESH_UPDATE("Mesh Update"); -LLFastTimer::DeclareTimer FTM_LOAD_MESH("Load Mesh"); - LLMeshRepository gMeshRepo; const U32 MAX_MESH_REQUESTS_PER_SECOND = 100; +// Maximum mesh version to support. Three least significant digits are reserved for the minor version, +// with major version changes indicating a format change that is not backwards compatible and should not +// be parsed by viewers that don't specifically support that version. For example, if the integer "1" is +// present, the version is 0.001. A viewer that can parse version 0.001 can also parse versions up to 0.999, +// but not 1.0 (integer 1000). +// See wiki at https://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format +const S32 MAX_MESH_VERSION = 999; + U32 LLMeshRepository::sBytesReceived = 0; U32 LLMeshRepository::sHTTPRequestCount = 0; U32 LLMeshRepository::sHTTPRetryCount = 0; +U32 LLMeshRepository::sLODProcessing = 0; +U32 LLMeshRepository::sLODPending = 0; + U32 LLMeshRepository::sCacheBytesRead = 0; U32 LLMeshRepository::sCacheBytesWritten = 0; U32 LLMeshRepository::sPeakKbps = 0; @@ -190,196 +200,6 @@ S32 LLMeshRepoThread::sActiveHeaderRequests = 0; S32 LLMeshRepoThread::sActiveLODRequests = 0; U32 LLMeshRepoThread::sMaxConcurrentRequests = 1; - -class LLTextureCostResponder : public LLCurl::Responder -{ -public: - LLTextureUploadData mData; - LLMeshUploadThread* mThread; - - LLTextureCostResponder(LLTextureUploadData data, LLMeshUploadThread* thread) - : mData(data), mThread(thread) - { - - } - - virtual void completed(U32 status, const std::string& reason, const LLSD& content) - { - mThread->mPendingConfirmations--; - if (isGoodStatus(status)) - { - mThread->priceResult(mData, content); - } - else - { - llwarns << status << ": " << reason << llendl; - - if (mData.mRetries < MAX_TEXTURE_UPLOAD_RETRIES) - { - llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; - - if (status == 499 || status == 500) - { - mThread->uploadTexture(mData); - } - else - { - llerrs << "Unhandled status " << status << llendl; - } - } - else - { - llwarns << "Giving up after " << mData.mRetries << " retries." << llendl; - } - } - } -}; - -class LLTextureUploadResponder : public LLCurl::Responder -{ -public: - LLTextureUploadData mData; - LLMeshUploadThread* mThread; - - LLTextureUploadResponder(LLTextureUploadData data, LLMeshUploadThread* thread) - : mData(data), mThread(thread) - { - } - - virtual void completed(U32 status, const std::string& reason, const LLSD& content) - { - mThread->mPendingUploads--; - if (isGoodStatus(status)) - { - mData.mUUID = content["new_asset"].asUUID(); - gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mData.mPostData, content)); - mThread->onTextureUploaded(mData); - } - else - { - llwarns << status << ": " << reason << llendl; - llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; - - if (status == 404) - { - mThread->uploadTexture(mData); - } - else if (status == 499) - { - mThread->mConfirmedTextureQ.push(mData); - } - else - { - llerrs << "Unhandled status " << status << llendl; - } - } - } -}; - -class LLMeshCostResponder : public LLCurl::Responder -{ -public: - LLMeshUploadData mData; - LLMeshUploadThread* mThread; - - LLMeshCostResponder(LLMeshUploadData data, LLMeshUploadThread* thread) - : mData(data), mThread(thread) - { - - } - - virtual void completed(U32 status, const std::string& reason, const LLSD& content) - { - mThread->mPendingConfirmations--; - - if (isGoodStatus(status)) - { - mThread->priceResult(mData, content); - } - else - { - llwarns << status << ": " << reason << llendl; - - if (status == HTTP_INTERNAL_ERROR) - { - llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; - mThread->uploadModel(mData); - } - else if (status == HTTP_BAD_REQUEST) - { - llwarns << "Status 400 received from server, giving up." << llendl; - } - else if (status == HTTP_NOT_FOUND) - { - llwarns <<"Status 404 received, server is disconnected, giving up." << llendl ; - } - else - { - llerrs << "Unhandled status " << status << llendl; - } - } - } -}; - -class LLMeshUploadResponder : public LLCurl::Responder -{ -public: - LLMeshUploadData mData; - LLMeshUploadThread* mThread; - - LLMeshUploadResponder(LLMeshUploadData data, LLMeshUploadThread* thread) - : mData(data), mThread(thread) - { - } - - virtual void completed(U32 status, const std::string& reason, const LLSD& content) - { - mThread->mPendingUploads--; - if (isGoodStatus(status)) - { - mData.mUUID = content["new_asset"].asUUID(); - if (mData.mUUID.isNull()) - { - LLSD args; - std::string message = content["error"]["message"]; - std::string identifier = content["error"]["identifier"]; - std::string invalidity_identifier = content["error"]["invalidity_identifier"]; - - args["MESSAGE"] = message; - args["IDENTIFIER"] = identifier; - args["INVALIDITY_IDENTIFIER"] = invalidity_identifier; - args["LABEL"] = mData.mBaseModel->mLabel; - - gMeshRepo.uploadError(args); - } - else - { - gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mData.mPostData, content)); - mThread->onModelUploaded(mData); - } - } - else - { - llwarns << status << ": " << reason << llendl; - llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; - - if (status == 404) - { - mThread->uploadModel(mData); - } - else if (status == 499) - { - mThread->mConfirmedQ.push(mData); - } - else if (status != 500) - { //drop internal server errors on the floor, otherwise grab - llerrs << "Unhandled status " << status << llendl; - } - } - } -}; - - class LLMeshHeaderResponder : public LLCurl::Responder { public: @@ -388,6 +208,12 @@ public: LLMeshHeaderResponder(const LLVolumeParams& mesh_params) : mMeshParams(mesh_params) { + LLMeshRepoThread::sActiveHeaderRequests++; + } + + ~LLMeshHeaderResponder() + { + LLMeshRepoThread::sActiveHeaderRequests--; } virtual void completedRaw(U32 status, const std::string& reason, @@ -407,6 +233,12 @@ public: LLMeshLODResponder(const LLVolumeParams& mesh_params, S32 lod, U32 offset, U32 requested_bytes) : mMeshParams(mesh_params), mLOD(lod), mOffset(offset), mRequestedBytes(requested_bytes) { + LLMeshRepoThread::sActiveLODRequests++; + } + + ~LLMeshLODResponder() + { + LLMeshRepoThread::sActiveLODRequests--; } virtual void completedRaw(U32 status, const std::string& reason, @@ -518,38 +350,16 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s } } -class LLModelObjectUploadResponder: public LLCurl::Responder -{ - LLSD mObjectAsset; - LLMeshUploadThread* mThread; - -public: - LLModelObjectUploadResponder(LLMeshUploadThread* thread, const LLSD& object_asset): - mThread(thread), - mObjectAsset(object_asset) - { - } - - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - assert_main_thread(); - - llinfos << "completed" << llendl; - mThread->mPendingUploads--; - mThread->mFinished = true; - } -}; - class LLWholeModelFeeResponder: public LLCurl::Responder { LLMeshUploadThread* mThread; LLSD mModelData; + LLHandle<LLWholeModelFeeObserver> mObserverHandle; public: - LLWholeModelFeeResponder(LLMeshUploadThread* thread, LLSD& model_data): + LLWholeModelFeeResponder(LLMeshUploadThread* thread, LLSD& model_data, LLHandle<LLWholeModelFeeObserver> observer_handle): mThread(thread), - mModelData(model_data) + mModelData(model_data), + mObserverHandle(observer_handle) { } virtual void completed(U32 status, @@ -562,20 +372,32 @@ public: cc = llsd_from_file("fake_upload_error.xml"); } - llinfos << "completed" << llendl; mThread->mPendingUploads--; dump_llsd_to_file(cc,make_dump_name("whole_model_fee_response_",dump_num)); + + LLWholeModelFeeObserver* observer = mObserverHandle.get(); + if (isGoodStatus(status) && cc["state"].asString() == "upload") { - llinfos << "fee request succeeded" << llendl; - mThread->mWholeModelUploadURL = cc["uploader"].asString(); + mThread->mWholeModelUploadURL = cc["uploader"].asString(); + + if (observer) + { + cc["data"]["upload_price"] = cc["upload_price"]; + observer->onModelPhysicsFeeReceived(cc["data"], mThread->mWholeModelUploadURL); + } } else { llwarns << "fee request failed" << llendl; log_upload_error(status,cc,"fee",mModelData["name"]); mThread->mWholeModelUploadURL = ""; + + if (observer) + { + observer->setModelPhysicsFeeErrorStatus(status, reason); + } } } @@ -585,11 +407,13 @@ class LLWholeModelUploadResponder: public LLCurl::Responder { LLMeshUploadThread* mThread; LLSD mModelData; + LLHandle<LLWholeModelUploadObserver> mObserverHandle; public: - LLWholeModelUploadResponder(LLMeshUploadThread* thread, LLSD& model_data): + LLWholeModelUploadResponder(LLMeshUploadThread* thread, LLSD& model_data, LLHandle<LLWholeModelUploadObserver> observer_handle): mThread(thread), - mModelData(model_data) + mModelData(model_data), + mObserverHandle(observer_handle) { } virtual void completed(U32 status, @@ -602,30 +426,40 @@ public: cc = llsd_from_file("fake_upload_error.xml"); } - //assert_main_thread(); mThread->mPendingUploads--; dump_llsd_to_file(cc,make_dump_name("whole_model_upload_response_",dump_num)); - llinfos << "LLWholeModelUploadResponder content: " << cc << llendl; + + LLWholeModelUploadObserver* observer = mObserverHandle.get(); + // requested "mesh" asset type isn't actually the type // of the resultant object, fix it up here. if (isGoodStatus(status) && cc["state"].asString() == "complete") { - llinfos << "upload succeeded" << llendl; mModelData["asset_type"] = "object"; gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mModelData,cc)); + + if (observer) + { + doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadSuccess, observer)); + } } else { llwarns << "upload failed" << llendl; std::string model_name = mModelData["name"].asString(); log_upload_error(status,cc,"upload",model_name); + + if (observer) + { + doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadFailure, observer)); + } } } }; LLMeshRepoThread::LLMeshRepoThread() -: LLThread("mesh repo", NULL) +: LLThread("mesh repo") { mWaiting = false; mMutex = new LLMutex(NULL); @@ -674,28 +508,35 @@ void LLMeshRepoThread::run() while (!mLODReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveLODRequests < sMaxConcurrentRequests) { + if (mMutex) { mMutex->lock(); LODRequest req = mLODReqQ.front(); mLODReqQ.pop(); + LLMeshRepository::sLODProcessing--; mMutex->unlock(); - if (fetchMeshLOD(req.mMeshParams, req.mLOD)) + if (!fetchMeshLOD(req.mMeshParams, req.mLOD, count))//failed, resubmit { - count++; + mMutex->lock(); + mLODReqQ.push(req) ; + mMutex->unlock(); } } } while (!mHeaderReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveHeaderRequests < sMaxConcurrentRequests) { + if (mMutex) { mMutex->lock(); HeaderRequest req = mHeaderReqQ.front(); mHeaderReqQ.pop(); mMutex->unlock(); - if (fetchMeshHeader(req.mMeshParams)) + if (!fetchMeshHeader(req.mMeshParams, count))//failed, resubmit { - count++; + mMutex->lock(); + mHeaderReqQ.push(req) ; + mMutex->unlock(); } } } @@ -784,6 +625,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { LLMutexLock lock(mMutex); mLODReqQ.push(req); + LLMeshRepository::sLODProcessing++; } } else @@ -831,6 +673,12 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id) bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) { //protected by mMutex + + if (!mHeaderMutex) + { + return false; + } + mHeaderMutex->lock(); if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) @@ -839,27 +687,29 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) return false; } + bool ret = true ; U32 header_size = mMeshHeaderSize[mesh_id]; - + if (header_size > 0) { + S32 version = mMeshHeader[mesh_id]["version"].asInteger(); S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger(); S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger(); mHeaderMutex->unlock(); - if (offset >= 0 && size > 0) + if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { //check VFS for mesh skin info LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); if (file.getSize() >= offset+size) - { + { LLMeshRepository::sCacheBytesRead += size; file.seek(offset); U8* buffer = new U8[size]; file.read(buffer, size); - //make sure buffer isn't all 0's (reserved block but not written) + //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) bool zero = true; for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) { @@ -869,7 +719,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) if (!zero) { //attempt to parse if (skinInfoReceived(mesh_id, buffer, size)) - { + { delete[] buffer; return true; } @@ -884,11 +734,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - ++sActiveLODRequests; - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, - new LLMeshSkinInfoResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshSkinInfoResponder(mesh_id, offset, size)); + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } } @@ -898,11 +750,16 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) { //protected by mMutex + if (!mHeaderMutex) + { + return false; + } + mHeaderMutex->lock(); if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) @@ -912,26 +769,29 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } U32 header_size = mMeshHeaderSize[mesh_id]; - + bool ret = true ; + if (header_size > 0) { + S32 version = mMeshHeader[mesh_id]["version"].asInteger(); S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger(); S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger(); mHeaderMutex->unlock(); - if (offset >= 0 && size > 0) + if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { //check VFS for mesh skin info LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesRead += size; + file.seek(offset); U8* buffer = new U8[size]; file.read(buffer, size); - //make sure buffer isn't all 0's (reserved block but not written) + //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) bool zero = true; for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) { @@ -956,11 +816,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - ++sActiveLODRequests; - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, offset, size, - new LLMeshDecompositionResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshDecompositionResponder(mesh_id, offset, size)); + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } } @@ -970,11 +832,16 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) { //protected by mMutex + if (!mHeaderMutex) + { + return false; + } + mHeaderMutex->lock(); if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) @@ -984,15 +851,17 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) } U32 header_size = mMeshHeaderSize[mesh_id]; + bool ret = true ; if (header_size > 0) { + S32 version = mMeshHeader[mesh_id]["version"].asInteger(); S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger(); S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger(); mHeaderMutex->unlock(); - if (offset >= 0 && size > 0) + if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { //check VFS for mesh physics shape info LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); @@ -1003,7 +872,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) U8* buffer = new U8[size]; file.read(buffer, size); - //make sure buffer isn't all 0's (reserved block but not written) + //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) bool zero = true; for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) { @@ -1028,11 +897,14 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - ++sActiveLODRequests; - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, offset, size, - new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } else @@ -1046,13 +918,12 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } -bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) +//return false if failed to get header +bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count) { - bool retval = false; - { //look for mesh in asset in vfs LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH); @@ -1060,42 +931,51 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) S32 size = file.getSize(); if (size > 0) - { - U8 buffer[1024]; - S32 bytes = llmin(size, 1024); + { //NOTE -- if the header size is ever more than 4KB, this will break + U8 buffer[4096]; + S32 bytes = llmin(size, 4096); LLMeshRepository::sCacheBytesRead += bytes; file.read(buffer, bytes); if (headerReceived(mesh_params, buffer, bytes)) { //did not do an HTTP request, return false - return false; + return true; } } } - //either cache entry doesn't exist or is corrupt, request header from simulator - + //either cache entry doesn't exist or is corrupt, request header from simulator + bool retval = true ; std::vector<std::string> headers; headers.push_back("Accept: application/octet-stream"); std::string http_url = constructUrl(mesh_params.getSculptID()); if (!http_url.empty()) { - ++sActiveHeaderRequests; - retval = true; //grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits //within the first 4KB - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + //NOTE -- this will break of headers ever exceed 4KB + retval = mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + if(retval) + { + LLMeshRepository::sHTTPRequestCount++; + } + count++; } return retval; } -bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) +//return false if failed to get mesh lod. +bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count) { //protected by mMutex + if (!mHeaderMutex) + { + return false; + } + mHeaderMutex->lock(); - bool retval = false; + bool retval = true; LLUUID mesh_id = mesh_params.getSculptID(); @@ -1103,10 +983,12 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (header_size > 0) { + S32 version = mMeshHeader[mesh_id]["version"].asInteger(); S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger(); S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger(); mHeaderMutex->unlock(); - if (offset >= 0 && size > 0) + + if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) { //check VFS for mesh asset @@ -1118,7 +1000,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) U8* buffer = new U8[size]; file.read(buffer, size); - //make sure buffer isn't all 0's (reserved block but not written) + //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) bool zero = true; for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) { @@ -1130,7 +1012,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (lodReceived(mesh_params, lod, buffer, size)) { delete[] buffer; - return false; + return true; } } @@ -1143,12 +1025,15 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - ++sActiveLODRequests; - retval = true; - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + { + retval = mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, new LLMeshLODResponder(mesh_params, lod, offset, size)); + + if(retval) + { + LLMeshRepository::sHTTPRequestCount++; + } + count++; } else { @@ -1204,15 +1089,13 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat } { - U32 cost = gMeshRepo.calcResourceCost(header); - LLUUID mesh_id = mesh_params.getSculptID(); - mHeaderMutex->lock(); - mMeshHeaderSize[mesh_id] = header_size; - mMeshHeader[mesh_id] = header; - mMeshResourceCost[mesh_id] = cost; - mHeaderMutex->unlock(); + { + LLMutexLock lock(mHeaderMutex); + mMeshHeaderSize[mesh_id] = header_size; + mMeshHeader[mesh_id] = header; + } //check for pending requests pending_lod_map::iterator iter = mPendingLOD.find(mesh_params); @@ -1223,6 +1106,7 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat { LODRequest req(mesh_params, iter->second[i]); mLODReqQ.push(req); + LLMeshRepository::sLODProcessing++; } } mPendingLOD.erase(iter); @@ -1233,17 +1117,19 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size) { - LLVolume* volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); + LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); std::string mesh_string((char*) data, data_size); std::istringstream stream(mesh_string); if (volume->unpackVolumeFaces(stream, data_size)) { - LoadedMesh mesh(volume, mesh_params, lod); if (volume->getNumFaces() > 0) { - LLMutexLock lock(mMutex); - mLoadedQ.push(mesh); + LoadedMesh mesh(volume, mesh_params, lod); + { + LLMutexLock lock(mMutex); + mLoadedQ.push(mesh); + } return true; } } @@ -1363,9 +1249,14 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 } LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, - bool upload_skin, bool upload_joints) + bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload, + LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer) : LLThread("mesh upload"), - mDiscarded(FALSE) + mDiscarded(FALSE), + mDoUpload(do_upload), + mWholeModelUploadURL(upload_url), + mFeeObserverHandle(fee_observer), + mUploadObserverHandle(upload_observer) { mInstanceList = data; mUploadTextures = upload_textures; @@ -1373,9 +1264,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadJoints = upload_joints; mMutex = new LLMutex(NULL); mCurlRequest = NULL; - mPendingConfirmations = 0; mPendingUploads = 0; - mPendingCost = 0; mFinished = false; mOrigin = gAgent.getPositionAgent(); mHost = gAgent.getRegionHost(); @@ -1383,6 +1272,8 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mWholeModelFeeCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory"); mOrigin += gAgent.getAtAxis() * scale.magVec(); + + mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ; } LLMeshUploadThread::~LLMeshUploadThread() @@ -1441,7 +1332,14 @@ BOOL LLMeshUploadThread::isDiscarded() void LLMeshUploadThread::run() { - doWholeModelUpload(); + if (mDoUpload) + { + doWholeModelUpload(); + } + else + { + requestWholeModelFee(); + } } void dump_llsd_to_file(const LLSD& content, std::string filename) @@ -1467,10 +1365,13 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) LLSD res; result["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + result["texture_folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE); result["asset_type"] = "mesh"; result["inventory_type"] = "object"; - result["name"] = "mesh model"; - result["description"] = "your description here"; + result["description"] = "(No Description)"; + result["next_owner_mask"] = LLSD::Integer(LLFloaterPerms::getNextOwnerPerms()); + result["group_mask"] = LLSD::Integer(LLFloaterPerms::getGroupPerms()); + result["everyone_mask"] = LLSD::Integer(LLFloaterPerms::getEveryonePerms()); res["mesh_list"] = LLSD::emptyArray(); res["texture_list"] = LLSD::emptyArray(); @@ -1482,6 +1383,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) std::map<LLViewerTexture*,S32> texture_index; std::map<LLModel*,S32> mesh_index; + std::string model_name; + std::string model_metric; S32 instance_num = 0; @@ -1498,10 +1401,14 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) if (mesh_index.find(data.mBaseModel) == mesh_index.end()) { // Have not seen this model before - create a new mesh_list entry for it. - std::string model_name = data.mBaseModel->getName(); - if (!model_name.empty()) + if (model_name.empty()) { - result["name"] = model_name; + model_name = data.mBaseModel->getName(); + } + + if (model_metric.empty()) + { + model_metric = data.mBaseModel->getMetric(); } std::stringstream ostr; @@ -1556,24 +1463,15 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) instance_entry["scale"] = ll_sd_from_vector3(scale); instance_entry["material"] = LL_MCODE_WOOD; - LLPermissions perm; - perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false); - perm.setCreator(gAgent.getID()); - - perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base - PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner - LLFloaterPerms::getEveryonePerms(), - LLFloaterPerms::getGroupPerms(), - LLFloaterPerms::getNextOwnerPerms()); - instance_entry["permissions"] = ll_create_sd_from_permissions(perm); instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); instance_entry["mesh"] = mesh_index[data.mBaseModel]; instance_entry["face_list"] = LLSD::emptyArray(); - for (S32 face_num = 0; face_num < data.mBaseModel->getNumVolumeFaces(); face_num++) + S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ; + for (S32 face_num = 0; face_num < end; face_num++) { - LLImportMaterial& material = instance.mMaterial[face_num]; + LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]]; LLSD face_entry = LLSD::emptyMap(); LLViewerFetchedTexture *texture = material.mDiffuseMap.get(); @@ -1624,19 +1522,20 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) } } + if (model_name.empty()) model_name = "mesh model"; + result["name"] = model_name; + if (model_metric.empty()) model_metric = "MUT_Unspecified"; + res["metric"] = model_metric; result["asset_resources"] = res; dump_llsd_to_file(result,make_dump_name("whole_model_",dump_num)); dest = result; } -void LLMeshUploadThread::doWholeModelUpload() +void LLMeshUploadThread::generateHulls() { - dump_num++; - - mCurlRequest = new LLCurlRequest(); + bool has_valid_requests = false ; - // Queue up models for hull generation (viewer-side) for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) { LLMeshUploadData data; @@ -1656,6 +1555,10 @@ void LLMeshUploadThread::doWholeModelUpload() { physics = data.mModel[LLModel::LOD_PHYSICS]; } + else if (data.mModel[LLModel::LOD_LOW].notNull()) + { + physics = data.mModel[LLModel::LOD_LOW]; + } else if (data.mModel[LLModel::LOD_MEDIUM].notNull()) { physics = data.mModel[LLModel::LOD_MEDIUM]; @@ -1666,33 +1569,27 @@ void LLMeshUploadThread::doWholeModelUpload() } llassert(physics != NULL); - + DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this); if(request->isValid()) { gMeshRepo.mDecompThread->submitRequest(request); - } - } - - while (!mPhysicsComplete) - { - apr_sleep(100); + has_valid_requests = true ; + } } - - LLSD model_data; - wholeModelToLLSD(model_data,false); - dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num)); - - mPendingUploads++; - LLCurlRequest::headers_t headers; - mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, - new LLWholeModelFeeResponder(this,model_data)); - - do + + if(has_valid_requests) { - mCurlRequest->process(); - } while (mCurlRequest->getQueued() > 0); + while (!mPhysicsComplete) + { + apr_sleep(100); + } + } +} +void LLMeshUploadThread::doWholeModelUpload() +{ + mCurlRequest = new LLCurlRequest(); if (mWholeModelUploadURL.empty()) { @@ -1700,15 +1597,29 @@ void LLMeshUploadThread::doWholeModelUpload() } else { + generateHulls(); + LLSD full_model_data; wholeModelToLLSD(full_model_data, true); LLSD body = full_model_data["asset_resources"]; dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num)); - mCurlRequest->post(mWholeModelUploadURL, headers, body, - new LLWholeModelUploadResponder(this, model_data)); + LLCurlRequest::headers_t headers; + + { + LLCurl::ResponderPtr responder = new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle) ; + + while(!mCurlRequest->post(mWholeModelUploadURL, headers, body, responder, mMeshUploadTimeOut)) + { + //sleep for 10ms to prevent eating a whole core + apr_sleep(10000); + } + } + do { mCurlRequest->process(); + //sleep for 10ms to prevent eating a whole core + apr_sleep(10000); } while (mCurlRequest->getQueued() > 0); } @@ -1719,25 +1630,51 @@ void LLMeshUploadThread::doWholeModelUpload() mFinished = true; } -void LLMeshUploadThread::uploadModel(LLMeshUploadData& data) -{ //called from arbitrary thread +void LLMeshUploadThread::requestWholeModelFee() +{ + dump_num++; + + mCurlRequest = new LLCurlRequest(); + + generateHulls(); + + LLSD model_data; + wholeModelToLLSD(model_data,false); + dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num)); + + mPendingUploads++; + LLCurlRequest::headers_t headers; + { - LLMutexLock lock(mMutex); - mUploadQ.push(data); + LLCurl::ResponderPtr responder = new LLWholeModelFeeResponder(this,model_data, mFeeObserverHandle) ; + while(!mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, responder, mMeshUploadTimeOut)) + { + //sleep for 10ms to prevent eating a whole core + apr_sleep(10000); + } } -} -void LLMeshUploadThread::uploadTexture(LLTextureUploadData& data) -{ //called from mesh upload thread - mTextureQ.push(data); -} + do + { + mCurlRequest->process(); + //sleep for 10ms to prevent eating a whole core + apr_sleep(10000); + } while (mCurlRequest->getQueued() > 0); + delete mCurlRequest; + mCurlRequest = NULL; -static LLFastTimer::DeclareTimer FTM_NOTIFY_MESH_LOADED("Notify Loaded"); -static LLFastTimer::DeclareTimer FTM_NOTIFY_MESH_UNAVAILABLE("Notify Unavailable"); + // Currently a no-op. + mFinished = true; +} void LLMeshRepoThread::notifyLoadedMeshes() { + if (!mMutex) + { + return; + } + while (!mLoadedQ.empty()) { mMutex->lock(); @@ -1799,7 +1736,9 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) { lod = llclamp(lod, 0, 3); - if (header.has("404")) + S32 version = header["version"]; + + if (header.has("404") || version > MAX_MESH_VERSION) { return -1; } @@ -1832,19 +1771,6 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) return -1; } -U32 LLMeshRepoThread::getResourceCost(const LLUUID& mesh_id) -{ - LLMutexLock lock(mHeaderMutex); - - std::map<LLUUID, U32>::iterator iter = mMeshResourceCost.find(mesh_id); - if (iter != mMeshResourceCost.end()) - { - return iter->second; - } - - return 0; -} - void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header) { mThread->mMeshHeader[data.mUUID] = header; @@ -1860,6 +1786,7 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header) { LLPointer<LLVolume> volume = new LLVolume(volume_params, LLVolumeLODGroup::getVolumeScaleFromDetail(i)); volume->copyVolumeFaces(data.mModel[i]); + volume->setMeshAssetLoaded(TRUE); } } @@ -1870,7 +1797,6 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, const LLIOPipe::buffer_ptr_t& buffer) { - LLMeshRepoThread::sActiveLODRequests--; S32 data_size = buffer->countAfter(channels.in(), NULL); if (status < 200 || status > 400) @@ -2087,7 +2013,6 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - LLMeshRepoThread::sActiveHeaderRequests--; if (status < 200 || status > 400) { //llwarns @@ -2135,54 +2060,54 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, LLUUID mesh_id = mMeshParams.getSculptID(); LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id]; - std::stringstream str; + S32 version = header["version"].asInteger(); - S32 lod_bytes = 0; + if (version <= MAX_MESH_VERSION) + { + std::stringstream str; - for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i) - { //figure out how many bytes we'll need to reserve in the file - std::string lod_name = header_lod[i]; - lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger()); - } + S32 lod_bytes = 0; + + for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i) + { //figure out how many bytes we'll need to reserve in the file + 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()); + //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()); - S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; - S32 bytes = lod_bytes + header_bytes; + 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); + //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); - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE); - if (file.getMaxSize() >= bytes || file.setMaxSize(bytes)) - { - LLMeshRepository::sCacheBytesWritten += data_size; + LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE); + if (file.getMaxSize() >= bytes || file.setMaxSize(bytes)) + { + LLMeshRepository::sCacheBytesWritten += data_size; - file.write((const U8*) data, data_size); + file.write((const U8*) data, data_size); - //zero out the rest of the file - U8 block[4096]; - memset(block, 0, 4096); - - while (bytes-file.tell() > 4096) - { - file.write(block, 4096); - } + //zero out the rest of the file + U8 block[4096]; + memset(block, 0, 4096); - S32 remaining = bytes-file.tell(); + while (bytes-file.tell() > 4096) + { + file.write(block, 4096); + } - if (remaining < 0 || remaining > 4096) - { - llerrs << "Bad padding of mesh asset cache entry." << llendl; - } + S32 remaining = bytes-file.tell(); - if (remaining > 0) - { - file.write(block, remaining); + if (remaining > 0) + { + file.write(block, remaining); + } } } } @@ -2292,8 +2217,6 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para return detail; } - LLFastTimer t(FTM_LOAD_MESH); - { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes @@ -2307,6 +2230,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para //first request for this mesh mLoadingMeshes[detail][mesh_params].insert(vobj->getID()); mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail)); + LLMeshRepository::sLODPending++; } } @@ -2315,11 +2239,6 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para if (volume) { - if (volume->getNumVolumeFaces() == 0 && !volume->isTetrahedron()) - { - volume->makeTetrahedron(); - } - LLVolumeParams params = volume->getParams(); LLVolumeLODGroup* group = LLPrimitive::getVolumeManager()->getGroup(params); @@ -2330,7 +2249,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para if (last_lod >= 0) { LLVolume* lod = group->refLOD(last_lod); - if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) + if (lod && lod->isMeshAssetLoaded() && lod->getNumVolumeFaces() > 0) { group->derefLOD(lod); return last_lod; @@ -2342,7 +2261,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para for (S32 i = detail-1; i >= 0; --i) { LLVolume* lod = group->refLOD(i); - if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) + if (lod && lod->isMeshAssetLoaded() && lod->getNumVolumeFaces() > 0) { group->derefLOD(lod); return i; @@ -2355,7 +2274,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para for (S32 i = detail+1; i < 4; ++i) { LLVolume* lod = group->refLOD(i); - if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) + if (lod && lod->isMeshAssetLoaded() && lod->getNumVolumeFaces() > 0) { group->derefLOD(lod); return i; @@ -2369,11 +2288,6 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para return detail; } -static LLFastTimer::DeclareTimer FTM_START_MESH_THREAD("Start Thread"); -static LLFastTimer::DeclareTimer FTM_LOAD_MESH_LOD("Load LOD"); -static LLFastTimer::DeclareTimer FTM_MESH_LOCK1("Lock 1"); -static LLFastTimer::DeclareTimer FTM_MESH_LOCK2("Lock 2"); - void LLMeshRepository::notifyLoadedMeshes() { //called from main thread @@ -2406,6 +2320,38 @@ void LLMeshRepository::notifyLoadedMeshes() LLAssetType::EType asset_type = LLAssetType::lookup(data.mPostData["asset_type"].asString()); LLInventoryType::EType inventory_type = LLInventoryType::lookup(data.mPostData["inventory_type"].asString()); + // Handle addition of texture, if any. + if ( data.mResponse.has("new_texture_folder_id") ) + { + const LLUUID& folder_id = data.mResponse["new_texture_folder_id"].asUUID(); + + if ( folder_id.notNull() ) + { + LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE); + + std::string name; + // Check if the server built a different name for the texture folder + if ( data.mResponse.has("new_texture_folder_name") ) + { + name = data.mResponse["new_texture_folder_name"].asString(); + } + else + { + name = data.mPostData["name"].asString(); + } + + // Add the category to the internal representation + LLPointer<LLViewerInventoryCategory> cat = + new LLViewerInventoryCategory(folder_id, parent_id, + LLFolderType::FT_NONE, name, gAgent.getID()); + cat->setVersion(LLViewerInventoryCategory::VERSION_UNKNOWN); + + LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); + gInventory.accountForUpdate(update); + gInventory.updateCategory(cat); + } + } + on_new_single_inventory_upload_complete( asset_type, inventory_type, @@ -2414,7 +2360,8 @@ void LLMeshRepository::notifyLoadedMeshes() data.mPostData["name"], data.mPostData["description"], data.mResponse, - 0); + data.mResponse["upload_price"]); + //} mInventoryQ.pop(); } @@ -2439,102 +2386,92 @@ void LLMeshRepository::notifyLoadedMeshes() } } - LLFastTimer t(FTM_MESH_UPDATE); - { - LLFastTimer t(FTM_MESH_LOCK1); - mMeshMutex->lock(); - } - - { - LLFastTimer t(FTM_MESH_LOCK2); - mThread->mMutex->lock(); - } - - //popup queued error messages from background threads - while (!mUploadErrorQ.empty()) - { - LLNotificationsUtil::add("MeshUploadError", mUploadErrorQ.front()); - mUploadErrorQ.pop(); - } + LLMutexLock lock1(mMeshMutex); + LLMutexLock lock2(mThread->mMutex); + + //popup queued error messages from background threads + while (!mUploadErrorQ.empty()) + { + LLNotificationsUtil::add("MeshUploadError", mUploadErrorQ.front()); + mUploadErrorQ.pop(); + } - S32 push_count = LLMeshRepoThread::sMaxConcurrentRequests-(LLMeshRepoThread::sActiveHeaderRequests+LLMeshRepoThread::sActiveLODRequests); + S32 push_count = LLMeshRepoThread::sMaxConcurrentRequests-(LLMeshRepoThread::sActiveHeaderRequests+LLMeshRepoThread::sActiveLODRequests); - if (push_count > 0) - { - //calculate "score" for pending requests + if (push_count > 0) + { + //calculate "score" for pending requests - //create score map - std::map<LLUUID, F32> score_map; + //create score map + std::map<LLUUID, F32> score_map; - for (U32 i = 0; i < 4; ++i) - { - for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter) + for (U32 i = 0; i < 4; ++i) { - F32 max_score = 0.f; - for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter) + for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter) { - LLViewerObject* object = gObjectList.findObject(*obj_iter); - - if (object) + F32 max_score = 0.f; + for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter) { - LLDrawable* drawable = object->mDrawable; - if (drawable) + LLViewerObject* object = gObjectList.findObject(*obj_iter); + + if (object) { - F32 cur_score = drawable->getRadius()/llmax(drawable->mDistanceWRTCamera, 1.f); - max_score = llmax(max_score, cur_score); + LLDrawable* drawable = object->mDrawable; + if (drawable) + { + F32 cur_score = drawable->getRadius()/llmax(drawable->mDistanceWRTCamera, 1.f); + max_score = llmax(max_score, cur_score); + } } } - } - score_map[iter->first.getSculptID()] = max_score; + score_map[iter->first.getSculptID()] = max_score; + } + } + + //set "score" for pending requests + for (std::vector<LLMeshRepoThread::LODRequest>::iterator iter = mPendingRequests.begin(); iter != mPendingRequests.end(); ++iter) + { + iter->mScore = score_map[iter->mMeshParams.getSculptID()]; + } + + //sort by "score" + std::sort(mPendingRequests.begin(), mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater()); + + while (!mPendingRequests.empty() && push_count > 0) + { + LLMeshRepoThread::LODRequest& request = mPendingRequests.front(); + mThread->loadMeshLOD(request.mMeshParams, request.mLOD); + mPendingRequests.erase(mPendingRequests.begin()); + LLMeshRepository::sLODPending--; + push_count--; } } - //set "score" for pending requests - for (std::vector<LLMeshRepoThread::LODRequest>::iterator iter = mPendingRequests.begin(); iter != mPendingRequests.end(); ++iter) + //send skin info requests + while (!mPendingSkinRequests.empty()) { - iter->mScore = score_map[iter->mMeshParams.getSculptID()]; + mThread->loadMeshSkinInfo(mPendingSkinRequests.front()); + mPendingSkinRequests.pop(); } - - //sort by "score" - std::sort(mPendingRequests.begin(), mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater()); - - while (!mPendingRequests.empty() && push_count > 0) + + //send decomposition requests + while (!mPendingDecompositionRequests.empty()) { - LLFastTimer t(FTM_LOAD_MESH_LOD); - LLMeshRepoThread::LODRequest& request = mPendingRequests.front(); - mThread->loadMeshLOD(request.mMeshParams, request.mLOD); - mPendingRequests.erase(mPendingRequests.begin()); - push_count--; + mThread->loadMeshDecomposition(mPendingDecompositionRequests.front()); + mPendingDecompositionRequests.pop(); } - } - - //send skin info requests - while (!mPendingSkinRequests.empty()) - { - mThread->loadMeshSkinInfo(mPendingSkinRequests.front()); - mPendingSkinRequests.pop(); - } - //send decomposition requests - while (!mPendingDecompositionRequests.empty()) - { - mThread->loadMeshDecomposition(mPendingDecompositionRequests.front()); - mPendingDecompositionRequests.pop(); - } + //send physics shapes decomposition requests + while (!mPendingPhysicsShapeRequests.empty()) + { + mThread->loadMeshPhysicsShape(mPendingPhysicsShapeRequests.front()); + mPendingPhysicsShapeRequests.pop(); + } - //send physics shapes decomposition requests - while (!mPendingPhysicsShapeRequests.empty()) - { - mThread->loadMeshPhysicsShape(mPendingPhysicsShapeRequests.front()); - mPendingPhysicsShapeRequests.pop(); + mThread->notifyLoadedMeshes(); } - - mThread->notifyLoadedMeshes(); - - mThread->mMutex->unlock(); - mMeshMutex->unlock(); mThread->mSignal->signal(); } @@ -2588,7 +2525,6 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol if (volume->getNumVolumeFaces() <= 0) { llwarns << "Mesh loading returned empty volume." << llendl; - volume->makeTetrahedron(); } { //update system volume @@ -2596,6 +2532,7 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol if (sys_volume) { sys_volume->copyVolumeFaces(volume); + sys_volume->setMeshAssetLoaded(TRUE); LLPrimitive::getVolumeManager()->unrefVolume(sys_volume); } else @@ -2652,26 +2589,7 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo return mThread->getActualMeshLOD(mesh_params, lod); } -U32 LLMeshRepository::calcResourceCost(LLSD& header) -{ - U32 bytes = 0; - - for (U32 i = 0; i < 4; i++) - { - bytes += header[header_lod[i]]["size"].asInteger(); - } - - bytes += header["skin"]["size"].asInteger(); - - return bytes/4096 + 1; -} - -U32 LLMeshRepository::getResourceCost(const LLUUID& mesh_id) -{ - return mThread->getResourceCost(mesh_id); -} - -const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj) +const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj) { if (mesh_id.notNull()) { @@ -2809,9 +2727,11 @@ 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) + 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); + LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url, + do_upload, fee_observer, upload_observer); mUploadWaitList.push_back(thread); } @@ -2839,101 +2759,6 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) } - -void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) -{ - if(isDiscarded()) - { - return ; - } - - if (!data.mRSVP.empty()) - { - 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]; - - 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); - - data.mAssetData = ostr.str(); - - LLCurlRequest::headers_t headers; - mPendingUploads++; - - mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLMeshUploadResponder(data, this)); - } -} - -void LLMeshUploadThread::doUploadTexture(LLTextureUploadData& data) -{ - if(isDiscarded()) - { - return ; - } - - if (!data.mRSVP.empty()) - { - std::stringstream ostr; - - if (!data.mTexture->isRawImageValid()) - { - data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel()); - } - - if(data.mTexture->hasSavedRawImage()) - { - LLPointer<LLImageJ2C> upload_file = LLViewerTextureList::convertToUploadFile(data.mTexture->getSavedRawImage()); - - ostr.write((const char*) upload_file->getData(), upload_file->getDataSize()); - } - - data.mAssetData = ostr.str(); - - LLCurlRequest::headers_t headers; - mPendingUploads++; - - mCurlRequest->post(data.mRSVP, headers, data.mAssetData, new LLTextureUploadResponder(data, this)); - } -} - - -void LLMeshUploadThread::onModelUploaded(LLMeshUploadData& data) -{ - createObjects(data); -} - -void LLMeshUploadThread::onTextureUploaded(LLTextureUploadData& data) -{ - mTextureMap[data.mTexture] = data; -} - - -void LLMeshUploadThread::createObjects(LLMeshUploadData& data) -{ - instance_list& instances = mInstance[data.mBaseModel]; - - for (instance_list::iterator iter = instances.begin(); iter != instances.end(); ++iter) - { //create prims that reference given mesh - LLModelInstance& instance = *iter; - instance.mMeshID = data.mUUID; - mInstanceQ.push(instance); - } -} - void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation, LLVector3& result_pos, LLQuaternion& result_rot, @@ -2974,147 +2799,6 @@ void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation, result_rot = quat_rotation; } - -LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) -{ - LLMatrix4 transformation = instance.mTransform; - - llassert(instance.mMeshID.notNull()); - - // check for reflection - BOOL reflected = (transformation.determinant() < 0); - - // compute position - LLVector3 position = LLVector3(0, 0, 0) * transformation; - - // compute scale - LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - LLVector3 scale = LLVector3(x_length, y_length, z_length); - - // adjust for "reflected" geometry - LLVector3 x_transformed_reflected = x_transformed; - if (reflected) - { - x_transformed_reflected *= -1.0; - } - - // compute rotation - LLMatrix3 rotation_matrix; - rotation_matrix.setRows(x_transformed_reflected, y_transformed, z_transformed); - LLQuaternion quat_rotation = rotation_matrix.quaternion(); - quat_rotation.normalize(); // the rotation_matrix might not have been orthoginal. make it so here. - LLVector3 euler_rotation; - quat_rotation.getEulerAngles(&euler_rotation.mV[VX], &euler_rotation.mV[VY], &euler_rotation.mV[VZ]); - - // - // build parameter block to construct this prim - // - - LLSD object_params; - - // create prim - - // set volume params - U8 sculpt_type = LL_SCULPT_TYPE_MESH; - if (reflected) - { - sculpt_type |= LL_SCULPT_FLAG_MIRROR; - } - LLVolumeParams volume_params; - volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - volume_params.setSculptID(instance.mMeshID, sculpt_type); - object_params["shape"] = volume_params.asLLSD(); - - object_params["material"] = LL_MCODE_WOOD; - - object_params["group-id"] = gAgent.getGroupID(); - object_params["pos"] = ll_sd_from_vector3(position + mOrigin); - object_params["rotation"] = ll_sd_from_quaternion(quat_rotation); - object_params["scale"] = ll_sd_from_vector3(scale); - object_params["name"] = instance.mLabel; - - // load material from dae file - object_params["facelist"] = LLSD::emptyArray(); - for (S32 i = 0; i < instance.mMaterial.size(); i++) - { - LLTextureEntry te; - LLImportMaterial& mat = instance.mMaterial[i]; - - te.setColor(mat.mDiffuseColor); - - LLUUID diffuse_id = mTextureMap[mat.mDiffuseMap].mUUID; - - if (diffuse_id.notNull()) - { - te.setID(diffuse_id); - } - else - { - te.setID(LLUUID("5748decc-f629-461c-9a36-a35a221fe21f")); // blank texture - } - - te.setFullbright(mat.mFullbright); - - object_params["facelist"][i] = te.asLLSD(); - } - - // set extra parameters - LLSculptParams sculpt_params; - sculpt_params.setSculptTexture(instance.mMeshID); - sculpt_params.setSculptType(sculpt_type); - U8 buffer[MAX_OBJECT_PARAMS_SIZE+1]; - LLDataPackerBinaryBuffer dp(buffer, MAX_OBJECT_PARAMS_SIZE); - sculpt_params.pack(dp); - std::vector<U8> v(dp.getCurrentSize()); - memcpy(&v[0], buffer, dp.getCurrentSize()); - LLSD extra_parameter; - extra_parameter["extra_parameter"] = sculpt_params.mType; - extra_parameter["param_data"] = v; - object_params["extra_parameters"].append(extra_parameter); - - LLPermissions perm; - perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false); - perm.setCreator(gAgent.getID()); - - perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base - PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner - LLFloaterPerms::getEveryonePerms(), - LLFloaterPerms::getGroupPerms(), - LLFloaterPerms::getNextOwnerPerms()); - - object_params["permissions"] = ll_create_sd_from_permissions(perm); - - object_params["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); - - return object_params; -} - -void LLMeshUploadThread::priceResult(LLMeshUploadData& data, const LLSD& content) -{ - mPendingCost += content["upload_price"].asInteger(); - data.mRSVP = content["rsvp"].asString(); - - mConfirmedQ.push(data); -} - -void LLMeshUploadThread::priceResult(LLTextureUploadData& data, const LLSD& content) -{ - mPendingCost += content["upload_price"].asInteger(); - data.mRSVP = content["rsvp"].asString(); - - mConfirmedTextureQ.push(data); -} - - bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const { if (mDiffuseMap != rhs.mDiffuseMap) @@ -3137,6 +2821,11 @@ bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const return mDiffuseColor < rhs.mDiffuseColor; } + if (mBinding != rhs.mBinding) + { + return mBinding < rhs.mBinding; + } + return mFullbright < rhs.mFullbright; } @@ -3156,57 +2845,68 @@ void LLMeshRepository::uploadError(LLSD& args) } //static -F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod) +F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { - F32 dlowest = llmin(radius/0.03f, 256.f); - F32 dlow = llmin(radius/0.06f, 256.f); - F32 dmid = llmin(radius/0.24f, 256.f); - - F32 bytes_lowest = header["lowest_lod"]["size"].asReal()/1024.f; - F32 bytes_low = header["low_lod"]["size"].asReal()/1024.f; - F32 bytes_mid = header["medium_lod"]["size"].asReal()/1024.f; - F32 bytes_high = header["high_lod"]["size"].asReal()/1024.f; + F32 max_distance = 512.f; - if (bytes) - { - *bytes = 0; - *bytes += header["lowest_lod"]["size"].asInteger(); - *bytes += header["low_lod"]["size"].asInteger(); - *bytes += header["medium_lod"]["size"].asInteger(); - *bytes += header["high_lod"]["size"].asInteger(); - } + F32 dlowest = llmin(radius/0.03f, max_distance); + F32 dlow = llmin(radius/0.06f, max_distance); + F32 dmid = llmin(radius/0.24f, max_distance); + + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); - if (bytes_visible) - { - lod = LLMeshRepository::getActualMeshLOD(header, lod); - if (lod >= 0 && lod <= 3) - { - *bytes_visible = header[header_lod[lod]]["size"].asInteger(); - } - } + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + S32 bytes_low = header["low_lod"]["size"].asInteger(); + S32 bytes_mid = header["medium_lod"]["size"].asInteger(); + S32 bytes_high = header["high_lod"]["size"].asInteger(); - if (bytes_high == 0.f) + if (bytes_high == 0) { return 0.f; } - if (bytes_mid == 0.f) + if (bytes_mid == 0) { bytes_mid = bytes_high; } - if (bytes_low == 0.f) + if (bytes_low == 0) { bytes_low = bytes_mid; } - if (bytes_lowest == 0.f) + if (bytes_lowest == 0) { bytes_lowest = bytes_low; } - F32 max_area = 65536.f; + F32 triangles_lowest = llmax((F32) bytes_lowest-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + F32 triangles_low = llmax((F32) bytes_low-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + F32 triangles_mid = llmax((F32) bytes_mid-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + F32 triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + + if (bytes) + { + *bytes = 0; + *bytes += header["lowest_lod"]["size"].asInteger(); + *bytes += header["low_lod"]["size"].asInteger(); + *bytes += header["medium_lod"]["size"].asInteger(); + *bytes += header["high_lod"]["size"].asInteger(); + } + + if (bytes_visible) + { + lod = LLMeshRepository::getActualMeshLOD(header, lod); + if (lod >= 0 && lod <= 3) + { + *bytes_visible = header[header_lod[lod]]["size"].asInteger(); + } + } + + F32 max_area = 102932.f; //area of circle that encompasses region F32 min_area = 1.f; F32 high_area = llmin(F_PI*dmid*dmid, max_area); @@ -3229,12 +2929,17 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 low_area /= total_area; lowest_area /= total_area; - F32 weighted_avg = bytes_high*high_area + - bytes_mid*mid_area + - bytes_low*low_area + - bytes_lowest*lowest_area; + F32 weighted_avg = triangles_high*high_area + + triangles_mid*mid_area + + triangles_low*low_area + + triangles_lowest*lowest_area; + + if (unscaled_value) + { + *unscaled_value = weighted_avg; + } - return weighted_avg * gSavedSettings.getF32("MeshStreamingCostScaler"); + return weighted_avg/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; } @@ -3291,24 +2996,27 @@ S32 LLPhysicsDecomp::llcdCallback(const char* status, S32 p1, S32 p2) return 1; } -void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh) +void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh, bool vertex_based) { mesh.mVertexBase = mCurRequest->mPositions[0].mV; mesh.mVertexStrideBytes = 12; mesh.mNumVertices = mCurRequest->mPositions.size(); - mesh.mIndexType = LLCDMeshData::INT_16; - mesh.mIndexBase = &(mCurRequest->mIndices[0]); - mesh.mIndexStrideBytes = 6; + if(!vertex_based) + { + mesh.mIndexType = LLCDMeshData::INT_16; + mesh.mIndexBase = &(mCurRequest->mIndices[0]); + mesh.mIndexStrideBytes = 6; - mesh.mNumTriangles = mCurRequest->mIndices.size()/3; + mesh.mNumTriangles = mCurRequest->mIndices.size()/3; + } - if (mesh.mNumTriangles > 0 && mesh.mNumVertices > 2) + if ((vertex_based || mesh.mNumTriangles > 0) && mesh.mNumVertices > 2) { LLCDResult ret = LLCD_OK; if (LLConvexDecomposition::getInstance() != NULL) { - ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh); + ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh, vertex_based); } if (ret) @@ -3332,7 +3040,7 @@ void LLPhysicsDecomp::doDecomposition() //load data intoLLCD if (stage == 0) { - setMeshData(mesh); + setMeshData(mesh, false); } //build parameter map @@ -3411,13 +3119,14 @@ void LLPhysicsDecomp::doDecomposition() num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(stage); } - mMutex->lock(); - mCurRequest->mHull.clear(); - mCurRequest->mHull.resize(num_hulls); + { + LLMutexLock lock(mMutex); + mCurRequest->mHull.clear(); + mCurRequest->mHull.resize(num_hulls); - mCurRequest->mHullMesh.clear(); - mCurRequest->mHullMesh.resize(num_hulls); - mMutex->unlock(); + mCurRequest->mHullMesh.clear(); + mCurRequest->mHullMesh.resize(num_hulls); + } for (S32 i = 0; i < num_hulls; ++i) { @@ -3441,14 +3150,14 @@ void LLPhysicsDecomp::doDecomposition() get_vertex_buffer_from_mesh(mesh, mCurRequest->mHullMesh[i]); - mMutex->lock(); - mCurRequest->mHull[i] = p; - mMutex->unlock(); + { + LLMutexLock lock(mMutex); + mCurRequest->mHull[i] = p; + } } { LLMutexLock lock(mMutex); - mCurRequest->setStatusMessage("FAIL"); completeCurrent(); } @@ -3506,22 +3215,6 @@ void make_box(LLPhysicsDecomp::Request * request) void LLPhysicsDecomp::doDecompositionSingleHull() { - LLCDMeshData mesh; - - setMeshData(mesh); - - - //set all parameters to default - std::map<std::string, const LLCDParam*> param_map; - - static const LLCDParam* params = NULL; - static S32 param_count = 0; - - if (!params) - { - param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); - } - LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); if (decomp == NULL) @@ -3529,75 +3222,46 @@ void LLPhysicsDecomp::doDecompositionSingleHull() //stub. do nothing. return; } - - for (S32 i = 0; i < param_count; ++i) - { - decomp->setParam(params[i].mName, params[i].mDefault.mIntOrEnumValue); - } - - const S32 STAGE_DECOMPOSE = mStageID["Decompose"]; - const S32 STAGE_SIMPLIFY = mStageID["Simplify"]; - const S32 DECOMP_PREVIEW = 0; - const S32 SIMPLIFY_RETAIN = 0; - decomp->setParam("Decompose Quality", DECOMP_PREVIEW); - decomp->setParam("Simplify Method", SIMPLIFY_RETAIN); - decomp->setParam("Retain%", 0.f); + LLCDMeshData mesh; - LLCDResult ret = LLCD_OK; - ret = decomp->executeStage(STAGE_DECOMPOSE); - - if (ret) + setMeshData(mesh, true); + + LLCDResult ret = decomp->buildSingleHull() ; + if(ret) { llwarns << "Could not execute decomposition stage when attempting to create single hull." << llendl; make_box(mCurRequest); } else { - ret = decomp->executeStage(STAGE_SIMPLIFY); - - if (ret) { - llwarns << "Could not execute simiplification stage when attempting to create single hull." << llendl; - make_box(mCurRequest); - } - else - { - S32 num_hulls =0; - if (LLConvexDecomposition::getInstance() != NULL) - { - num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(STAGE_SIMPLIFY); - } - - mMutex->lock(); + LLMutexLock lock(mMutex); mCurRequest->mHull.clear(); - mCurRequest->mHull.resize(num_hulls); + mCurRequest->mHull.resize(1); mCurRequest->mHullMesh.clear(); - mMutex->unlock(); + } - for (S32 i = 0; i < num_hulls; ++i) - { - std::vector<LLVector3> p; - LLCDHull hull; - // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code - LLConvexDecomposition::getInstance()->getHullFromStage(STAGE_SIMPLIFY, i, &hull); + std::vector<LLVector3> p; + LLCDHull hull; + + // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code + decomp->getSingleHull(&hull); - const F32* v = hull.mVertexBase; + const F32* v = hull.mVertexBase; - for (S32 j = 0; j < hull.mNumVertices; ++j) - { - LLVector3 vert(v[0], v[1], v[2]); - p.push_back(vert); - v = (F32*) (((U8*) v) + hull.mVertexStrideBytes); - } - - mMutex->lock(); - mCurRequest->mHull[i] = p; - mMutex->unlock(); - } + for (S32 j = 0; j < hull.mNumVertices; ++j) + { + LLVector3 vert(v[0], v[1], v[2]); + p.push_back(vert); + v = (F32*) (((U8*) v) + hull.mVertexStrideBytes); } - } - + + { + LLMutexLock lock(mMutex); + mCurRequest->mHull[0] = p; + } + } { completeCurrent(); @@ -3760,7 +3424,8 @@ LLModelInstance::LLModelInstance(LLSD& data) for (U32 i = 0; i < data["material"].size(); ++i) { - mMaterial.push_back(LLImportMaterial(data["material"][i])); + LLImportMaterial mat(data["material"][i]); + mMaterial[mat.mBinding] = mat; } } @@ -3773,9 +3438,10 @@ LLSD LLModelInstance::asLLSD() ret["label"] = mLabel; ret["transform"] = mTransform.getValue(); - for (U32 i = 0; i < mMaterial.size(); ++i) + U32 i = 0; + for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter) { - ret["material"][i] = mMaterial[i].asLLSD(); + ret["material"][i++] = iter->second.asLLSD(); } return ret; @@ -3787,6 +3453,7 @@ LLImportMaterial::LLImportMaterial(LLSD& data) mDiffuseMapLabel = data["diffuse"]["label"].asString(); mDiffuseColor.setValue(data["diffuse"]["color"]); mFullbright = data["fullbright"].asBoolean(); + mBinding = data["binding"].asString(); } @@ -3798,7 +3465,8 @@ LLSD LLImportMaterial::asLLSD() ret["diffuse"]["label"] = mDiffuseMapLabel; ret["diffuse"]["color"] = mDiffuseColor.getValue(); ret["fullbright"] = mFullbright; - + ret["binding"] = mBinding; + return ret; } @@ -3849,8 +3517,7 @@ void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp) bool LLMeshRepository::meshUploadEnabled() { LLViewerRegion *region = gAgent.getRegion(); - if(gSavedSettings.getBOOL("MeshEnabled") && - LLViewerParcelMgr::getInstance()->allowAgentBuild() && + if(gSavedSettings.getBOOL("MeshEnabled") && region) { return region->meshUploadEnabled(); |