diff options
Diffstat (limited to 'indra/newview/llmeshrepository.cpp')
-rw-r--r-- | indra/newview/llmeshrepository.cpp | 326 |
1 files changed, 320 insertions, 6 deletions
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<LLVector3> pos; LLStrider<LLVector3> 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<LLUUID> incomplete; + for (std::set<LLUUID>::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<std::string> 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<LLVolume> 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<LLVector3> pos; + LLStrider<U16> 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<LLUUID>::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) |