From 71de5f622a7917f78823a7e7840194e1b0f8f070 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 26 Aug 2010 14:23:12 -0500 Subject: Add missing files from viewer-experimental --- indra/newview/llmeshrepository.cpp | 2676 ++++++++++++++++++++++++++++++++++++ 1 file changed, 2676 insertions(+) create mode 100644 indra/newview/llmeshrepository.cpp (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp new file mode 100644 index 0000000000..96a170ef07 --- /dev/null +++ b/indra/newview/llmeshrepository.cpp @@ -0,0 +1,2676 @@ +/** + * @file llmeshrepository.cpp + * @brief Mesh repository implementation. + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + * + * Copyright (c) 2005-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "apr_pools.h" +#include "apr_dso.h" + +#include "llmeshrepository.h" + +#include "llagent.h" +#include "llappviewer.h" +#include "llbufferstream.h" +#include "llcurl.h" +#include "llfasttimer.h" +#include "llfloatermodelpreview.h" +#include "llfloaterperms.h" +#include "lleconomy.h" +#include "llimagej2c.h" +#include "llhost.h" +#include "llnotificationsutil.h" +#include "llsd.h" +#include "llsdutil_math.h" +#include "llsdserialize.h" +#include "llthread.h" +#include "llvfile.h" +#include "llviewercontrol.h" +#include "llviewermenufile.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llviewertexturelist.h" +#include "llvolume.h" +#include "llvolumemgr.h" +#include "llvovolume.h" +#include "llworld.h" +#include "material_codes.h" +#include "pipeline.h" + + +#include + +#if LL_MESH_ENABLED + +LLFastTimer::DeclareTimer FTM_MESH_UPDATE("Mesh Update"); +LLFastTimer::DeclareTimer FTM_LOAD_MESH("Load Mesh"); + +LLMeshRepository gMeshRepo; + +const U32 MAX_MESH_REQUESTS_PER_SECOND = 100; + +U32 LLMeshRepository::sBytesReceived = 0; +U32 LLMeshRepository::sHTTPRequestCount = 0; +U32 LLMeshRepository::sHTTPRetryCount = 0; +U32 LLMeshRepository::sCacheBytesRead = 0; +U32 LLMeshRepository::sCacheBytesWritten = 0; +U32 LLMeshRepository::sPeakKbps = 0; + + +std::string header_lod[] = +{ + "lowest_lod", + "low_lod", + "medium_lod", + "high_lod" +}; + + +//get the number of bytes resident in memory for given volume +U32 get_volume_memory_size(const LLVolume* volume) +{ + U32 indices = 0; + U32 vertices = 0; + + for (U32 i = 0; i < volume->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + indices += face.mNumIndices; + vertices += face.mNumVertices; + } + + + return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces(); +} + +std::string scrub_host_name(std::string http_url, const LLHost& host) +{ //curl loves to abuse the DNS cache, so scrub host names out of urls where trivial to prevent DNS timeouts + std::string ip_string = host.getIPString(); + std::string host_string = host.getHostName(); + + std::string::size_type idx = http_url.find(host_string); + + if (!ip_string.empty() && !host_string.empty() && idx != std::string::npos) + { + http_url.replace(idx, host_string.length(), ip_string); + } + + return http_url; +} + +LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f) +{ + LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0); + buff->allocateBuffer(mesh.mNumTriangles*3, 0, true); + + LLStrider pos; + LLStrider norm; + + buff->getVertexStrider(pos); + buff->getNormalStrider(norm); + + const F32* v = mesh.mVertexBase; + + if (mesh.mIndexType == LLCDMeshData::INT_16) + { + U16* idx = (U16*) mesh.mIndexBase; + for (S32 j = 0; j < mesh.mNumTriangles; ++j) + { + F32* mp0 = (F32*) ((U8*)v+idx[0]*mesh.mVertexStrideBytes); + F32* mp1 = (F32*) ((U8*)v+idx[1]*mesh.mVertexStrideBytes); + F32* mp2 = (F32*) ((U8*)v+idx[2]*mesh.mVertexStrideBytes); + + idx = (U16*) (((U8*)idx)+mesh.mIndexStrideBytes); + + LLVector3 v0(mp0); + LLVector3 v1(mp1); + LLVector3 v2(mp2); + + LLVector3 n = (v1-v0)%(v2-v0); + n.normalize(); + + *pos++ = v0*scale; + *pos++ = v1*scale; + *pos++ = v2*scale; + + *norm++ = n; + *norm++ = n; + *norm++ = n; + } + } + else + { + U32* idx = (U32*) mesh.mIndexBase; + for (S32 j = 0; j < mesh.mNumTriangles; ++j) + { + F32* mp0 = (F32*) ((U8*)v+idx[0]*mesh.mVertexStrideBytes); + F32* mp1 = (F32*) ((U8*)v+idx[1]*mesh.mVertexStrideBytes); + F32* mp2 = (F32*) ((U8*)v+idx[2]*mesh.mVertexStrideBytes); + + idx = (U32*) (((U8*)idx)+mesh.mIndexStrideBytes); + + LLVector3 v0(mp0); + LLVector3 v1(mp1); + LLVector3 v2(mp2); + + LLVector3 n = (v1-v0)%(v2-v0); + n.normalize(); + + *(pos++) = v0*scale; + *(pos++) = v1*scale; + *(pos++) = v2*scale; + + *(norm++) = n; + *(norm++) = n; + *(norm++) = n; + } + } + + return buff; +} + +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; + llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; + + if (status == 499) + { + mThread->uploadTexture(mData); + } + else + { + llerrs << "Unhandled status " << status << 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; + llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; + + if (status == 499) + { + mThread->uploadModel(mData); + } + else if (status == 400) + { + llwarns << "Status 400 received from server, 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: + LLVolumeParams mMeshParams; + + LLMeshHeaderResponder(const LLVolumeParams& mesh_params) + : mMeshParams(mesh_params) + { + } + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + +}; + +class LLMeshLODResponder : public LLCurl::Responder +{ +public: + LLVolumeParams mMeshParams; + S32 mLOD; + U32 mRequestedBytes; + U32 mOffset; + + LLMeshLODResponder(const LLVolumeParams& mesh_params, S32 lod, U32 offset, U32 requested_bytes) + : mMeshParams(mesh_params), mLOD(lod), mOffset(offset), mRequestedBytes(requested_bytes) + { + } + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + +}; + +class LLMeshSkinInfoResponder : public LLCurl::Responder +{ +public: + LLUUID mMeshID; + U32 mRequestedBytes; + U32 mOffset; + + LLMeshSkinInfoResponder(const LLUUID& id, U32 offset, U32 size) + : mMeshID(id), mRequestedBytes(size), mOffset(offset) + { + } + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + +}; + +class LLMeshDecompositionResponder : public LLCurl::Responder +{ +public: + LLUUID mMeshID; + U32 mRequestedBytes; + U32 mOffset; + + LLMeshDecompositionResponder(const LLUUID& id, U32 offset, U32 size) + : mMeshID(id), mRequestedBytes(size), mOffset(offset) + { + } + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + +}; + + +LLMeshRepoThread::LLMeshRepoThread() +: LLThread("mesh repo", NULL) +{ + mWaiting = false; + mMutex = new LLMutex(NULL); + mHeaderMutex = new LLMutex(NULL); + mSignal = new LLCondition(NULL); +} + +LLMeshRepoThread::~LLMeshRepoThread() +{ + +} + +void LLMeshRepoThread::run() +{ + mCurlRequest = new LLCurlRequest(); + LLCDResult res = LLConvexDecomposition::initThread(); + if (res != LLCD_OK) + { + llwarns << "convex decomposition unable to be loaded" << llendl; + } + + while (!LLApp::isQuitting()) + { + mWaiting = true; + mSignal->wait(); + mWaiting = false; + + if (!LLApp::isQuitting()) + { + static U32 count = 0; + + static F32 last_hundred = gFrameTimeSeconds; + + if (gFrameTimeSeconds - last_hundred > 1.f) + { //a second has gone by, clear count + last_hundred = gFrameTimeSeconds; + count = 0; + } + + // NOTE: throttling intentionally favors LOD requests over header requests + + while (!mLODReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveLODRequests < sMaxConcurrentRequests) + { + { + LLMutexLock lock(mMutex); + LODRequest req = mLODReqQ.front(); + mLODReqQ.pop(); + if (fetchMeshLOD(req.mMeshParams, req.mLOD)) + { + count++; + } + } + } + + while (!mHeaderReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveHeaderRequests < sMaxConcurrentRequests) + { + { + LLMutexLock lock(mMutex); + HeaderRequest req = mHeaderReqQ.front(); + mHeaderReqQ.pop(); + if (fetchMeshHeader(req.mMeshParams)) + { + count++; + } + } + } + + { + std::set incomplete; + for (std::set::iterator iter = mSkinRequests.begin(); iter != mSkinRequests.end(); ++iter) + { + LLUUID mesh_id = *iter; + if (!fetchMeshSkinInfo(mesh_id)) + { + incomplete.insert(mesh_id); + } + } + mSkinRequests = incomplete; + } + + { + std::set incomplete; + for (std::set::iterator iter = mDecompositionRequests.begin(); iter != mDecompositionRequests.end(); ++iter) + { + LLUUID mesh_id = *iter; + if (!fetchMeshDecomposition(mesh_id)) + { + incomplete.insert(mesh_id); + } + } + mDecompositionRequests = incomplete; + } + + + } + + mCurlRequest->process(); + } + + res = LLConvexDecomposition::quitThread(); + if (res != LLCD_OK) + { + llwarns << "convex decomposition unable to be quit" << llendl; + } + + delete mCurlRequest; + delete mMutex; +} + +void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id) +{ //protected by mSignal, no locking needed here + mSkinRequests.insert(mesh_id); +} + +void LLMeshRepoThread::loadMeshDecomposition(const LLUUID& mesh_id) +{ //protected by mSignal, no locking needed here + mDecompositionRequests.insert(mesh_id); +} + +void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) +{ //protected by mSignal, no locking needed here + + mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID()); + if (iter != mMeshHeader.end()) + { //if we have the header, request LOD byte range + LODRequest req(mesh_params, lod); + mLODReqQ.push(req); + } + else + { + HeaderRequest req(mesh_params); + + pending_lod_map::iterator pending = mPendingLOD.find(mesh_params); + + if (pending != mPendingLOD.end()) + { //append this lod request to existing header request + pending->second.push_back(lod); + if (pending->second.size() > 4) + { + llerrs << "WTF?" << llendl; + } + } + else + { //if no header request is pending, fetch header + mHeaderReqQ.push(req); + mPendingLOD[mesh_params].push_back(lod); + } + } +} + +//static +std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id) +{ + std::string http_url; + + if (gAgent.getRegion()) + { + http_url = gAgent.getRegion()->getCapability("GetMesh"); + scrub_host_name(http_url, gAgent.getRegionHost()); + } + + if (!http_url.empty()) + { + http_url += "/?mesh_id="; + http_url += mesh_id.asString().c_str(); + } + else + { + llwarns << "Current region does not have GetMesh capability! Cannot load " << mesh_id << ".mesh" << llendl; + } + + return http_url; +} + +bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) +{ //protected by mMutex + mHeaderMutex->lock(); + + if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) + { //we have no header info for this mesh, do nothing + mHeaderMutex->unlock(); + return false; + } + + U32 header_size = mMeshHeaderSize[mesh_id]; + + if (header_size > 0) + { + 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) + { + //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) + bool zero = true; + for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) + { + zero = buffer[i] > 0 ? false : true; + } + + if (!zero) + { //attempt to parse + if (skinInfoReceived(mesh_id, buffer, size)) + { + delete[] buffer; + return true; + } + } + + delete[] buffer; + } + + //reading from VFS failed for whatever reason, fetch from sim + std::vector headers; + headers.push_back("Accept: application/octet-stream"); + + 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)); + } + } + } + else + { + mHeaderMutex->unlock(); + } + + //early out was not hit, effectively fetched + return true; +} + +bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) +{ //protected by mMutex + mHeaderMutex->lock(); + + if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) + { //we have no header info for this mesh, do nothing + mHeaderMutex->unlock(); + return false; + } + + U32 header_size = mMeshHeaderSize[mesh_id]; + + if (header_size > 0) + { + S32 offset = header_size + mMeshHeader[mesh_id]["decomposition"]["offset"].asInteger(); + S32 size = mMeshHeader[mesh_id]["decomposition"]["size"].asInteger(); + + mHeaderMutex->unlock(); + + if (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) + bool zero = true; + for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) + { + zero = buffer[i] > 0 ? false : true; + } + + if (!zero) + { //attempt to parse + if (decompositionReceived(mesh_id, buffer, size)) + { + delete[] buffer; + return true; + } + } + + delete[] buffer; + } + + //reading from VFS failed for whatever reason, fetch from sim + std::vector headers; + headers.push_back("Accept: application/octet-stream"); + + std::string http_url = constructUrl(mesh_id); + if (!http_url.empty()) + { + ++sActiveLODRequests; + LLMeshRepository::sHTTPRequestCount++; + mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + new LLMeshDecompositionResponder(mesh_id, offset, size)); + } + } + } + else + { + mHeaderMutex->unlock(); + } + + //early out was not hit, effectively fetched + return true; +} + +bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) +{ + bool retval = false; + + { + //look for mesh in asset in vfs + LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH); + + S32 size = file.getSize(); + + if (size > 0) + { + U8 buffer[1024]; + S32 bytes = llmin(size, 1024); + LLMeshRepository::sCacheBytesRead += bytes; + file.read(buffer, bytes); + if (headerReceived(mesh_params, buffer, bytes)) + { //did not do an HTTP request, return false + return false; + } + } + } + + //either cache entry doesn't exist or is corrupt, request header from simulator + + std::vector 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)); + } + + return retval; +} + +bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) +{ //protected by mMutex + mHeaderMutex->lock(); + + bool retval = false; + + LLUUID mesh_id = mesh_params.getSculptID(); + + U32 header_size = mMeshHeaderSize[mesh_id]; + + if (header_size > 0) + { + 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) + { + + //check VFS for mesh asset + 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) + bool zero = true; + for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) + { + zero = buffer[i] > 0 ? false : true; + } + + if (!zero) + { //attempt to parse + if (lodReceived(mesh_params, lod, buffer, size)) + { + delete[] buffer; + return false; + } + } + + delete[] buffer; + } + + //reading from VFS failed for whatever reason, fetch from sim + std::vector headers; + headers.push_back("Accept: application/octet-stream"); + + std::string http_url = constructUrl(mesh_id); + if (!http_url.empty()) + { + ++sActiveLODRequests; + retval = true; + LLMeshRepository::sHTTPRequestCount++; + mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + new LLMeshLODResponder(mesh_params, lod, offset, size)); + } + else + { + mUnavailableQ.push(LODRequest(mesh_params, lod)); + } + } + else + { + mUnavailableQ.push(LODRequest(mesh_params, lod)); + } + } + else + { + mHeaderMutex->unlock(); + } + + return retval; +} + +bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size) +{ + LLSD header; + + U32 header_size = 0; + if (data_size > 0) + { + std::string res_str((char*) data, data_size); + + std::istringstream stream(res_str); + + if (!LLSDSerialize::deserialize(header, stream, data_size)) + { + llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; + return false; + } + + header_size = stream.tellg(); + } + else + { + header["404"] = 1; + } + + { + 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(); + + //check for pending requests + pending_lod_map::iterator iter = mPendingLOD.find(mesh_params); + if (iter != mPendingLOD.end()) + { + for (U32 i = 0; i < iter->second.size(); ++i) + { + LODRequest req(mesh_params, iter->second[i]); + mLODReqQ.push(req); + } + } + mPendingLOD.erase(iter); + } + + return true; +} + +bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size) +{ + 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); + return true; + } + } + + return false; +} + +bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size) +{ + LLSD skin; + + if (data_size > 0) + { + std::string res_str((char*) data, data_size); + + std::istringstream stream(res_str); + + if (!unzip_llsd(skin, stream, data_size)) + { + llwarns << "Mesh skin info parse error. Not a valid mesh asset!" << llendl; + return false; + } + } + + { + LLMeshSkinInfo info; + info.mMeshID = mesh_id; + + if (skin.has("joint_names")) + { + for (U32 i = 0; i < skin["joint_names"].size(); ++i) + { + info.mJointNames.push_back(skin["joint_names"][i]); + } + } + + if (skin.has("inverse_bind_matrix")) + { + for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i) + { + LLMatrix4 mat; + for (U32 j = 0; j < 4; j++) + { + for (U32 k = 0; k < 4; k++) + { + mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal(); + } + } + + info.mInvBindMatrix.push_back(mat); + } + } + + if (skin.has("bind_shape_matrix")) + { + for (U32 j = 0; j < 4; j++) + { + for (U32 k = 0; k < 4; k++) + { + info.mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal(); + } + } + } + + mSkinInfoQ.push(info); + } + + return true; +} + +bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size) +{ + LLSD decomp; + + if (data_size > 0) + { + std::string res_str((char*) data, data_size); + + std::istringstream stream(res_str); + + if (!unzip_llsd(decomp, stream, data_size)) + { + llwarns << "Mesh decomposition parse error. Not a valid mesh asset!" << llendl; + return false; + } + } + + { + LLMeshDecomposition* d = new LLMeshDecomposition(); + d->mMeshID = mesh_id; + + // updated for const-correctness. gcc is picky about this type of thing - Nyx + const LLSD::Binary& hulls = decomp["HullList"].asBinary(); + const LLSD::Binary& position = decomp["Position"].asBinary(); + + U16* p = (U16*) &position[0]; + + d->mHull.resize(hulls.size()); + + LLVector3 min; + LLVector3 max; + LLVector3 range; + + min.setValue(decomp["Min"]); + max.setValue(decomp["Max"]); + range = max-min; + + for (U32 i = 0; i < hulls.size(); ++i) + { + U8 count = hulls[i]; + + for (U32 j = 0; j < count; ++j) + { + d->mHull[i].push_back(LLVector3( + (F32) p[0]/65535.f*range.mV[0]+min.mV[0], + (F32) p[1]/65535.f*range.mV[1]+min.mV[1], + (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); + p += 3; + } + + } + + //get mesh for decomposition + for (U32 i = 0; i < d->mHull.size(); ++i) + { + LLCDHull hull; + hull.mNumVertices = d->mHull[i].size(); + hull.mVertexBase = d->mHull[i][0].mV; + hull.mVertexStrideBytes = 12; + + LLCDMeshData mesh; + LLCDResult res = LLCD_OK; + if (LLConvexDecomposition::getInstance() != NULL) + { + res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); + } + if (res != LLCD_OK) + { + llwarns << "could not get mesh from hull from convex decomposition lib." << llendl; + return false; + } + + + d->mMesh.push_back(get_vertex_buffer_from_mesh(mesh)); + } + + mDecompositionQ.push(d); + } + + return true; +} + +LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures) +: LLThread("mesh upload") +{ + mInstanceList = data; + mUploadTextures = upload_textures; + mMutex = new LLMutex(NULL); + mCurlRequest = NULL; + mPendingConfirmations = 0; + mPendingUploads = 0; + mPendingCost = 0; + mFinished = false; + mOrigin = gAgent.getPositionAgent(); + mHost = gAgent.getRegionHost(); + mUploadObjectAssetCapability = gAgent.getRegion()->getCapability("UploadObjectAsset"); + mNewInventoryCapability = gAgent.getRegion()->getCapability("NewFileAgentInventoryVariablePrice"); + + mOrigin += gAgent.getAtAxis() * scale.magVec(); + + scrub_host_name(mUploadObjectAssetCapability, mHost); + scrub_host_name(mNewInventoryCapability, mHost); +} + +LLMeshUploadThread::~LLMeshUploadThread() +{ + +} + +void LLMeshUploadThread::run() +{ + mCurlRequest = new LLCurlRequest(); + + //build map of LLModel refs to instances for callbacks + for (instance_list::iterator iter = mInstanceList.begin(); iter != mInstanceList.end(); ++iter) + { + mInstance[iter->mModel].push_back(*iter); + } + + std::set > textures; + + //populate upload queue with relevant models + for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) + { + LLMeshUploadData data; + data.mBaseModel = iter->first; + + LLModelInstance& instance = *(iter->second.begin()); + + for (S32 i = 0; i < 5; i++) + { + data.mModel[i] = instance.mLOD[i]; + } + + uploadModel(data); + + if (mUploadTextures) + { + for (std::vector::iterator material_iter = instance.mMaterial.begin(); + material_iter != instance.mMaterial.end(); ++material_iter) + { + + if (textures.find(material_iter->mDiffuseMap) == textures.end()) + { + textures.insert(material_iter->mDiffuseMap); + + LLTextureUploadData data(material_iter->mDiffuseMap, material_iter->mDiffuseMapLabel); + uploadTexture(data); + } + } + } + } + + + //upload textures + bool done = false; + do + { + if (!mTextureQ.empty()) + { + sendCostRequest(mTextureQ.front()); + mTextureQ.pop(); + } + + if (!mConfirmedTextureQ.empty()) + { + doUploadTexture(mConfirmedTextureQ.front()); + mConfirmedTextureQ.pop(); + } + + mCurlRequest->process(); + + done = mTextureQ.empty() && mConfirmedTextureQ.empty(); + } + while (!done || mCurlRequest->getQueued() > 0); + + LLSD object_asset; + object_asset["objects"] = LLSD::emptyArray(); + + done = false; + do + { + static S32 count = 0; + static F32 last_hundred = gFrameTimeSeconds; + if (gFrameTimeSeconds - last_hundred > 1.f) + { + last_hundred = gFrameTimeSeconds; + count = 0; + } + + //how many requests to push before calling process + const S32 PUSH_PER_PROCESS = 32; + + S32 tcount = llmin(count+PUSH_PER_PROCESS, 100); + + while (!mUploadQ.empty() && count < tcount) + { //send any pending upload requests + mMutex->lock(); + LLMeshUploadData data = mUploadQ.front(); + mUploadQ.pop(); + mMutex->unlock(); + sendCostRequest(data); + count++; + } + + tcount = llmin(count+PUSH_PER_PROCESS, 100); + + while (!mConfirmedQ.empty() && count < tcount) + { //process any meshes that have been confirmed for upload + LLMeshUploadData& data = mConfirmedQ.front(); + doUploadModel(data); + mConfirmedQ.pop(); + count++; + } + + tcount = llmin(count+PUSH_PER_PROCESS, 100); + + while (!mInstanceQ.empty() && count < tcount) + { //create any objects waiting for upload + count++; + object_asset["objects"].append(createObject(mInstanceQ.front())); + mInstanceQ.pop(); + } + + mCurlRequest->process(); + + done = mInstanceQ.empty() && mConfirmedQ.empty() && mUploadQ.empty(); + } + while (!done || mCurlRequest->getQueued() > 0); + + delete mCurlRequest; + mCurlRequest = NULL; + + // now upload the object asset + std::string url = mUploadObjectAssetCapability; + LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder()); + + mFinished = true; +} + +void LLMeshUploadThread::uploadModel(LLMeshUploadData& data) +{ //called from arbitrary thread + { + LLMutexLock lock(mMutex); + mUploadQ.push(data); + } +} + +void LLMeshUploadThread::uploadTexture(LLTextureUploadData& data) +{ //called from mesh upload thread + mTextureQ.push(data); +} + + +static LLFastTimer::DeclareTimer FTM_NOTIFY_MESH_LOADED("Notify Loaded"); +static LLFastTimer::DeclareTimer FTM_NOTIFY_MESH_UNAVAILABLE("Notify Unavailable"); + +void LLMeshRepoThread::notifyLoadedMeshes() +{ + while (!mLoadedQ.empty()) + { + mMutex->lock(); + LoadedMesh mesh = mLoadedQ.front(); + mLoadedQ.pop(); + mMutex->unlock(); + + if (mesh.mVolume && mesh.mVolume->getNumVolumeFaces() > 0) + { + gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); + } + else + { + gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams, + LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail())); + } + } + + while (!mUnavailableQ.empty()) + { + mMutex->lock(); + LODRequest req = mUnavailableQ.front(); + mUnavailableQ.pop(); + mMutex->unlock(); + + gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD); + } + + while (!mSkinInfoQ.empty()) + { + gMeshRepo.notifySkinInfoReceived(mSkinInfoQ.front()); + mSkinInfoQ.pop(); + } + + while (!mDecompositionQ.empty()) + { + gMeshRepo.notifyDecompositionReceived(mDecompositionQ.front()); + mDecompositionQ.pop(); + } +} + +S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod) +{ //only ever called from main thread + lod = llclamp(lod, 0, 3); + + LLMutexLock lock(mHeaderMutex); + mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID()); + + if (iter != mMeshHeader.end()) + { + LLSD& header = iter->second; + + if (header.has("404")) + { + return -1; + } + + if (header[header_lod[lod]]["size"].asInteger() > 0) + { + return lod; + } + + //search down to find the next available lower lod + for (S32 i = lod-1; i >= 0; --i) + { + if (header[header_lod[i]]["size"].asInteger() > 0) + { + return i; + } + } + + //search up to find then ext available higher lod + for (S32 i = lod+1; i < 4; ++i) + { + if (header[header_lod[i]]["size"].asInteger() > 0) + { + return i; + } + } + + //header exists and no good lod found, treat as 404 + header["404"] = 1; + return -1; + } + + return lod; +} + +U32 LLMeshRepoThread::getResourceCost(const LLUUID& mesh_id) +{ + LLMutexLock lock(mHeaderMutex); + + std::map::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; + + // we cache the mesh for default parameters + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + volume_params.setSculptID(data.mUUID, LL_SCULPT_TYPE_MESH); + + for (U32 i = 0; i < 4; i++) + { + if (data.mModel[i].notNull()) + { + LLPointer volume = new LLVolume(volume_params, LLVolumeLODGroup::getVolumeScaleFromDetail(i)); + volume->copyVolumeFaces(data.mModel[i]); + } + } + +} + +void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) +{ + + LLMeshRepoThread::sActiveLODRequests--; + S32 data_size = buffer->countAfter(channels.in(), NULL); + + if (status < 200 || status > 400) + { + llwarns << status << ": " << reason << llendl; + } + + if (data_size < mRequestedBytes) + { + if (status == 499 || status == 503) + { //timeout or service unavailable, try again + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshLOD(mMeshParams, mLOD); + } + else + { + llwarns << "Unhandled status " << status << llendl; + } + return; + } + + LLMeshRepository::sBytesReceived += mRequestedBytes; + + U8* data = NULL; + + if (data_size > 0) + { + data = new U8[data_size]; + buffer->readAfter(channels.in(), NULL, data, data_size); + } + + if (gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size)) + { + //good fetch from sim, write to VFS for caching + LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE); + + S32 offset = mOffset; + S32 size = mRequestedBytes; + + if (file.getSize() >= offset+size) + { + file.seek(offset); + file.write(data, size); + LLMeshRepository::sCacheBytesWritten += size; + } + } + + delete [] data; +} + +void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) +{ + S32 data_size = buffer->countAfter(channels.in(), NULL); + + if (status < 200 || status > 400) + { + llwarns << status << ": " << reason << llendl; + } + + if (data_size < mRequestedBytes) + { + if (status == 499 || status == 503) + { //timeout or service unavailable, try again + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshSkinInfo(mMeshID); + } + else + { + llwarns << "Unhandled status " << status << llendl; + } + return; + } + + LLMeshRepository::sBytesReceived += mRequestedBytes; + + U8* data = NULL; + + if (data_size > 0) + { + data = new U8[data_size]; + buffer->readAfter(channels.in(), NULL, data, data_size); + } + + if (gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size)) + { + //good fetch from sim, write to VFS for caching + LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); + + S32 offset = mOffset; + S32 size = mRequestedBytes; + + if (file.getSize() >= offset+size) + { + LLMeshRepository::sCacheBytesWritten += size; + file.seek(offset); + file.write(data, size); + } + } + + delete [] data; +} + +void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) +{ + S32 data_size = buffer->countAfter(channels.in(), NULL); + + if (status < 200 || status > 400) + { + llwarns << status << ": " << reason << llendl; + } + + if (data_size < mRequestedBytes) + { + if (status == 499 || status == 503) + { //timeout or service unavailable, try again + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshDecomposition(mMeshID); + } + else + { + llwarns << "Unhandled status " << status << llendl; + } + return; + } + + LLMeshRepository::sBytesReceived += mRequestedBytes; + + U8* data = NULL; + + if (data_size > 0) + { + data = new U8[data_size]; + buffer->readAfter(channels.in(), NULL, data, data_size); + } + + if (gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size)) + { + //good fetch from sim, write to VFS for caching + LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); + + S32 offset = mOffset; + S32 size = mRequestedBytes; + + if (file.getSize() >= offset+size) + { + LLMeshRepository::sCacheBytesWritten += size; + file.seek(offset); + file.write(data, size); + } + } + + delete [] data; +} + +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 << status << ": " << reason << llendl; + } + + S32 data_size = buffer->countAfter(channels.in(), NULL); + + U8* data = NULL; + + if (data_size > 0) + { + data = new U8[data_size]; + buffer->readAfter(channels.in(), NULL, data, data_size); + } + + LLMeshRepository::sBytesReceived += llmin(data_size, 4096); + + if (!gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size)) + { + llwarns << "Header responder failed with status: " << status << ": " << reason << llendl; + if (status == 503 || status == 499) + { //retry + LLMeshRepository::sHTTPRetryCount++; + LLMeshRepoThread::HeaderRequest req(mMeshParams); + gMeshRepo.mThread->mHeaderReqQ.push(req); + } + } + else if (data && data_size > 0) + { + //header was successfully retrieved from sim, cache in vfs + LLUUID mesh_id = mMeshParams.getSculptID(); + LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id]; + + std::stringstream str; + + 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["decomposition"]["offset"].asInteger() + header["decomposition"]["size"].asInteger()); + + 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); + + 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); + + //zero out the rest of the file + U8 block[4096]; + memset(block, 0, 4096); + + while (bytes-file.tell() > 4096) + { + file.write(block, 4096); + } + + S32 remaining = bytes-file.tell(); + + if (remaining < 0 || remaining > 4096) + { + llerrs << "Bad padding of mesh asset cache entry." << llendl; + } + + if (remaining > 0) + { + file.write(block, remaining); + } + } + } + + delete [] data; +} + + +LLMeshRepository::LLMeshRepository() +: mMeshMutex(NULL), + mMeshThreadCount(0), + mThread(NULL) +{ + +} + +void LLMeshRepository::init() +{ + mMeshMutex = new LLMutex(NULL); + + mDecompThread = new LLPhysicsDecomp(); + mDecompThread->start(); + + while (!mDecompThread->mInited) + { //wait for physics decomp thread to init + apr_sleep(100); + } + + mThread = new LLMeshRepoThread(); + mThread->start(); +} + +void LLMeshRepository::shutdown() +{ + mThread->mSignal->signal(); + + delete mThread; + mThread = NULL; + + for (U32 i = 0; i < mUploads.size(); ++i) + { + delete mUploads[i]; + } + + mUploads.clear(); + + delete mMeshMutex; + mMeshMutex = NULL; + + if (mDecompThread) + { + mDecompThread->shutdown(); + delete mDecompThread; + mDecompThread = NULL; + } +} + + +S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail) +{ + if (detail < 0 || detail > 4) + { + return detail; + } + + LLFastTimer t(FTM_LOAD_MESH); + + { + LLMutexLock lock(mMeshMutex); + //add volume to list of loading meshes + mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params); + if (iter != mLoadingMeshes[detail].end()) + { //request pending for this mesh, append volume id to list + iter->second.insert(vobj->getID()); + } + else + { + //first request for this mesh + mLoadingMeshes[detail][mesh_params].insert(vobj->getID()); + mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail)); + } + } + + //do a quick search to see if we can't display something while we wait for this mesh to load + LLVolume* volume = vobj->getVolume(); + + if (volume) + { + if (volume->getNumVolumeFaces() == 0 && !volume->isTetrahedron()) + { + volume->makeTetrahedron(); + } + + LLVolumeParams params = volume->getParams(); + + LLVolumeLODGroup* group = LLPrimitive::getVolumeManager()->getGroup(params); + + if (group) + { + //first see what the next lowest LOD available might be + for (S32 i = detail-1; i >= 0; --i) + { + LLVolume* lod = group->refLOD(i); + if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) + { + group->derefLOD(lod); + return i; + } + + group->derefLOD(lod); + } + + //no lower LOD is a available, is a higher lod available? + for (S32 i = detail+1; i < 4; ++i) + { + LLVolume* lod = group->refLOD(i); + if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) + { + group->derefLOD(lod); + return i; + } + + group->derefLOD(lod); + } + } + else + { + llerrs << "WTF?" << llendl; + } + } + + 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 + + LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("MeshMaxConcurrentRequests"); + + //clean up completed upload threads + for (std::vector::iterator iter = mUploads.begin(); iter != mUploads.end(); ) + { + LLMeshUploadThread* thread = *iter; + + if (thread->isStopped() && thread->finished()) + { + iter = mUploads.erase(iter); + delete thread; + } + else + { + ++iter; + } + } + + //update inventory + if (!mInventoryQ.empty()) + { + LLMutexLock lock(mMeshMutex); + while (!mInventoryQ.empty()) + { + inventory_data& data = mInventoryQ.front(); + + LLAssetType::EType asset_type = LLAssetType::lookup(data.mPostData["asset_type"].asString()); + LLInventoryType::EType inventory_type = LLInventoryType::lookup(data.mPostData["inventory_type"].asString()); + + on_new_single_inventory_upload_complete( + asset_type, + inventory_type, + data.mPostData["asset_type"].asString(), + data.mPostData["folder_id"].asUUID(), + data.mPostData["name"], + data.mPostData["description"], + data.mResponse, + 0); + + mInventoryQ.pop(); + } + } + + if (!mThread->mWaiting) + { //curl thread is churning, wait for it to go idle + return; + } + + 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(); + } + + S32 push_count = LLMeshRepoThread::sMaxConcurrentRequests-(LLMeshRepoThread::sActiveHeaderRequests+LLMeshRepoThread::sActiveLODRequests); + + if (push_count > 0) + { + //calculate "score" for pending requests + + //create score map + std::map score_map; + + for (U32 i = 0; i < 4; ++i) + { + for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter) + { + F32 max_score = 0.f; + for (std::set::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter) + { + LLViewerObject* object = gObjectList.findObject(*obj_iter); + + if (object) + { + 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; + } + } + + //set "score" for pending requests + for (std::vector::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) + { + LLFastTimer t(FTM_LOAD_MESH_LOD); + LLMeshRepoThread::LODRequest& request = mPendingRequests.front(); + mThread->loadMeshLOD(request.mMeshParams, request.mLOD); + mPendingRequests.erase(mPendingRequests.begin()); + push_count--; + } + } + + //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(); + } + + mThread->notifyLoadedMeshes(); + + mThread->mMutex->unlock(); + mMeshMutex->unlock(); + + mThread->mSignal->signal(); +} + +void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info) +{ + mSkinMap[info.mMeshID] = info; + mLoadingSkins.erase(info.mMeshID); +} + +void LLMeshRepository::notifyDecompositionReceived(LLMeshDecomposition* decomp) +{ + mDecompositionMap[decomp->mMeshID] = decomp; + mLoadingDecompositions.erase(decomp->mMeshID); +} + +void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume) +{ + S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail()); + + //get list of objects waiting to be notified this mesh is loaded + mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_params); + + if (volume && obj_iter != mLoadingMeshes[detail].end()) + { + //make sure target volume is still valid + if (volume->getNumVolumeFaces() <= 0) + { + llwarns << "Mesh loading returned empty volume." << llendl; + volume->makeTetrahedron(); + } + + { //update system volume + LLVolume* sys_volume = LLPrimitive::getVolumeManager()->refVolume(mesh_params, detail); + if (sys_volume) + { + sys_volume->copyVolumeFaces(volume); + LLPrimitive::getVolumeManager()->unrefVolume(sys_volume); + } + else + { + llwarns << "Couldn't find system volume for given mesh." << llendl; + } + } + + //notify waiting LLVOVolume instances that their requested mesh is available + for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) + { + LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); + if (vobj) + { + vobj->notifyMeshLoaded(); + } + } + + mLoadingMeshes[detail].erase(mesh_params); + } +} + +void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod) +{ + //get list of objects waiting to be notified this mesh is loaded + mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_params); + + F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod); + + if (obj_iter != mLoadingMeshes[lod].end()) + { + for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) + { + LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); + if (vobj) + { + LLVolume* obj_volume = vobj->getVolume(); + + if (obj_volume && + obj_volume->getDetail() == detail && + obj_volume->getParams() == mesh_params) + { //should force volume to find most appropriate LOD + vobj->setVolume(obj_volume->getParams(), lod); + } + } + } + + mLoadingMeshes[lod].erase(mesh_params); + } +} + +S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod) +{ + 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) +{ + if (mesh_id.notNull()) + { + skin_map::iterator iter = mSkinMap.find(mesh_id); + if (iter != mSkinMap.end()) + { + return &(iter->second); + } + + //no skin info known about given mesh, try to fetch it + { + LLMutexLock lock(mMeshMutex); + //add volume to list of loading meshes + std::set::iterator iter = mLoadingSkins.find(mesh_id); + if (iter == mLoadingSkins.end()) + { //no request pending for this skin info + mLoadingSkins.insert(mesh_id); + mPendingSkinRequests.push(mesh_id); + } + } + } + + return NULL; +} + +const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id) +{ + if (mesh_id.notNull()) + { + decomposition_map::iterator iter = mDecompositionMap.find(mesh_id); + if (iter != mDecompositionMap.end()) + { + return iter->second; + } + + //no skin info known about given mesh, try to fetch it + { + LLMutexLock lock(mMeshMutex); + //add volume to list of loading meshes + std::set::iterator iter = mLoadingDecompositions.find(mesh_id); + if (iter == mLoadingDecompositions.end()) + { //no request pending for this skin info + mLoadingDecompositions.insert(mesh_id); + mPendingDecompositionRequests.push(mesh_id); + } + } + } + + return NULL; +} + +void LLMeshRepository::uploadModel(std::vector& data, LLVector3& scale, bool upload_textures) +{ + LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures); + mUploads.push_back(thread); + thread->start(); +} + +void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) +{ + //write model file to memory buffer + std::stringstream ostr; + + LLModel::physics_shape& phys_shape = data.mModel[LLModel::LOD_PHYSICS].notNull() ? + data.mModel[LLModel::LOD_PHYSICS]->mPhysicsShape : + data.mBaseModel->mPhysicsShape; + + LLSD header = LLModel::writeModel(ostr, + data.mModel[LLModel::LOD_PHYSICS], + data.mModel[LLModel::LOD_HIGH], + data.mModel[LLModel::LOD_MEDIUM], + data.mModel[LLModel::LOD_LOW], + data.mModel[LLModel::LOD_IMPOSTOR], + phys_shape, + true); + + std::string desc = data.mBaseModel->mLabel; + + // Grab the total vertex count of the model + // along with other information for the "asset_resources" map + // to send to the server. + LLSD asset_resources = LLSD::emptyMap(); + + + std::string url = mNewInventoryCapability; + + if (!url.empty()) + { + LLSD body = generate_new_resource_upload_capability_body( + LLAssetType::AT_MESH, + desc, + desc, + LLFolderType::FT_MESH, + LLInventoryType::IT_MESH, + LLFloaterPerms::getNextOwnerPerms(), + LLFloaterPerms::getGroupPerms(), + LLFloaterPerms::getEveryonePerms()); + + body["asset_resources"] = asset_resources; + + mPendingConfirmations++; + LLCurlRequest::headers_t headers; + + data.mPostData = body; + + mCurlRequest->post(url, headers, body, new LLMeshCostResponder(data, this)); + } +} + +void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data) +{ + if (data.mTexture.notNull() && data.mTexture->getDiscardLevel() >= 0) + { + LLSD asset_resources = LLSD::emptyMap(); + + std::string url = mNewInventoryCapability; + + if (!url.empty()) + { + LLSD body = generate_new_resource_upload_capability_body( + LLAssetType::AT_TEXTURE, + data.mLabel, + data.mLabel, + LLFolderType::FT_TEXTURE, + LLInventoryType::IT_TEXTURE, + LLFloaterPerms::getNextOwnerPerms(), + LLFloaterPerms::getGroupPerms(), + LLFloaterPerms::getEveryonePerms()); + + body["asset_resources"] = asset_resources; + + mPendingConfirmations++; + LLCurlRequest::headers_t headers; + + data.mPostData = body; + mCurlRequest->post(url, headers, body, new LLTextureCostResponder(data, this)); + } + } +} + + +void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) +{ + if (!data.mRSVP.empty()) + { + std::stringstream ostr; + + LLModel::physics_shape& phys_shape = data.mModel[LLModel::LOD_PHYSICS].notNull() ? + data.mModel[LLModel::LOD_PHYSICS]->mPhysicsShape : + data.mBaseModel->mPhysicsShape; + + 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], + phys_shape); + + 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 (!data.mRSVP.empty()) + { + std::stringstream ostr; + + if (!data.mTexture->isRawImageValid()) + { + data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel()); + } + + LLPointer upload_file = LLViewerTextureList::convertToUploadFile(data.mTexture->getRawImage()); + + 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); + } +} + +LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) +{ + LLMatrix4 transformation = instance.mTransform; + + if (instance.mMeshID.isNull()) + { + llerrs << "WTF?" << llendl; + } + + // 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.mModel->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 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); + + return object_params; +} + +void LLMeshUploadThread::priceResult(LLMeshUploadData& data, const LLSD& content) +{ + mPendingCost += content["upload_price"].asInteger(); + data.mRSVP = content["rsvp"].asString(); + data.mRSVP = scrub_host_name(data.mRSVP, mHost); + + mConfirmedQ.push(data); +} + +void LLMeshUploadThread::priceResult(LLTextureUploadData& data, const LLSD& content) +{ + mPendingCost += content["upload_price"].asInteger(); + data.mRSVP = content["rsvp"].asString(); + data.mRSVP = scrub_host_name(data.mRSVP, mHost); + + mConfirmedTextureQ.push(data); +} + + +bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const +{ + if (mDiffuseMap != rhs.mDiffuseMap) + { + return mDiffuseMap < rhs.mDiffuseMap; + } + + if (mDiffuseMapFilename != rhs.mDiffuseMapFilename) + { + return mDiffuseMapFilename < rhs.mDiffuseMapFilename; + } + + if (mDiffuseMapLabel != rhs.mDiffuseMapLabel) + { + return mDiffuseMapLabel < rhs.mDiffuseMapLabel; + } + + if (mDiffuseColor != rhs.mDiffuseColor) + { + return mDiffuseColor < rhs.mDiffuseColor; + } + + return mFullbright < rhs.mFullbright; +} + + +void LLMeshRepository::updateInventory(inventory_data data) +{ + LLMutexLock lock(mMeshMutex); + mInventoryQ.push(data); +} + +void LLMeshRepository::uploadError(LLSD& args) +{ + LLMutexLock lock(mMeshMutex); + mUploadErrorQ.push(args); +} + + +LLPhysicsDecomp::LLPhysicsDecomp() +: LLThread("Physics Decomp") +{ + mInited = false; + mQuitting = false; + mDone = false; + mStage = -1; + mContinue = 1; + + mSignal = new LLCondition(NULL); + mMutex = new LLMutex(NULL); + + setStatusMessage("Idle"); +} + +LLPhysicsDecomp::~LLPhysicsDecomp() +{ + shutdown(); +} + +void LLPhysicsDecomp::shutdown() +{ + if (mSignal) + { + mQuitting = true; + mContinue = 0; + mSignal->signal(); + + while (!mDone) + { + apr_sleep(100); + } + } +} + +void LLPhysicsDecomp::setStatusMessage(std::string msg) +{ + LLMutexLock lock(mMutex); + mStatus = msg; +} + +void LLPhysicsDecomp::execute(const char* stage, LLModel* mdl) +{ + LLMutexLock lock(mMutex); + + if (mModel.notNull()) + { + llwarns << "Not done processing previous model." << llendl; + return; + } + + mModel = mdl; + //load model into LLCD + if (mdl) + { + mStage = mStageID[stage]; + + U16 index_offset = 0; + + if (mStage == 0) + { + mPositions.clear(); + mIndices.clear(); + + //queue up vertex positions and indices + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = mdl->getVolumeFace(i); + if (mPositions.size() + face.mNumVertices > 65535) + { + continue; + } + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); + } + + for (U32 j = 0; j < face.mNumIndices; ++j) + { + mIndices.push_back(face.mIndices[j]+index_offset); + } + + index_offset += face.mNumVertices; + } + } + + //signal decomposition thread + mSignal->signal(); + } +} + +//static +S32 LLPhysicsDecomp::llcdCallback(const char* status, S32 p1, S32 p2) +{ + LLPhysicsDecomp* comp = gMeshRepo.mDecompThread; + comp->setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + return comp->mContinue; +} + +void LLPhysicsDecomp::cancel() +{ + mContinue = 0; +} + +void LLPhysicsDecomp::run() +{ + LLConvexDecomposition::initSystem(); + mInited = true; + + while (!mQuitting) + { + mSignal->wait(); + if (!mQuitting) + { + //load data intoLLCD + if (mStage == 0) + { + mMesh.mVertexBase = mPositions[0].mV; + mMesh.mVertexStrideBytes = 12; + mMesh.mNumVertices = mPositions.size(); + + mMesh.mIndexType = LLCDMeshData::INT_16; + mMesh.mIndexBase = &(mIndices[0]); + mMesh.mIndexStrideBytes = 6; + + mMesh.mNumTriangles = mIndices.size()/3; + + LLCDResult ret = LLCD_OK; + if (LLConvexDecomposition::getInstance() != NULL) + { + ret = LLConvexDecomposition::getInstance()->setMeshData(&mMesh); + } + + if (ret) + { + llerrs << "Convex Decomposition thread valid but could not set mesh data" << llendl; + } + } + + setStatusMessage("Executing."); + + mContinue = 1; + LLCDResult ret = LLCD_OK; + if (LLConvexDecomposition::getInstance() != NULL) + { + ret = LLConvexDecomposition::getInstance()->executeStage(mStage); + } + + mContinue = 0; + if (ret) + { + llerrs << "Convex Decomposition thread valid but could not execute stage " << mStage << llendl; + } + + + setStatusMessage("Reading results"); + + S32 num_hulls =0; + if (LLConvexDecomposition::getInstance() != NULL) + { + num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(mStage); + } + + if (mModel.isNull()) + { + llerrs << "mModel should never be null here!" << llendl; + } + + mMutex->lock(); + mModel->mPhysicsShape.clear(); + mModel->mPhysicsShape.resize(num_hulls); + mModel->mHullCenter.clear(); + mModel->mHullCenter.resize(num_hulls); + std::vector > mesh_buffer; + mesh_buffer.resize(num_hulls); + mModel->mPhysicsCenter.clearVec(); + mModel->mPhysicsPoints = 0; + mMutex->unlock(); + + for (S32 i = 0; i < num_hulls; ++i) + { + std::vector 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(mStage, i, &hull); + + const F32* v = hull.mVertexBase; + + LLVector3 hull_center; + + for (S32 j = 0; j < hull.mNumVertices; ++j) + { + LLVector3 vert(v[0], v[1], v[2]); + p.push_back(vert); + hull_center += vert; + v = (F32*) (((U8*) v) + hull.mVertexStrideBytes); + } + + + hull_center *= 1.f/hull.mNumVertices; + + LLCDMeshData mesh; + // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code + LLConvexDecomposition::getInstance()->getMeshFromStage(mStage, i, &mesh); + + mesh_buffer[i] = get_vertex_buffer_from_mesh(mesh); + + mMutex->lock(); + mModel->mPhysicsShape[i] = p; + mModel->mHullCenter[i] = hull_center; + mModel->mPhysicsPoints += hull.mNumVertices; + mModel->mPhysicsCenter += hull_center; + + mMutex->unlock(); + } + + { + LLMutexLock lock(mMutex); + mModel->mPhysicsCenter *= 1.f/mModel->mPhysicsPoints; + + LLFloaterModelPreview::onModelDecompositionComplete(mModel, mesh_buffer); + //done updating model + mModel = NULL; + } + + setStatusMessage("Done."); + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } + } + + LLConvexDecomposition::quitSystem(); + + //delete mSignal; + delete mMutex; + mSignal = NULL; + mMutex = NULL; + mDone = true; +} + +#endif + -- cgit v1.2.3 From e3fec30097a28689a7022d06005d7d59a3004f0c Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Wed, 1 Sep 2010 10:59:45 -0400 Subject: CTS-231 WIP create new ARC algorithm to be more accurate and account for meshes First pass - uses the new algorithm to hopefully be more accurate of render load on low-end machines. Also accounts for mesh complexity, including if a mesh is weighted or non-weighted. Code reviewed by davep --- indra/newview/llmeshrepository.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 96a170ef07..069642b711 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2104,6 +2104,30 @@ void LLMeshRepository::uploadModel(std::vector& data, LLVector3 thread->start(); } +S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) +{ + if (mThread) + { + LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); + if (iter != mThread->mMeshHeader.end()) + { + LLSD& header = iter->second; + + if (header.has("404")) + { + return -1; + } + + S32 size = header[header_lod[lod]]["size"].asInteger(); + return size; + } + + } + + return -1; + +} + void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) { //write model file to memory buffer -- cgit v1.2.3 From 90e3d83a5cb35e98a02a3017dd79ebc272bbfe85 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 21 Sep 2010 13:26:52 -0400 Subject: Fix for build failures - disabling tcmalloc for now --- indra/newview/llmeshrepository.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 indra/newview/llmeshrepository.cpp (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp old mode 100644 new mode 100755 -- cgit v1.2.3 From cf09d6c58a741263cddcf338c2f79836873475b1 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 22 Sep 2010 03:04:21 -0500 Subject: Remove LL_MESH_ENABLED macros (fixes drag and drop). Add mesh stitching type back into tools floater. --- indra/newview/llmeshrepository.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 069642b711..ecf75415ab 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -68,8 +68,6 @@ #include -#if LL_MESH_ENABLED - LLFastTimer::DeclareTimer FTM_MESH_UPDATE("Mesh Update"); LLFastTimer::DeclareTimer FTM_LOAD_MESH("Load Mesh"); @@ -2395,6 +2393,13 @@ LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) extra_parameter["param_data"] = v; object_params["extra_parameters"].append(extra_parameter); + LLPermissions perm; + perm.setNextOwnerBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getNextOwnerPerms()); + perm.setGroupBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getGroupPerms()); + perm.setEveryoneBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getEveryonePerms()); + + object_params["permissions"] = ll_create_sd_from_permissions(perm); + return object_params; } @@ -2696,5 +2701,4 @@ void LLPhysicsDecomp::run() mDone = true; } -#endif -- cgit v1.2.3 From ae3eed68d1452111c1e8664c8e940e850ebfaea2 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 22 Sep 2010 18:09:21 -0500 Subject: SH-108/SH-88 Add better permissions block and physics_shape_type to uploaded mesh assets. Reviewed by Falcon. --- indra/newview/llmeshrepository.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index ecf75415ab..8b14af009c 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1257,6 +1257,12 @@ void LLMeshUploadThread::run() // now upload the object asset std::string url = mUploadObjectAssetCapability; + + if (object_asset["objects"][0].has("permissions")) + { //copy permissions from first available object to be used for coalesced object + object_asset["permissions"] = object_asset["objects"][0]["permissions"]; + } + LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder()); mFinished = true; @@ -2400,6 +2406,8 @@ LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) object_params["permissions"] = ll_create_sd_from_permissions(perm); + object_params["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); + return object_params; } -- cgit v1.2.3 From c7f5a9419b4b93efdc04ebfbb8e05a2ef0e09142 Mon Sep 17 00:00:00 2001 From: prep linden Date: Fri, 24 Sep 2010 13:11:53 -0400 Subject: Added support for joint offsets --- indra/newview/llmeshrepository.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8b14af009c..8381847842 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1016,6 +1016,23 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat } } + if (skin.has("alt_inverse_bind_matrix")) + { + for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i) + { + LLMatrix4 mat; + for (U32 j = 0; j < 4; j++) + { + for (U32 k = 0; k < 4; k++) + { + mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal(); + } + } + + info.mAlternateBindMatrix.push_back(mat); + } + } + mSkinInfoQ.push(info); } -- cgit v1.2.3 From 613894c8cca25f9fa86da7056da3594fe8771d46 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 28 Sep 2010 13:45:42 -0500 Subject: SH-238 Add check boxes to upload skin weights (or not) and/or joint positions (or not). Remove llfloaterimportcollada Reviewed by Prep. --- indra/newview/llmeshrepository.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8381847842..508e1a9444 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1121,11 +1121,14 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 return true; } -LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures) +LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, + bool upload_skin, bool upload_joints) : LLThread("mesh upload") { mInstanceList = data; mUploadTextures = upload_textures; + mUploadSkin = upload_skin; + mUploadJoints = upload_joints; mMutex = new LLMutex(NULL); mCurlRequest = NULL; mPendingConfirmations = 0; @@ -2118,9 +2121,10 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh return NULL; } -void LLMeshRepository::uploadModel(std::vector& data, LLVector3& scale, bool upload_textures) +void LLMeshRepository::uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, + bool upload_skin, bool upload_joints) { - LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures); + LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints); mUploads.push_back(thread); thread->start(); } @@ -2165,6 +2169,8 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) data.mModel[LLModel::LOD_LOW], data.mModel[LLModel::LOD_IMPOSTOR], phys_shape, + mUploadSkin, + mUploadJoints, true); std::string desc = data.mBaseModel->mLabel; @@ -2248,7 +2254,9 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) data.mModel[LLModel::LOD_MEDIUM], data.mModel[LLModel::LOD_LOW], data.mModel[LLModel::LOD_IMPOSTOR], - phys_shape); + phys_shape, + mUploadSkin, + mUploadJoints); data.mAssetData = ostr.str(); -- cgit v1.2.3 From 0c93da0501ab1debd6fa11af29a215be81f7b803 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 29 Sep 2010 16:09:21 -0500 Subject: SH-224 Add new streaming cost algorithm debug displays to viewer. Add the ability to clear LOD slots. Make triangle count UI more responsive to Generate LOD button. Add triangle count debug display for current selection. Reviewed by Nyx --- indra/newview/llmeshrepository.cpp | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 508e1a9444..5347b7313e 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2121,6 +2121,28 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh return NULL; } +const LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id) +{ + return mThread->getMeshHeader(mesh_id); +} + +const LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) +{ + static LLSD dummy_ret; + if (mesh_id.notNull()) + { + LLMutexLock lock(mHeaderMutex); + mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); + if (iter != mMeshHeader.end()) + { + return iter->second; + } + } + + return dummy_ret; +} + + void LLMeshRepository::uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints) { @@ -2493,6 +2515,50 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } +//static +F32 LLMeshRepository::getStreamingCost(const LLSD& header, F32 radius) +{ + F32 dlowest = llmin(radius/0.06f, 256.f); + F32 dlow = llmin(radius/0.24f, 256.f); + F32 dmid = llmin(radius/1.0f, 256.f); + F32 dhigh = 0.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; + + if (bytes_high == 0.f) + { + return 0.f; + } + + if (bytes_mid == 0.f) + { + bytes_mid = bytes_high; + } + + if (bytes_low == 0.f) + { + bytes_low = bytes_mid; + } + + if (bytes_lowest == 0.f) + { + bytes_lowest = bytes_low; + } + + F32 cost = 0.f; + cost += llmax(256.f-dlowest, 1.f)/32.f*bytes_lowest; + cost += llmax(dlowest-dlow, 1.f)/32.f*bytes_low; + cost += llmax(dlow-dmid, 1.f)/32.f*bytes_mid; + cost += llmax(dmid-dhigh, 1.f)/32.f*bytes_high; + + cost *= gSavedSettings.getF32("MeshStreamingCostScaler"); + return cost; +} + LLPhysicsDecomp::LLPhysicsDecomp() : LLThread("Physics Decomp") -- cgit v1.2.3 From 23b4dc61893f90abd49957a9b377312012fa0161 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 29 Sep 2010 18:10:27 -0500 Subject: Fix for serialization deprecation problems. --- indra/newview/llmeshrepository.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 5347b7313e..17b101e410 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -897,15 +897,24 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat { std::string res_str((char*) data, data_size); + std::string deprecated_header(""); + + if (res_str.substr(0, deprecated_header.size()) == deprecated_header) + { + res_str = res_str.substr(deprecated_header.size()+1, data_size); + header_size = deprecated_header.size()+1; + } + data_size = res_str.size(); + std::istringstream stream(res_str); - if (!LLSDSerialize::deserialize(header, stream, data_size)) + if (!LLSDSerialize::fromBinary(header, stream, data_size)) { llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; return false; } - header_size = stream.tellg(); + header_size += stream.tellg(); } else { -- cgit v1.2.3 From b26f7f5a6bfadde1f556f4b3aec62176ed514b83 Mon Sep 17 00:00:00 2001 From: "Matthew Breindel (Falcon)" Date: Thu, 30 Sep 2010 13:35:43 -0700 Subject: Added fix for viewing convex decomps in Render Physics Shapes mode when hull has exactly 256 verts. --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 17b101e410..757497060a 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1087,7 +1087,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 for (U32 i = 0; i < hulls.size(); ++i) { - U8 count = hulls[i]; + U16 count = (hulls[i] == 0) ? 256 : hulls[i]; for (U32 j = 0; j < count; ++j) { -- cgit v1.2.3 From 478e0927c87338e02e75d3791f51ad2b4e7b8c74 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 4 Oct 2010 09:48:05 -0500 Subject: Interface/state for rendering convex hull physics shapes. Still need to implement gMeshRepo.buildHull --- indra/newview/llmeshrepository.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 757497060a..9aba84acb4 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2130,6 +2130,11 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh return NULL; } +void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail) +{ + +} + const LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id) { return mThread->getMeshHeader(mesh_id); -- cgit v1.2.3 From 87a9f475756d54d9d98c8cbb6395f89d6fc4606a Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 5 Oct 2010 16:49:05 -0500 Subject: Rewrite LLPhysicsDecomp to have a more generic callback system. Reviewed by prep. --- indra/newview/llmeshrepository.cpp | 223 +++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 118 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 9aba84acb4..bec2e208aa 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2132,7 +2132,18 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail) { + LLVolume* volume = LLPrimitive::sVolumeManager->refVolume(params, detail); + if (!volume->mHullPoints) + { + //all default params + //execute first stage + //set simplify mode to retain + //set retain percentage to zero + //run second stage + } + + LLPrimitive::sVolumeManager->unrefVolume(volume); } const LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id) @@ -2580,13 +2591,9 @@ LLPhysicsDecomp::LLPhysicsDecomp() mInited = false; mQuitting = false; mDone = false; - mStage = -1; - mContinue = 1; mSignal = new LLCondition(NULL); mMutex = new LLMutex(NULL); - - setStatusMessage("Idle"); } LLPhysicsDecomp::~LLPhysicsDecomp() @@ -2599,7 +2606,6 @@ void LLPhysicsDecomp::shutdown() if (mSignal) { mQuitting = true; - mContinue = 0; mSignal->signal(); while (!mDone) @@ -2609,74 +2615,24 @@ void LLPhysicsDecomp::shutdown() } } -void LLPhysicsDecomp::setStatusMessage(std::string msg) -{ - LLMutexLock lock(mMutex); - mStatus = msg; -} - -void LLPhysicsDecomp::execute(const char* stage, LLModel* mdl) +void LLPhysicsDecomp::submitRequest(LLPhysicsDecomp::Request* request) { LLMutexLock lock(mMutex); + mRequestQ.push(request); + mSignal->signal(); - if (mModel.notNull()) - { - llwarns << "Not done processing previous model." << llendl; - return; - } - - mModel = mdl; - //load model into LLCD - if (mdl) - { - mStage = mStageID[stage]; - - U16 index_offset = 0; - - if (mStage == 0) - { - mPositions.clear(); - mIndices.clear(); - - //queue up vertex positions and indices - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = mdl->getVolumeFace(i); - if (mPositions.size() + face.mNumVertices > 65535) - { - continue; - } - - for (U32 j = 0; j < face.mNumVertices; ++j) - { - mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); - } - - for (U32 j = 0; j < face.mNumIndices; ++j) - { - mIndices.push_back(face.mIndices[j]+index_offset); - } - - index_offset += face.mNumVertices; - } - } - - //signal decomposition thread - mSignal->signal(); - } + } //static S32 LLPhysicsDecomp::llcdCallback(const char* status, S32 p1, S32 p2) { - LLPhysicsDecomp* comp = gMeshRepo.mDecompThread; - comp->setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - return comp->mContinue; -} + if (gMeshRepo.mDecompThread && gMeshRepo.mDecompThread->mCurRequest.notNull()) + { + return gMeshRepo.mDecompThread->mCurRequest->statusCallback(status, p1, p2); + } -void LLPhysicsDecomp::cancel() -{ - mContinue = 0; + return 1; } void LLPhysicsDecomp::run() @@ -2687,25 +2643,31 @@ void LLPhysicsDecomp::run() while (!mQuitting) { mSignal->wait(); - if (!mQuitting) + while (!mQuitting && !mRequestQ.empty()) { + mCurRequest = mRequestQ.front(); + mRequestQ.pop(); + + LLCDMeshData mesh; + S32 stage = mStageID[mCurRequest->mStage]; + //load data intoLLCD - if (mStage == 0) + if (stage == 0) { - mMesh.mVertexBase = mPositions[0].mV; - mMesh.mVertexStrideBytes = 12; - mMesh.mNumVertices = mPositions.size(); + mesh.mVertexBase = mCurRequest->mPositions[0].mV; + mesh.mVertexStrideBytes = 12; + mesh.mNumVertices = mCurRequest->mPositions.size(); - mMesh.mIndexType = LLCDMeshData::INT_16; - mMesh.mIndexBase = &(mIndices[0]); - mMesh.mIndexStrideBytes = 6; + mesh.mIndexType = LLCDMeshData::INT_16; + mesh.mIndexBase = &(mCurRequest->mIndices[0]); + mesh.mIndexStrideBytes = 6; - mMesh.mNumTriangles = mIndices.size()/3; + mesh.mNumTriangles = mCurRequest->mIndices.size()/3; LLCDResult ret = LLCD_OK; if (LLConvexDecomposition::getInstance() != NULL) { - ret = LLConvexDecomposition::getInstance()->setMeshData(&mMesh); + ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh); } if (ret) @@ -2714,44 +2676,78 @@ void LLPhysicsDecomp::run() } } - setStatusMessage("Executing."); - mContinue = 1; + //build parameter map + std::map param_map; + + const LLCDParam* params; + S32 param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); + + for (S32 i = 0; i < param_count; ++i) + { + param_map[params[i].mName] = params+i; + } + + //set parameter values + for (decomp_params::iterator iter = mCurRequest->mParams.begin(); iter != mCurRequest->mParams.end(); ++iter) + { + const std::string& name = iter->first; + const LLSD& value = iter->second; + + const LLCDParam* param = param_map[name]; + + U32 ret = LLCD_OK; + + if (param->mType == LLCDParam::LLCD_FLOAT) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) value.asReal()); + } + else if (param->mType == LLCDParam::LLCD_INTEGER || + param->mType == LLCDParam::LLCD_ENUM) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asInteger()); + } + else if (param->mType == LLCDParam::LLCD_BOOLEAN) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asBoolean()); + } + + if (ret) + { + llerrs << "WTF?" << llendl; + } + } + + mCurRequest->setStatusMessage("Executing."); + + S32 keep_going = 1; LLCDResult ret = LLCD_OK; + if (LLConvexDecomposition::getInstance() != NULL) { - ret = LLConvexDecomposition::getInstance()->executeStage(mStage); + ret = LLConvexDecomposition::getInstance()->executeStage(stage); } - mContinue = 0; + keep_going = 0; if (ret) { - llerrs << "Convex Decomposition thread valid but could not execute stage " << mStage << llendl; + llerrs << "Convex Decomposition thread valid but could not execute stage " << stage << llendl; } - - setStatusMessage("Reading results"); + mCurRequest->setStatusMessage("Reading results"); S32 num_hulls =0; if (LLConvexDecomposition::getInstance() != NULL) { - num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(mStage); + num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(stage); } - if (mModel.isNull()) - { - llerrs << "mModel should never be null here!" << llendl; - } - mMutex->lock(); - mModel->mPhysicsShape.clear(); - mModel->mPhysicsShape.resize(num_hulls); - mModel->mHullCenter.clear(); - mModel->mHullCenter.resize(num_hulls); - std::vector > mesh_buffer; - mesh_buffer.resize(num_hulls); - mModel->mPhysicsCenter.clearVec(); - mModel->mPhysicsPoints = 0; + mCurRequest->mHull.clear(); + mCurRequest->mHull.resize(num_hulls); + + mCurRequest->mHullMesh.clear(); + mCurRequest->mHullMesh.resize(num_hulls); mMutex->unlock(); for (S32 i = 0; i < num_hulls; ++i) @@ -2759,49 +2755,36 @@ void LLPhysicsDecomp::run() std::vector 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(mStage, i, &hull); + LLConvexDecomposition::getInstance()->getHullFromStage(stage, i, &hull); const F32* v = hull.mVertexBase; - LLVector3 hull_center; - for (S32 j = 0; j < hull.mNumVertices; ++j) { LLVector3 vert(v[0], v[1], v[2]); p.push_back(vert); - hull_center += vert; v = (F32*) (((U8*) v) + hull.mVertexStrideBytes); } - - hull_center *= 1.f/hull.mNumVertices; - LLCDMeshData mesh; // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code - LLConvexDecomposition::getInstance()->getMeshFromStage(mStage, i, &mesh); - - mesh_buffer[i] = get_vertex_buffer_from_mesh(mesh); + LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh); + mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh); + mMutex->lock(); - mModel->mPhysicsShape[i] = p; - mModel->mHullCenter[i] = hull_center; - mModel->mPhysicsPoints += hull.mNumVertices; - mModel->mPhysicsCenter += hull_center; - + mCurRequest->mHull[i] = p; mMutex->unlock(); } { LLMutexLock lock(mMutex); - mModel->mPhysicsCenter *= 1.f/mModel->mPhysicsPoints; - - LLFloaterModelPreview::onModelDecompositionComplete(mModel, mesh_buffer); - //done updating model - mModel = NULL; + + mCurRequest->setStatusMessage("Done."); + mCurRequest->completed(); + + mCurRequest = NULL; } - - setStatusMessage("Done."); - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); } } @@ -2814,4 +2797,8 @@ void LLPhysicsDecomp::run() mDone = true; } +void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg) +{ + mStatusMessage = msg; +} -- cgit v1.2.3 From 1f00747cd2accbe1b243e5c23f6e74a061a22bfa Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 5 Oct 2010 16:55:19 -0500 Subject: Post review cleanup. --- indra/newview/llmeshrepository.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index bec2e208aa..eae5cf59f0 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2696,6 +2696,11 @@ void LLPhysicsDecomp::run() const LLCDParam* param = param_map[name]; + if (param == NULL) + { //couldn't find valid parameter + continue; + } + U32 ret = LLCD_OK; if (param->mType == LLCDParam::LLCD_FLOAT) @@ -2720,7 +2725,6 @@ void LLPhysicsDecomp::run() mCurRequest->setStatusMessage("Executing."); - S32 keep_going = 1; LLCDResult ret = LLCD_OK; if (LLConvexDecomposition::getInstance() != NULL) @@ -2728,7 +2732,6 @@ void LLPhysicsDecomp::run() ret = LLConvexDecomposition::getInstance()->executeStage(stage); } - keep_going = 0; if (ret) { llerrs << "Convex Decomposition thread valid but could not execute stage " << stage << llendl; -- cgit v1.2.3 From 24e0d62a5eb3299a877d7a6b37e1881ec3d1ca0c Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 6 Oct 2010 01:17:12 -0500 Subject: Added mandatory single hull simplification to mesh upload. --- indra/newview/llmeshrepository.cpp | 541 +++++++++++++++++++++++++++---------- 1 file changed, 394 insertions(+), 147 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index eae5cf59f0..681748694c 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1069,43 +1069,93 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 LLMeshDecomposition* d = new LLMeshDecomposition(); d->mMeshID = mesh_id; - // updated for const-correctness. gcc is picky about this type of thing - Nyx - const LLSD::Binary& hulls = decomp["HullList"].asBinary(); - const LLSD::Binary& position = decomp["Position"].asBinary(); + if (decomp.has("HullList")) + { + // updated for const-correctness. gcc is picky about this type of thing - Nyx + const LLSD::Binary& hulls = decomp["HullList"].asBinary(); + const LLSD::Binary& position = decomp["Position"].asBinary(); + + U16* p = (U16*) &position[0]; - U16* p = (U16*) &position[0]; + d->mHull.resize(hulls.size()); - d->mHull.resize(hulls.size()); + LLVector3 min; + LLVector3 max; + LLVector3 range; - LLVector3 min; - LLVector3 max; - LLVector3 range; + min.setValue(decomp["Min"]); + max.setValue(decomp["Max"]); + range = max-min; - min.setValue(decomp["Min"]); - max.setValue(decomp["Max"]); - range = max-min; + for (U32 i = 0; i < hulls.size(); ++i) + { + U16 count = (hulls[i] == 0) ? 256 : hulls[i]; + + for (U32 j = 0; j < count; ++j) + { + d->mHull[i].push_back(LLVector3( + (F32) p[0]/65535.f*range.mV[0]+min.mV[0], + (F32) p[1]/65535.f*range.mV[1]+min.mV[1], + (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); + p += 3; + } - for (U32 i = 0; i < hulls.size(); ++i) + } + + //get mesh for decomposition + for (U32 i = 0; i < d->mHull.size(); ++i) + { + LLCDHull hull; + hull.mNumVertices = d->mHull[i].size(); + hull.mVertexBase = d->mHull[i][0].mV; + hull.mVertexStrideBytes = 12; + + LLCDMeshData mesh; + LLCDResult res = LLCD_OK; + if (LLConvexDecomposition::getInstance() != NULL) + { + res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); + } + if (res != LLCD_OK) + { + llwarns << "could not get mesh from hull from convex decomposition lib." << llendl; + return false; + } + + + d->mMesh.push_back(get_vertex_buffer_from_mesh(mesh)); + } + } + + if (decomp.has("Hull")) { - U16 count = (hulls[i] == 0) ? 256 : hulls[i]; + const LLSD::Binary& position = decomp["Hull"].asBinary(); + + U16* p = (U16*) &position[0]; + + LLVector3 min; + LLVector3 max; + LLVector3 range; + + min.setValue(decomp["Min"]); + max.setValue(decomp["Max"]); + range = max-min; + + U16 count = position.size()/6; for (U32 j = 0; j < count; ++j) { - d->mHull[i].push_back(LLVector3( + d->mBaseHull.push_back(LLVector3( (F32) p[0]/65535.f*range.mV[0]+min.mV[0], (F32) p[1]/65535.f*range.mV[1]+min.mV[1], (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); p += 3; } - - } - - //get mesh for decomposition - for (U32 i = 0; i < d->mHull.size(); ++i) - { + + //get mesh for decomposition LLCDHull hull; - hull.mNumVertices = d->mHull[i].size(); - hull.mVertexBase = d->mHull[i][0].mV; + hull.mNumVertices = d->mBaseHull.size(); + hull.mVertexBase = d->mBaseHull[0].mV; hull.mVertexStrideBytes = 12; LLCDMeshData mesh; @@ -1120,9 +1170,8 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 return false; } - - d->mMesh.push_back(get_vertex_buffer_from_mesh(mesh)); - } + d->mBaseHullMesh = get_vertex_buffer_from_mesh(mesh); + } mDecompositionQ.push(d); } @@ -1160,6 +1209,63 @@ LLMeshUploadThread::~LLMeshUploadThread() } +LLMeshUploadThread::DecompRequest::DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread) +{ + mStage = "single_hull"; + mModel = mdl; + mBaseModel = base_model; + mThread = thread; + + //copy out positions and indices + if (mdl) + { + U16 index_offset = 0; + + mPositions.clear(); + mIndices.clear(); + + //queue up vertex positions and indices + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = mdl->getVolumeFace(i); + if (mPositions.size() + face.mNumVertices > 65535) + { + continue; + } + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); + } + + for (U32 j = 0; j < face.mNumIndices; ++j) + { + mIndices.push_back(face.mIndices[j]+index_offset); + } + + index_offset += face.mNumVertices; + } + } + + mThread->mFinalDecomp = this; + mThread->mPhysicsComplete = false; +} + +void LLMeshUploadThread::DecompRequest::completed() +{ + if (mThread->mFinalDecomp == this) + { + mThread->mPhysicsComplete = true; + } + + if (mHull.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + mThread->mHullMap[mBaseModel] = mHull[0]; +} + void LLMeshUploadThread::run() { mCurlRequest = new LLCurlRequest(); @@ -1202,8 +1308,31 @@ void LLMeshUploadThread::run() } } } - } + //queue up models for hull generation + LLModel* physics = NULL; + + if (data.mModel[LLModel::LOD_PHYSICS].notNull()) + { + physics = data.mModel[LLModel::LOD_PHYSICS]; + } + else if (data.mModel[LLModel::LOD_MEDIUM].notNull()) + { + physics = data.mModel[LLModel::LOD_MEDIUM]; + } + else + { + physics = data.mModel[LLModel::LOD_HIGH]; + } + + if (!physics) + { + llerrs << "WTF?" << llendl; + } + + DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this); + gMeshRepo.mDecompThread->submitRequest(request); + } //upload textures bool done = false; @@ -2209,6 +2338,8 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) data.mModel[LLModel::LOD_PHYSICS]->mPhysicsShape : data.mBaseModel->mPhysicsShape; + LLModel::hull dummy_hull; + LLSD header = LLModel::writeModel(ostr, data.mModel[LLModel::LOD_PHYSICS], data.mModel[LLModel::LOD_HIGH], @@ -2216,6 +2347,7 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) data.mModel[LLModel::LOD_LOW], data.mModel[LLModel::LOD_IMPOSTOR], phys_shape, + dummy_hull, mUploadSkin, mUploadJoints, true); @@ -2295,6 +2427,8 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) data.mModel[LLModel::LOD_PHYSICS]->mPhysicsShape : data.mBaseModel->mPhysicsShape; + + LLModel::writeModel(ostr, data.mModel[LLModel::LOD_PHYSICS], data.mModel[LLModel::LOD_HIGH], @@ -2302,6 +2436,7 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) data.mModel[LLModel::LOD_LOW], data.mModel[LLModel::LOD_IMPOSTOR], phys_shape, + mHullMap[data.mBaseModel], mUploadSkin, mUploadJoints); @@ -2475,6 +2610,8 @@ LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) perm.setNextOwnerBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getNextOwnerPerms()); perm.setGroupBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getGroupPerms()); perm.setEveryoneBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getEveryonePerms()); + perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false); + perm.setCreator(gAgent.getID()); object_params["permissions"] = ll_create_sd_from_permissions(perm); @@ -2635,159 +2772,269 @@ S32 LLPhysicsDecomp::llcdCallback(const char* status, S32 p1, S32 p2) return 1; } -void LLPhysicsDecomp::run() +void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh) { - LLConvexDecomposition::initSystem(); - mInited = true; + mesh.mVertexBase = mCurRequest->mPositions[0].mV; + mesh.mVertexStrideBytes = 12; + mesh.mNumVertices = mCurRequest->mPositions.size(); - while (!mQuitting) + mesh.mIndexType = LLCDMeshData::INT_16; + mesh.mIndexBase = &(mCurRequest->mIndices[0]); + mesh.mIndexStrideBytes = 6; + + mesh.mNumTriangles = mCurRequest->mIndices.size()/3; + + LLCDResult ret = LLCD_OK; + if (LLConvexDecomposition::getInstance() != NULL) { - mSignal->wait(); - while (!mQuitting && !mRequestQ.empty()) - { - mCurRequest = mRequestQ.front(); - mRequestQ.pop(); + ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh); + } - LLCDMeshData mesh; - S32 stage = mStageID[mCurRequest->mStage]; + if (ret) + { + llerrs << "Convex Decomposition thread valid but could not set mesh data" << llendl; + } +} - //load data intoLLCD - if (stage == 0) - { - mesh.mVertexBase = mCurRequest->mPositions[0].mV; - mesh.mVertexStrideBytes = 12; - mesh.mNumVertices = mCurRequest->mPositions.size(); +void LLPhysicsDecomp::doDecomposition() +{ + LLCDMeshData mesh; + S32 stage = mStageID[mCurRequest->mStage]; - mesh.mIndexType = LLCDMeshData::INT_16; - mesh.mIndexBase = &(mCurRequest->mIndices[0]); - mesh.mIndexStrideBytes = 6; - - mesh.mNumTriangles = mCurRequest->mIndices.size()/3; + //load data intoLLCD + if (stage == 0) + { + setMeshData(mesh); + } + + //build parameter map + std::map param_map; - LLCDResult ret = LLCD_OK; - if (LLConvexDecomposition::getInstance() != NULL) - { - ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh); - } + const LLCDParam* params; + S32 param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); + + for (S32 i = 0; i < param_count; ++i) + { + param_map[params[i].mName] = params+i; + } - if (ret) - { - llerrs << "Convex Decomposition thread valid but could not set mesh data" << llendl; - } - } + //set parameter values + for (decomp_params::iterator iter = mCurRequest->mParams.begin(); iter != mCurRequest->mParams.end(); ++iter) + { + const std::string& name = iter->first; + const LLSD& value = iter->second; + const LLCDParam* param = param_map[name]; - //build parameter map - std::map param_map; + if (param == NULL) + { //couldn't find valid parameter + continue; + } - const LLCDParam* params; - S32 param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); - - for (S32 i = 0; i < param_count; ++i) - { - param_map[params[i].mName] = params+i; - } + U32 ret = LLCD_OK; - //set parameter values - for (decomp_params::iterator iter = mCurRequest->mParams.begin(); iter != mCurRequest->mParams.end(); ++iter) - { - const std::string& name = iter->first; - const LLSD& value = iter->second; + if (param->mType == LLCDParam::LLCD_FLOAT) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) value.asReal()); + } + else if (param->mType == LLCDParam::LLCD_INTEGER || + param->mType == LLCDParam::LLCD_ENUM) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asInteger()); + } + else if (param->mType == LLCDParam::LLCD_BOOLEAN) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asBoolean()); + } - const LLCDParam* param = param_map[name]; + if (ret) + { + llerrs << "WTF?" << llendl; + } + } - if (param == NULL) - { //couldn't find valid parameter - continue; - } + mCurRequest->setStatusMessage("Executing."); - U32 ret = LLCD_OK; + LLCDResult ret = LLCD_OK; + + if (LLConvexDecomposition::getInstance() != NULL) + { + ret = LLConvexDecomposition::getInstance()->executeStage(stage); + } - if (param->mType == LLCDParam::LLCD_FLOAT) - { - ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) value.asReal()); - } - else if (param->mType == LLCDParam::LLCD_INTEGER || - param->mType == LLCDParam::LLCD_ENUM) - { - ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asInteger()); - } - else if (param->mType == LLCDParam::LLCD_BOOLEAN) - { - ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asBoolean()); - } + if (ret) + { + llerrs << "Convex Decomposition thread valid but could not execute stage " << stage << llendl; + } - if (ret) - { - llerrs << "WTF?" << llendl; - } - } + mCurRequest->setStatusMessage("Reading results"); + + S32 num_hulls =0; + if (LLConvexDecomposition::getInstance() != NULL) + { + num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(stage); + } + + mMutex->lock(); + mCurRequest->mHull.clear(); + mCurRequest->mHull.resize(num_hulls); - mCurRequest->setStatusMessage("Executing."); + mCurRequest->mHullMesh.clear(); + mCurRequest->mHullMesh.resize(num_hulls); + mMutex->unlock(); - LLCDResult ret = LLCD_OK; - - if (LLConvexDecomposition::getInstance() != NULL) - { - ret = LLConvexDecomposition::getInstance()->executeStage(stage); - } + for (S32 i = 0; i < num_hulls; ++i) + { + std::vector 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, i, &hull); - if (ret) - { - llerrs << "Convex Decomposition thread valid but could not execute stage " << stage << llendl; - } + const F32* v = hull.mVertexBase; - mCurRequest->setStatusMessage("Reading results"); + 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); + } + + LLCDMeshData mesh; + // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code + LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh); - S32 num_hulls =0; - if (LLConvexDecomposition::getInstance() != NULL) - { - num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(stage); - } + mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh); + + mMutex->lock(); + mCurRequest->mHull[i] = p; + mMutex->unlock(); + } + + { + LLMutexLock lock(mMutex); + + mCurRequest->setStatusMessage("Done."); + mCurRequest->completed(); + + mCurRequest = NULL; + } +} + +void LLPhysicsDecomp::doDecompositionSingleHull() +{ + LLCDMeshData mesh; + + setMeshData(mesh); - mMutex->lock(); - mCurRequest->mHull.clear(); - mCurRequest->mHull.resize(num_hulls); + + //set all parameters to default + std::map param_map; - mCurRequest->mHullMesh.clear(); - mCurRequest->mHullMesh.resize(num_hulls); - mMutex->unlock(); + const LLCDParam* params; + S32 param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); + + LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); - for (S32 i = 0; i < num_hulls; ++i) - { - std::vector 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, i, &hull); + for (S32 i = 0; i < param_count; ++i) + { + decomp->setParam(params[i].mName, params[i].mDefault.mIntOrEnumValue); + } - const F32* v = hull.mVertexBase; + 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); - 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); - } - - LLCDMeshData mesh; - // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code - LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh); + LLCDResult ret = LLCD_OK; + ret = decomp->executeStage(STAGE_DECOMPOSE); + + if (ret) + { + llerrs << "Could not execute decomposition stage when attempting to create single hull." << llendl; + } - mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh); + ret = decomp->executeStage(STAGE_SIMPLIFY); + + if (ret) + { + llerrs << "Could not execute simiplification stage when attempting to create single hull." << llendl; + } + + S32 num_hulls =0; + if (LLConvexDecomposition::getInstance() != NULL) + { + num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(STAGE_SIMPLIFY); + } + + mMutex->lock(); + mCurRequest->mHull.clear(); + mCurRequest->mHull.resize(num_hulls); + mCurRequest->mHullMesh.clear(); + mMutex->unlock(); + + for (S32 i = 0; i < num_hulls; ++i) + { + std::vector 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); + + 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(); - } + mMutex->lock(); + mCurRequest->mHull[i] = p; + mMutex->unlock(); + } + + { + LLMutexLock lock(mMutex); + mCurRequest->completed(); + mCurRequest = NULL; + } +} + +void LLPhysicsDecomp::run() +{ + LLConvexDecomposition::initSystem(); + mInited = true; + + LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); + + const LLCDStageData* stages; + S32 num_stages = decomp->getStages(&stages); + for (S32 i = 0; i < num_stages; i++) + { + mStageID[stages[i].mName] = i; + } + + while (!mQuitting) + { + mSignal->wait(); + while (!mQuitting && !mRequestQ.empty()) + { + mCurRequest = mRequestQ.front(); + mRequestQ.pop(); + + if (mCurRequest->mStage == "single_hull") { - LLMutexLock lock(mMutex); - - mCurRequest->setStatusMessage("Done."); - mCurRequest->completed(); - - mCurRequest = NULL; + doDecompositionSingleHull(); } + else + { + doDecomposition(); + } } } -- cgit v1.2.3 From 141f886d49a3c663de13f77900077ee00141cafd Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 7 Oct 2010 17:59:27 -0500 Subject: Fix for crash when convex decomposition fails. --- indra/newview/llmeshrepository.cpp | 193 +++++++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 74 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 681748694c..15e4149e5d 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2864,62 +2864,100 @@ void LLPhysicsDecomp::doDecomposition() if (ret) { - llerrs << "Convex Decomposition thread valid but could not execute stage " << stage << llendl; - } + llwarns << "Convex Decomposition thread valid but could not execute stage " << stage << llendl; + LLMutexLock lock(mMutex); - mCurRequest->setStatusMessage("Reading results"); + mCurRequest->mHull.clear(); + mCurRequest->mHullMesh.clear(); - S32 num_hulls =0; - if (LLConvexDecomposition::getInstance() != NULL) - { - num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(stage); + mCurRequest->setStatusMessage("FAIL"); + mCurRequest->completed(); + + mCurRequest = NULL; } - - mMutex->lock(); - mCurRequest->mHull.clear(); - mCurRequest->mHull.resize(num_hulls); - - mCurRequest->mHullMesh.clear(); - mCurRequest->mHullMesh.resize(num_hulls); - mMutex->unlock(); - - for (S32 i = 0; i < num_hulls; ++i) + else { - std::vector 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, i, &hull); - - const F32* v = hull.mVertexBase; + mCurRequest->setStatusMessage("Reading results"); - for (S32 j = 0; j < hull.mNumVertices; ++j) + S32 num_hulls =0; + if (LLConvexDecomposition::getInstance() != NULL) { - LLVector3 vert(v[0], v[1], v[2]); - p.push_back(vert); - v = (F32*) (((U8*) v) + hull.mVertexStrideBytes); + num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(stage); } - LLCDMeshData mesh; - // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code - LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh); - - mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh); - mMutex->lock(); - mCurRequest->mHull[i] = p; + mCurRequest->mHull.clear(); + mCurRequest->mHull.resize(num_hulls); + + mCurRequest->mHullMesh.clear(); + mCurRequest->mHullMesh.resize(num_hulls); mMutex->unlock(); + + for (S32 i = 0; i < num_hulls; ++i) + { + std::vector 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, i, &hull); + + 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); + } + + LLCDMeshData mesh; + // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code + LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh); + + mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh); + + mMutex->lock(); + mCurRequest->mHull[i] = p; + mMutex->unlock(); + } + + { + LLMutexLock lock(mMutex); + + mCurRequest->setStatusMessage("FAIL"); + mCurRequest->completed(); + + mCurRequest = NULL; + } } +} - { - LLMutexLock lock(mMutex); +void make_box(LLPhysicsDecomp::Request * request) +{ + LLVector3 min,max; + min = request->mPositions[0]; + max = min; - mCurRequest->setStatusMessage("Done."); - mCurRequest->completed(); - - mCurRequest = NULL; + for (U32 i = 0; i < request->mPositions.size(); ++i) + { + update_min_max(min, max, request->mPositions[i]); } + + request->mHull.clear(); + + LLModel::hull box; + box.push_back(LLVector3(min[0],min[1],min[2])); + box.push_back(LLVector3(max[0],min[1],min[2])); + box.push_back(LLVector3(min[0],max[1],min[2])); + box.push_back(LLVector3(max[0],max[1],min[2])); + box.push_back(LLVector3(min[0],min[1],max[2])); + box.push_back(LLVector3(max[0],min[1],max[2])); + box.push_back(LLVector3(min[0],max[1],max[2])); + box.push_back(LLVector3(max[0],max[1],max[2])); + + request->mHull.push_back(box); } + void LLPhysicsDecomp::doDecompositionSingleHull() { LLCDMeshData mesh; @@ -2954,49 +2992,56 @@ void LLPhysicsDecomp::doDecompositionSingleHull() if (ret) { - llerrs << "Could not execute decomposition stage when attempting to create single hull." << llendl; + llwarns << "Could not execute decomposition stage when attempting to create single hull." << llendl; + make_box(mCurRequest); } - - ret = decomp->executeStage(STAGE_SIMPLIFY); - - if (ret) + else { - llerrs << "Could not execute simiplification stage when attempting to create single hull." << llendl; - } + ret = decomp->executeStage(STAGE_SIMPLIFY); - S32 num_hulls =0; - if (LLConvexDecomposition::getInstance() != NULL) - { - num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(STAGE_SIMPLIFY); - } - - mMutex->lock(); - mCurRequest->mHull.clear(); - mCurRequest->mHull.resize(num_hulls); - mCurRequest->mHullMesh.clear(); - mMutex->unlock(); + 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(); + mCurRequest->mHull.clear(); + mCurRequest->mHull.resize(num_hulls); + mCurRequest->mHullMesh.clear(); + mMutex->unlock(); - for (S32 i = 0; i < num_hulls; ++i) - { - std::vector 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); + for (S32 i = 0; i < num_hulls; ++i) + { + std::vector 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); - 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); + 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(); + } } - - mMutex->lock(); - mCurRequest->mHull[i] = p; - mMutex->unlock(); } + { LLMutexLock lock(mMutex); mCurRequest->completed(); -- cgit v1.2.3 From 93dc8f09ea5f44bb5bdd73a469c984cf7d714149 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 8 Oct 2010 00:11:22 -0500 Subject: Fix for bad labels on physics shape in importer. Fix for crash due to race condition when uploading meshes. --- indra/newview/llmeshrepository.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 15e4149e5d..0af885068e 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1334,6 +1334,11 @@ void LLMeshUploadThread::run() gMeshRepo.mDecompThread->submitRequest(request); } + while (!mPhysicsComplete) + { + apr_sleep(100); + } + //upload textures bool done = false; do -- cgit v1.2.3 From 894971c7b304a23d37fbfccbaaa1d75a93e01456 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 12 Oct 2010 15:08:01 -0500 Subject: SH-302 Fix for crash when uploading models with hundreds of meshes. --- indra/newview/llmeshrepository.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 0af885068e..77f89b01b3 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2762,8 +2762,6 @@ void LLPhysicsDecomp::submitRequest(LLPhysicsDecomp::Request* request) LLMutexLock lock(mMutex); mRequestQ.push(request); mSignal->signal(); - - } //static @@ -3074,8 +3072,11 @@ void LLPhysicsDecomp::run() mSignal->wait(); while (!mQuitting && !mRequestQ.empty()) { - mCurRequest = mRequestQ.front(); - mRequestQ.pop(); + { + LLMutexLock lock(mMutex); + mCurRequest = mRequestQ.front(); + mRequestQ.pop(); + } if (mCurRequest->mStage == "single_hull") { -- cgit v1.2.3 From a5619d16f74863168f45b04b37cc6383e1a92263 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Wed, 13 Oct 2010 07:24:37 -0400 Subject: correct licenses (fix problem with license change merge) --- indra/newview/llmeshrepository.cpp | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 77f89b01b3..e97fd52c7e 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2,31 +2,25 @@ * @file llmeshrepository.cpp * @brief Mesh repository implementation. * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -- cgit v1.2.3 From 997d66d348b3c6a19ecd2f5b092f68f645712eb1 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 15 Oct 2010 16:33:22 -0500 Subject: Fix for various crashes on exit and leaks when using convex decomposition. Make rendering of convex hullified prims work in physics shape display. Reviewed by Falcon. --- indra/newview/llmeshrepository.cpp | 40 ++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index e97fd52c7e..3c51781dfa 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -460,7 +460,7 @@ LLMeshRepoThread::~LLMeshRepoThread() void LLMeshRepoThread::run() { mCurlRequest = new LLCurlRequest(); - LLCDResult res = LLConvexDecomposition::initThread(); + LLCDResult res = LLConvexDecomposition::initThread(); if (res != LLCD_OK) { llwarns << "convex decomposition unable to be loaded" << llendl; @@ -1835,6 +1835,8 @@ void LLMeshRepository::init() { mMeshMutex = new LLMutex(NULL); + LLConvexDecomposition::getInstance()->initSystem(); + mDecompThread = new LLPhysicsDecomp(); mDecompThread->start(); @@ -1843,6 +1845,8 @@ void LLMeshRepository::init() apr_sleep(100); } + + mThread = new LLMeshRepoThread(); mThread->start(); } @@ -1870,6 +1874,8 @@ void LLMeshRepository::shutdown() delete mDecompThread; mDecompThread = NULL; } + + LLConvexDecomposition::quitSystem(); } @@ -2807,8 +2813,12 @@ void LLPhysicsDecomp::doDecomposition() //build parameter map std::map param_map; - const LLCDParam* params; - S32 param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); + static const LLCDParam* params = NULL; + static S32 param_count = 0; + if (!params) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); + } for (S32 i = 0; i < param_count; ++i) { @@ -2965,8 +2975,13 @@ void LLPhysicsDecomp::doDecompositionSingleHull() //set all parameters to default std::map param_map; - const LLCDParam* params; - S32 param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); + static const LLCDParam* params = NULL; + static S32 param_count = 0; + + if (!params) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶ms); + } LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); @@ -3048,13 +3063,18 @@ void LLPhysicsDecomp::doDecompositionSingleHull() void LLPhysicsDecomp::run() { - LLConvexDecomposition::initSystem(); + LLConvexDecomposition::getInstance()->initThread(); mInited = true; LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); - const LLCDStageData* stages; - S32 num_stages = decomp->getStages(&stages); + static const LLCDStageData* stages = NULL; + static S32 num_stages = 0; + + if (!stages) + { + num_stages = decomp->getStages(&stages); + } for (S32 i = 0; i < num_stages; i++) { @@ -3083,8 +3103,8 @@ void LLPhysicsDecomp::run() } } - LLConvexDecomposition::quitSystem(); - + LLConvexDecomposition::getInstance()->quitThread(); + //delete mSignal; delete mMutex; mSignal = NULL; -- cgit v1.2.3 From 028bb02a6b325f8a1079030414872ab20db944ca Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Sat, 16 Oct 2010 04:02:52 -0500 Subject: Better physics shape display. --- indra/newview/llmeshrepository.cpp | 326 ++++++++++++++++++++++++++++++++++++- 1 file changed, 320 insertions(+), 6 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 3c51781dfa..5f70fb6345 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -125,7 +125,7 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f) LLStrider pos; LLStrider norm; - + buff->getVertexStrider(pos); buff->getNormalStrider(norm); @@ -442,6 +442,24 @@ public: }; +class LLMeshPhysicsShapeResponder : public LLCurl::Responder +{ +public: + LLUUID mMeshID; + U32 mRequestedBytes; + U32 mOffset; + + LLMeshPhysicsShapeResponder(const LLUUID& id, U32 offset, U32 size) + : mMeshID(id), mRequestedBytes(size), mOffset(offset) + { + } + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer); + +}; + LLMeshRepoThread::LLMeshRepoThread() : LLThread("mesh repo", NULL) @@ -538,6 +556,19 @@ void LLMeshRepoThread::run() mDecompositionRequests = incomplete; } + { + std::set incomplete; + for (std::set::iterator iter = mPhysicsShapeRequests.begin(); iter != mPhysicsShapeRequests.end(); ++iter) + { + LLUUID mesh_id = *iter; + if (!fetchMeshPhysicsShape(mesh_id)) + { + incomplete.insert(mesh_id); + } + } + mPhysicsShapeRequests = incomplete; + } + } @@ -563,7 +594,13 @@ void LLMeshRepoThread::loadMeshDecomposition(const LLUUID& mesh_id) { //protected by mSignal, no locking needed here mDecompositionRequests.insert(mesh_id); } - + +void LLMeshRepoThread::loadMeshPhysicsShape(const LLUUID& mesh_id) +{ //protected by mSignal, no locking needed here + mPhysicsShapeRequests.insert(mesh_id); +} + + void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { //protected by mSignal, no locking needed here @@ -763,6 +800,82 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) return true; } +bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) +{ //protected by mMutex + mHeaderMutex->lock(); + + if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) + { //we have no header info for this mesh, do nothing + mHeaderMutex->unlock(); + return false; + } + + U32 header_size = mMeshHeaderSize[mesh_id]; + + if (header_size > 0) + { + S32 offset = header_size + mMeshHeader[mesh_id]["physics_shape"]["offset"].asInteger(); + S32 size = mMeshHeader[mesh_id]["physics_shape"]["size"].asInteger(); + + mHeaderMutex->unlock(); + + if (offset >= 0 && size > 0) + { + //check VFS for mesh physics shape 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) + bool zero = true; + for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) + { + zero = buffer[i] > 0 ? false : true; + } + + if (!zero) + { //attempt to parse + if (physicsShapeReceived(mesh_id, buffer, size)) + { + delete[] buffer; + return true; + } + } + + delete[] buffer; + } + + //reading from VFS failed for whatever reason, fetch from sim + std::vector headers; + headers.push_back("Accept: application/octet-stream"); + + std::string http_url = constructUrl(mesh_id); + if (!http_url.empty()) + { + ++sActiveLODRequests; + LLMeshRepository::sHTTPRequestCount++; + mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + } + } + else + { //no physics shape whatsoever, report back NULL + physicsShapeReceived(mesh_id, NULL, 0); + } + } + else + { + mHeaderMutex->unlock(); + } + + //early out was not hit, effectively fetched + return true; +} + bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) { bool retval = false; @@ -1166,6 +1279,12 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 d->mBaseHullMesh = get_vertex_buffer_from_mesh(mesh); } + else + { + //empty vertex buffer to indicate decomposition has been fetched + //but contains no base hull + d->mBaseHullMesh = new LLVertexBuffer(0, 0); + } mDecompositionQ.push(d); } @@ -1173,6 +1292,74 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 return true; } +bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size) +{ + LLSD physics_shape; + + LLMeshDecomposition* d = new LLMeshDecomposition(); + d->mMeshID = mesh_id; + + if (data == NULL) + { //no data, no physics shape exists + d->mPhysicsShapeMesh = new LLVertexBuffer(0,0); + } + else + { + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH); + LLPointer volume = new LLVolume(volume_params,0); + std::string mesh_string((char*) data, data_size); + std::istringstream stream(mesh_string); + + if (volume->unpackVolumeFaces(stream, data_size)) + { + //load volume faces into decomposition buffer + S32 vertex_count = 0; + S32 index_count = 0; + + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + vertex_count += face.mNumVertices; + index_count += face.mNumIndices; + } + + d->mPhysicsShapeMesh = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); + + d->mPhysicsShapeMesh->allocateBuffer(vertex_count, index_count, true); + + LLStrider pos; + LLStrider idx; + + d->mPhysicsShapeMesh->getVertexStrider(pos); + d->mPhysicsShapeMesh->getIndexStrider(idx); + + S32 idx_offset = 0; + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + if (idx_offset + face.mNumIndices > 65535) + { //avoid 16-bit index overflow + continue; + } + + LLVector4a::memcpyNonAliased16(pos[idx_offset].mV, face.mPositions[0].getF32ptr(), face.mNumVertices*sizeof(LLVector4a)); + + for (S32 i = 0; i < face.mNumIndices; ++i) + { + *idx++ = face.mIndices[i] + idx_offset; + } + + idx_offset += face.mNumVertices; + } + } + } + + mDecompositionQ.push(d); + return true; +} + LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints) : LLThread("mesh upload") @@ -1729,6 +1916,60 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r delete [] data; } +void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) +{ + S32 data_size = buffer->countAfter(channels.in(), NULL); + + if (status < 200 || status > 400) + { + llwarns << status << ": " << reason << llendl; + } + + if (data_size < mRequestedBytes) + { + if (status == 499 || status == 503) + { //timeout or service unavailable, try again + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID); + } + else + { + llwarns << "Unhandled status " << status << llendl; + } + return; + } + + LLMeshRepository::sBytesReceived += mRequestedBytes; + + U8* data = NULL; + + if (data_size > 0) + { + data = new U8[data_size]; + buffer->readAfter(channels.in(), NULL, data, data_size); + } + + if (gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size)) + { + //good fetch from sim, write to VFS for caching + LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); + + S32 offset = mOffset; + S32 size = mRequestedBytes; + + if (file.getSize() >= offset+size) + { + LLMeshRepository::sCacheBytesWritten += size; + file.seek(offset); + file.write(data, size); + } + } + + delete [] data; +} + void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) @@ -2096,6 +2337,13 @@ void LLMeshRepository::notifyLoadedMeshes() mPendingDecompositionRequests.pop(); } + //send physics shapes decomposition requests + while (!mPendingPhysicsShapeRequests.empty()) + { + mThread->loadMeshPhysicsShape(mPendingPhysicsShapeRequests.front()); + mPendingPhysicsShapeRequests.pop(); + } + mThread->notifyLoadedMeshes(); mThread->mMutex->unlock(); @@ -2110,9 +2358,45 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info) mLoadingSkins.erase(info.mMeshID); } +void LLMeshDecomposition::merge(const LLMeshDecomposition* rhs) +{ + if (!rhs) + { + return; + } + + if (mMeshID != rhs->mMeshID) + { + llerrs << "Attempted to merge with decomposition of some other mesh." << llendl; + } + + if (mBaseHull.empty()) + { //take base hull and decomposition from rhs + mHull = rhs->mHull; + mBaseHull = rhs->mBaseHull; + mMesh = rhs->mMesh; + mBaseHullMesh = rhs->mBaseHullMesh; + } + + if (mPhysicsShapeMesh.isNull()) + { //take physics shape mesh from rhs + mPhysicsShapeMesh = rhs->mPhysicsShapeMesh; + } +} + void LLMeshRepository::notifyDecompositionReceived(LLMeshDecomposition* decomp) { - mDecompositionMap[decomp->mMeshID] = decomp; + decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID); + if (iter == mDecompositionMap.end()) + { //just insert decomp into map + mDecompositionMap[decomp->mMeshID] = decomp; + } + else + { //merge decomp with existing entry + iter->second->merge(decomp); + delete decomp; + } + mLoadingDecompositions.erase(decomp->mMeshID); } @@ -2238,17 +2522,47 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id) return NULL; } +void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) +{ + if (mesh_id.notNull()) + { + LLMeshDecomposition* decomp = NULL; + decomposition_map::iterator iter = mDecompositionMap.find(mesh_id); + if (iter != mDecompositionMap.end()) + { + decomp = iter->second; + } + + //decomposition block hasn't been fetched yet + if (!decomp || decomp->mPhysicsShapeMesh.isNull()) + { + LLMutexLock lock(mMeshMutex); + //add volume to list of loading meshes + std::set::iterator iter = mLoadingPhysicsShapes.find(mesh_id); + if (iter == mLoadingPhysicsShapes.end()) + { //no request pending for this skin info + mLoadingPhysicsShapes.insert(mesh_id); + mPendingPhysicsShapeRequests.push(mesh_id); + } + } + } + +} + const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id) { + LLMeshDecomposition* ret = NULL; + if (mesh_id.notNull()) { decomposition_map::iterator iter = mDecompositionMap.find(mesh_id); if (iter != mDecompositionMap.end()) { - return iter->second; + ret = iter->second; } - //no skin info known about given mesh, try to fetch it + //decomposition block hasn't been fetched yet + if (!ret || ret->mBaseHullMesh.isNull()) { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes @@ -2261,7 +2575,7 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh } } - return NULL; + return ret; } void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail) -- cgit v1.2.3 From a3c84b5c582293bf54f4b98c36f6398f42c195d2 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 18 Oct 2010 17:45:25 -0500 Subject: Improved locking around command queues. --- indra/newview/llmeshrepository.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 5f70fb6345..28db665ff9 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -507,9 +507,10 @@ void LLMeshRepoThread::run() while (!mLODReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveLODRequests < sMaxConcurrentRequests) { { - LLMutexLock lock(mMutex); + mMutex->lock(); LODRequest req = mLODReqQ.front(); mLODReqQ.pop(); + mMutex->unlock(); if (fetchMeshLOD(req.mMeshParams, req.mLOD)) { count++; @@ -520,9 +521,10 @@ void LLMeshRepoThread::run() while (!mHeaderReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveHeaderRequests < sMaxConcurrentRequests) { { - LLMutexLock lock(mMutex); + mMutex->lock(); HeaderRequest req = mHeaderReqQ.front(); mHeaderReqQ.pop(); + mMutex->unlock(); if (fetchMeshHeader(req.mMeshParams)) { count++; @@ -530,7 +532,7 @@ void LLMeshRepoThread::run() } } - { + { //mSkinRequests is protected by mSignal std::set incomplete; for (std::set::iterator iter = mSkinRequests.begin(); iter != mSkinRequests.end(); ++iter) { @@ -543,7 +545,7 @@ void LLMeshRepoThread::run() mSkinRequests = incomplete; } - { + { //mDecompositionRequests is protected by mSignal std::set incomplete; for (std::set::iterator iter = mDecompositionRequests.begin(); iter != mDecompositionRequests.end(); ++iter) { @@ -556,7 +558,7 @@ void LLMeshRepoThread::run() mDecompositionRequests = incomplete; } - { + { //mPhysicsShapeRequests is protected by mSignal std::set incomplete; for (std::set::iterator iter = mPhysicsShapeRequests.begin(); iter != mPhysicsShapeRequests.end(); ++iter) { @@ -608,7 +610,10 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (iter != mMeshHeader.end()) { //if we have the header, request LOD byte range LODRequest req(mesh_params, lod); - mLODReqQ.push(req); + { + LLMutexLock lock(mMutex); + mLODReqQ.push(req); + } } else { @@ -626,6 +631,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) } else { //if no header request is pending, fetch header + LLMutexLock lock(mMutex); mHeaderReqQ.push(req); mPendingLOD[mesh_params].push_back(lod); } @@ -1043,6 +1049,7 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat pending_lod_map::iterator iter = mPendingLOD.find(mesh_params); if (iter != mPendingLOD.end()) { + LLMutexLock lock(mMutex); for (U32 i = 0; i < iter->second.size(); ++i) { LODRequest req(mesh_params, iter->second[i]); @@ -1999,6 +2006,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, { //retry LLMeshRepository::sHTTPRetryCount++; LLMeshRepoThread::HeaderRequest req(mMeshParams); + LLMutexLock lock(gMeshRepo.mThread->mMutex); gMeshRepo.mThread->mHeaderReqQ.push(req); } } @@ -2401,7 +2409,7 @@ void LLMeshRepository::notifyDecompositionReceived(LLMeshDecomposition* decomp) } void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume) -{ +{ //called from main thread S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail()); //get list of objects waiting to be notified this mesh is loaded @@ -2444,7 +2452,7 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol } void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod) -{ +{ //called from main thread //get list of objects waiting to be notified this mesh is loaded mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_params); @@ -2926,12 +2934,16 @@ LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) object_params["extra_parameters"].append(extra_parameter); LLPermissions perm; - perm.setNextOwnerBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getNextOwnerPerms()); - perm.setGroupBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getGroupPerms()); - perm.setEveryoneBits(gAgent.getID(), LLUUID::null, TRUE, LLFloaterPerms::getEveryonePerms()); perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false); perm.setCreator(gAgent.getID()); + perm.initMasks(PERM_ITEM_UNRESTRICTED, //base + PERM_ITEM_UNRESTRICTED, //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); -- cgit v1.2.3 From 256c6e6a252feaa7ae50f81778aab1e0246a526a Mon Sep 17 00:00:00 2001 From: Jonathan Wolk Date: Tue, 19 Oct 2010 11:29:42 -0700 Subject: Moved retry logic for certain mesh header fetches to help with SH-323 'Some mesh objects fail to load data for valid meshes'. Renamed some variables to be more clear. --- indra/newview/llmeshrepository.cpp | 61 ++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 22 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 28db665ff9..5e95376830 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1031,6 +1031,8 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat } else { + llinfos + << "Marking header as non-existent, will not retry." << llendl; header["404"] = 1; } @@ -1984,7 +1986,25 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, LLMeshRepoThread::sActiveHeaderRequests--; if (status < 200 || status > 400) { - llwarns << status << ": " << reason << llendl; + llwarns + << "Header responder failed with status: " + << status << ": " << reason << llendl; + + // 503 (service unavailable) or 499 (timeout) + // can be due to server load and can be retried + + // TODO*: Add maximum retry logic, exponential backoff + // and (somewhat more optional than the others) retries + // again after some set period of time + if (status == 503 || status == 499) + { //retry + LLMeshRepository::sHTTPRetryCount++; + LLMeshRepoThread::HeaderRequest req(mMeshParams); + LLMutexLock lock(gMeshRepo.mThread->mMutex); + gMeshRepo.mThread->mHeaderReqQ.push(req); + + return; + } } S32 data_size = buffer->countAfter(channels.in(), NULL); @@ -2001,14 +2021,9 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, if (!gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size)) { - llwarns << "Header responder failed with status: " << status << ": " << reason << llendl; - if (status == 503 || status == 499) - { //retry - LLMeshRepository::sHTTPRetryCount++; - LLMeshRepoThread::HeaderRequest req(mMeshParams); - LLMutexLock lock(gMeshRepo.mThread->mMutex); - gMeshRepo.mThread->mHeaderReqQ.push(req); - } + llwarns + << "Unable to parse mesh header: " + << status << ": " << reason << llendl; } else if (data && data_size > 0) { @@ -2660,20 +2675,22 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) { //write model file to memory buffer std::stringstream ostr; - - LLModel::physics_shape& phys_shape = data.mModel[LLModel::LOD_PHYSICS].notNull() ? - data.mModel[LLModel::LOD_PHYSICS]->mPhysicsShape : - data.mBaseModel->mPhysicsShape; + + LLModel::convex_hull_decomposition& decomp = + data.mModel[LLModel::LOD_PHYSICS].notNull() ? + data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + data.mBaseModel->mConvexHullDecomp; LLModel::hull dummy_hull; - LLSD header = LLModel::writeModel(ostr, + LLSD header = LLModel::writeModel( + ostr, data.mModel[LLModel::LOD_PHYSICS], data.mModel[LLModel::LOD_HIGH], data.mModel[LLModel::LOD_MEDIUM], data.mModel[LLModel::LOD_LOW], data.mModel[LLModel::LOD_IMPOSTOR], - phys_shape, + decomp, dummy_hull, mUploadSkin, mUploadJoints, @@ -2750,19 +2767,19 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) { std::stringstream ostr; - LLModel::physics_shape& phys_shape = data.mModel[LLModel::LOD_PHYSICS].notNull() ? - data.mModel[LLModel::LOD_PHYSICS]->mPhysicsShape : - data.mBaseModel->mPhysicsShape; - - + LLModel::convex_hull_decomposition& decomp = + data.mModel[LLModel::LOD_PHYSICS].notNull() ? + data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + data.mBaseModel->mConvexHullDecomp; - LLModel::writeModel(ostr, + 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], - phys_shape, + decomp, mHullMap[data.mBaseModel], mUploadSkin, mUploadJoints); -- cgit v1.2.3 From 9db8e12f3381cdf928b422e7c6e9b400cb155d52 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 19 Oct 2010 14:16:24 -0500 Subject: CTS-283 Fix for objects being locked when imported. --- indra/newview/llmeshrepository.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 28db665ff9..08740a4e12 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2937,13 +2937,12 @@ LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false); perm.setCreator(gAgent.getID()); - perm.initMasks(PERM_ITEM_UNRESTRICTED, //base - PERM_ITEM_UNRESTRICTED, //owner + perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base + PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner LLFloaterPerms::getEveryonePerms(), LLFloaterPerms::getGroupPerms(), - LLFloaterPerms::getNextOwnerPerms()); - - + LLFloaterPerms::getNextOwnerPerms()); + object_params["permissions"] = ll_create_sd_from_permissions(perm); object_params["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); -- cgit v1.2.3 From 94c1670934bc3a00e45823784cb8c25dea7908f0 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 19 Oct 2010 23:19:10 -0500 Subject: Don't call getCapability from a background thread. --- indra/newview/llmeshrepository.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 72019d8de8..1885b48812 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -645,7 +645,7 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id) if (gAgent.getRegion()) { - http_url = gAgent.getRegion()->getCapability("GetMesh"); + http_url = gMeshRepo.mGetMeshCapability; scrub_host_name(http_url, gAgent.getRegionHost()); } @@ -2275,6 +2275,12 @@ void LLMeshRepository::notifyLoadedMeshes() return; } + if (gAgent.getRegion()) + { //update capability url + //TODO: only do this when region changes + mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh"); + } + LLFastTimer t(FTM_MESH_UPDATE); { -- cgit v1.2.3 From ce667514032510ff1ae47daf0f2727933be849bc Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 11 Nov 2010 11:22:35 -0600 Subject: Fix for crash in curl. --- indra/newview/llmeshrepository.cpp | 67 ++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 21 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 1885b48812..94ed2697c5 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -103,16 +103,36 @@ U32 get_volume_memory_size(const LLVolume* volume) return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces(); } -std::string scrub_host_name(std::string http_url, const LLHost& host) +std::string scrub_host_name(std::string http_url) { //curl loves to abuse the DNS cache, so scrub host names out of urls where trivial to prevent DNS timeouts - std::string ip_string = host.getIPString(); - std::string host_string = host.getHostName(); + + if (!http_url.empty()) + { + std::string::size_type begin_host = http_url.find("://")+3; + std::string host_string = http_url.substr(begin_host); - std::string::size_type idx = http_url.find(host_string); + std::string::size_type end_host = host_string.find(":"); + if (end_host == std::string::npos) + { + end_host = host_string.find("/"); + } - if (!ip_string.empty() && !host_string.empty() && idx != std::string::npos) - { - http_url.replace(idx, host_string.length(), ip_string); + host_string = host_string.substr(0, end_host); + + std::string::size_type idx = http_url.find(host_string); + + hostent* ent = gethostbyname(host_string.c_str()); + + if (ent && ent->h_length > 0) + { + U8* addr = (U8*) ent->h_addr_list[0]; + + std::string ip_string = llformat("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); + if (!ip_string.empty() && !host_string.empty() && idx != std::string::npos) + { + http_url.replace(idx, host_string.length(), ip_string); + } + } } return http_url; @@ -571,10 +591,8 @@ void LLMeshRepoThread::run() mPhysicsShapeRequests = incomplete; } - + mCurlRequest->process(); } - - mCurlRequest->process(); } res = LLConvexDecomposition::quitThread(); @@ -646,7 +664,6 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id) if (gAgent.getRegion()) { http_url = gMeshRepo.mGetMeshCapability; - scrub_host_name(http_url, gAgent.getRegionHost()); } if (!http_url.empty()) @@ -1385,13 +1402,14 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mFinished = false; mOrigin = gAgent.getPositionAgent(); mHost = gAgent.getRegionHost(); + mUploadObjectAssetCapability = gAgent.getRegion()->getCapability("UploadObjectAsset"); mNewInventoryCapability = gAgent.getRegion()->getCapability("NewFileAgentInventoryVariablePrice"); + mUploadObjectAssetCapability = scrub_host_name(mUploadObjectAssetCapability); + mNewInventoryCapability = scrub_host_name(mNewInventoryCapability); + mOrigin += gAgent.getAtAxis() * scale.magVec(); - - scrub_host_name(mUploadObjectAssetCapability, mHost); - scrub_host_name(mNewInventoryCapability, mHost); } LLMeshUploadThread::~LLMeshUploadThread() @@ -1986,9 +2004,9 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, LLMeshRepoThread::sActiveHeaderRequests--; if (status < 200 || status > 400) { - llwarns - << "Header responder failed with status: " - << status << ": " << reason << llendl; + //llwarns + // << "Header responder failed with status: " + // << status << ": " << reason << llendl; // 503 (service unavailable) or 499 (timeout) // can be due to server load and can be retried @@ -2275,10 +2293,17 @@ void LLMeshRepository::notifyLoadedMeshes() return; } + static std::string region_name("never name a region this"); + if (gAgent.getRegion()) { //update capability url - //TODO: only do this when region changes - mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh"); + if (gAgent.getRegion()->getName() != region_name) + { + region_name = gAgent.getRegion()->getName(); + + mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh"); + mGetMeshCapability = scrub_host_name(mGetMeshCapability); + } } LLFastTimer t(FTM_MESH_UPDATE); @@ -2977,7 +3002,7 @@ void LLMeshUploadThread::priceResult(LLMeshUploadData& data, const LLSD& content { mPendingCost += content["upload_price"].asInteger(); data.mRSVP = content["rsvp"].asString(); - data.mRSVP = scrub_host_name(data.mRSVP, mHost); + data.mRSVP = scrub_host_name(data.mRSVP); mConfirmedQ.push(data); } @@ -2986,7 +3011,7 @@ void LLMeshUploadThread::priceResult(LLTextureUploadData& data, const LLSD& cont { mPendingCost += content["upload_price"].asInteger(); data.mRSVP = content["rsvp"].asString(); - data.mRSVP = scrub_host_name(data.mRSVP, mHost); + data.mRSVP = scrub_host_name(data.mRSVP); mConfirmedTextureQ.push(data); } -- cgit v1.2.3 From ace36d042e0cd2443ddd07e0bd43d1086a81adcd Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Fri, 12 Nov 2010 17:42:33 -0500 Subject: BUILDFIX allow curl host name scrub to work on non-windows platforms Needed an include for gethostbyname to be called properly. --- indra/newview/llmeshrepository.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 94ed2697c5..f00a8565f7 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -59,6 +59,9 @@ #include "material_codes.h" #include "pipeline.h" +#ifndef LL_WINDOWS +#include "netdb.h" +#endif #include -- cgit v1.2.3 From 29852bc012afbed303159b895ae8dc9448500ca5 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 17 Nov 2010 15:01:41 -0500 Subject: SH-476 FIX. Map tiles were failing when numeric addrs were substituted in amazon S3 image queries --- indra/newview/llmeshrepository.cpp | 54 +++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 24 deletions(-) mode change 100644 => 100755 indra/newview/llmeshrepository.cpp (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp old mode 100644 new mode 100755 index 94ed2697c5..b26f2dd0de --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -105,36 +105,42 @@ U32 get_volume_memory_size(const LLVolume* volume) std::string scrub_host_name(std::string http_url) { //curl loves to abuse the DNS cache, so scrub host names out of urls where trivial to prevent DNS timeouts + + if (http_url.empty()) + { + return http_url; + } + // Not safe to scrub amazon paths + if (http_url.find("s3.amazonaws.com") != std::string::npos) + { + return http_url; + } + std::string::size_type begin_host = http_url.find("://")+3; + std::string host_string = http_url.substr(begin_host); - if (!http_url.empty()) + std::string::size_type end_host = host_string.find(":"); + if (end_host == std::string::npos) { - std::string::size_type begin_host = http_url.find("://")+3; - std::string host_string = http_url.substr(begin_host); - - std::string::size_type end_host = host_string.find(":"); - if (end_host == std::string::npos) - { - end_host = host_string.find("/"); - } - - host_string = host_string.substr(0, end_host); + end_host = host_string.find("/"); + } + + host_string = host_string.substr(0, end_host); + + std::string::size_type idx = http_url.find(host_string); + + hostent* ent = gethostbyname(host_string.c_str()); + + if (ent && ent->h_length > 0) + { + U8* addr = (U8*) ent->h_addr_list[0]; - std::string::size_type idx = http_url.find(host_string); - - hostent* ent = gethostbyname(host_string.c_str()); - - if (ent && ent->h_length > 0) + std::string ip_string = llformat("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); + if (!ip_string.empty() && !host_string.empty() && idx != std::string::npos) { - U8* addr = (U8*) ent->h_addr_list[0]; - - std::string ip_string = llformat("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); - if (!ip_string.empty() && !host_string.empty() && idx != std::string::npos) - { - http_url.replace(idx, host_string.length(), ip_string); - } + http_url.replace(idx, host_string.length(), ip_string); } } - + return http_url; } -- cgit v1.2.3 From 48e2ec0340272efcb5caa7c5affaabfbf8d69c78 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Wed, 17 Nov 2010 20:04:30 -0500 Subject: SH-480 FIX meshes are not added to objects folder on upload curl host scrubbing was causing object creation for mesh prims to fail. Commenting out the offending lines so we can have a functional release. Will file a separate bug for Vir to investigate when/if we can re-enable host scrubbing on these URLs for a future release. Approach approved by davep. --- indra/newview/llmeshrepository.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index f00a8565f7..1313033f4e 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1409,8 +1409,8 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadObjectAssetCapability = gAgent.getRegion()->getCapability("UploadObjectAsset"); mNewInventoryCapability = gAgent.getRegion()->getCapability("NewFileAgentInventoryVariablePrice"); - mUploadObjectAssetCapability = scrub_host_name(mUploadObjectAssetCapability); - mNewInventoryCapability = scrub_host_name(mNewInventoryCapability); + //mUploadObjectAssetCapability = scrub_host_name(mUploadObjectAssetCapability); + //mNewInventoryCapability = scrub_host_name(mNewInventoryCapability); mOrigin += gAgent.getAtAxis() * scale.magVec(); } -- cgit v1.2.3 From 6866900e9267fd9d2b694e3d68187d4bb0162424 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Sun, 21 Nov 2010 00:09:33 -0600 Subject: Fix for crash when uploading textures via importer. Uploads still fail, though, fix just makes them stop trying after 5 retries when getting 499 or 500 status codes. --- indra/newview/llmeshrepository.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 2f432ba0be..1ff11f2c01 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -80,6 +80,8 @@ U32 LLMeshRepository::sCacheBytesWritten = 0; U32 LLMeshRepository::sPeakKbps = 0; +const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5; + std::string header_lod[] = { "lowest_lod", @@ -245,15 +247,23 @@ public: else { llwarns << status << ": " << reason << llendl; - llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; - - if (status == 499) + + if (mData.mRetries < MAX_TEXTURE_UPLOAD_RETRIES) { - mThread->uploadTexture(mData); + llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; + + if (status == 499 || status == 500) + { + mThread->uploadTexture(mData); + } + else + { + llerrs << "Unhandled status " << status << llendl; + } } else - { - llerrs << "Unhandled status " << status << llendl; + { + llwarns << "Giving up after " << mData.mRetries << " retries." << llendl; } } } -- cgit v1.2.3 From fae00f8c794c067f7a6c72032698c9c413be041c Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 24 Nov 2010 09:03:14 -0500 Subject: SH-564 WIP - scrubbing not needed if curl uses thread-safe c-ares lib --- indra/newview/llmeshrepository.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 1ff11f2c01..2f355520ff 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -110,7 +110,7 @@ U32 get_volume_memory_size(const LLVolume* volume) std::string scrub_host_name(std::string http_url) { //curl loves to abuse the DNS cache, so scrub host names out of urls where trivial to prevent DNS timeouts - +#if 0 if (http_url.empty()) { return http_url; @@ -145,6 +145,7 @@ std::string scrub_host_name(std::string http_url) http_url.replace(idx, host_string.length(), ip_string); } } +#endif return http_url; } -- cgit v1.2.3 From 689555fda2d580808ef4b9012b14716b4d1193e5 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 29 Nov 2010 11:54:58 -0600 Subject: Get rid of some redudnant calls to constructUrl --- indra/newview/llmeshrepository.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 1ff11f2c01..d8aeb1bf81 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -828,7 +828,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) { ++sActiveLODRequests; LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + mCurlRequest->getByteRange(http_url, headers, offset, size, new LLMeshDecompositionResponder(mesh_id, offset, size)); } } @@ -900,7 +900,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) { ++sActiveLODRequests; LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + mCurlRequest->getByteRange(http_url, headers, offset, size, new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); } } -- cgit v1.2.3 From 32d496e472d1b49b713832c9d239334cf6288542 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 29 Nov 2010 16:24:52 -0500 Subject: removed scrub_host_name --- indra/newview/llmeshrepository.cpp | 48 -------------------------------------- 1 file changed, 48 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 2f355520ff..17be8586b5 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -108,48 +108,6 @@ U32 get_volume_memory_size(const LLVolume* volume) return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces(); } -std::string scrub_host_name(std::string http_url) -{ //curl loves to abuse the DNS cache, so scrub host names out of urls where trivial to prevent DNS timeouts -#if 0 - if (http_url.empty()) - { - return http_url; - } - // Not safe to scrub amazon paths - if (http_url.find("s3.amazonaws.com") != std::string::npos) - { - return http_url; - } - std::string::size_type begin_host = http_url.find("://")+3; - std::string host_string = http_url.substr(begin_host); - - std::string::size_type end_host = host_string.find(":"); - if (end_host == std::string::npos) - { - end_host = host_string.find("/"); - } - - host_string = host_string.substr(0, end_host); - - std::string::size_type idx = http_url.find(host_string); - - hostent* ent = gethostbyname(host_string.c_str()); - - if (ent && ent->h_length > 0) - { - U8* addr = (U8*) ent->h_addr_list[0]; - - std::string ip_string = llformat("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); - if (!ip_string.empty() && !host_string.empty() && idx != std::string::npos) - { - http_url.replace(idx, host_string.length(), ip_string); - } - } -#endif - - return http_url; -} - LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f) { LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0); @@ -1426,9 +1384,6 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadObjectAssetCapability = gAgent.getRegion()->getCapability("UploadObjectAsset"); mNewInventoryCapability = gAgent.getRegion()->getCapability("NewFileAgentInventoryVariablePrice"); - //mUploadObjectAssetCapability = scrub_host_name(mUploadObjectAssetCapability); - //mNewInventoryCapability = scrub_host_name(mNewInventoryCapability); - mOrigin += gAgent.getAtAxis() * scale.magVec(); } @@ -2322,7 +2277,6 @@ void LLMeshRepository::notifyLoadedMeshes() region_name = gAgent.getRegion()->getName(); mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh"); - mGetMeshCapability = scrub_host_name(mGetMeshCapability); } } @@ -3022,7 +2976,6 @@ void LLMeshUploadThread::priceResult(LLMeshUploadData& data, const LLSD& content { mPendingCost += content["upload_price"].asInteger(); data.mRSVP = content["rsvp"].asString(); - data.mRSVP = scrub_host_name(data.mRSVP); mConfirmedQ.push(data); } @@ -3031,7 +2984,6 @@ void LLMeshUploadThread::priceResult(LLTextureUploadData& data, const LLSD& cont { mPendingCost += content["upload_price"].asInteger(); data.mRSVP = content["rsvp"].asString(); - data.mRSVP = scrub_host_name(data.mRSVP); mConfirmedTextureQ.push(data); } -- cgit v1.2.3 From 1be5133116c7e63bc621a4017bedaebf557c83db Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Wed, 8 Dec 2010 21:24:02 -0800 Subject: SH-541 - Physics mesh display shows inconsistent data. The object UI was allowing the user to set 'prim' physics for meshes for which no user physics had been uploaded, or decomposed. It defaulted to convex hull in that case. The fix is to fix the UI to disallow 'prim' for meshes without physics meshes, limiting those to only convex hull and none. We will also redo the task validation to detect invalid states related to this as part of the 'redo the validation' work --- indra/newview/llmeshrepository.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 1ff11f2c01..8d5ef4ae3d 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2667,6 +2667,12 @@ void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail) LLPrimitive::sVolumeManager->unrefVolume(volume); } +bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id) +{ + LLSD mesh = mThread->getMeshHeader(mesh_id); + return mesh.has("physics_shape") && mesh["physics_shape"].has("size") && (mesh["physics_shape"]["size"].asInteger() > 0); +} + const LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id) { return mThread->getMeshHeader(mesh_id); -- cgit v1.2.3 From 5f8110a68ed2fdfe70e2dbd7363f1194b0f3e67d Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 14 Dec 2010 15:52:26 -0500 Subject: SH-439 FIX: track name requested in UI separately, so we can fall back to name from dae if needed --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 0ee0d8393e..4873eaeabd 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2920,7 +2920,7 @@ LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) 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.mModel->mLabel; + object_params["name"] = instance.mModel->getName(); // load material from dae file object_params["facelist"] = LLSD::emptyArray(); -- cgit v1.2.3 From e1b1db9575945fa8436b4ebabf55242635b61f38 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 22 Dec 2010 01:05:35 -0600 Subject: SH-636 Update physics tab to new spec, move "completed" physics decomp callbacks to main thread, add object model to decomposition tool, make imported model scales non-uniform. --- indra/newview/llmeshrepository.cpp | 55 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 13 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 4873eaeabd..861db7fd5d 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1396,6 +1396,7 @@ LLMeshUploadThread::DecompRequest::DecompRequest(LLModel* mdl, LLModel* base_mod { mStage = "single_hull"; mModel = mdl; + mDecompID = &mdl->mDecompID; mBaseModel = base_model; mThread = thread; @@ -2262,6 +2263,9 @@ void LLMeshRepository::notifyLoadedMeshes() mInventoryQ.pop(); } } + + //call completed callbacks on finished decompositions + mDecompThread->notifyCompleted(); if (!mThread->mWaiting) { //curl thread is churning, wait for it to go idle @@ -3229,9 +3233,8 @@ void LLPhysicsDecomp::doDecomposition() mCurRequest->mHullMesh.clear(); mCurRequest->setStatusMessage("FAIL"); - mCurRequest->completed(); - - mCurRequest = NULL; + + completeCurrent(); } else { @@ -3282,13 +3285,33 @@ void LLPhysicsDecomp::doDecomposition() LLMutexLock lock(mMutex); mCurRequest->setStatusMessage("FAIL"); - mCurRequest->completed(); - - mCurRequest = NULL; + completeCurrent(); + } + } +} + +void LLPhysicsDecomp::completeCurrent() +{ + LLMutexLock lock(mMutex); + mCompletedQ.push(mCurRequest); + mCurRequest = NULL; +} + +void LLPhysicsDecomp::notifyCompleted() +{ + if (!mCompletedQ.empty()) + { + LLMutexLock lock(mMutex); + while (!mCompletedQ.empty()) + { + Request* req = mCompletedQ.front(); + req->completed(); + mCompletedQ.pop(); } } } + void make_box(LLPhysicsDecomp::Request * request) { LLVector3 min,max; @@ -3406,18 +3429,17 @@ void LLPhysicsDecomp::doDecompositionSingleHull() { - LLMutexLock lock(mMutex); - mCurRequest->completed(); - mCurRequest = NULL; + completeCurrent(); + } } + void LLPhysicsDecomp::run() { - LLConvexDecomposition::getInstance()->initThread(); - mInited = true; - LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); + decomp->initThread(); + mInited = true; static const LLCDStageData* stages = NULL; static S32 num_stages = 0; @@ -3443,6 +3465,13 @@ void LLPhysicsDecomp::run() mRequestQ.pop(); } + S32& id = *(mCurRequest->mDecompID); + if (id == -1) + { + decomp->genDecomposition(id); + } + decomp->bindDecomposition(id); + if (mCurRequest->mStage == "single_hull") { doDecompositionSingleHull(); @@ -3454,7 +3483,7 @@ void LLPhysicsDecomp::run() } } - LLConvexDecomposition::getInstance()->quitThread(); + decomp->quitThread(); //delete mSignal; delete mMutex; -- cgit v1.2.3 From 8ba0baa63109d5e45c1f3cfd75c7d230ff99031f Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 22 Dec 2010 10:55:48 -0700 Subject: fix for SH-648: Crash on exit in LLViewerFetchedTexture (ref count error) --- indra/newview/llmeshrepository.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 4873eaeabd..2815054865 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1486,7 +1486,7 @@ void LLMeshUploadThread::run() { textures.insert(material_iter->mDiffuseMap); - LLTextureUploadData data(material_iter->mDiffuseMap, material_iter->mDiffuseMapLabel); + LLTextureUploadData data(material_iter->mDiffuseMap.get(), material_iter->mDiffuseMapLabel); uploadTexture(data); } } @@ -2135,6 +2135,24 @@ void LLMeshRepository::shutdown() LLConvexDecomposition::quitSystem(); } +//called in the main thread. +S32 LLMeshRepository::update() +{ + if(mUploadWaitList.empty()) + { + return 0 ; + } + + S32 size = mUploadWaitList.size() ; + for (S32 i = 0; i < size; ++i) + { + mUploads.push_back(mUploadWaitList[i]); + mUploadWaitList[i]->start() ; + } + mUploadWaitList.clear() ; + + return size ; +} S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail) { @@ -2654,8 +2672,7 @@ void LLMeshRepository::uploadModel(std::vector& data, LLVector3 bool upload_skin, bool upload_joints) { LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints); - mUploads.push_back(thread); - thread->start(); + mUploadWaitList.push_back(thread); } S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) @@ -2742,7 +2759,7 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data) { - if (data.mTexture.notNull() && data.mTexture->getDiscardLevel() >= 0) + if (data.mTexture && data.mTexture->getDiscardLevel() >= 0) { LLSD asset_resources = LLSD::emptyMap(); -- cgit v1.2.3 From 961e50aab40fe09632e4f3f9aa385abd0fb42735 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 4 Jan 2011 16:22:38 -0700 Subject: clear some LLPointer issues for SH-694: check if there are any other LLPointer issues in the mesh model uploading flow and fix them if exist. --- indra/newview/llmeshrepository.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index dd2dcffc28..d2f76eceb0 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1450,17 +1450,21 @@ void LLMeshUploadThread::DecompRequest::completed() mThread->mHullMap[mBaseModel] = mHull[0]; } -void LLMeshUploadThread::run() +//called in the main thread. +void LLMeshUploadThread::preStart() { - mCurlRequest = new LLCurlRequest(); - //build map of LLModel refs to instances for callbacks for (instance_list::iterator iter = mInstanceList.begin(); iter != mInstanceList.end(); ++iter) { mInstance[iter->mModel].push_back(*iter); } +} + +void LLMeshUploadThread::run() +{ + mCurlRequest = new LLCurlRequest(); - std::set > textures; + std::set textures; //populate upload queue with relevant models for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) @@ -1483,9 +1487,9 @@ void LLMeshUploadThread::run() material_iter != instance.mMaterial.end(); ++material_iter) { - if (textures.find(material_iter->mDiffuseMap) == textures.end()) + if (textures.find(material_iter->mDiffuseMap.get()) == textures.end()) { - textures.insert(material_iter->mDiffuseMap); + textures.insert(material_iter->mDiffuseMap.get()); LLTextureUploadData data(material_iter->mDiffuseMap.get(), material_iter->mDiffuseMapLabel); uploadTexture(data); @@ -2148,6 +2152,7 @@ S32 LLMeshRepository::update() for (S32 i = 0; i < size; ++i) { mUploads.push_back(mUploadWaitList[i]); + mUploadWaitList[i]->preStart() ; mUploadWaitList[i]->start() ; } mUploadWaitList.clear() ; -- cgit v1.2.3 From 53d03606f13d52b4282e91e391eb761dbd96a1ad Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Fri, 14 Jan 2011 13:23:14 -0500 Subject: SH-557 FIX meshes sometimes don't load in a region Found that we were storing an empty string as a getMesh capability in the case that we checked for the new url before getting the list of caps from the server after a teleport. Made sure we didn't overwrite the caps url until we have the list of caps for the new region after teleport. Will be post-reviewed by davep --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index d2f76eceb0..b772999ee2 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2299,7 +2299,7 @@ void LLMeshRepository::notifyLoadedMeshes() if (gAgent.getRegion()) { //update capability url - if (gAgent.getRegion()->getName() != region_name) + if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived()) { region_name = gAgent.getRegion()->getName(); -- cgit v1.2.3 From 1a51db5b53b3783b002bfa870fa45244df8fafdc Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 1 Feb 2011 02:33:14 -0600 Subject: SH-641 Cosmetic fix -- keep showing last rendered mesh LoD if requested LoD is unavailable. --- indra/newview/llmeshrepository.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index b772999ee2..edcf249a21 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2160,7 +2160,7 @@ S32 LLMeshRepository::update() return size ; } -S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail) +S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod) { if (detail < 0 || detail > 4) { @@ -2201,7 +2201,19 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para if (group) { - //first see what the next lowest LOD available might be + //first, see if last_lod is available (don't transition down to avoid funny popping a la SH-641) + if (last_lod >= 0) + { + LLVolume* lod = group->refLOD(last_lod); + if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) + { + group->derefLOD(lod); + return last_lod; + } + group->derefLOD(lod); + } + + //next, see what the next lowest LOD available might be for (S32 i = detail-1; i >= 0; --i) { LLVolume* lod = group->refLOD(i); -- cgit v1.2.3 From d94117b80b67b6d27d2b2e14fb420682474e439e Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Feb 2011 20:06:46 -0600 Subject: SH-920 Wait for threads to shut down before deleting them -- also, fix some assertions that were encouraging people to comment out the destruction of LLSignal. --- indra/newview/llmeshrepository.cpp | 49 ++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index edcf249a21..a2b0ac09af 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -470,7 +470,12 @@ LLMeshRepoThread::LLMeshRepoThread() LLMeshRepoThread::~LLMeshRepoThread() { - + delete mMutex; + mMutex = NULL; + delete mHeaderMutex; + mHeaderMutex = NULL; + delete mSignal; + mSignal = NULL; } void LLMeshRepoThread::run() @@ -573,6 +578,11 @@ void LLMeshRepoThread::run() } } + if (mSignal->isLocked()) + { //make sure to let go of the mutex associated with the given signal before shutting down + mSignal->unlock(); + } + res = LLConvexDecomposition::quitThread(); if (res != LLCD_OK) { @@ -580,7 +590,7 @@ void LLMeshRepoThread::run() } delete mCurlRequest; - delete mMutex; + mCurlRequest = NULL; } void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id) @@ -2115,13 +2125,24 @@ void LLMeshRepository::init() void LLMeshRepository::shutdown() { - mThread->mSignal->signal(); + llinfos << "Shutting down mesh repository." << llendl; + mThread->mSignal->signal(); + + while (!mThread->isStopped()) + { + apr_sleep(10); + } delete mThread; mThread = NULL; for (U32 i = 0; i < mUploads.size(); ++i) { + llinfos << "Waiting for pending mesh upload " << i << "/" << mUploads.size() << llendl; + while (!mUploads[i]->isStopped()) + { + apr_sleep(10); + } delete mUploads[i]; } @@ -2130,9 +2151,11 @@ void LLMeshRepository::shutdown() delete mMeshMutex; mMeshMutex = NULL; + llinfos << "Shutting down decomposition system." << llendl; + if (mDecompThread) { - mDecompThread->shutdown(); + mDecompThread->shutdown(); delete mDecompThread; mDecompThread = NULL; } @@ -3130,6 +3153,11 @@ LLPhysicsDecomp::LLPhysicsDecomp() LLPhysicsDecomp::~LLPhysicsDecomp() { shutdown(); + + delete mSignal; + mSignal = NULL; + delete mMutex; + mMutex = NULL; } void LLPhysicsDecomp::shutdown() @@ -3139,9 +3167,9 @@ void LLPhysicsDecomp::shutdown() mQuitting = true; mSignal->signal(); - while (!mDone) + while (!isStopped()) { - apr_sleep(100); + apr_sleep(10); } } } @@ -3519,10 +3547,11 @@ void LLPhysicsDecomp::run() decomp->quitThread(); - //delete mSignal; - delete mMutex; - mSignal = NULL; - mMutex = NULL; + if (mSignal->isLocked()) + { //let go of mSignal's associated mutex + mSignal->unlock(); + } + mDone = true; } -- cgit v1.2.3 From c690c30ec173faf8d8087ecb38cadbb9dd1adb4e Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 22 Feb 2011 18:33:33 -0600 Subject: SH-438 Use node name instead of mesh name for object names when importing meshes. --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a2b0ac09af..b6e3626cba 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2981,7 +2981,7 @@ LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) 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.mModel->getName(); + object_params["name"] = instance.mLabel; // load material from dae file object_params["facelist"] = LLSD::emptyArray(); -- cgit v1.2.3 From bcc54d496490c501bb212466ff1bc5a143b12a4f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 11 Mar 2011 16:39:03 -0600 Subject: SH-477 Put estimated streaming cost back in the debug display -- use newfangled equation. --- indra/newview/llmeshrepository.cpp | 39 ++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index b6e3626cba..e259ee9846 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3100,9 +3100,7 @@ F32 LLMeshRepository::getStreamingCost(const LLSD& header, F32 radius) F32 dlowest = llmin(radius/0.06f, 256.f); F32 dlow = llmin(radius/0.24f, 256.f); F32 dmid = llmin(radius/1.0f, 256.f); - F32 dhigh = 0.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; @@ -3128,14 +3126,35 @@ F32 LLMeshRepository::getStreamingCost(const LLSD& header, F32 radius) bytes_lowest = bytes_low; } - F32 cost = 0.f; - cost += llmax(256.f-dlowest, 1.f)/32.f*bytes_lowest; - cost += llmax(dlowest-dlow, 1.f)/32.f*bytes_low; - cost += llmax(dlow-dmid, 1.f)/32.f*bytes_mid; - cost += llmax(dmid-dhigh, 1.f)/32.f*bytes_high; + F32 max_area = 65536.f; + F32 min_area = 1.f; + + F32 high_area = llmin(F_PI*dmid*dmid, max_area); + F32 mid_area = llmin(F_PI*dlow*dlow, max_area); + F32 low_area = llmin(F_PI*dlowest*dlowest, max_area); + F32 lowest_area = max_area; + + lowest_area -= low_area; + low_area -= mid_area; + mid_area -= high_area; + + high_area = llclamp(high_area, min_area, max_area); + mid_area = llclamp(mid_area, min_area, max_area); + low_area = llclamp(low_area, min_area, max_area); + lowest_area = llclamp(lowest_area, min_area, max_area); + + F32 total_area = high_area + mid_area + low_area + lowest_area; + high_area /= total_area; + mid_area /= total_area; + 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; - cost *= gSavedSettings.getF32("MeshStreamingCostScaler"); - return cost; + return weighted_avg * gSavedSettings.getF32("MeshStreamingCostScaler"); } -- cgit v1.2.3 From 16ff50719055aae202011e4b20aeae41d98493fa Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 14 Mar 2011 18:02:25 -0400 Subject: WIP:Added pelvis offset to skinning info --- indra/newview/llmeshrepository.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index e259ee9846..8e869b2d5b 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1162,7 +1162,12 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat info.mAlternateBindMatrix.push_back(mat); } } - + + if (skin.has("pelvis_offset")) + { + info.mPelvisOffset = skin["pelvis_offset"].asReal(); + } + mSkinInfoQ.push(info); } -- cgit v1.2.3 From 5a940793e19225c065f1e37c1be32edd936a5246 Mon Sep 17 00:00:00 2001 From: prep linden Date: Wed, 16 Mar 2011 10:15:06 -0400 Subject: WIP:Manual pelvis offset --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8e869b2d5b..93e6c3aafc 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1167,7 +1167,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat { info.mPelvisOffset = skin["pelvis_offset"].asReal(); } - + llinfos<<"info pelvis offset"< Date: Wed, 16 Mar 2011 10:19:56 -0400 Subject: WIP:commented out pelvis offset log --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 93e6c3aafc..93e773d33b 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1167,7 +1167,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat { info.mPelvisOffset = skin["pelvis_offset"].asReal(); } - llinfos<<"info pelvis offset"< Date: Mon, 21 Mar 2011 17:31:25 -0500 Subject: SH-1168 Export upload data to disk on upload. --- indra/newview/llmeshrepository.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 93e773d33b..47dc343f5e 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3584,3 +3584,30 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg) mStatusMessage = msg; } +LLSD LLModelInstance::asLLSD() +{ + LLSD ret; + + ret["mesh_id"] = mModel->mLocalID; + ret["label"] = mLabel; + ret["transform"] = mTransform.getValue(); + + for (U32 i = 0; i < mMaterial.size(); ++i) + { + ret["material"][i] = mMaterial[i].asLLSD(); + } + + return ret; +} + +LLSD LLImportMaterial::asLLSD() +{ + LLSD ret; + + ret["diffuse"]["filename"] = mDiffuseMapFilename; + ret["diffuse"]["label"] = mDiffuseMapLabel; + ret["diffuse"]["color"] = mDiffuseColor.getValue(); + ret["fullbright"] = mFullbright; + + return ret; +} -- cgit v1.2.3 From 6ff87e2840c585711e2927028a11ba5ce78a192a Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 22 Mar 2011 17:23:48 -0500 Subject: SH-1169 Import from slm instead of dae when appropriate. --- indra/newview/llmeshrepository.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 47dc343f5e..a227627bc1 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3584,6 +3584,19 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg) mStatusMessage = msg; } +LLModelInstance::LLModelInstance(LLSD& data) +{ + mLocalMeshID = data["mesh_id"].asInteger(); + mLabel = data["label"].asString(); + mTransform.setValue(data["transform"]); + + for (U32 i = 0; i < data["material"].size(); ++i) + { + mMaterial.push_back(LLImportMaterial(data["material"][i])); + } +} + + LLSD LLModelInstance::asLLSD() { LLSD ret; @@ -3600,6 +3613,15 @@ LLSD LLModelInstance::asLLSD() return ret; } +LLImportMaterial::LLImportMaterial(LLSD& data) +{ + mDiffuseMapFilename = data["diffuse"]["filename"].asString(); + mDiffuseMapLabel = data["diffuse"]["label"].asString(); + mDiffuseColor.setValue(data["diffuse"]["color"]); + mFullbright = data["fullbright"].asBoolean(); +} + + LLSD LLImportMaterial::asLLSD() { LLSD ret; -- cgit v1.2.3 From d2bb490702921b5ca9fdcd562c67844e2d4802e1 Mon Sep 17 00:00:00 2001 From: prep Date: Thu, 24 Mar 2011 09:48:34 -0400 Subject: Crash fix for SH-1176 and WIP for pelvis z offset --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a227627bc1..60cbdcc98b 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1179,7 +1179,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 LLSD decomp; if (data_size > 0) - { + { std::string res_str((char*) data, data_size); std::istringstream stream(res_str); -- cgit v1.2.3 From 971eac1aa26fecaf6a8bbb7ca568ed400866c197 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 25 Mar 2011 14:04:52 -0600 Subject: fix for SH-838: Crash if exit during mesh upload --- indra/newview/llmeshrepository.cpp | 70 +++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 9 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 60cbdcc98b..a2792bcdc6 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -28,7 +28,7 @@ #include "apr_pools.h" #include "apr_dso.h" - +#include "llhttpstatuscodes.h" #include "llmeshrepository.h" #include "llagent.h" @@ -291,17 +291,21 @@ public: } else { - llwarns << status << ": " << reason << llendl; - llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; + llwarns << status << ": " << reason << llendl; - if (status == 499) + if (status == HTTP_INTERNAL_ERROR) { + llwarns << "Retrying. (" << ++mData.mRetries << ")" << llendl; mThread->uploadModel(mData); } - else if (status == 400) + 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; @@ -1381,7 +1385,8 @@ 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) -: LLThread("mesh upload") +: LLThread("mesh upload"), + mDiscarded(FALSE) { mInstanceList = data; mUploadTextures = upload_textures; @@ -1475,8 +1480,26 @@ void LLMeshUploadThread::preStart() } } +void LLMeshUploadThread::discard() +{ + LLMutexLock lock(mMutex) ; + mDiscarded = TRUE ; +} + +BOOL LLMeshUploadThread::isDiscarded() +{ + LLMutexLock lock(mMutex) ; + return mDiscarded ; +} + void LLMeshUploadThread::run() { + if(isDiscarded()) + { + mFinished = true; + return ; + } + mCurlRequest = new LLCurlRequest(); std::set textures; @@ -1605,7 +1628,7 @@ void LLMeshUploadThread::run() tcount = llmin(count+PUSH_PER_PROCESS, 100); - while (!mInstanceQ.empty() && count < tcount) + while (!mInstanceQ.empty() && count < tcount && !isDiscarded()) { //create any objects waiting for upload count++; object_asset["objects"].append(createObject(mInstanceQ.front())); @@ -1614,7 +1637,7 @@ void LLMeshUploadThread::run() mCurlRequest->process(); - done = mInstanceQ.empty() && mConfirmedQ.empty() && mUploadQ.empty(); + done = isDiscarded() || (mInstanceQ.empty() && mConfirmedQ.empty() && mUploadQ.empty()); } while (!done || mCurlRequest->getQueued() > 0); @@ -1629,7 +1652,10 @@ void LLMeshUploadThread::run() object_asset["permissions"] = object_asset["objects"][0]["permissions"]; } - LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder()); + if(!isDiscarded()) + { + LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder()); + } mFinished = true; } @@ -2132,6 +2158,12 @@ void LLMeshRepository::shutdown() { llinfos << "Shutting down mesh repository." << llendl; + for (U32 i = 0; i < mUploads.size(); ++i) + { + llinfos << "Discard the pending mesh uploads " << llendl; + mUploads[i]->discard() ; //discard the uploading requests. + } + mThread->mSignal->signal(); while (!mThread->isStopped()) @@ -2750,6 +2782,11 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) { + if(isDiscarded()) + { + return ; + } + //write model file to memory buffer std::stringstream ostr; @@ -2808,6 +2845,11 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data) { + if(isDiscarded()) + { + return ; + } + if (data.mTexture && data.mTexture->getDiscardLevel() >= 0) { LLSD asset_resources = LLSD::emptyMap(); @@ -2840,6 +2882,11 @@ void LLMeshUploadThread::sendCostRequest(LLTextureUploadData& data) void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) { + if(isDiscarded()) + { + return ; + } + if (!data.mRSVP.empty()) { std::stringstream ostr; @@ -2872,6 +2919,11 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) void LLMeshUploadThread::doUploadTexture(LLTextureUploadData& data) { + if(isDiscarded()) + { + return ; + } + if (!data.mRSVP.empty()) { std::stringstream ostr; -- cgit v1.2.3 From 1ff79683128f09baf6dbaf081092fda7e5f2fe65 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 28 Mar 2011 23:50:23 -0500 Subject: SH-1225 Add skinning info to import path of .slm files. --- indra/newview/llmeshrepository.cpp | 59 +------------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a2792bcdc6..f5fc0de0d3 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1111,66 +1111,9 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat } { - LLMeshSkinInfo info; + LLMeshSkinInfo info(skin); info.mMeshID = mesh_id; - if (skin.has("joint_names")) - { - for (U32 i = 0; i < skin["joint_names"].size(); ++i) - { - info.mJointNames.push_back(skin["joint_names"][i]); - } - } - - if (skin.has("inverse_bind_matrix")) - { - for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i) - { - LLMatrix4 mat; - for (U32 j = 0; j < 4; j++) - { - for (U32 k = 0; k < 4; k++) - { - mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal(); - } - } - - info.mInvBindMatrix.push_back(mat); - } - } - - if (skin.has("bind_shape_matrix")) - { - for (U32 j = 0; j < 4; j++) - { - for (U32 k = 0; k < 4; k++) - { - info.mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal(); - } - } - } - - if (skin.has("alt_inverse_bind_matrix")) - { - for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i) - { - LLMatrix4 mat; - for (U32 j = 0; j < 4; j++) - { - for (U32 k = 0; k < 4; k++) - { - mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal(); - } - } - - info.mAlternateBindMatrix.push_back(mat); - } - } - - if (skin.has("pelvis_offset")) - { - info.mPelvisOffset = skin["pelvis_offset"].asReal(); - } //llinfos<<"info pelvis offset"< Date: Tue, 29 Mar 2011 11:50:02 -0500 Subject: SH-1225 Import convex hull data from .slm --- indra/newview/llmeshrepository.cpp | 273 +++++++++++-------------------------- 1 file changed, 80 insertions(+), 193 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index f5fc0de0d3..752e4c8744 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -108,19 +108,13 @@ U32 get_volume_memory_size(const LLVolume* volume) return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces(); } -LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f) +void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, F32 scale = 1.f) { - LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0); - buff->allocateBuffer(mesh.mNumTriangles*3, 0, true); - - LLStrider pos; - LLStrider norm; + res.mPositions.clear(); + res.mNormals.clear(); - buff->getVertexStrider(pos); - buff->getNormalStrider(norm); - const F32* v = mesh.mVertexBase; - + if (mesh.mIndexType == LLCDMeshData::INT_16) { U16* idx = (U16*) mesh.mIndexBase; @@ -139,13 +133,13 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f) LLVector3 n = (v1-v0)%(v2-v0); n.normalize(); - *pos++ = v0*scale; - *pos++ = v1*scale; - *pos++ = v2*scale; + res.mPositions.push_back(v0*scale); + res.mPositions.push_back(v1*scale); + res.mPositions.push_back(v2*scale); - *norm++ = n; - *norm++ = n; - *norm++ = n; + res.mNormals.push_back(n); + res.mNormals.push_back(n); + res.mNormals.push_back(n); } } else @@ -166,17 +160,15 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f) LLVector3 n = (v1-v0)%(v2-v0); n.normalize(); - *(pos++) = v0*scale; - *(pos++) = v1*scale; - *(pos++) = v2*scale; + res.mPositions.push_back(v0*scale); + res.mPositions.push_back(v1*scale); + res.mPositions.push_back(v2*scale); - *(norm++) = n; - *(norm++) = n; - *(norm++) = n; + res.mNormals.push_back(n); + res.mNormals.push_back(n); + res.mNormals.push_back(n); } } - - return buff; } S32 LLMeshRepoThread::sActiveHeaderRequests = 0; @@ -1139,119 +1131,8 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 } { - LLMeshDecomposition* d = new LLMeshDecomposition(); + LLModel::Decomposition* d = new LLModel::Decomposition(decomp); d->mMeshID = mesh_id; - - if (decomp.has("HullList")) - { - // updated for const-correctness. gcc is picky about this type of thing - Nyx - const LLSD::Binary& hulls = decomp["HullList"].asBinary(); - const LLSD::Binary& position = decomp["Position"].asBinary(); - - U16* p = (U16*) &position[0]; - - d->mHull.resize(hulls.size()); - - LLVector3 min; - LLVector3 max; - LLVector3 range; - - min.setValue(decomp["Min"]); - max.setValue(decomp["Max"]); - range = max-min; - - for (U32 i = 0; i < hulls.size(); ++i) - { - U16 count = (hulls[i] == 0) ? 256 : hulls[i]; - - for (U32 j = 0; j < count; ++j) - { - d->mHull[i].push_back(LLVector3( - (F32) p[0]/65535.f*range.mV[0]+min.mV[0], - (F32) p[1]/65535.f*range.mV[1]+min.mV[1], - (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); - p += 3; - } - - } - - //get mesh for decomposition - for (U32 i = 0; i < d->mHull.size(); ++i) - { - LLCDHull hull; - hull.mNumVertices = d->mHull[i].size(); - hull.mVertexBase = d->mHull[i][0].mV; - hull.mVertexStrideBytes = 12; - - LLCDMeshData mesh; - LLCDResult res = LLCD_OK; - if (LLConvexDecomposition::getInstance() != NULL) - { - res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); - } - if (res != LLCD_OK) - { - llwarns << "could not get mesh from hull from convex decomposition lib." << llendl; - return false; - } - - - d->mMesh.push_back(get_vertex_buffer_from_mesh(mesh)); - } - } - - if (decomp.has("Hull")) - { - const LLSD::Binary& position = decomp["Hull"].asBinary(); - - U16* p = (U16*) &position[0]; - - LLVector3 min; - LLVector3 max; - LLVector3 range; - - min.setValue(decomp["Min"]); - max.setValue(decomp["Max"]); - range = max-min; - - U16 count = position.size()/6; - - for (U32 j = 0; j < count; ++j) - { - d->mBaseHull.push_back(LLVector3( - (F32) p[0]/65535.f*range.mV[0]+min.mV[0], - (F32) p[1]/65535.f*range.mV[1]+min.mV[1], - (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); - p += 3; - } - - //get mesh for decomposition - LLCDHull hull; - hull.mNumVertices = d->mBaseHull.size(); - hull.mVertexBase = d->mBaseHull[0].mV; - hull.mVertexStrideBytes = 12; - - LLCDMeshData mesh; - LLCDResult res = LLCD_OK; - if (LLConvexDecomposition::getInstance() != NULL) - { - res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); - } - if (res != LLCD_OK) - { - llwarns << "could not get mesh from hull from convex decomposition lib." << llendl; - return false; - } - - d->mBaseHullMesh = get_vertex_buffer_from_mesh(mesh); - } - else - { - //empty vertex buffer to indicate decomposition has been fetched - //but contains no base hull - d->mBaseHullMesh = new LLVertexBuffer(0, 0); - } - mDecompositionQ.push(d); } @@ -1262,12 +1143,12 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 { LLSD physics_shape; - LLMeshDecomposition* d = new LLMeshDecomposition(); + LLModel::Decomposition* d = new LLModel::Decomposition(); d->mMeshID = mesh_id; if (data == NULL) { //no data, no physics shape exists - d->mPhysicsShapeMesh = new LLVertexBuffer(0,0); + d->mPhysicsShapeMesh.clear(); } else { @@ -1291,33 +1172,22 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 index_count += face.mNumIndices; } - d->mPhysicsShapeMesh = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); - - d->mPhysicsShapeMesh->allocateBuffer(vertex_count, index_count, true); + d->mPhysicsShapeMesh.clear(); - LLStrider pos; - LLStrider idx; + std::vector& pos = d->mPhysicsShapeMesh.mPositions; + std::vector& norm = d->mPhysicsShapeMesh.mNormals; - d->mPhysicsShapeMesh->getVertexStrider(pos); - d->mPhysicsShapeMesh->getIndexStrider(idx); - - S32 idx_offset = 0; for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { const LLVolumeFace& face = volume->getVolumeFace(i); - if (idx_offset + face.mNumIndices > 65535) - { //avoid 16-bit index overflow - continue; - } - - LLVector4a::memcpyNonAliased16(pos[idx_offset].mV, face.mPositions[0].getF32ptr(), face.mNumVertices*sizeof(LLVector4a)); for (S32 i = 0; i < face.mNumIndices; ++i) { - *idx++ = face.mIndices[i] + idx_offset; - } + U16 idx = face.mIndices[i]; - idx_offset += face.mNumVertices; + pos.push_back(LLVector3(face.mPositions[idx].getF32ptr())); + norm.push_back(LLVector3(face.mNormals[idx].getF32ptr())); + } } } } @@ -2428,33 +2298,7 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info) mLoadingSkins.erase(info.mMeshID); } -void LLMeshDecomposition::merge(const LLMeshDecomposition* rhs) -{ - if (!rhs) - { - return; - } - - if (mMeshID != rhs->mMeshID) - { - llerrs << "Attempted to merge with decomposition of some other mesh." << llendl; - } - - if (mBaseHull.empty()) - { //take base hull and decomposition from rhs - mHull = rhs->mHull; - mBaseHull = rhs->mBaseHull; - mMesh = rhs->mMesh; - mBaseHullMesh = rhs->mBaseHullMesh; - } - - if (mPhysicsShapeMesh.isNull()) - { //take physics shape mesh from rhs - mPhysicsShapeMesh = rhs->mPhysicsShapeMesh; - } -} - -void LLMeshRepository::notifyDecompositionReceived(LLMeshDecomposition* decomp) +void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp) { decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID); if (iter == mDecompositionMap.end()) @@ -2596,7 +2440,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) { if (mesh_id.notNull()) { - LLMeshDecomposition* decomp = NULL; + LLModel::Decomposition* decomp = NULL; decomposition_map::iterator iter = mDecompositionMap.find(mesh_id); if (iter != mDecompositionMap.end()) { @@ -2604,7 +2448,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) } //decomposition block hasn't been fetched yet - if (!decomp || decomp->mPhysicsShapeMesh.isNull()) + if (!decomp || decomp->mPhysicsShapeMesh.empty()) { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes @@ -2619,9 +2463,9 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) } -const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id) +LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id) { - LLMeshDecomposition* ret = NULL; + LLModel::Decomposition* ret = NULL; if (mesh_id.notNull()) { @@ -2632,7 +2476,7 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh } //decomposition block hasn't been fetched yet - if (!ret || ret->mBaseHullMesh.isNull()) + if (!ret || ret->mBaseHullMesh.empty()) { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes @@ -2735,8 +2579,8 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) LLModel::convex_hull_decomposition& decomp = data.mModel[LLModel::LOD_PHYSICS].notNull() ? - data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - data.mBaseModel->mConvexHullDecomp; + data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : + data.mBaseModel->mPhysics.mHull; LLModel::hull dummy_hull; @@ -2836,8 +2680,8 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) LLModel::convex_hull_decomposition& decomp = data.mModel[LLModel::LOD_PHYSICS].notNull() ? - data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - data.mBaseModel->mConvexHullDecomp; + data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : + data.mBaseModel->mPhysics.mHull; LLModel::writeModel( ostr, @@ -3355,7 +3199,7 @@ void LLPhysicsDecomp::doDecomposition() // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh); - mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh); + get_vertex_buffer_from_mesh(mesh, mCurRequest->mHullMesh[i]); mMutex->lock(); mCurRequest->mHull[i] = p; @@ -3628,3 +3472,46 @@ LLSD LLImportMaterial::asLLSD() return ret; } + +void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp) +{ + decomp.mMesh.resize(decomp.mHull.size()); + + for (U32 i = 0; i < decomp.mHull.size(); ++i) + { + LLCDHull hull; + hull.mNumVertices = decomp.mHull[i].size(); + hull.mVertexBase = decomp.mHull[i][0].mV; + hull.mVertexStrideBytes = 12; + + LLCDMeshData mesh; + LLCDResult res = LLCD_OK; + if (LLConvexDecomposition::getInstance() != NULL) + { + res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); + } + if (res == LLCD_OK) + { + get_vertex_buffer_from_mesh(mesh, decomp.mMesh[i]); + } + } + + if (!decomp.mBaseHull.empty() && decomp.mBaseHullMesh.empty()) + { //get mesh for base hull + LLCDHull hull; + hull.mNumVertices = decomp.mBaseHull.size(); + hull.mVertexBase = decomp.mBaseHull[0].mV; + hull.mVertexStrideBytes = 12; + + LLCDMeshData mesh; + LLCDResult res = LLCD_OK; + if (LLConvexDecomposition::getInstance() != NULL) + { + res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); + } + if (res == LLCD_OK) + { + get_vertex_buffer_from_mesh(mesh, decomp.mBaseHullMesh); + } + } +} -- cgit v1.2.3 From 73bf43b5933846e786d7e97310488fc72b06d645 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 30 Mar 2011 10:49:14 -0400 Subject: line ending fixes --- indra/newview/llmeshrepository.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 752e4c8744..cfb0609111 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3475,10 +3475,10 @@ LLSD LLImportMaterial::asLLSD() void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp) { - decomp.mMesh.resize(decomp.mHull.size()); - - for (U32 i = 0; i < decomp.mHull.size(); ++i) - { + decomp.mMesh.resize(decomp.mHull.size()); + + for (U32 i = 0; i < decomp.mHull.size(); ++i) + { LLCDHull hull; hull.mNumVertices = decomp.mHull[i].size(); hull.mVertexBase = decomp.mHull[i][0].mV; @@ -3492,8 +3492,8 @@ void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp) } if (res == LLCD_OK) { - get_vertex_buffer_from_mesh(mesh, decomp.mMesh[i]); - } + get_vertex_buffer_from_mesh(mesh, decomp.mMesh[i]); + } } if (!decomp.mBaseHull.empty() && decomp.mBaseHullMesh.empty()) -- cgit v1.2.3 From 6b9a2d24cce8efaa72c2fd60655998844394312d Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 30 Mar 2011 18:38:22 -0500 Subject: SH-477 Better mesh streaming cost estimation. --- indra/newview/llmeshrepository.cpp | 109 ++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 43 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 752e4c8744..78943ef1b6 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1535,8 +1535,6 @@ void LLMeshRepoThread::notifyLoadedMeshes() S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { //only ever called from main thread - lod = llclamp(lod, 0, 3); - LLMutexLock lock(mHeaderMutex); mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID()); @@ -1544,40 +1542,48 @@ S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo { LLSD& header = iter->second; - if (header.has("404")) - { - return -1; - } + return LLMeshRepository::getActualMeshLOD(header, lod); + } - if (header[header_lod[lod]]["size"].asInteger() > 0) - { - return lod; - } + return lod; +} + +//static +S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) +{ + lod = llclamp(lod, 0, 3); + + if (header.has("404")) + { + return -1; + } - //search down to find the next available lower lod - for (S32 i = lod-1; i >= 0; --i) + if (header[header_lod[lod]]["size"].asInteger() > 0) + { + return lod; + } + + //search down to find the next available lower lod + for (S32 i = lod-1; i >= 0; --i) + { + if (header[header_lod[i]]["size"].asInteger() > 0) { - if (header[header_lod[i]]["size"].asInteger() > 0) - { - return i; - } + return i; } + } - //search up to find then ext available higher lod - for (S32 i = lod+1; i < 4; ++i) + //search up to find then ext available higher lod + for (S32 i = lod+1; i < 4; ++i) + { + if (header[header_lod[i]]["size"].asInteger() > 0) { - if (header[header_lod[i]]["size"].asInteger() > 0) - { - return i; - } + return i; } - - //header exists and no good lod found, treat as 404 - header["404"] = 1; - return -1; } - return lod; + //header exists and no good lod found, treat as 404 + header["404"] = 1; + return -1; } U32 LLMeshRepoThread::getResourceCost(const LLUUID& mesh_id) @@ -2514,12 +2520,12 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id) return mesh.has("physics_shape") && mesh["physics_shape"].has("size") && (mesh["physics_shape"]["size"].asInteger() > 0); } -const LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id) +LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id) { return mThread->getMeshHeader(mesh_id); } -const LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) +LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) { static LLSD dummy_ret; if (mesh_id.notNull()) @@ -2577,12 +2583,10 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) //write model file to memory buffer std::stringstream ostr; - LLModel::convex_hull_decomposition& decomp = + LLModel::Decomposition& decomp = data.mModel[LLModel::LOD_PHYSICS].notNull() ? - data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : - data.mBaseModel->mPhysics.mHull; - - LLModel::hull dummy_hull; + data.mModel[LLModel::LOD_PHYSICS]->mPhysics : + data.mBaseModel->mPhysics; LLSD header = LLModel::writeModel( ostr, @@ -2592,7 +2596,6 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data) data.mModel[LLModel::LOD_LOW], data.mModel[LLModel::LOD_IMPOSTOR], decomp, - dummy_hull, mUploadSkin, mUploadJoints, true); @@ -2678,10 +2681,12 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) { std::stringstream ostr; - LLModel::convex_hull_decomposition& decomp = + LLModel::Decomposition& decomp = data.mModel[LLModel::LOD_PHYSICS].notNull() ? - data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : - data.mBaseModel->mPhysics.mHull; + data.mModel[LLModel::LOD_PHYSICS]->mPhysics : + data.mBaseModel->mPhysics; + + decomp.mBaseHull = mHullMap[data.mBaseModel]; LLModel::writeModel( ostr, @@ -2691,7 +2696,6 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data) data.mModel[LLModel::LOD_LOW], data.mModel[LLModel::LOD_IMPOSTOR], decomp, - mHullMap[data.mBaseModel], mUploadSkin, mUploadJoints); @@ -2939,17 +2943,36 @@ void LLMeshRepository::uploadError(LLSD& args) } //static -F32 LLMeshRepository::getStreamingCost(const LLSD& header, F32 radius) +F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod) { - F32 dlowest = llmin(radius/0.06f, 256.f); - F32 dlow = llmin(radius/0.24f, 256.f); - F32 dmid = llmin(radius/1.0f, 256.f); + 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; + 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(); + } + } + if (bytes_high == 0.f) { return 0.f; -- cgit v1.2.3 From 50caebbad7f2e8f743b6a08831df2e525e8e6baa Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 2 May 2011 10:39:18 -0400 Subject: Added handler for final mesh object upload --- indra/newview/llmeshrepository.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) mode change 100644 => 100755 indra/newview/llmeshrepository.cpp (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp old mode 100644 new mode 100755 index e20e918a2a..dd2ffdf7f1 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -454,6 +454,29 @@ public: }; +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; + } +}; LLMeshRepoThread::LLMeshRepoThread() : LLThread("mesh repo", NULL) @@ -1467,10 +1490,13 @@ void LLMeshUploadThread::run() if(!isDiscarded()) { - LLHTTPClient::post(url, object_asset, new LLHTTPClient::Responder()); + mPendingUploads++; + LLHTTPClient::post(url, object_asset, new LLModelObjectUploadResponder(this,object_asset)); + } + else + { + mFinished = true; } - - mFinished = true; } void LLMeshUploadThread::uploadModel(LLMeshUploadData& data) -- cgit v1.2.3 From 9b0f5c815fcd8381f336ba860ae1f5bf0c842e58 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 5 May 2011 17:40:35 -0400 Subject: started new code path for whole model fee request/upload --- indra/newview/llmeshrepository.cpp | 65 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) mode change 100644 => 100755 indra/newview/llmeshrepository.cpp (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp old mode 100644 new mode 100755 index dd2ffdf7f1..4c04b0ea35 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1239,6 +1239,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadObjectAssetCapability = gAgent.getRegion()->getCapability("UploadObjectAsset"); mNewInventoryCapability = gAgent.getRegion()->getCapability("NewFileAgentInventoryVariablePrice"); + mWholeModelUploadCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory"); mOrigin += gAgent.getAtAxis() * scale.magVec(); } @@ -1329,6 +1330,70 @@ BOOL LLMeshUploadThread::isDiscarded() } void LLMeshUploadThread::run() +{ + if (gSavedSettings.getBOOL("MeshUseWholeModelUpload")) + { + doWholeModelUpload(); + } + else + { + doIterativeUpload(); + } +} + +void LLMeshUploadThread::doWholeModelUpload() +{ + // Queue up models for hull generation (viewer-side) + for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) + { + LLMeshUploadData data; + data.mBaseModel = iter->first; + + LLModelInstance& instance = *(iter->second.begin()); + + for (S32 i = 0; i < 5; i++) + { + data.mModel[i] = instance.mLOD[i]; + } + + //queue up models for hull generation + LLModel* physics = NULL; + + if (data.mModel[LLModel::LOD_PHYSICS].notNull()) + { + physics = data.mModel[LLModel::LOD_PHYSICS]; + } + else if (data.mModel[LLModel::LOD_MEDIUM].notNull()) + { + physics = data.mModel[LLModel::LOD_MEDIUM]; + } + else + { + physics = data.mModel[LLModel::LOD_HIGH]; + } + + if (!physics) + { + llerrs << "WTF?" << llendl; + } + + DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this); + gMeshRepo.mDecompThread->submitRequest(request); + } + + while (!mPhysicsComplete) + { + apr_sleep(100); + } + + bool do_include_textures = false; // not needed for initial cost/validation check. + LLSD model_data = wholeModelToLLSD(do_include_textures); + + // Currently a no-op. + mFinished = true; +} + +void LLMeshUploadThread::doIterativeUpload() { if(isDiscarded()) { -- cgit v1.2.3 From 369b34443d3d09b8bc71e85f23628c079935b615 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 9 May 2011 11:23:15 -0400 Subject: SH-1491 WIP - whole model upload for fee request --- indra/newview/llmeshrepository.cpp | 101 ++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 4c04b0ea35..0789bbe28a 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -58,6 +58,8 @@ #include "llworld.h" #include "material_codes.h" #include "pipeline.h" +#include "llinventorymodel.h" +#include "llfoldertype.h" #ifndef LL_WINDOWS #include "netdb.h" @@ -478,6 +480,25 @@ public: } }; +class LLWholeModelFeeResponder: public LLCurl::Responder +{ + LLMeshUploadThread* mThread; +public: + LLWholeModelFeeResponder(LLMeshUploadThread* thread): + mThread(thread) + { + } + 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--; + } + +}; + LLMeshRepoThread::LLMeshRepoThread() : LLThread("mesh repo", NULL) { @@ -1341,8 +1362,81 @@ void LLMeshUploadThread::run() } } +LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) +{ + // TODO where do textures go? + + LLSD result; + + result["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + result["asset_type"] = "mesh"; + result["inventory_type"] = "object"; + result["name"] = "your name here"; + result["description"] = "your description here"; + + LLSD res; + res["mesh_list"] = LLSD::emptyArray(); + S32 mesh_num = 0; + + for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) + { + LLMeshUploadData data; + data.mBaseModel = iter->first; + + LLModelInstance& instance = *(iter->second.begin()); + + for (S32 i = 0; i < 5; i++) + { + data.mModel[i] = instance.mLOD[i]; + } + + 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(); + + LLSD mesh_entry; + + // TODO - correct coords based on instance.mTransform. + mesh_entry["coords"]["x"] = 1.0; + mesh_entry["coords"]["y"] = 1.0; + mesh_entry["coords"]["z"] = 1.0; + mesh_entry["coords"]["rot_x"] = 1.0; + mesh_entry["coords"]["rot_y"] = 1.0; + mesh_entry["coords"]["rot_z"] = 1.0; + mesh_entry["mesh_data"] = ostr.str(); + + res["mesh_list"][mesh_num] = mesh_entry; + + mesh_num++; + } + + result["asset_resources"] = res; + + return result; +} + void LLMeshUploadThread::doWholeModelUpload() { + mCurlRequest = new LLCurlRequest(); + // Queue up models for hull generation (viewer-side) for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) { @@ -1388,7 +1482,12 @@ void LLMeshUploadThread::doWholeModelUpload() bool do_include_textures = false; // not needed for initial cost/validation check. LLSD model_data = wholeModelToLLSD(do_include_textures); - + + mPendingUploads++; + LLCurlRequest::headers_t headers; + mCurlRequest->post(mWholeModelUploadCapability, headers, model_data.asString(), + new LLWholeModelFeeResponder(this)); + // Currently a no-op. mFinished = true; } -- cgit v1.2.3 From fac4ca594f4efee1da05bdc74164f56690d03bfb Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 9 May 2011 12:56:28 -0500 Subject: SH-1517 Always build bounding hull from highest LoD. --- indra/newview/llmeshrepository.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index dd2ffdf7f1..ff91ce74f1 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1372,27 +1372,7 @@ void LLMeshUploadThread::run() } //queue up models for hull generation - LLModel* physics = NULL; - - if (data.mModel[LLModel::LOD_PHYSICS].notNull()) - { - physics = data.mModel[LLModel::LOD_PHYSICS]; - } - else if (data.mModel[LLModel::LOD_MEDIUM].notNull()) - { - physics = data.mModel[LLModel::LOD_MEDIUM]; - } - else - { - physics = data.mModel[LLModel::LOD_HIGH]; - } - - if (!physics) - { - llerrs << "WTF?" << llendl; - } - - DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this); + DecompRequest* request = new DecompRequest(data.mModel[LLModel::LOD_HIGH], data.mBaseModel, this); gMeshRepo.mDecompThread->submitRequest(request); } -- cgit v1.2.3 From 0b677dd2198af4608435fd5c8d84cc4f77db47b8 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 9 May 2011 16:56:29 -0400 Subject: SH-1491 WIP - whole model upload for fee request --- indra/newview/llmeshrepository.cpp | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 0789bbe28a..9c72550847 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1362,6 +1362,12 @@ void LLMeshUploadThread::run() } } +void dumpLLSDToFile(LLSD& content, std::string& filename) +{ + std::ofstream of(filename); + LLSDSerialize::toXML(content,of); +} + LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) { // TODO where do textures go? @@ -1376,8 +1382,12 @@ LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) LLSD res; res["mesh_list"] = LLSD::emptyArray(); + res["texture_list"] = LLSD::emptyArray(); S32 mesh_num = 0; + S32 texture_num = 0; + std::set textures; + for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) { LLMeshUploadData data; @@ -1425,11 +1435,44 @@ LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) res["mesh_list"][mesh_num] = mesh_entry; + if (mUploadTextures) + { + for (std::vector::iterator material_iter = instance.mMaterial.begin(); + material_iter != instance.mMaterial.end(); ++material_iter) + { + + if (textures.find(material_iter->mDiffuseMap.get()) == textures.end()) + { + textures.insert(material_iter->mDiffuseMap.get()); + + std::stringstream ostr; + if (include_textures) // otherwise data is blank. + { + LLTextureUploadData data(material_iter->mDiffuseMap.get(), material_iter->mDiffuseMapLabel); + if (!data.mTexture->isRawImageValid()) + { + data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel()); + } + + LLPointer upload_file = + LLViewerTextureList::convertToUploadFile(data.mTexture->getRawImage()); + ostr.write((const char*) upload_file->getData(), upload_file->getDataSize()); + } + LLSD texture_entry; + texture_entry["texture_data"] = ostr.str(); + res["texture_list"][texture_num] = texture_entry; + texture_num++; + } + } + } + mesh_num++; } result["asset_resources"] = res; + dumpLLSDToFile(result,std::string("whole_model.xml")); + return result; } -- cgit v1.2.3 From 49cadf47f3eeaee9da3fca55a321211456f86019 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 9 May 2011 17:30:40 -0400 Subject: SH-1491 WIP - whole model upload for fee request --- indra/newview/llmeshrepository.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 9c72550847..c2c373d07f 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1365,7 +1365,7 @@ void LLMeshUploadThread::run() void dumpLLSDToFile(LLSD& content, std::string& filename) { std::ofstream of(filename); - LLSDSerialize::toXML(content,of); + LLSDSerialize::toPrettyXML(content,of); } LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) @@ -1431,7 +1431,7 @@ LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) mesh_entry["coords"]["rot_x"] = 1.0; mesh_entry["coords"]["rot_y"] = 1.0; mesh_entry["coords"]["rot_z"] = 1.0; - mesh_entry["mesh_data"] = ostr.str(); + mesh_entry["mesh_data"] = "RESTORE_ME"; //ostr.str(); res["mesh_list"][mesh_num] = mesh_entry; -- cgit v1.2.3 From fa77ab85f152b6b8501cbee960839512a22c3bda Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 11 May 2011 15:45:29 -0400 Subject: disable debugging stuff by default --- indra/newview/llmeshrepository.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index c2c373d07f..54f699e396 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1470,8 +1470,9 @@ LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) } result["asset_resources"] = res; - +#if 0 dumpLLSDToFile(result,std::string("whole_model.xml")); +#endif return result; } -- cgit v1.2.3 From 7cad431c6e4ea920a998ac1d3cdf385722fe5f7b Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 12 May 2011 10:17:08 -0400 Subject: small API change --- indra/newview/llmeshrepository.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 9f302f9e57..3163f4f186 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1368,7 +1368,7 @@ void dumpLLSDToFile(LLSD& content, std::string& filename) LLSDSerialize::toPrettyXML(content,of); } -LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) +void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) { // TODO where do textures go? @@ -1470,11 +1470,11 @@ LLSD LLMeshUploadThread::wholeModelToLLSD(bool include_textures) } result["asset_resources"] = res; -#if 0 +#if 1 dumpLLSDToFile(result,std::string("whole_model.xml")); #endif - - return result; + + dest = result; } void LLMeshUploadThread::doWholeModelUpload() @@ -1525,7 +1525,8 @@ void LLMeshUploadThread::doWholeModelUpload() } bool do_include_textures = false; // not needed for initial cost/validation check. - LLSD model_data = wholeModelToLLSD(do_include_textures); + LLSD model_data; + wholeModelToLLSD(model_data, do_include_textures); mPendingUploads++; LLCurlRequest::headers_t headers; -- cgit v1.2.3 From a65cd77f40791c16fc77b318abe4f8a4b3b42751 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 12 May 2011 18:28:31 -0400 Subject: mesh coords for whole model upload --- indra/newview/llmeshrepository.cpp | 68 ++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 10 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 3163f4f186..1544a0d542 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1380,6 +1380,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) result["name"] = "your name here"; result["description"] = "your description here"; + // TODO "optional" fields from the spec + LLSD res; res["mesh_list"] = LLSD::emptyArray(); res["texture_list"] = LLSD::emptyArray(); @@ -1409,7 +1411,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) decomp.mBaseHull = mHullMap[data.mBaseModel]; - LLModel::writeModel( + LLSD mesh_header = LLModel::writeModel( ostr, data.mModel[LLModel::LOD_PHYSICS], data.mModel[LLModel::LOD_HIGH], @@ -1424,17 +1426,22 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) LLSD mesh_entry; - // TODO - correct coords based on instance.mTransform. - mesh_entry["coords"]["x"] = 1.0; - mesh_entry["coords"]["y"] = 1.0; - mesh_entry["coords"]["z"] = 1.0; - mesh_entry["coords"]["rot_x"] = 1.0; - mesh_entry["coords"]["rot_y"] = 1.0; - mesh_entry["coords"]["rot_z"] = 1.0; - mesh_entry["mesh_data"] = "RESTORE_ME"; //ostr.str(); + LLVector3 pos, scale; + LLQuaternion rot; + LLMatrix4 transformation = instance.mTransform; + decomposeMeshMatrix(transformation,pos,rot,scale); + + mesh_entry["childpos"] = ll_sd_from_vector3(pos); + mesh_entry["childrot"] = ll_sd_from_quaternion(rot); + mesh_entry["scale"] = ll_sd_from_vector3(scale); + + // TODO should be binary. + std::string str = ostr.str(); + mesh_entry["mesh_data"] = LLSD::Binary(str.begin(),str.end()); res["mesh_list"][mesh_num] = mesh_entry; - + + // TODO how do textures in the list map to textures in the meshes? if (mUploadTextures) { for (std::vector::iterator material_iter = instance.mMaterial.begin(); @@ -2976,6 +2983,47 @@ void LLMeshUploadThread::createObjects(LLMeshUploadData& data) } } +void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation, + LLVector3& result_pos, + LLQuaternion& result_rot, + LLVector3& result_scale) +{ + // 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]); + + result_pos = position + mOrigin; + result_scale = scale; + result_rot = quat_rotation; +} + + LLSD LLMeshUploadThread::createObject(LLModelInstance& instance) { LLMatrix4 transformation = instance.mTransform; -- cgit v1.2.3 From 34d016ac476354c1313da6a0b5e07ee764343f8e Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 13 May 2011 11:37:55 -0400 Subject: removed some XML logging --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 1544a0d542..2ebe6cf6bd 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1477,7 +1477,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) } result["asset_resources"] = res; -#if 1 +#if 0 dumpLLSDToFile(result,std::string("whole_model.xml")); #endif -- cgit v1.2.3 From d6fda15c34896db3b911c3719871ce317edaab1d Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 13 May 2011 12:01:39 -0400 Subject: Fixed more build breakages due to persnickety compilers on mac/linux --- indra/newview/llmeshrepository.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 2ebe6cf6bd..2a68fbac8d 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1362,11 +1362,13 @@ void LLMeshUploadThread::run() } } +#if 0 void dumpLLSDToFile(LLSD& content, std::string& filename) { std::ofstream of(filename); LLSDSerialize::toPrettyXML(content,of); } +#endif void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) { @@ -1478,7 +1480,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) result["asset_resources"] = res; #if 0 - dumpLLSDToFile(result,std::string("whole_model.xml")); + std::string name("whole_model.xml"); + dumpLLSDToFile(result,name); #endif dest = result; -- cgit v1.2.3 From db05176138e6bf3e2011db1b5db4bc1b125d070f Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 16 May 2011 12:56:18 -0400 Subject: sh-1491 WIP --- indra/newview/llmeshrepository.cpp | 43 +++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 12 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 2a68fbac8d..653fb46754 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -84,6 +84,8 @@ U32 LLMeshRepository::sPeakKbps = 0; const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5; +void dumpLLSDToFile(LLSD& content, std::string filename); + std::string header_lod[] = { "lowest_lod", @@ -492,11 +494,18 @@ public: const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - assert_main_thread(); + //assert_main_thread(); llinfos << "completed" << llendl; mThread->mPendingUploads--; + + LLSD content; + LLBufferStream istr(channels, buffer.get()); + if (!LLSDSerialize::fromXML(content, istr)) + { + llinfos << "Failed to deserialize LLSD. " << " [" << status << "]: " << reason << llendl; + } + dumpLLSDToFile(content,"whole_model_response.xml"); } - }; LLMeshRepoThread::LLMeshRepoThread() @@ -1362,8 +1371,8 @@ void LLMeshUploadThread::run() } } -#if 0 -void dumpLLSDToFile(LLSD& content, std::string& filename) +#if 1 +void dumpLLSDToFile(LLSD& content, std::string filename) { std::ofstream of(filename); LLSDSerialize::toPrettyXML(content,of); @@ -1373,9 +1382,10 @@ void dumpLLSDToFile(LLSD& content, std::string& filename) void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) { // TODO where do textures go? - + LLSD result; + LLSD res; result["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); result["asset_type"] = "mesh"; result["inventory_type"] = "object"; @@ -1384,9 +1394,9 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) // TODO "optional" fields from the spec - LLSD res; res["mesh_list"] = LLSD::emptyArray(); - res["texture_list"] = LLSD::emptyArray(); +// TODO Textures + //res["texture_list"] = LLSD::emptyArray(); S32 mesh_num = 0; S32 texture_num = 0; @@ -1432,10 +1442,15 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) LLQuaternion rot; LLMatrix4 transformation = instance.mTransform; decomposeMeshMatrix(transformation,pos,rot,scale); - + +#if 0 mesh_entry["childpos"] = ll_sd_from_vector3(pos); mesh_entry["childrot"] = ll_sd_from_quaternion(rot); mesh_entry["scale"] = ll_sd_from_vector3(scale); +#endif + mesh_entry["position"] = ll_sd_from_vector3(LLVector3()); + mesh_entry["rotation"] = ll_sd_from_quaternion(rot); + mesh_entry["scale"] = ll_sd_from_vector3(scale); // TODO should be binary. std::string str = ostr.str(); @@ -1479,9 +1494,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) } result["asset_resources"] = res; -#if 0 - std::string name("whole_model.xml"); - dumpLLSDToFile(result,name); +#if 1 + dumpLLSDToFile(result,"whole_model.xml"); #endif dest = result; @@ -1540,9 +1554,14 @@ void LLMeshUploadThread::doWholeModelUpload() mPendingUploads++; LLCurlRequest::headers_t headers; - mCurlRequest->post(mWholeModelUploadCapability, headers, model_data.asString(), + mCurlRequest->post(mWholeModelUploadCapability, headers, model_data, new LLWholeModelFeeResponder(this)); + do + { + mCurlRequest->process(); + } while (mCurlRequest->getQueued() > 0); + // Currently a no-op. mFinished = true; } -- cgit v1.2.3 From 8ae550996c70df16b707f6773666b93409123689 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 16 May 2011 13:48:55 -0500 Subject: Merge cleanup. --- indra/newview/llmeshrepository.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 2a68fbac8d..0a1eadf4d0 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -35,6 +35,7 @@ #include "llappviewer.h" #include "llbufferstream.h" #include "llcurl.h" +#include "lldatapacker.h" #include "llfasttimer.h" #include "llfloatermodelpreview.h" #include "llfloaterperms.h" -- cgit v1.2.3 From bde7cd91130ee91993f6b42863ac7ab6430bafd6 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 16 May 2011 17:39:42 -0400 Subject: sh-1491 WIP --- indra/newview/llmeshrepository.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 653fb46754..7d48416292 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -84,7 +84,7 @@ U32 LLMeshRepository::sPeakKbps = 0; const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5; -void dumpLLSDToFile(LLSD& content, std::string filename); +void dumpLLSDToFile(const LLSD& content, std::string filename); std::string header_lod[] = { @@ -490,20 +490,13 @@ public: mThread(thread) { } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + virtual void completed(U32 status, + const std::string& reason, + const LLSD& content) { //assert_main_thread(); llinfos << "completed" << llendl; mThread->mPendingUploads--; - - LLSD content; - LLBufferStream istr(channels, buffer.get()); - if (!LLSDSerialize::fromXML(content, istr)) - { - llinfos << "Failed to deserialize LLSD. " << " [" << status << "]: " << reason << llendl; - } dumpLLSDToFile(content,"whole_model_response.xml"); } }; @@ -1372,7 +1365,7 @@ void LLMeshUploadThread::run() } #if 1 -void dumpLLSDToFile(LLSD& content, std::string filename) +void dumpLLSDToFile(const LLSD& content, std::string filename) { std::ofstream of(filename); LLSDSerialize::toPrettyXML(content,of); @@ -1562,6 +1555,9 @@ void LLMeshUploadThread::doWholeModelUpload() mCurlRequest->process(); } while (mCurlRequest->getQueued() > 0); + delete mCurlRequest; + mCurlRequest = NULL; + // Currently a no-op. mFinished = true; } -- cgit v1.2.3 From 7a02501aae8a21f4bf552d47e0799c4abdcd4228 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 18 May 2011 09:47:58 -0400 Subject: SH-1492 WIP --- indra/newview/llmeshrepository.cpp | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) mode change 100644 => 100755 indra/newview/llmeshrepository.cpp (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp old mode 100644 new mode 100755 index 922291c9e1..5305f3dbca --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -499,6 +499,27 @@ public: llinfos << "completed" << llendl; mThread->mPendingUploads--; dumpLLSDToFile(content,"whole_model_response.xml"); + + mThread->mWholeModelUploadURL = content["uploader"]; + } +}; + +class LLWholeModelUploadResponder: public LLCurl::Responder +{ + LLMeshUploadThread* mThread; +public: + LLWholeModelUploadResponder(LLMeshUploadThread* thread): + mThread(thread) + { + } + virtual void completed(U32 status, + const std::string& reason, + const LLSD& content) + { + //assert_main_thread(); + llinfos << "upload completed" << llendl; + mThread->mPendingUploads--; + dumpLLSDToFile(content,"whole_model_upload_response.xml"); } }; @@ -1263,7 +1284,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadObjectAssetCapability = gAgent.getRegion()->getCapability("UploadObjectAsset"); mNewInventoryCapability = gAgent.getRegion()->getCapability("NewFileAgentInventoryVariablePrice"); - mWholeModelUploadCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory"); + mWholeModelFeeCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory"); mOrigin += gAgent.getAtAxis() * scale.magVec(); } @@ -1548,7 +1569,7 @@ void LLMeshUploadThread::doWholeModelUpload() mPendingUploads++; LLCurlRequest::headers_t headers; - mCurlRequest->post(mWholeModelUploadCapability, headers, model_data, + mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, new LLWholeModelFeeResponder(this)); do @@ -1556,6 +1577,13 @@ void LLMeshUploadThread::doWholeModelUpload() mCurlRequest->process(); } while (mCurlRequest->getQueued() > 0); + mCurlRequest->post(mWholeModelUploadURL, headers, model_data["asset_resources"], new LLWholeModelUploadResponder(this)); + + do + { + mCurlRequest->process(); + } while (mCurlRequest->getQueued() > 0); + delete mCurlRequest; mCurlRequest = NULL; -- cgit v1.2.3 From 3990324e8f8391aee335ad74b33b22e0b1c849af Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 18 May 2011 11:33:28 -0400 Subject: trying to fix mac build complaints --- indra/newview/llmeshrepository.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 5305f3dbca..d9a58d56fe 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -500,7 +500,7 @@ public: mThread->mPendingUploads--; dumpLLSDToFile(content,"whole_model_response.xml"); - mThread->mWholeModelUploadURL = content["uploader"]; + mThread->mWholeModelUploadURL = content["uploader"].asString(); } }; @@ -1389,7 +1389,7 @@ void LLMeshUploadThread::run() #if 1 void dumpLLSDToFile(const LLSD& content, std::string filename) { - std::ofstream of(filename); + std::ofstream of(filename.c_str()); LLSDSerialize::toPrettyXML(content,of); } #endif -- cgit v1.2.3 From 294c5f3d3a29f1d52b587b9b1750b65238ca2dee Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Mon, 23 May 2011 12:15:04 -0400 Subject: SH-1616 FIX SL client crashes on startup for debug builds Added more NULL checks for llconvexdecompositionstub, to avoid crashing. Clients won't be able to upload meshes using the stub, but should be able to run the client otherwise. --- indra/newview/llmeshrepository.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 0a1eadf4d0..f06c5dcd64 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3374,6 +3374,12 @@ void LLPhysicsDecomp::doDecomposition() LLCDMeshData mesh; S32 stage = mStageID[mCurRequest->mStage]; + if (LLConvexDecomposition::getInstance() == NULL) + { + // stub library. do nothing. + return; + } + //load data intoLLCD if (stage == 0) { @@ -3574,6 +3580,12 @@ void LLPhysicsDecomp::doDecompositionSingleHull() LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); + if (decomp == NULL) + { + //stub. do nothing. + return; + } + for (S32 i = 0; i < param_count; ++i) { decomp->setParam(params[i].mName, params[i].mDefault.mIntOrEnumValue); @@ -3653,6 +3665,11 @@ void LLPhysicsDecomp::doDecompositionSingleHull() void LLPhysicsDecomp::run() { LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); + if (decomp == NULL) + { + return; + } + decomp->initThread(); mInited = true; -- cgit v1.2.3 From 0ef13640636bf8dbc252b9b4ee3849ccc0d2148c Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Mon, 23 May 2011 16:56:06 -0400 Subject: STORM-1275 FIX viewer gets caught in infinite loop for decompstub Fixed setting the initialized flag for the decomposition stub case (for OS builds) so that the viewer doesn't hang when initializing the stub. Note that initialized will be set to true even when instance will return NULL. --- indra/newview/llmeshrepository.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index f06c5dcd64..0b96a3b34f 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3667,6 +3667,9 @@ void LLPhysicsDecomp::run() LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance(); if (decomp == NULL) { + // stub library. Set init to true so the main thread + // doesn't wait for this to finish. + mInited = true; return; } -- cgit v1.2.3