This fixes https://code.google.com/p/singularity-viewer/issues/detail?id=736 The problem was that we need to keep the 'user' derived THREAD_IMPL alive in the thread, and therefore used an LLPointer<THREAD_IMPL> (as base class of AIStateMachineThread<THREAD_IMPL>), and therefore THREAD_IMPL, derived from AIThreadImpl had to be derived from LLThreadSafeRefCount. However, AIStateMachineThread<THREAD_IMPL> also needed to be a statemachine of itself and is derived from AIStateMachineThreadBase derived from AIStateMachine which is ALSO derived from LLThreadSafeRefCount - that in this case wasn't really needed. An attempt to deactive it by calling ref() from the constructor of AIStateMachineThreadBase failed on the fact that LLThreadSafeRefCount insists that its ref count mRef is exactly zero when it is being deleted. The chosen solution is to remove the ref count from AIThreadImpl and use the LLThreadSafeRefCount base class of AIStateMachineThreadBase. The result is that not only THREAD_IMPL, but also the state machine object is kept alive, but that doesn't seem like a problem. Thus, instead of passing a AIThreadImpl* to AIStateMachineThreadBase::Thread, we now pass a AIStateMachineThreadBase* to it to keep the whole of the AIStateMachineThread<THREAD_IMPL> object alive, which has a THREAD_IMPL as member now. This member then can be accessed through a virtual function impl(). Another result of this change is that the 'user' (the class derived from AIThreadImpl, THREAD_IMPL) now has to deal with the LLPointer, and use LLPointer<AIStateMachineThread<THREAD_IMPL> > instead of just AIStateMachineThread<THREAD_IMPL> and also allocate this object himself. The access from there then changes into a -> to access the state machine (as opposed to a .) and ->thread_impl() to access the THREAD_IMPL object (as opposed to a ->).
572 lines
15 KiB
C++
572 lines
15 KiB
C++
/**
|
|
* @file llmeshrepository.h
|
|
* @brief Client-side repository of mesh assets.
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/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"
|
|
#include "lluploadfloaterobservers.h"
|
|
#include "aistatemachinethread.h"
|
|
|
|
class LLVOVolume;
|
|
class LLMeshResponder;
|
|
class LLMutex;
|
|
class LLCondition;
|
|
class LLVFS;
|
|
class LLMeshRepository;
|
|
class AIMeshUpload;
|
|
|
|
class LLMeshUploadData
|
|
{
|
|
public:
|
|
LLPointer<LLModel> mBaseModel;
|
|
LLPointer<LLModel> mModel[5];
|
|
LLUUID mUUID;
|
|
U32 mRetries;
|
|
std::string mRSVP;
|
|
std::string mAssetData;
|
|
LLSD mPostData;
|
|
|
|
LLMeshUploadData()
|
|
{
|
|
mRetries = 0;
|
|
}
|
|
};
|
|
|
|
class LLTextureUploadData
|
|
{
|
|
public:
|
|
LLViewerFetchedTexture* 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<LLViewerFetchedTexture> mDiffuseMap;
|
|
std::string mDiffuseMapFilename;
|
|
std::string mDiffuseMapLabel;
|
|
std::string mBinding;
|
|
LLColor4 mDiffuseColor;
|
|
bool mFullbright;
|
|
|
|
bool operator<(const LLImportMaterial ¶ms) const;
|
|
|
|
LLImportMaterial()
|
|
: mFullbright(false)
|
|
{
|
|
mDiffuseColor.set(1, 1, 1, 1);
|
|
}
|
|
|
|
LLImportMaterial(LLSD& data);
|
|
|
|
LLSD asLLSD();
|
|
};
|
|
|
|
class LLModelInstance
|
|
{
|
|
public:
|
|
LLPointer<LLModel> mModel;
|
|
LLPointer<LLModel> mLOD[5];
|
|
|
|
std::string mLabel;
|
|
|
|
LLUUID mMeshID;
|
|
S32 mLocalMeshID;
|
|
|
|
LLMatrix4 mTransform;
|
|
std::map<std::string, LLImportMaterial> mMaterial;
|
|
|
|
LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials)
|
|
: mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
|
|
{
|
|
mLocalMeshID = -1;
|
|
}
|
|
|
|
LLModelInstance(LLSD& data);
|
|
|
|
LLSD asLLSD();
|
|
};
|
|
|
|
class LLPhysicsDecomp : public LLThread
|
|
{
|
|
public:
|
|
|
|
typedef std::map<std::string, LLSD> decomp_params;
|
|
|
|
class Request : public LLRefCount
|
|
{
|
|
public:
|
|
//input params
|
|
S32* mDecompID;
|
|
std::string mStage;
|
|
std::vector<LLVector3> mPositions;
|
|
std::vector<U16> mIndices;
|
|
decomp_params mParams;
|
|
|
|
//output state
|
|
std::string mStatusMessage;
|
|
std::vector<LLModel::PhysicsMesh> mHullMesh;
|
|
LLModel::convex_hull_decomposition mHull;
|
|
|
|
//status message callback, called from decomposition thread
|
|
virtual S32 statusCallback(const char* status, S32 p1, S32 p2) = 0;
|
|
|
|
//completed callback, called from the main thread
|
|
virtual void completed() = 0;
|
|
|
|
virtual void setStatusMessage(const std::string& msg);
|
|
|
|
bool isValid() const {return mPositions.size() > 2 && mIndices.size() > 2 ;}
|
|
|
|
protected:
|
|
//internal use
|
|
LLVector3 mBBox[2] ;
|
|
F32 mTriangleAreaThreshold ;
|
|
|
|
void assignData(LLModel* mdl) ;
|
|
void updateTriangleAreaThreshold() ;
|
|
bool isValidTriangle(U16 idx1, U16 idx2, U16 idx3) ;
|
|
};
|
|
|
|
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();
|
|
|
|
void setMeshData(LLCDMeshData& mesh, bool vertex_based);
|
|
void doDecomposition();
|
|
void doDecompositionSingleHull();
|
|
|
|
virtual void run();
|
|
|
|
void completeCurrent();
|
|
void notifyCompleted();
|
|
|
|
std::map<std::string, S32> mStageID;
|
|
|
|
typedef std::queue<LLPointer<Request> > request_queue;
|
|
request_queue mRequestQ;
|
|
|
|
LLPointer<Request> mCurRequest;
|
|
|
|
std::queue<LLPointer<Request> > mCompletedQ;
|
|
|
|
};
|
|
|
|
class LLMeshRepoThread : public LLThread
|
|
{
|
|
public:
|
|
|
|
static S32 sActiveHeaderRequests;
|
|
static S32 sActiveLODRequests;
|
|
static U32 sMaxConcurrentRequests;
|
|
|
|
LLMutex* mMutex;
|
|
LLMutex* mHeaderMutex;
|
|
LLCondition* mSignal;
|
|
|
|
//map of known mesh headers
|
|
typedef std::map<LLUUID, LLSD> mesh_header_map;
|
|
mesh_header_map mMeshHeader;
|
|
|
|
std::map<LLUUID, U32> mMeshHeaderSize;
|
|
|
|
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<LLVolume> 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<LLUUID> mSkinRequests;
|
|
|
|
//queue of completed skin info requests
|
|
std::queue<LLMeshSkinInfo> mSkinInfoQ;
|
|
|
|
//set of requested decompositions
|
|
std::set<LLUUID> mDecompositionRequests;
|
|
|
|
//set of requested physics shapes
|
|
std::set<LLUUID> mPhysicsShapeRequests;
|
|
|
|
//queue of completed Decomposition info requests
|
|
std::queue<LLModel::Decomposition*> mDecompositionQ;
|
|
|
|
//queue of requested headers
|
|
std::queue<HeaderRequest> mHeaderReqQ;
|
|
|
|
//queue of requested LODs
|
|
std::queue<LODRequest> mLODReqQ;
|
|
|
|
//queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD)
|
|
std::queue<LODRequest> mUnavailableQ;
|
|
|
|
//queue of successfully loaded meshes
|
|
std::queue<LoadedMesh> mLoadedQ;
|
|
|
|
//map of pending header requests and currently desired LODs
|
|
typedef std::map<LLVolumeParams, std::vector<S32> > 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, U32& count);
|
|
void fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count);
|
|
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);
|
|
bool physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
|
|
LLSD& getMeshHeader(const LLUUID& mesh_id);
|
|
|
|
void notifyLoadedMeshes();
|
|
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
|
|
|
|
void loadMeshSkinInfo(const LLUUID& mesh_id);
|
|
void loadMeshDecomposition(const LLUUID& mesh_id);
|
|
void loadMeshPhysicsShape(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);
|
|
|
|
//send request for PhysicsShape, returns true if header info exists
|
|
// (should hold onto mesh_id and try again later if header info does not exist)
|
|
bool fetchMeshPhysicsShape(const LLUUID& mesh_id);
|
|
|
|
|
|
};
|
|
|
|
class LLMeshUploadThread : public AIThreadImpl
|
|
{
|
|
private:
|
|
S32 mMeshUploadTimeOut ; //maximum time in seconds to execute an uploading request.
|
|
|
|
public:
|
|
class DecompRequest : public LLPhysicsDecomp::Request
|
|
{
|
|
public:
|
|
LLPointer<LLModel> mModel;
|
|
LLPointer<LLModel> mBaseModel;
|
|
|
|
LLMeshUploadThread* mThread;
|
|
|
|
DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread);
|
|
|
|
S32 statusCallback(const char* status, S32 p1, S32 p2) { return 1; }
|
|
void completed();
|
|
};
|
|
|
|
LLPointer<DecompRequest> mFinalDecomp;
|
|
bool mPhysicsComplete;
|
|
LLSD mModelData;
|
|
LLSD mBody;
|
|
|
|
typedef std::map<LLPointer<LLModel>, std::vector<LLVector3> > hull_map;
|
|
hull_map mHullMap;
|
|
|
|
typedef std::vector<LLModelInstance> instance_list;
|
|
instance_list mInstanceList;
|
|
|
|
typedef std::map<LLPointer<LLModel>, instance_list> instance_map;
|
|
instance_map mInstance;
|
|
|
|
LLVector3 mOrigin;
|
|
bool mUploadTextures;
|
|
bool mUploadSkin;
|
|
bool mUploadJoints;
|
|
|
|
LLHost mHost;
|
|
std::string mWholeModelFeeCapability;
|
|
|
|
#ifdef LL_DEBUG
|
|
LLMeshUploadThread(void) : AIThreadImpl("mesh upload") { }
|
|
#endif
|
|
void init(instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool do_upload,
|
|
LLHandle<LLWholeModelFeeObserver> const& fee_observer, LLHandle<LLWholeModelUploadObserver> const& upload_observer);
|
|
|
|
void postRequest(std::string& url, AIMeshUpload* state_machine);
|
|
|
|
/*virtual*/ bool run();
|
|
void preStart();
|
|
|
|
void generateHulls();
|
|
|
|
void wholeModelToLLSD(LLSD& dest, bool include_textures);
|
|
|
|
void decomposeMeshMatrix(LLMatrix4& transformation,
|
|
LLVector3& result_pos,
|
|
LLQuaternion& result_rot,
|
|
LLVector3& result_scale);
|
|
|
|
void setFeeObserverHandle(LLHandle<LLWholeModelFeeObserver> observer_handle) { mFeeObserverHandle = observer_handle; }
|
|
void setUploadObserverHandle(LLHandle<LLWholeModelUploadObserver> observer_handle) { mUploadObserverHandle = observer_handle; }
|
|
|
|
private:
|
|
LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;
|
|
LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle;
|
|
|
|
bool mDoUpload; // if FALSE only model data will be requested, otherwise the model will be uploaded
|
|
};
|
|
|
|
enum AIMeshUpload_state_type {
|
|
AIMeshUpload_start = AIStateMachine::max_state,
|
|
AIMeshUpload_threadFinished,
|
|
AIMeshUpload_responderFinished
|
|
};
|
|
|
|
class AIMeshUpload : public AIStateMachine
|
|
{
|
|
private:
|
|
LLPointer<AIStateMachineThread<LLMeshUploadThread> > mMeshUpload;
|
|
std::string mWholeModelUploadURL;
|
|
|
|
public:
|
|
AIMeshUpload(LLMeshUploadThread::instance_list& data, LLVector3& scale,
|
|
bool upload_textures, bool upload_skin, bool upload_joints, std::string const& upload_url, bool do_upload,
|
|
LLHandle<LLWholeModelFeeObserver> const& fee_observer, LLHandle<LLWholeModelUploadObserver> const& upload_observer);
|
|
|
|
void setWholeModelUploadURL(std::string const& whole_model_upload_url) { mWholeModelUploadURL = whole_model_upload_url; }
|
|
|
|
protected:
|
|
// Implement AIStateMachine.
|
|
/*virtual*/ const char* state_str_impl(state_type run_state) const;
|
|
/*virtual*/ void initialize_impl();
|
|
/*virtual*/ void multiplex_impl(state_type run_state);
|
|
};
|
|
|
|
class LLMeshRepository
|
|
{
|
|
public:
|
|
|
|
//metrics
|
|
static U32 sBytesReceived;
|
|
static U32 sHTTPRequestCount;
|
|
static U32 sHTTPRetryCount;
|
|
static U32 sLODPending;
|
|
static U32 sLODProcessing;
|
|
static U32 sCacheBytesRead;
|
|
static U32 sCacheBytesWritten;
|
|
static U32 sPeakKbps;
|
|
|
|
static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL);
|
|
|
|
LLMeshRepository();
|
|
|
|
void init();
|
|
void shutdown();
|
|
|
|
//mesh management functions
|
|
S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);
|
|
|
|
void notifyLoadedMeshes();
|
|
void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
|
|
void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
|
|
void notifySkinInfoReceived(LLMeshSkinInfo& info);
|
|
void notifyDecompositionReceived(LLModel::Decomposition* info);
|
|
|
|
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
|
|
static S32 getActualMeshLOD(LLSD& header, S32 lod);
|
|
const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj);
|
|
LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
|
|
void fetchPhysicsShape(const LLUUID& mesh_id);
|
|
bool hasPhysicsShape(const LLUUID& mesh_id);
|
|
|
|
void buildHull(const LLVolumeParams& params, S32 detail);
|
|
void buildPhysicsMesh(LLModel::Decomposition& decomp);
|
|
|
|
bool meshUploadEnabled();
|
|
bool meshRezEnabled();
|
|
|
|
|
|
LLSD& getMeshHeader(const LLUUID& mesh_id);
|
|
|
|
void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
|
|
bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true,
|
|
LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()),
|
|
LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
|
|
|
|
S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
|
|
|
|
typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
|
|
mesh_load_map mLoadingMeshes[4];
|
|
|
|
typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;
|
|
skin_map mSkinMap;
|
|
|
|
typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
|
|
decomposition_map mDecompositionMap;
|
|
|
|
LLMutex* mMeshMutex;
|
|
|
|
std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;
|
|
|
|
//list of mesh ids awaiting skin info
|
|
typedef std::map<LLUUID, std::set<LLUUID> > skin_load_map;
|
|
skin_load_map mLoadingSkins;
|
|
|
|
//list of mesh ids that need to send skin info fetch requests
|
|
std::queue<LLUUID> mPendingSkinRequests;
|
|
|
|
//list of mesh ids awaiting decompositions
|
|
std::set<LLUUID> mLoadingDecompositions;
|
|
|
|
//list of mesh ids that need to send decomposition fetch requests
|
|
std::queue<LLUUID> mPendingDecompositionRequests;
|
|
|
|
//list of mesh ids awaiting physics shapes
|
|
std::set<LLUUID> mLoadingPhysicsShapes;
|
|
|
|
//list of mesh ids that need to send physics shape fetch requests
|
|
std::queue<LLUUID> mPendingPhysicsShapeRequests;
|
|
|
|
U32 mMeshThreadCount;
|
|
|
|
void cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header);
|
|
|
|
LLMeshRepoThread* mThread;
|
|
|
|
LLPhysicsDecomp* mDecompThread;
|
|
|
|
class inventory_data
|
|
{
|
|
public:
|
|
LLSD mPostData;
|
|
LLSD mResponse;
|
|
|
|
inventory_data(const LLSD& data, const LLSD& content)
|
|
: mPostData(data), mResponse(content)
|
|
{
|
|
}
|
|
};
|
|
|
|
std::queue<inventory_data> mInventoryQ;
|
|
|
|
std::queue<LLSD> mUploadErrorQ;
|
|
|
|
void uploadError(LLSD& args);
|
|
void updateInventory(inventory_data data);
|
|
|
|
std::string mGetMeshCapability;
|
|
|
|
};
|
|
|
|
extern LLMeshRepository gMeshRepo;
|
|
|
|
#endif
|