/** * @file llfloatermodelpreview.h * @brief LLFloaterModelPreview class definition * * $LicenseInfo:firstyear=2004&license=viewergpl$ * * Copyright (c) 2010, 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_LLFLOATERMODELPREVIEW_H #define LL_LLFLOATERMODELPREVIEW_H #include "lldynamictexture.h" #include "llquaternion.h" #include "llmeshrepository.h" #include "llmodel.h" #include "llthread.h" #include "llviewermenufile.h" #include "llfloatermodeluploadbase.h" class LLComboBox; class LLVOAvatar; class LLVertexBuffer; class LLModelPreview; class LLFloaterModelPreview; class daeElement; class domProfile_COMMON; class domInstance_geometry; class domNode; class domTranslate; class domController; typedef std::map JointTransformMap; typedef std::map:: iterator JointTransformMapIt; const S32 NUM_LOD = 4; class LLModelLoader : public LLThread { public: typedef enum { STARTING = 0, READING_FILE, CREATING_FACES, GENERATING_VERTEX_BUFFERS, GENERATING_LOD, DONE, ERROR_PARSING, //basically loading failed ERROR_MATERIALS, } eLoadState; U32 mState; std::string mFilename; S32 mLod; LLModelPreview* mPreview; LLMatrix4 mTransform; BOOL mFirstTransform; LLVector3 mExtents[2]; bool mTrySLM; std::map > mModel; typedef std::vector > model_list; model_list mModelList; typedef std::vector model_instance_list; typedef std::map scene; scene mScene; typedef std::queue > model_queue; //queue of models that need a physics rep model_queue mPhysicsQ; LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap, std::deque& jointsFromNodes); ~LLModelLoader() ; virtual void run(); bool doLoadModel(); bool loadFromSLM(const std::string& filename); void loadModelCallback(); void loadTextures() ; //called in the main thread. void processElement(daeElement* element, bool& badElement); std::map getMaterials(LLModel* model, domInstance_geometry* instance_geo); LLImportMaterial profileToMaterial(domProfile_COMMON* material); std::string getElementLabel(daeElement *element); LLColor4 getDaeColor(daeElement* element); daeElement* getChildFromElement(daeElement* pElement, std::string const & name); bool isNodeAJoint(domNode* pNode); void processJointNode(domNode* pNode, std::map& jointTransforms); void extractTranslation(domTranslate* pTranslate, LLMatrix4& transform); void extractTranslationViaElement(daeElement* pTranslateElement, LLMatrix4& transform); void extractTranslationViaSID(daeElement* pElement, LLMatrix4& transform); void setLoadState(U32 state); void buildJointToNodeMappingFromScene(daeElement* pRoot); void processJointToNodeMapping(domNode* pNode); void processChildJoints(domNode* pParentNode); //map of avatar joints as named in COLLADA assets to internal joint names std::map mJointMap; JointTransformMap& mJointList; std::deque& mJointsFromNode; S32 mNumOfFetchingTextures ; //updated in the main thread bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. private: static std::list sActiveLoaderList; static bool isAlive(LLModelLoader* loader) ; }; class LLFloaterModelPreview : public LLFloaterModelUploadBase { public: class DecompRequest : public LLPhysicsDecomp::Request { public: S32 mContinue; LLPointer mModel; DecompRequest(const std::string& stage, LLModel* mdl); virtual S32 statusCallback(const char* status, S32 p1, S32 p2); virtual void completed(); }; static LLFloaterModelPreview* sInstance; LLFloaterModelPreview(const std::string& name); virtual ~LLFloaterModelPreview(); virtual BOOL postBuild(); void initModelPreview(); BOOL handleMouseDown(S32 x, S32 y, MASK mask); BOOL handleMouseUp(S32 x, S32 y, MASK mask); BOOL handleHover(S32 x, S32 y, MASK mask); BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); /*virtual*/ void onOpen(/*const LLSD& key*/); static void onMouseCaptureLostModelPreview(LLMouseHandler*); static void setUploadAmount(S32 amount) { sUploadAmount = amount; } void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); void onBrowseLOD(S32 lod); static void onReset(void* data); static void onUpload(void* data); void refresh(); void loadModel(S32 lod); void loadModel_continued(AIFilePicker* filepicker, S32 lod); void loadModel(S32 lod, const std::string& file_name, bool force_disable_slm = false); void onViewOptionChecked(LLUICtrl* ctrl); bool isViewOptionChecked(const LLSD& userdata); bool isViewOptionEnabled(const LLSD& userdata); void setViewOptionEnabled(const std::string& option, bool enabled); void enableViewOption(const std::string& option); void disableViewOption(const std::string& option); // shows warning message if agent has no permissions to upload model /*virtual*/ void onPermissionsReceived(const LLSD& result); // called when error occurs during permissions request /*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason); /*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url); void handleModelPhysicsFeeReceived(); /*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason); /*virtual*/ void onModelUploadSuccess(); /*virtual*/ void onModelUploadFailure(); protected: friend class LLModelPreview; friend class LLPhysicsDecomp; static void onImportScaleCommit(LLUICtrl*, void*); static void onPelvisOffsetCommit(LLUICtrl*, void*); static void onUploadJointsCommit(LLUICtrl*,void*); static void onUploadSkinCommit(LLUICtrl*,void*); static void onPreviewLODCommit(LLUICtrl*,void*); static void onGenerateNormalsCommit(LLUICtrl*,void*); void toggleGenerateNormals(); static void onAutoFillCommit(LLUICtrl*,void*); void onLODParamCommit(S32 lod, bool enforce_tri_limit); static void onExplodeCommit(LLUICtrl*, void*); static void onPhysicsParamCommit(LLUICtrl* ctrl, void* userdata); static void onPhysicsStageExecute(LLUICtrl* ctrl, void* userdata); static void onCancel(LLUICtrl* ctrl, void* userdata); static void onPhysicsStageCancel(LLUICtrl* ctrl, void* userdata); static void onPhysicsBrowse(LLUICtrl* ctrl, void* userdata); static void onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata); static void onPhysicsOptimize(LLUICtrl* ctrl, void* userdata); static void onPhysicsDecomposeBack(LLUICtrl* ctrl, void* userdata); static void onPhysicsSimplifyBack(LLUICtrl* ctrl, void* userdata); void draw(); void initDecompControls(); void setStatusMessage(const std::string& msg); LLModelPreview* mModelPreview; LLPhysicsDecomp::decomp_params mDecompParams; S32 mLastMouseX; S32 mLastMouseY; LLRect mPreviewRect; static S32 sUploadAmount; std::set > mCurRequest; std::string mStatusMessage; //use "disabled" as false by default std::map mViewOptionDisabled; //store which lod mode each LOD is using // 0 - load from file // 1 - auto generate // 2 - use LoD above S32 mLODMode[4]; LLMutex* mStatusLock; LLSD mModelPhysicsFee; private: void onClickCalculateBtn(); void toggleCalculateButton(); void onLoDSourceCommit(S32 lod); // Toggles between "Calculate weights & fee" and "Upload" buttons. void toggleCalculateButton(bool visible); // resets display options of model preview to their defaults. void resetDisplayOptions(); void createSmoothComboBox(LLComboBox* combo_box, float min, float max); LLButton* mUploadBtn; LLButton* mCalculateBtn; }; class LLModelPreview : public LLViewerDynamicTexture, public LLMutex { typedef boost::signals2::signal details_signal_t; typedef boost::signals2::signal model_loaded_signal_t; typedef boost::signals2::signal model_updated_signal_t; public: LLModelPreview(S32 width, S32 height, LLFloater* fmp); virtual ~LLModelPreview(); void resetPreviewTarget(); void setPreviewTarget(F32 distance); void setTexture(U32 name) { mTextureName = name; } void setPhysicsFromLOD(S32 lod); BOOL render(); void update(); void genBuffers(S32 lod, bool skinned); void clearBuffers(); void refresh(); void rotate(F32 yaw_radians, F32 pitch_radians); void zoom(F32 zoom_amt); void pan(F32 right, F32 up); virtual BOOL needsRender() { return mNeedsUpdate; } void setPreviewLOD(S32 lod); void clearModel(S32 lod); void loadModel(std::string filename, S32 lod, bool force_disable_slm = false); void loadModelCallback(S32 lod); void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); void generateNormals(); U32 calcResourceCost(); void rebuildUploadData(); void saveUploadData(bool save_skinweights, bool save_joint_poisitions); void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_poisitions); void clearIncompatible(S32 lod); void updateStatusMessages(); void updateLodControls(S32 lod); void clearGLODGroup(); void onLODParamCommit(S32 lod, bool enforce_tri_limit); void addEmptyFace(LLModel* pTarget); const bool getModelPivot(void) const { return mHasPivot; } void setHasPivot(bool val) { mHasPivot = val; } void setModelPivot(const LLVector3& pivot) { mModelPivot = pivot; } //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps) void critiqueRigForUploadApplicability(const std::vector &jointListFromAsset); void critiqueJointToNodeMappingFromScene(void); //Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions //Accessors for joint position upload friendly rigs const bool isRigValidForJointPositionUpload(void) const { return mRigValidJointUpload; } void setRigValidForJointPositionUpload(bool rigValid) { mRigValidJointUpload = rigValid; } bool isRigSuitableForJointPositionUpload(const std::vector &jointListFromAsset); //Determines if a rig is a legacy from the joint list bool isRigLegacy(const std::vector &jointListFromAsset); //Accessors for the legacy rigs const bool isLegacyRigValid(void) const { return mLegacyRigValid; } void setLegacyRigValid(bool rigValid) { mLegacyRigValid = rigValid; } //Verify that a controller matches vertex counts bool verifyController(domController* pController); static void textureLoadedCallback(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata); boost::signals2::connection setDetailsCallback(const details_signal_t::slot_type& cb){ return mDetailsSignal.connect(cb); } boost::signals2::connection setModelLoadedCallback(const model_loaded_signal_t::slot_type& cb){ return mModelLoadedSignal.connect(cb); } boost::signals2::connection setModelUpdatedCallback(const model_updated_signal_t::slot_type& cb){ return mModelUpdatedSignal.connect(cb); } void setLoadState(U32 state) { mLoadState = state; } U32 getLoadState() { return mLoadState; } void setRigWithSceneParity(bool state) { mRigParityWithScene = state; } const bool getRigWithSceneParity(void) const { return mRigParityWithScene; } LLVector3 getTranslationForJointOffset(std::string joint); private: //Utility function for controller vertex compare bool verifyCount(int expected, int result); //Creates the dummy avatar for the preview window void createPreviewAvatar(void); //Accessor for the dummy avatar LLVOAvatar* getPreviewAvatar(void) { return mPreviewAvatar; } protected: friend class LLModelLoader; friend class LLFloaterModelPreview; friend class LLFloaterModelPreview::DecompRequest; friend class LLPhysicsDecomp; LLFloater* mFMP; BOOL mNeedsUpdate; bool mDirty; bool mGenLOD; U32 mTextureName; F32 mCameraDistance; F32 mCameraYaw; F32 mCameraPitch; F32 mCameraZoom; LLVector3 mCameraOffset; LLVector3 mPreviewTarget; LLVector3 mPreviewScale; S32 mPreviewLOD; U32 mResourceCost; std::string mLODFile[LLModel::NUM_LODS]; bool mLoading; U32 mLoadState; bool mResetJoints; bool mRigParityWithScene; std::map mViewOption; //GLOD object parameters (must rebuild object if these change) bool mLODFrozen; F32 mBuildShareTolerance; U32 mBuildQueueMode; U32 mBuildOperator; U32 mBuildBorderMode; U32 mRequestedLoDMode[LLModel::NUM_LODS]; S32 mRequestedTriangleCount[LLModel::NUM_LODS]; F32 mRequestedErrorThreshold[LLModel::NUM_LODS]; U32 mRequestedBuildOperator[LLModel::NUM_LODS]; U32 mRequestedQueueMode[LLModel::NUM_LODS]; U32 mRequestedBorderMode[LLModel::NUM_LODS]; F32 mRequestedShareTolerance[LLModel::NUM_LODS]; F32 mRequestedCreaseAngle[LLModel::NUM_LODS]; LLModelLoader* mModelLoader; LLModelLoader::scene mScene[LLModel::NUM_LODS]; LLModelLoader::scene mBaseScene; LLModelLoader::model_list mModel[LLModel::NUM_LODS]; LLModelLoader::model_list mBaseModel; U32 mGroup; std::map, U32> mObject; U32 mMaxTriangleLimit; LLMeshUploadThread::instance_list mUploadData; std::set mTextureSet; //map of vertex buffers to models (one vertex buffer in vector per face in model std::map > > mVertexBuffer[LLModel::NUM_LODS+1]; details_signal_t mDetailsSignal; model_loaded_signal_t mModelLoadedSignal; model_updated_signal_t mModelUpdatedSignal; LLVector3 mModelPivot; bool mHasPivot; float mPelvisZOffset; bool mRigValidJointUpload; bool mLegacyRigValid; bool mLastJointUpdate; std::deque mMasterJointList; std::deque mMasterLegacyJointList; std::deque mJointsFromNode; JointTransformMap mJointTransformMap; LLPointer mPreviewAvatar; }; #endif // LL_LLFLOATERMODELPREVIEW_H