/** * @file llmeshrepository.h * @brief Client-side repository of mesh assets. * * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-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$ */ #ifndef LL_MESH_REPOSITORY_H #define LL_MESH_REPOSITORY_H #include "llassettype.h" #include "llmodel.h" #include "lluuid.h" #include "llviewertexture.h" #include "llvolume.h" #define LLCONVEXDECOMPINTER_STATIC 1 #include "llconvexdecomposition.h" class LLVOVolume; class LLMeshResponder; class LLCurlRequest; class LLMutex; class LLCondition; class LLVFS; class LLMeshRepository; class LLMeshUploadData { public: LLPointer mBaseModel; LLPointer mModel[5]; LLUUID mUUID; U32 mRetries; std::string mRSVP; std::string mAssetData; LLSD mPostData; LLMeshUploadData() { mRetries = 0; } }; class LLTextureUploadData { public: LLPointer mTexture; LLUUID mUUID; std::string mRSVP; std::string mLabel; U32 mRetries; std::string mAssetData; LLSD mPostData; LLTextureUploadData() { mRetries = 0; } LLTextureUploadData(LLViewerFetchedTexture* texture, std::string& label) : mTexture(texture), mLabel(label) { mRetries = 0; } }; class LLImportMaterial { public: LLPointer mDiffuseMap; std::string mDiffuseMapFilename; std::string mDiffuseMapLabel; LLColor4 mDiffuseColor; bool mFullbright; bool operator<(const LLImportMaterial ¶ms) const; LLImportMaterial() : mFullbright(false) { mDiffuseColor.set(1,1,1,1); } }; class LLModelInstance { public: LLPointer mModel; LLPointer mLOD[5]; LLUUID mMeshID; LLMatrix4 mTransform; std::vector mMaterial; LLModelInstance(LLModel* model, LLMatrix4& transform, std::vector& materials) : mModel(model), mTransform(transform), mMaterial(materials) { } }; class LLMeshSkinInfo { public: LLUUID mMeshID; std::vector mJointNames; std::vector mInvBindMatrix; std::vector mAlternateBindMatrix; LLMatrix4 mBindShapeMatrix; }; class LLMeshDecomposition { public: LLMeshDecomposition() { } LLUUID mMeshID; LLModel::physics_shape mHull; std::vector > mMesh; }; class LLPhysicsDecomp : public LLThread { public: typedef std::map decomp_params; class Request : public LLRefCount { public: //input params std::string mStage; std::vector mPositions; std::vector mIndices; decomp_params mParams; //output state std::string mStatusMessage; std::vector > mHullMesh; LLModel::physics_shape mHull; virtual S32 statusCallback(const char* status, S32 p1, S32 p2) = 0; virtual void completed() = 0; virtual void setStatusMessage(const std::string& msg); }; LLCondition* mSignal; LLMutex* mMutex; bool mInited; bool mQuitting; bool mDone; LLPhysicsDecomp(); ~LLPhysicsDecomp(); void shutdown(); void submitRequest(Request* request); static S32 llcdCallback(const char*, S32, S32); void cancel(); virtual void run(); std::map mStageID; typedef std::queue > request_queue; request_queue mRequestQ; LLPointer mCurRequest; }; class LLMeshRepoThread : public LLThread { public: static S32 sActiveHeaderRequests; static S32 sActiveLODRequests; static U32 sMaxConcurrentRequests; LLCurlRequest* mCurlRequest; LLMutex* mMutex; LLMutex* mHeaderMutex; LLCondition* mSignal; bool mWaiting; //map of known mesh headers typedef std::map mesh_header_map; mesh_header_map mMeshHeader; std::map mMeshHeaderSize; std::map mMeshResourceCost; class HeaderRequest { public: const LLVolumeParams mMeshParams; HeaderRequest(const LLVolumeParams& mesh_params) : mMeshParams(mesh_params) { } bool operator<(const HeaderRequest& rhs) const { return mMeshParams < rhs.mMeshParams; } }; class LODRequest { public: LLVolumeParams mMeshParams; S32 mLOD; F32 mScore; LODRequest(const LLVolumeParams& mesh_params, S32 lod) : mMeshParams(mesh_params), mLOD(lod), mScore(0.f) { } }; struct CompareScoreGreater { bool operator()(const LODRequest& lhs, const LODRequest& rhs) { return lhs.mScore > rhs.mScore; // greatest = first } }; class LoadedMesh { public: LLPointer mVolume; LLVolumeParams mMeshParams; S32 mLOD; LoadedMesh(LLVolume* volume, const LLVolumeParams& mesh_params, S32 lod) : mVolume(volume), mMeshParams(mesh_params), mLOD(lod) { } }; //set of requested skin info std::set mSkinRequests; //queue of completed skin info requests std::queue mSkinInfoQ; //set of requested decompositions std::set mDecompositionRequests; //queue of completed Decomposition info requests std::queue mDecompositionQ; //queue of requested headers std::queue mHeaderReqQ; //queue of requested LODs std::queue mLODReqQ; //queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD) std::queue mUnavailableQ; //queue of successfully loaded meshes std::queue mLoadedQ; //map of pending header requests and currently desired LODs typedef std::map > pending_lod_map; pending_lod_map mPendingLOD; static std::string constructUrl(LLUUID mesh_id); LLMeshRepoThread(); ~LLMeshRepoThread(); virtual void run(); void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod); bool fetchMeshHeader(const LLVolumeParams& mesh_params); bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod); bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size); bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size); bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size); bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size); const LLSD& getMeshHeader(const LLUUID& mesh_id); void notifyLoadedMeshes(); S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); U32 getResourceCost(const LLUUID& mesh_params); void loadMeshSkinInfo(const LLUUID& mesh_id); void loadMeshDecomposition(const LLUUID& mesh_id); //send request for skin info, returns true if header info exists // (should hold onto mesh_id and try again later if header info does not exist) bool fetchMeshSkinInfo(const LLUUID& mesh_id); //send request for decomposition, returns true if header info exists // (should hold onto mesh_id and try again later if header info does not exist) bool fetchMeshDecomposition(const LLUUID& mesh_id); }; class LLMeshUploadThread : public LLThread { public: typedef std::vector instance_list; instance_list mInstanceList; typedef std::map, instance_list> instance_map; instance_map mInstance; LLMutex* mMutex; LLCurlRequest* mCurlRequest; S32 mPendingConfirmations; S32 mPendingUploads; S32 mPendingCost; bool mFinished; LLVector3 mOrigin; bool mUploadTextures; bool mUploadSkin; bool mUploadJoints; LLHost mHost; std::string mUploadObjectAssetCapability; std::string mNewInventoryCapability; std::queue mUploadQ; std::queue mConfirmedQ; std::queue mInstanceQ; std::queue mTextureQ; std::queue mConfirmedTextureQ; std::map, LLTextureUploadData> mTextureMap; LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints); ~LLMeshUploadThread(); void uploadTexture(LLTextureUploadData& data); void doUploadTexture(LLTextureUploadData& data); void sendCostRequest(LLTextureUploadData& data); void priceResult(LLTextureUploadData& data, const LLSD& content); void onTextureUploaded(LLTextureUploadData& data); void uploadModel(LLMeshUploadData& data); void sendCostRequest(LLMeshUploadData& data); void doUploadModel(LLMeshUploadData& data); void onModelUploaded(LLMeshUploadData& data); void createObjects(LLMeshUploadData& data); LLSD createObject(LLModelInstance& instance); void priceResult(LLMeshUploadData& data, const LLSD& content); bool finished() { return mFinished; } virtual void run(); }; class LLMeshRepository { public: //metrics static U32 sBytesReceived; static U32 sHTTPRequestCount; static U32 sHTTPRetryCount; static U32 sCacheBytesRead; static U32 sCacheBytesWritten; static U32 sPeakKbps; static F32 getStreamingCost(const LLSD& header, F32 radius); LLMeshRepository(); void init(); void shutdown(); //mesh management functions S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0); void notifyLoadedMeshes(); void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume); void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod); void notifySkinInfoReceived(LLMeshSkinInfo& info); void notifyDecompositionReceived(LLMeshDecomposition* info); S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); U32 calcResourceCost(LLSD& header); U32 getResourceCost(const LLUUID& mesh_params); const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id); const LLMeshDecomposition* getDecomposition(const LLUUID& mesh_id); void buildHull(const LLVolumeParams& params, S32 detail); const LLSD& getMeshHeader(const LLUUID& mesh_id); void uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints); S32 getMeshSize(const LLUUID& mesh_id, S32 lod); typedef std::map > mesh_load_map; mesh_load_map mLoadingMeshes[4]; typedef std::map skin_map; skin_map mSkinMap; typedef std::map decomposition_map; decomposition_map mDecompositionMap; LLMutex* mMeshMutex; std::vector mPendingRequests; //list of mesh ids awaiting skin info std::set mLoadingSkins; //list of mesh ids that need to send skin info fetch requests std::queue mPendingSkinRequests; //list of mesh ids awaiting decompositions std::set mLoadingDecompositions; //list of mesh ids that need to send decomposition fetch requests std::queue mPendingDecompositionRequests; U32 mMeshThreadCount; void cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header); LLMeshRepoThread* mThread; std::vector mUploads; LLPhysicsDecomp* mDecompThread; class inventory_data { public: LLSD mPostData; LLSD mResponse; inventory_data(const LLSD& data, const LLSD& content) : mPostData(data), mResponse(content) { } }; std::queue mInventoryQ; std::queue mUploadErrorQ; void uploadError(LLSD& args); void updateInventory(inventory_data data); }; extern LLMeshRepository gMeshRepo; #endif