summaryrefslogtreecommitdiff
path: root/indra/newview/llmodelpreview.h
blob: 064623ac6a9541b44bfa780fd00369e5ea5607fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
/**
 * @file llmodelpreview.h
 * @brief LLModelPreview class definition, class
 * responsible for model preview inside LLFloaterModelPreview
 *
 * $LicenseInfo:firstyear=2020&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2020, 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_LLMODELPREVIEW_H
#define LL_LLMODELPREVIEW_H

#include "lldynamictexture.h"
#include "llfloatermodelpreview.h"
#include "llmeshrepository.h"
#include "llmodelloader.h" //NUM_LOD
#include "llmodel.h"

class LLJoint;
class LLVOAvatar;
class LLTextBox;
class LLVertexBuffer;
class DAE;
class daeElement;
class domProfile_COMMON;
class domInstance_geometry;
class domNode;
class domTranslate;
class domController;
class domSkin;
class domMesh;

// const strings needed by classes that use model preivew
static const std::string lod_name[NUM_LOD + 1] =
{
    "lowest",
    "low",
    "medium",
    "high",
    "I went off the end of the lod_name array.  Me so smart."
};

static const std::string lod_triangles_name[NUM_LOD + 1] =
{
    "lowest_triangles",
    "low_triangles",
    "medium_triangles",
    "high_triangles",
    "I went off the end of the lod_triangles_name array.  Me so smart."
};

static const std::string lod_vertices_name[NUM_LOD + 1] =
{
    "lowest_vertices",
    "low_vertices",
    "medium_vertices",
    "high_vertices",
    "I went off the end of the lod_vertices_name array.  Me so smart."
};

static const std::string lod_status_name[NUM_LOD + 1] =
{
    "lowest_status",
    "low_status",
    "medium_status",
    "high_status",
    "I went off the end of the lod_status_name array.  Me so smart."
};

static const std::string lod_icon_name[NUM_LOD + 1] =
{
    "status_icon_lowest",
    "status_icon_low",
    "status_icon_medium",
    "status_icon_high",
    "I went off the end of the lod_status_name array.  Me so smart."
};

static const std::string lod_status_image[NUM_LOD + 1] =
{
    "ModelImport_Status_Good",
    "ModelImport_Status_Warning",
    "ModelImport_Status_Error",
    "I went off the end of the lod_status_image array.  Me so smart."
};

static const std::string lod_label_name[NUM_LOD + 1] =
{
    "lowest_label",
    "low_label",
    "medium_label",
    "high_label",
    "I went off the end of the lod_label_name array.  Me so smart."
};

class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
{
    LOG_CLASS(LLModelPreview);

    typedef boost::signals2::signal<void(F32 x, F32 y, F32 z)> details_signal_t;
    typedef boost::signals2::signal<void(void)> model_loaded_signal_t;
    typedef boost::signals2::signal<void(bool)> model_updated_signal_t;

public:

    typedef enum
    {
        LOD_FROM_FILE = 0,
        MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face
        MESH_OPTIMIZER_PRECISE, // combines faces into a single model, simplifies, then splits back into faces
        MESH_OPTIMIZER_SLOPPY, // uses sloppy method, works per face
        USE_LOD_ABOVE,
    } eLoDMode;

    typedef enum
    {
        LIMIT_TRIANGLES = 0,
        LIMIT_ERROR_TRESHOLD,
    } eLoDLimit;

public:
    // Todo: model preview shouldn't need floater dependency, it
    // should just expose data to floater, not control flaoter like it does
    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 getJointAliases(JointMap& joint_map);
    void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);
    void loadModelCallback(S32 lod);
    bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
    void queryLODs() { mGenLOD = true; };
    void genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation = 3, bool enforce_tri_limit = false);
    void generateNormals();
    void restoreNormals();
    void updateDimentionsAndOffsets();
    void rebuildUploadData();
    void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position);
    void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position);
    void clearIncompatible(S32 lod);
    void updateStatusMessages();
    void updateLodControls(S32 lod);
    void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, S32 mode);
    void addEmptyFace(LLModel* pTarget);

    const bool getModelPivot(void) const { return mHasPivot; }
    void setHasPivot(bool val) { mHasPivot = val; }
    void setModelPivot(const LLVector3& pivot) { mModelPivot = pivot; }

    //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; }

    //Accessors for the legacy rigs
    const bool isLegacyRigValid(void) const { return mLegacyRigFlags == 0; }
    U32 getLegacyRigFlags() const { return mLegacyRigFlags; }
    void setLegacyRigFlags(U32 rigFlags) { mLegacyRigFlags = rigFlags; }

    static void textureLoadedCallback(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata);
    static bool lodQueryCallback();

    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; }

    static bool         sIgnoreLoadedCallback;
    std::vector<S32> mLodsQuery;
    std::vector<S32> mLodsWithParsingError;
    bool mHasDegenerate;

protected:

    static void         loadedCallback(LLModelLoader::scene& scene, LLModelLoader::model_list& model_list, S32 lod, void* opaque);
    static void         stateChangedCallback(U32 state, void* opaque);

    static LLJoint* lookupJointByName(const std::string&, void* opaque);
    static U32          loadTextures(LLImportMaterial& material, void* opaque);

    void lookupLODModelFiles(S32 lod);

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; }
    // Count amount of original models, excluding sub-models
    static U32 countRootModels(LLModelLoader::model_list models);
    LLVector3   mGroundPlane[4];
    void        renderGroundPlane(float z_offset = 0.0f);
    /// Indicates whether we should warn of high-lod meshes that do not have a corresponding physics mesh.
    /// Reset when resetting the modelpreview (i.e., when the uploader dialog is created or reset), and when
    /// about to process a physics file. Set to true immediately after the file is loaded (before rebuildUploadData()).
    ///
    /// (The rules for mapping the correspondence of high-lod meshes to physics meshes are complex. When
    /// lod rendering meshes are used, there is never an unmatched mesh. Nor is there a mismatch when
    /// the high-lod file and physics file have ony one mesh each. In these cases, this value is moot.
    /// When there are multiple meshes in each file, they are matched by name or order, and some meshes
    /// are broken up by limitations into multiple objects, and thus there can be mismatches.)
    bool mWarnOfUnmatchedPhyicsMeshes{false};
    /// A mesh to use as the default physics shape in only those cases where the physics shape is not otherwise specified.
    /// It is set only when the user chooses a physics shape file that contains a mesh with a name that matches DEFAULT_PHYSICS_MESH_NAME.
    /// It is reset when such a name is not found, and when resetting the modelpreview.
    /// Not read unless mWarnOfUnmatchedPhyicsMeshes is true.
    LLModel* mDefaultPhysicsShapeP{};

    typedef enum
    {
        MESH_OPTIMIZER_FULL,
        MESH_OPTIMIZER_NO_NORMALS,
        MESH_OPTIMIZER_NO_UVS,
        MESH_OPTIMIZER_NO_TOPOLOGY,
    } eSimplificationMode;

    // Merges faces into single mesh, simplifies using mesh optimizer,
    // then splits back into faces.
    // Returns reached simplification ratio. -1 in case of a failure.
    F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode);
    // Simplifies specified face using mesh optimizer.
    // Returns reached simplification ratio. -1 in case of a failure.
    F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode);

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;
    S32         mPhysicsSearchLOD;
    std::string mLODFile[LLModel::NUM_LODS];
    bool        mLoading;
    U32         mLoadState;
    bool        mResetJoints;
    bool        mModelNoErrors;
    bool        mLookUpLodFiles;

    std::map<std::string, bool> mViewOption;

    // Model generation parameters (must rebuild object if these change)
    bool mLODFrozen;
    U32 mRequestedLoDMode[LLModel::NUM_LODS];
    S32 mRequestedTriangleCount[LLModel::NUM_LODS];
    F32 mRequestedErrorThreshold[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;

    typedef std::vector<LLVolumeFace>       v_LLVolumeFace_t;
    typedef std::vector<v_LLVolumeFace_t>   vv_LLVolumeFace_t;

    vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS];
    vv_LLVolumeFace_t mBaseModelFacesCopy;

    U32 mGroup;

    // Amount of triangles in original(base) model
    U32 mMaxTriangleLimit;

    LLMeshUploadThread::instance_list mUploadData;
    std::set<LLViewerFetchedTexture * > mTextureSet;

    //map of vertex buffers to models (one vertex buffer in vector per face in model
    std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > 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;
    U32         mLegacyRigFlags;

    bool        mLastJointUpdate;
    bool        mFirstSkinUpdate;

    JointNameSet        mJointsFromNode;
    JointTransformMap   mJointTransformMap;

    LLPointer<LLVOAvatar>   mPreviewAvatar;
    LLCachedControl<bool>   mImporterDebug;
};

#endif  // LL_LLMODELPREVIEW_H