From 97c954dd84d50ec7b739d2dd3adb7365589f3034 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 6 Jul 2021 21:26:15 +0300 Subject: SL-15522 Initial addition of meshoptimizer --- indra/newview/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 424fd17707..72d01b264c 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -33,6 +33,7 @@ include(LLInventory) include(LLKDU) include(LLLogin) include(LLMath) +include(LLMeshOptimizer) include(LLMessage) include(LLPhysicsExtensions) include(LLPlugin) @@ -79,6 +80,7 @@ include_directories( ${LLKDU_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} + ${LLMESHOPTIMIZER_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLPLUGIN_INCLUDE_DIRS} ${LLPRIMITIVE_INCLUDE_DIRS} @@ -2027,6 +2029,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLCHARACTER_LIBRARIES} ${LLIMAGE_LIBRARIES} ${LLINVENTORY_LIBRARIES} + ${LLMESHOPTIMIZER_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLPLUGIN_LIBRARIES} ${LLPRIMITIVE_LIBRARIES} -- cgit v1.2.3 From 7b7b8a8da8f3a7e726b7de2b152cd00c67df0f18 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 7 Jul 2021 22:34:26 +0300 Subject: DRTVWR-542 WIP --- indra/newview/llfloatermodelpreview.cpp | 19 +- indra/newview/llmodelpreview.cpp | 203 ++++++++++++++++++++- indra/newview/llmodelpreview.h | 12 +- .../skins/default/xui/en/floater_model_preview.xml | 16 ++ 4 files changed, 240 insertions(+), 10 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d9edd4dc30..d8f3021fb2 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -722,7 +722,20 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) { - mModelPreview->onLODParamCommit(lod, enforce_tri_limit); + LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[lod]); + S32 mode = lod_source_combo->getCurrentIndex(); + switch (mode) + { + case LLModelPreview::GENERATE: + mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit); + break; + case LLModelPreview::MESH_OPTIMIZER: + mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit); + break; + default: + LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL; + break; + } //refresh LoDs that reference this one for (S32 i = lod - 1; i >= 0; --i) @@ -1721,7 +1734,9 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) refresh(); LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[lod]); - if (lod_source_combo->getCurrentIndex() == LLModelPreview::GENERATE) + S32 index = lod_source_combo->getCurrentIndex(); + if (index == LLModelPreview::GENERATE + || index == LLModelPreview::MESH_OPTIMIZER) { //rebuild LoD to update triangle counts onLODParamCommit(lod, true); } diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index a9e80ab5da..a6eef74cdc 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -41,6 +41,7 @@ #include "lliconctrl.h" #include "llmatrix4a.h" #include "llmeshrepository.h" +#include "llmeshoptimizer.h" #include "llrender.h" #include "llsdutil_math.h" #include "llskinningutil.h" @@ -1339,7 +1340,7 @@ void LLModelPreview::restoreNormals() updateStatusMessages(); } -void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) +void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) { // Allow LoD from -1 to LLModel::LOD_PHYSICS if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) @@ -1424,7 +1425,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim mRequestedLoDMode[which_lod] = lod_mode; } - if (lod_mode == 0) + if (lod_mode == LIMIT_TRIANGLES) { lod_mode = GLOD_TRIANGLE_BUDGET; @@ -2957,7 +2958,7 @@ BOOL LLModelPreview::render() { genBuffers(-1, skin_weight); //genBuffers(3); - //genLODs(); + //genGlodLODs(); } if (!mModel[mPreviewLOD].empty()) @@ -3544,7 +3545,7 @@ bool LLModelPreview::lodQueryCallback() { S32 lod = preview->mLodsQuery.back(); preview->mLodsQuery.pop_back(); - preview->genLODs(lod); + preview->genGlodLODs(lod); if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH)) { @@ -3559,12 +3560,202 @@ bool LLModelPreview::lodQueryCallback() return true; } -void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) +void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit) { if (!mLODFrozen) { - genLODs(lod, 3, enforce_tri_limit); + genGlodLODs(lod, 3, enforce_tri_limit); refresh(); } } +void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit) +{ + if (mLODFrozen) + { + return; + } + + // Allow LoD from -1 to LLModel::LOD_PHYSICS + if (lod < -1 || lod > LLModel::NUM_LODS - 1) + { + std::ostringstream out; + out << "Invalid level of detail: " << lod; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + assert(lod >= -1 && lod < LLModel::NUM_LODS); + return; + } + + if (mBaseModel.empty()) + { + return; + } + + + U32 triangle_count = 0; + U32 instanced_triangle_count = 0; + + //get the triangle count for the whole scene + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter) + { + for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) + { + LLModel* mdl = instance->mModel; + if (mdl) + { + instanced_triangle_count += mdl->getNumTriangles(); + } + } + } + + //get the triangle count for the non-instanced set of models + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + triangle_count += mBaseModel[i]->getNumTriangles(); + } + + //get ratio of uninstanced triangles to instanced triangles + F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count; + U32 base_triangle_count = triangle_count; + U32 lod_mode = 0; + F32 lod_error_threshold = 0; + + + // Urgh... + // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview + // We should not be accesing views from other class! + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[lod]); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[lod]).asReal(); + + if (lod != -1) + { + mRequestedLoDMode[lod] = lod_mode; + } + + S32 limit = -1; + if (lod_mode == LIMIT_TRIANGLES) + { + limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[lod]).asInteger(); + //convert from "scene wide" to "non-instanced" triangle limit + limit = (S32)((F32)limit*triangle_ratio); + } + + // Glod regenerates vertex buffer at this stage + + // Build models + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + S32 decimation = 3; + + if (lod != -1) + { + start = lod; + end = lod; + } + + mMaxTriangleLimit = base_triangle_count; + + for (S32 lod = start; lod >= end; --lod) + { + if (lod == -1) + { + if (lod < start) + { + triangle_count /= decimation; + } + } + else + { + if (enforce_tri_limit) + { + triangle_count = limit; + } + else + { + for (S32 j = LLModel::LOD_HIGH; j > lod; --j) + { + triangle_count /= decimation; + } + } + } + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio); + mRequestedErrorThreshold[lod] = lod_error_threshold; + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + std::string name = base->mLabel + getLodSuffix(lod); + + mModel[lod][mdl_idx]->mLabel = name; + mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; + //mModel[lod][mdl_idx]->setNumVolumeFaces( ); + + LLModel* target_model = mModel[lod][mdl_idx]; + + + // + LLMeshOptimizer::simplifyModel(/*Some params*/); + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mSkinInfo = base->mSkinInfo; + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; + } + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + + LLMeshOptimizer::simplifyModel(); + refresh(); +} + diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 3664a27a72..df66d79b7b 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -125,9 +125,16 @@ public: { LOD_FROM_FILE = 0, GENERATE, + MESH_OPTIMIZER, 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 @@ -155,7 +162,7 @@ public: void loadModelCallback(S32 lod); bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } void queryLODs() { mGenLOD = true; }; - void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); + void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); void generateNormals(); void restoreNormals(); U32 calcResourceCost(); @@ -166,7 +173,8 @@ public: void updateStatusMessages(); void updateLodControls(S32 lod); void clearGLODGroup(); - void onLODParamCommit(S32 lod, bool enforce_tri_limit); + void onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit); + void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit); void addEmptyFace(LLModel* pTarget); const bool getModelPivot(void) const { return mHasPivot; } diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 7f863756eb..96bda42316 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -176,6 +176,10 @@ name="Generate" label="Generate" value="Generate" /> + + + + Date: Thu, 8 Jul 2021 20:29:28 +0300 Subject: DRTVWR-542 WIP #2 --- indra/newview/llmodelpreview.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index a6eef74cdc..f23143e3fa 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -3705,13 +3705,33 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim mModel[lod][mdl_idx]->mLabel = name; mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; - //mModel[lod][mdl_idx]->setNumVolumeFaces( ); + mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces()); LLModel* target_model = mModel[lod][mdl_idx]; + // Run meshoptimizer for each face + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) + { + const LLVolumeFace &face = base->getVolumeFace(face_idx); + S32 num_indices = face.mNumIndices; + std::vector output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere + + // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify + + F32 error_code = 0; + LLMeshOptimizer::simplify(&output[0], + &face.mIndices[0], + num_indices, + &face.mPositions[0], + face.mNumVertices, + triangle_count * 3, //todo: indices limit, not triangles limit*3 + lod_error_threshold, + &error_code); + + // todo: copy result into face + } - // - LLMeshOptimizer::simplifyModel(/*Some params*/); + LL_WARNS() << "WORK IN PROGRESS" << LL_ENDL; //blind copy skin weights and just take closest skin weight to point on //decimated mesh for now (auto-generating LODs with skin weights is still a bit @@ -3755,7 +3775,6 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim mResourceCost = calcResourceCost(); - LLMeshOptimizer::simplifyModel(); refresh(); } -- cgit v1.2.3 From 6047b7c4383be53718fc72d7058a7435ccda7785 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 9 Jul 2021 23:42:37 +0300 Subject: DRTVWR-542 WIP #3 First functional meshoptimizer --- indra/newview/llmodelpreview.cpp | 180 +++++++++++++++++++++------------------ 1 file changed, 99 insertions(+), 81 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index f23143e3fa..0cf44ca1cb 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1404,7 +1404,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - U32 lod_mode = 0; + U32 lod_mode = LIMIT_TRIANGLES; F32 lod_error_threshold = 0; @@ -3569,7 +3569,7 @@ void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit) } } -void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit) +void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit) { if (mLODFrozen) { @@ -3577,10 +3577,10 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim } // Allow LoD from -1 to LLModel::LOD_PHYSICS - if (lod < -1 || lod > LLModel::NUM_LODS - 1) + if (requested_lod < -1 || requested_lod > LLModel::NUM_LODS - 1) { std::ostringstream out; - out << "Invalid level of detail: " << lod; + out << "Invalid level of detail: " << requested_lod; LL_WARNS() << out.str() << LL_ENDL; LLFloaterModelPreview::addStringToLog(out, false); assert(lod >= -1 && lod < LLModel::NUM_LODS); @@ -3592,106 +3592,108 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim return; } - - U32 triangle_count = 0; - U32 instanced_triangle_count = 0; - - //get the triangle count for the whole scene - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter) - { - for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) - { - LLModel* mdl = instance->mModel; - if (mdl) - { - instanced_triangle_count += mdl->getNumTriangles(); - } - } - } - - //get the triangle count for the non-instanced set of models - for (U32 i = 0; i < mBaseModel.size(); ++i) + //get the triangle count for all base models + S32 base_triangle_count = 0; + for (S32 i = 0; i < mBaseModel.size(); ++i) { - triangle_count += mBaseModel[i]->getNumTriangles(); + base_triangle_count += mBaseModel[i]->getNumTriangles(); } - //get ratio of uninstanced triangles to instanced triangles - F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count; - U32 base_triangle_count = triangle_count; - U32 lod_mode = 0; - F32 lod_error_threshold = 0; - - // Urgh... // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview // We should not be accesing views from other class! - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[lod]); - if (iface) + U32 lod_mode = LIMIT_TRIANGLES; + F32 indices_ratio = 0; + F32 triangle_limit = 0; + F32 lod_error_threshold = 100; + F32 decimation = 3.f; + + // If requesting a single lod + if (requested_lod > -1 && requested_lod < NUM_LOD) { - lod_mode = iface->getFirstSelectedIndex(); - } + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[requested_lod]); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } - lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[lod]).asReal(); + if (lod_mode == LIMIT_TRIANGLES) + { + if (!enforce_tri_limit && lod_mode == LIMIT_TRIANGLES) + { + triangle_limit = base_triangle_count; + // reset to default value for this lod + for (S32 j = LLModel::LOD_HIGH; j > requested_lod; --j) + { + triangle_limit /= decimation; + indices_ratio /= decimation; + } + } + else + { + // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to ratio - if (lod != -1) - { - mRequestedLoDMode[lod] = lod_mode; - } + // UI spacifies limit for all models of single lod + triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[requested_lod]).asInteger(); - S32 limit = -1; - if (lod_mode == LIMIT_TRIANGLES) + // calculate aproximate ratio + indices_ratio = (F32)triangle_limit / (F32)base_triangle_count; + } + } + else + { + lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[requested_lod]).asReal(); + } + } + else { - limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[lod]).asInteger(); - //convert from "scene wide" to "non-instanced" triangle limit - limit = (S32)((F32)limit*triangle_ratio); + // we are genrating all lods and each lod will get own indices_ratio + indices_ratio = 1; + triangle_limit = base_triangle_count; } - // Glod regenerates vertex buffer at this stage + mMaxTriangleLimit = base_triangle_count; + + // TODO: Glod regenerates vertex buffer at this stage + // check why, it might be needed to regenerate buffer as well // Build models S32 start = LLModel::LOD_HIGH; S32 end = 0; - S32 decimation = 3; - if (lod != -1) + if (requested_lod != -1) { - start = lod; - end = lod; + start = requested_lod; + end = requested_lod; } - mMaxTriangleLimit = base_triangle_count; + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (shader) + { + shader->unbind(); + } for (S32 lod = start; lod >= end; --lod) { - if (lod == -1) + if (requested_lod == -1) { + // we are genrating all lods and each lod gets own indices_ratio if (lod < start) { - triangle_count /= decimation; - } - } - else - { - if (enforce_tri_limit) - { - triangle_count = limit; - } - else - { - for (S32 j = LLModel::LOD_HIGH; j > lod; --j) - { - triangle_count /= decimation; - } + indices_ratio /= decimation; + triangle_limit /= decimation; } } + mRequestedTriangleCount[lod] = triangle_limit; + mRequestedErrorThreshold[lod] = lod_error_threshold; + mRequestedLoDMode[requested_lod] = lod_mode; + mModel[lod].clear(); mModel[lod].resize(mBaseModel.size()); mVertexBuffer[lod].clear(); - mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio); - mRequestedErrorThreshold[lod] = lod_error_threshold; for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) { @@ -3718,20 +3720,30 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify - F32 error_code = 0; - LLMeshOptimizer::simplify(&output[0], - &face.mIndices[0], - num_indices, - &face.mPositions[0], - face.mNumVertices, - triangle_count * 3, //todo: indices limit, not triangles limit*3 - lod_error_threshold, - &error_code); + F32 result_code = 0; // how far from original the model is + S32 new_indices = LLMeshOptimizer::simplify(&output[0], + face.mIndices, + num_indices, + &face.mPositions[0], + face.mNumVertices, + num_indices * indices_ratio, + lod_error_threshold, + &result_code); - // todo: copy result into face - } + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + + // Copy old values + // todo: no point copying faces? + new_face = face; - LL_WARNS() << "WORK IN PROGRESS" << LL_ENDL; + // Assign new values + S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size); + new_face.mNumIndices = new_indices; + + // clear unused values + new_face.optimize(); + } //blind copy skin weights and just take closest skin weight to point on //decimated mesh for now (auto-generating LODs with skin weights is still a bit @@ -3739,6 +3751,7 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim target_model->mPosition = base->mPosition; target_model->mSkinWeights = base->mSkinWeights; target_model->mSkinInfo = base->mSkinInfo; + //copy material list target_model->mMaterialList = base->mMaterialList; @@ -3774,6 +3787,11 @@ void LLModelPreview::onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_lim mResourceCost = calcResourceCost(); + LLVertexBuffer::unbind(); + if (shader) + { + shader->bind(); + } refresh(); } -- cgit v1.2.3 From 17131ac20336b5561b574a9c121c6a5876be2d53 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sun, 11 Jul 2021 22:39:30 +0300 Subject: DRTVWR-542 WIP #4 Made meshoptimizer into default generation mechanism Ensured that at least one triangle will remain of any face --- indra/newview/llfloatermodelpreview.cpp | 4 +- indra/newview/llmodelpreview.cpp | 460 +++++++++++++++++--------------- indra/newview/llmodelpreview.h | 1 + 3 files changed, 241 insertions(+), 224 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d8f3021fb2..85250abefc 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -139,7 +139,7 @@ mAvatarTabIndex(0) mLODMode[LLModel::LOD_HIGH] = 0; for (U32 i = 0; i < LLModel::LOD_HIGH; i++) { - mLODMode[i] = 1; + mLODMode[i] = LLModelPreview::MESH_OPTIMIZER; } } @@ -1767,7 +1767,7 @@ void LLFloaterModelPreview::resetUploadOptions() getChild("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE); for (S32 lod = 0; lod < NUM_LOD - 1; ++lod) { - getChild("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::GENERATE); + getChild("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER); childSetValue("lod_file_" + lod_name[lod], ""); } diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 0cf44ca1cb..27341eff3c 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1342,6 +1342,7 @@ void LLModelPreview::restoreNormals() void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) { + LL_INFOS() << "Generating lod " << which_lod << " using glod" << LL_ENDL; // Allow LoD from -1 to LLModel::LOD_PHYSICS if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) { @@ -1705,6 +1706,239 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri } } +void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) +{ + LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL; + // Allow LoD from -1 to LLModel::LOD_PHYSICS + if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) + { + std::ostringstream out; + out << "Invalid level of detail: " << which_lod; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + assert(lod >= -1 && lod < LLModel::NUM_LODS); + return; + } + + if (mBaseModel.empty()) + { + return; + } + + //get the triangle count for all base models + S32 base_triangle_count = 0; + for (S32 i = 0; i < mBaseModel.size(); ++i) + { + base_triangle_count += mBaseModel[i]->getNumTriangles(); + } + + // Urgh... + // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview + // We should not be accesing views from other class! + U32 lod_mode = LIMIT_TRIANGLES; + F32 indices_ratio = 0; + F32 triangle_limit = 0; + F32 lod_error_threshold = 1; //100% + + // If requesting a single lod + if (which_lod > -1 && which_lod < NUM_LOD) + { + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + if (lod_mode == LIMIT_TRIANGLES) + { + if (!enforce_tri_limit) + { + triangle_limit = base_triangle_count; + // reset to default value for this lod + F32 pw = pow((F32)decimation, (F32)(LLModel::LOD_HIGH - which_lod)); + + triangle_limit /= pw; //indices_ratio can be 1/pw + } + else + { + + // UI spacifies limit for all models of single lod + triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger(); + + } + // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio + indices_ratio = (F32)triangle_limit / (F32)base_triangle_count; + } + else + { + lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal(); + } + } + else + { + // we are genrating all lods and each lod will get own indices_ratio + indices_ratio = 1; + triangle_limit = base_triangle_count; + } + + mMaxTriangleLimit = base_triangle_count; + + // TODO: Glod regenerates vertex buffer at this stage + // check why, it might be needed to regenerate buffer as well + + // Build models + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + if (which_lod != -1) + { + start = which_lod; + end = which_lod; + } + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (shader) + { + shader->unbind(); + } + + for (S32 lod = start; lod >= end; --lod) + { + if (which_lod == -1) + { + // we are genrating all lods and each lod gets own indices_ratio + if (lod < start) + { + indices_ratio /= decimation; + triangle_limit /= decimation; + } + } + + mRequestedTriangleCount[lod] = triangle_limit; + mRequestedErrorThreshold[lod] = lod_error_threshold; + mRequestedLoDMode[lod] = lod_mode; + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + std::string name = base->mLabel + getLodSuffix(lod); + + mModel[lod][mdl_idx]->mLabel = name; + mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; + mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces()); + + LLModel* target_model = mModel[lod][mdl_idx]; + + // Run meshoptimizer for each face + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) + { + const LLVolumeFace &face = base->getVolumeFace(face_idx); + S32 num_indices = face.mNumIndices; + std::vector output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere + + // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify + + F32 target_indices = llmax((F32)3, num_indices * indices_ratio); // leave at least one triangle + F32 result_code = 0; // how far from original the model is + S32 new_indices = LLMeshOptimizer::simplify(&output[0], + face.mIndices, + num_indices, + &face.mPositions[0], + face.mNumVertices, + target_indices, + lod_error_threshold, + &result_code); + + if (result_code < 0) + { + LL_WARNS() << "Negative result from meshoptimizer" << LL_ENDL; + } + + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + + // Copy old values + // todo: no point copying faces? + new_face = face; + + if (new_indices == 0) + { + LL_WARNS() << "No indices generated for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " original count: " << num_indices << LL_ENDL; + } + else + { + // Assign new values + S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size); + new_face.mNumIndices = new_indices; + + // clear unused values + new_face.optimize(); + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mSkinInfo = base->mSkinInfo; + + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; + } + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + LLVertexBuffer::unbind(); + if (shader) + { + shader->bind(); + } +} + void LLModelPreview::updateStatusMessages() { // bit mask values for physics errors. used to prevent overwrite of single line status @@ -3545,7 +3779,7 @@ bool LLModelPreview::lodQueryCallback() { S32 lod = preview->mLodsQuery.back(); preview->mLodsQuery.pop_back(); - preview->genGlodLODs(lod); + preview->genMeshOptimizerLODs(lod); if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH)) { @@ -3571,228 +3805,10 @@ void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit) void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit) { - if (mLODFrozen) - { - return; - } - - // Allow LoD from -1 to LLModel::LOD_PHYSICS - if (requested_lod < -1 || requested_lod > LLModel::NUM_LODS - 1) - { - std::ostringstream out; - out << "Invalid level of detail: " << requested_lod; - LL_WARNS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, false); - assert(lod >= -1 && lod < LLModel::NUM_LODS); - return; - } - - if (mBaseModel.empty()) - { - return; - } - - //get the triangle count for all base models - S32 base_triangle_count = 0; - for (S32 i = 0; i < mBaseModel.size(); ++i) - { - base_triangle_count += mBaseModel[i]->getNumTriangles(); - } - - // Urgh... - // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview - // We should not be accesing views from other class! - U32 lod_mode = LIMIT_TRIANGLES; - F32 indices_ratio = 0; - F32 triangle_limit = 0; - F32 lod_error_threshold = 100; - F32 decimation = 3.f; - - // If requesting a single lod - if (requested_lod > -1 && requested_lod < NUM_LOD) - { - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[requested_lod]); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - if (lod_mode == LIMIT_TRIANGLES) - { - if (!enforce_tri_limit && lod_mode == LIMIT_TRIANGLES) - { - triangle_limit = base_triangle_count; - // reset to default value for this lod - for (S32 j = LLModel::LOD_HIGH; j > requested_lod; --j) - { - triangle_limit /= decimation; - indices_ratio /= decimation; - } - } - else - { - // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to ratio - - // UI spacifies limit for all models of single lod - triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[requested_lod]).asInteger(); - - // calculate aproximate ratio - indices_ratio = (F32)triangle_limit / (F32)base_triangle_count; - } - } - else - { - lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[requested_lod]).asReal(); - } - } - else - { - // we are genrating all lods and each lod will get own indices_ratio - indices_ratio = 1; - triangle_limit = base_triangle_count; - } - - mMaxTriangleLimit = base_triangle_count; - - // TODO: Glod regenerates vertex buffer at this stage - // check why, it might be needed to regenerate buffer as well - - // Build models - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (requested_lod != -1) - { - start = requested_lod; - end = requested_lod; - } - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - if (shader) - { - shader->unbind(); - } - - for (S32 lod = start; lod >= end; --lod) - { - if (requested_lod == -1) - { - // we are genrating all lods and each lod gets own indices_ratio - if (lod < start) - { - indices_ratio /= decimation; - triangle_limit /= decimation; - } - } - - mRequestedTriangleCount[lod] = triangle_limit; - mRequestedErrorThreshold[lod] = lod_error_threshold; - mRequestedLoDMode[requested_lod] = lod_mode; - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - - std::string name = base->mLabel + getLodSuffix(lod); - - mModel[lod][mdl_idx]->mLabel = name; - mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; - mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces()); - - LLModel* target_model = mModel[lod][mdl_idx]; - - // Run meshoptimizer for each face - for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) - { - const LLVolumeFace &face = base->getVolumeFace(face_idx); - S32 num_indices = face.mNumIndices; - std::vector output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere - - // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify - - F32 result_code = 0; // how far from original the model is - S32 new_indices = LLMeshOptimizer::simplify(&output[0], - face.mIndices, - num_indices, - &face.mPositions[0], - face.mNumVertices, - num_indices * indices_ratio, - lod_error_threshold, - &result_code); - - LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); - - // Copy old values - // todo: no point copying faces? - new_face = face; - - // Assign new values - S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size); - new_face.mNumIndices = new_indices; - - // clear unused values - new_face.optimize(); - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mSkinInfo = base->mSkinInfo; - - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; - } - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - LLVertexBuffer::unbind(); - if (shader) + if (!mLODFrozen) { - shader->bind(); + genMeshOptimizerLODs(requested_lod, 3, enforce_tri_limit); + refresh(); } - - refresh(); } diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index df66d79b7b..f6f4ce580d 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -163,6 +163,7 @@ public: bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } void queryLODs() { mGenLOD = true; }; void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); + void genMeshOptimizerLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); void generateNormals(); void restoreNormals(); U32 calcResourceCost(); -- cgit v1.2.3 From eb13133e3e0020c73399414cea4d9b39ef526cd3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 12 Jul 2021 16:47:45 +0300 Subject: DRTVWR-542 WIP #5 --- indra/newview/llmodelpreview.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 27341eff3c..5eb49ee938 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1767,7 +1767,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en } // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio - indices_ratio = (F32)triangle_limit / (F32)base_triangle_count; + indices_ratio = triangle_limit / (F32)base_triangle_count; } else { @@ -1849,7 +1849,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify - F32 target_indices = llmax((F32)3, num_indices * indices_ratio); // leave at least one triangle + S32 target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle F32 result_code = 0; // how far from original the model is S32 new_indices = LLMeshOptimizer::simplify(&output[0], face.mIndices, @@ -1868,9 +1868,16 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); // Copy old values - // todo: no point copying faces? new_face = face; + // Assign new values + S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size); + new_face.mNumIndices = new_indices; + + // clear unused values + new_face.optimize(); + if (new_indices == 0) { LL_WARNS() << "No indices generated for face " << face_idx @@ -1878,16 +1885,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en << " target Indices: " << target_indices << " original count: " << num_indices << LL_ENDL; } - else - { - // Assign new values - S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size); - new_face.mNumIndices = new_indices; - - // clear unused values - new_face.optimize(); - } } //blind copy skin weights and just take closest skin weight to point on -- cgit v1.2.3 From 938969c811732a3e2faf0229301de286bd12c1a5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 12 Jul 2021 19:18:25 +0300 Subject: DRTVWR-542 WIP #6 Trying out 'sloppy' variant --- indra/newview/llfloatermodelpreview.cpp | 8 +++-- indra/newview/llmodelpreview.cpp | 42 ++++++++++++++++------ indra/newview/llmodelpreview.h | 5 +-- .../skins/default/xui/en/floater_model_preview.xml | 16 +++++++++ 4 files changed, 56 insertions(+), 15 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 85250abefc..d61311d610 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -730,7 +730,10 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit); break; case LLModelPreview::MESH_OPTIMIZER: - mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit); + mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, false); + break; + case LLModelPreview::MESH_OPTIMIZER_SLOPPY: + mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, true); break; default: LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL; @@ -1736,7 +1739,8 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[lod]); S32 index = lod_source_combo->getCurrentIndex(); if (index == LLModelPreview::GENERATE - || index == LLModelPreview::MESH_OPTIMIZER) + || index == LLModelPreview::MESH_OPTIMIZER + || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY) { //rebuild LoD to update triangle counts onLODParamCommit(lod, true); } diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 5eb49ee938..c33b48c16e 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1706,7 +1706,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri } } -void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) +void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit, bool sloppy) { LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL; // Allow LoD from -1 to LLModel::LOD_PHYSICS @@ -1851,14 +1851,34 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en S32 target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle F32 result_code = 0; // how far from original the model is - S32 new_indices = LLMeshOptimizer::simplify(&output[0], - face.mIndices, - num_indices, - &face.mPositions[0], - face.mNumVertices, - target_indices, - lod_error_threshold, - &result_code); + S32 new_indices = 0; + + if (sloppy) + { + new_indices = LLMeshOptimizer::simplifySloppy( + &output[0], + face.mIndices, + num_indices, + &face.mPositions[0], + face.mNumVertices, + target_indices, + lod_error_threshold, + &result_code); + } + + if (new_indices <= 0) + { + new_indices = LLMeshOptimizer::simplify( + &output[0], + face.mIndices, + num_indices, + &face.mPositions[0], + face.mNumVertices, + target_indices, + lod_error_threshold, + &result_code); + } + if (result_code < 0) { @@ -3800,11 +3820,11 @@ void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit) } } -void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit) +void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, bool sloppy) { if (!mLODFrozen) { - genMeshOptimizerLODs(requested_lod, 3, enforce_tri_limit); + genMeshOptimizerLODs(requested_lod, 3, enforce_tri_limit, sloppy); refresh(); } } diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index f6f4ce580d..9f38156ca2 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -126,6 +126,7 @@ public: LOD_FROM_FILE = 0, GENERATE, MESH_OPTIMIZER, + MESH_OPTIMIZER_SLOPPY, USE_LOD_ABOVE, } eLoDMode; @@ -163,7 +164,7 @@ public: bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } void queryLODs() { mGenLOD = true; }; void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); - void genMeshOptimizerLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); + void genMeshOptimizerLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false, bool sloppy = false); void generateNormals(); void restoreNormals(); U32 calcResourceCost(); @@ -175,7 +176,7 @@ public: void updateLodControls(S32 lod); void clearGLODGroup(); void onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit); - void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit); + void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, bool sloppy); void addEmptyFace(LLModel* pTarget); const bool getModelPivot(void) const { return mHasPivot; } diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 96bda42316..230284555c 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -180,6 +180,10 @@ name="MeshOpt" label="MeshOpt" value="MeshOpt" /> + + + + Date: Mon, 12 Jul 2021 23:23:08 +0300 Subject: DRTVWR-542 WIP #7 --- indra/newview/llmodelpreview.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index c33b48c16e..471b29d850 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1847,10 +1847,18 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en S32 num_indices = face.mNumIndices; std::vector output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere - // todo: run generateShadowIndexBuffer, at some stage, potentially inside simplify + /* + generateShadowIndexBuffer appears to deform model + LLMeshOptimizer::generateShadowIndexBuffer( + &shadow[0], + face.mIndices, + num_indices, + &face.mPositions[0], + face.mNumVertices); + */ S32 target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle - F32 result_code = 0; // how far from original the model is + F32 result_code = 0; // how far from original the model is, 1 == 100% S32 new_indices = 0; if (sloppy) @@ -1859,7 +1867,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en &output[0], face.mIndices, num_indices, - &face.mPositions[0], + face.mPositions, face.mNumVertices, target_indices, lod_error_threshold, @@ -1872,7 +1880,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en &output[0], face.mIndices, num_indices, - &face.mPositions[0], + face.mPositions, face.mNumVertices, target_indices, lod_error_threshold, -- cgit v1.2.3 From 66ba1c4c8e840bb5e9da23e2b5772cd24b23714f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 13 Jul 2021 02:14:16 +0300 Subject: DRTVWR-542 WIP Fixed Stride --- indra/newview/llmodelpreview.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 471b29d850..aa065edf92 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1869,6 +1869,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en num_indices, face.mPositions, face.mNumVertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], target_indices, lod_error_threshold, &result_code); @@ -1882,6 +1883,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en num_indices, face.mPositions, face.mNumVertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], target_indices, lod_error_threshold, &result_code); -- cgit v1.2.3 From 33819e157e9a9638d4869e90601f7b7011804e08 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 13 Jul 2021 11:32:59 +0300 Subject: DRTVWR-542 Fixed size of indices array --- indra/newview/llmodelpreview.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index aa065edf92..26eac71281 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1874,7 +1874,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en lod_error_threshold, &result_code); } - + + // todo: instead of checking (new_indices <= 0) + // create a dummy triangle if simplifySloppy returns nothing if (new_indices <= 0) { new_indices = LLMeshOptimizer::simplify( @@ -1892,7 +1894,18 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en if (result_code < 0) { - LL_WARNS() << "Negative result from meshoptimizer" << LL_ENDL; + LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << num_indices << LL_ENDL; + } + if (new_indices == 0) + { + LL_WARNS() << "No indices generated by meshoptimizer for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " original count: " << num_indices << LL_ENDL; } LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); @@ -1901,20 +1914,12 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en new_face = face; // Assign new values + new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size); - new_face.mNumIndices = new_indices; // clear unused values new_face.optimize(); - - if (new_indices == 0) - { - LL_WARNS() << "No indices generated for face " << face_idx - << " of model " << target_model->mLabel - << " target Indices: " << target_indices - << " original count: " << num_indices << LL_ENDL; - } } //blind copy skin weights and just take closest skin weight to point on -- cgit v1.2.3 From a607e7642071690dcab9a1fdf5453fcf83480982 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 13 Jul 2021 20:07:28 +0300 Subject: DRTVWR-542 output buffer should be indentical in size to indices array --- indra/newview/llmodelpreview.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 26eac71281..93186657ce 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1845,7 +1845,10 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en { const LLVolumeFace &face = base->getVolumeFace(face_idx); S32 num_indices = face.mNumIndices; - std::vector output(num_indices); //todo: do not allocate per each face, add one large buffer somewhere + // todo: do not allocate per each face, add one large buffer somewhere + // faces have limited amount of indices + S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF; + U16* output = (U16*)ll_aligned_malloc_16(size); /* generateShadowIndexBuffer appears to deform model @@ -1864,7 +1867,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en if (sloppy) { new_indices = LLMeshOptimizer::simplifySloppy( - &output[0], + output, face.mIndices, num_indices, face.mPositions, @@ -1880,7 +1883,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en if (new_indices <= 0) { new_indices = LLMeshOptimizer::simplify( - &output[0], + output, face.mIndices, num_indices, face.mPositions, @@ -1916,7 +1919,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en // Assign new values new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)(&output[0]), idx_size); + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); + + ll_aligned_free_16(output); // clear unused values new_face.optimize(); -- cgit v1.2.3 From d3d0711f1da33665df63be41758fbc1480244811 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 15 Jul 2021 17:30:21 +0300 Subject: SL-443 Keybindings: Restored default fails to save --- indra/newview/llkeyconflict.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index b6107eeedf..d7a17b237e 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -730,13 +730,19 @@ void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 i { return; } + LLKeyConflict &type_data = mControlsMap[control_name]; + if (!type_data.mAssignable) + { + return; + } LLKeyData data = getDefaultControl(control_name, index); - if (data != mControlsMap[control_name].getKeyData(index)) + if (data != type_data.getKeyData(index)) { // reset controls that might have been switched to our current control removeConflicts(data, mControlsMap[control_name].mConflictMask); mControlsMap[control_name].setKeyData(data, index); + mHasUnsavedChanges = true; } } -- cgit v1.2.3 From a5675bedbb2bd34ce03dd16651dc74d8078efea9 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 15 Jul 2021 17:34:16 +0300 Subject: SL-443 Keybindings: Support reassigment of script interaction button --- indra/newview/app_settings/key_bindings.xml | 8 +++ indra/newview/llkeyconflict.cpp | 58 ++++++++++++++-- indra/newview/llkeyconflict.h | 4 +- indra/newview/lltoolcomp.cpp | 10 ++- indra/newview/lltoolpie.cpp | 2 +- indra/newview/llviewerinput.cpp | 81 +++++++++++++++++++--- indra/newview/llviewerinput.h | 5 +- .../xui/en/control_table_contents_media.xml | 10 +++ 8 files changed, 158 insertions(+), 20 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml index 4f6deb1f98..ffc1b2e7cc 100644 --- a/indra/newview/app_settings/key_bindings.xml +++ b/indra/newview/app_settings/key_bindings.xml @@ -33,6 +33,8 @@ + + @@ -127,6 +129,8 @@ + + @@ -224,6 +228,8 @@ + + @@ -251,5 +257,7 @@ + + diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index d7a17b237e..58a740e16a 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -868,7 +868,7 @@ void LLKeyConflictHandler::resetKeyboardBindings() void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode) { - // These controls are meant to cause conflicts when user tries to assign same control somewhere else + // These placeholds are meant to cause conflict resolution when user tries to assign same control somewhere else // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks if (load_mode == MODE_FIRST_PERSON) @@ -928,25 +928,73 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode) registerTemporaryControl("spin_around_ccw_sitting"); registerTemporaryControl("spin_around_cw_sitting"); } + + + // Special case, mouse clicks passed to scripts have 'lowest' piority + // thus do not conflict, everything else has a chance before them + // also in ML they have highest priority, but only when script-grabbed, + // thus do not conflict + // (see AGENT_CONTROL_ML_LBUTTON_DOWN and CONTROL_LBUTTON_DOWN_INDEX) + LLKeyConflict *type_data = &mControlsMap[script_mouse_handler_name]; + type_data->mAssignable = true; + type_data->mConflictMask = U32_MAX - CONFLICT_LMOUSE; } -bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask) +bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, U32 conlict_mask) { if (conlict_mask == CONFLICT_NOTHING) { // Can't conflict return true; } + + if (data.mMouse == CLICK_LEFT + && data.mMask == MASK_NONE + && data.mKey == KEY_NONE) + { + if ((conlict_mask & CONFLICT_LMOUSE) == 0) + { + // Can't conflict + return true; + } + else + { + // simplify conflict mask + conlict_mask = CONFLICT_LMOUSE; + } + } + else + { + // simplify conflict mask + conlict_mask &= ~CONFLICT_LMOUSE; + } + std::map conflict_list; control_map_t::iterator cntrl_iter = mControlsMap.begin(); control_map_t::iterator cntrl_end = mControlsMap.end(); for (; cntrl_iter != cntrl_end; ++cntrl_iter) { + const U32 cmp_mask = cntrl_iter->second.mConflictMask; + if ((cmp_mask & conlict_mask) == 0) + { + // can't conflict + continue; + } S32 index = cntrl_iter->second.mKeyBind.findKeyData(data); - if (index >= 0 - && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING - && (cntrl_iter->second.mConflictMask & conlict_mask) != 0) + if (index >= 0) { + if (cmp_mask != U32_MAX) + { + const LLKeyData cmp_data = cntrl_iter->second.mKeyBind.getKeyData(index); + if ((cmp_mask & CONFLICT_LMOUSE) == 0 + && cmp_data.mMouse == CLICK_LEFT + && cmp_data.mMask == MASK_NONE + && cmp_data.mKey == KEY_NONE) + { + // Does not conflict + continue; + } + } if (cntrl_iter->second.mAssignable) { // Potentially we can have multiple conflict flags conflicting diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h index 2926ca3aeb..e78d2fa33b 100644 --- a/indra/newview/llkeyconflict.h +++ b/indra/newview/llkeyconflict.h @@ -66,6 +66,7 @@ public: }; const U32 CONFLICT_NOTHING = 0; + const U32 CONFLICT_LMOUSE = 0x1 << 1; // at the moment this just means that key will conflict with everything that is identical const U32 CONFLICT_ANY = U32_MAX; @@ -145,6 +146,7 @@ private: // at the moment these kind of control is not savable, but takes part in conflict resolution void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask); + // conflict mask 0 means that any conflicts will be ignored void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0); typedef std::map control_map_t; @@ -152,7 +154,7 @@ private: bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination); void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values // returns false in case user is trying to reuse control that can't be reassigned - bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask); + bool removeConflicts(const LLKeyData &data, U32 conlict_mask); // removes flags and removes temporary file, returns 'true' if file was removed bool clearUnsavedChanges(); diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp index f9c327b46e..9ac1810964 100644 --- a/indra/newview/lltoolcomp.cpp +++ b/indra/newview/lltoolcomp.cpp @@ -44,6 +44,7 @@ #include "lltoolmgr.h" #include "lltoolselectrect.h" #include "lltoolplacer.h" +#include "llviewerinput.h" #include "llviewermenu.h" #include "llviewerobject.h" #include "llviewerwindow.h" @@ -743,7 +744,7 @@ BOOL LLToolCompGun::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask) { // if the left button is grabbed, don't put up the pie menu - if (gAgent.leftButtonGrabbed()) + if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON)) { gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); return FALSE; @@ -760,7 +761,7 @@ BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLToolCompGun::handleDoubleClick(S32 x, S32 y, MASK mask) { // if the left button is grabbed, don't put up the pie menu - if (gAgent.leftButtonGrabbed()) + if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON)) { gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); return FALSE; @@ -794,7 +795,10 @@ BOOL LLToolCompGun::handleRightMouseDown(S32 x, S32 y, MASK mask) BOOL LLToolCompGun::handleMouseUp(S32 x, S32 y, MASK mask) { - gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP); + if (gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON)) + { + gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP); + } setCurrentTool( (LLTool*) mGun ); return TRUE; } diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 322d0bc727..543a93bf9b 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -746,7 +746,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) else if (!mMouseOutsideSlop && mMouseButtonDown // disable camera steering if click on land is not used for moving - && gViewerInput.isMouseBindUsed(CLICK_LEFT)) + && gViewerInput.isMouseBindUsed(CLICK_LEFT, MASK_NONE, MODE_THIRD_PERSON)) { S32 delta_x = x - mMouseDownX; S32 delta_y = y - mMouseDownY; diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index c0eaa88f54..8b3d406b78 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -61,7 +61,7 @@ const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true); struct LLKeyboardActionRegistry -: public LLRegistrySingleton, LLKeyboardActionRegistry> +: public LLRegistrySingleton, LLKeyboardActionRegistry> { LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry); }; @@ -836,7 +836,49 @@ bool voice_follow_key(EKeystate s) return false; } -bool agen_control_lbutton_handle(EKeystate s) +bool sript_trigger_lbutton(EKeystate s) +{ + // Check for script overriding/expecting left mouse button. + // Note that this does not pass event further and depends onto mouselook. + // Checks CONTROL_ML_LBUTTON_DOWN_INDEX for mouselook, + // CONTROL_LBUTTON_DOWN_INDEX for normal camera + if (gAgent.leftButtonGrabbed()) + { + bool mouselook = gAgentCamera.cameraMouselook(); + switch (s) + { + case KEYSTATE_DOWN: + // at the moment sript_trigger_lbutton is only intended for mouselook + // but handling other modes just in case + if (mouselook) + { + gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); + } + else + { + gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN); + } + return true; + case KEYSTATE_UP: + if (mouselook) + { + gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP); + } + else + { + gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP); + } + return true; + default: + break; + } + } + return false; +} + +// Used by scripts, for overriding/handling left mouse button +// see mControlsTakenCount +bool agent_control_lbutton_handle(EKeystate s) { switch (s) { @@ -905,6 +947,7 @@ REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to); REGISTER_KEYBOARD_ACTION("walk_to", walk_to); REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice); REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key); +REGISTER_KEYBOARD_ACTION(script_mouse_handler_name, sript_trigger_lbutton); #undef REGISTER_KEYBOARD_ACTION LLViewerInput::LLViewerInput() @@ -1104,6 +1147,20 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const typedef boost::function function_t; function_t function = NULL; + if (mouse == CLICK_LEFT + && mask == MASK_NONE + && function_name == script_mouse_handler_name) + { + // Special case + // Left click has script overrides and by default + // is handled via agent_control_lbutton as last option + // In case of mouselook and present overrides it has highest + // priority even over UI and is handled in LLToolCompGun::handleMouseDown + // so just mark it as having default handler + mLMouseDefaultHandling[mode] = true; + return TRUE; + } + function_t* result = LLKeyboardActionRegistry::getValue(function_name); if (result) { @@ -1164,6 +1221,7 @@ void LLViewerInput::resetBindings() { mKeyBindings[i].clear(); mMouseBindings[i].clear(); + mLMouseDefaultHandling[i] = false; } } @@ -1355,13 +1413,14 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask)) { + // pass mouse left button press to script if (key_down && !repeat) { - res = agen_control_lbutton_handle(KEYSTATE_DOWN); + res = agent_control_lbutton_handle(KEYSTATE_DOWN); } if (key_up) { - res = agen_control_lbutton_handle(KEYSTATE_UP); + res = agent_control_lbutton_handle(KEYSTATE_UP); } } return res; @@ -1481,24 +1540,28 @@ bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const S32 mode = getMode(); MASK mask = gKeyboard->currentMask(TRUE); res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state); + // no user defined actions found or those actions can't handle the key/button, handle control if nessesary - if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask)) + // This will pass AGENT_CONTROL_LBUTTON_DOWN to server, no idea why it doesn't do mouselook variant _ML_ + // but it was set this way forever (moved as is from LLTool::handleMouseDown) so lots of scripts probably + // rely on this. + if (!res && mLMouseDefaultHandling[mode] && agent_control_lbutton.canHandle(click, KEY_NONE, mask)) { switch (state) { case MOUSE_STATE_DOWN: - agen_control_lbutton_handle(KEYSTATE_DOWN); + agent_control_lbutton_handle(KEYSTATE_DOWN); res = true; break; case MOUSE_STATE_CLICK: // might not work best with some functions, // but some function need specific states too specifically - agen_control_lbutton_handle(KEYSTATE_DOWN); - agen_control_lbutton_handle(KEYSTATE_UP); + agent_control_lbutton_handle(KEYSTATE_DOWN); + agent_control_lbutton_handle(KEYSTATE_UP); res = true; break; case MOUSE_STATE_UP: - agen_control_lbutton_handle(KEYSTATE_UP); + agent_control_lbutton_handle(KEYSTATE_UP); res = true; break; default: diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h index 281a209896..32dd3c0e28 100644 --- a/indra/newview/llviewerinput.h +++ b/indra/newview/llviewerinput.h @@ -31,6 +31,7 @@ #include "llinitparam.h" const S32 MAX_KEY_BINDINGS = 128; // was 60 +const std::string script_mouse_handler_name = "sript_trigger_lbutton"; class LLNamedFunction { @@ -124,7 +125,8 @@ public: BOOL handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); void scanMouse(); - bool isMouseBindUsed(const EMouseClickType mouse, const MASK mask = MASK_NONE, const S32 mode = MODE_THIRD_PERSON); + bool isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode); + bool isLMouseHandlingDefault(const S32 mode) { return mLMouseDefaultHandling[mode]; } private: bool scanKey(const std::vector &binding, @@ -163,6 +165,7 @@ private: // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown) std::vector mKeyBindings[MODE_COUNT]; std::vector mMouseBindings[MODE_COUNT]; + bool mLMouseDefaultHandling[MODE_COUNT]; // Due to having special priority typedef std::map key_remap_t; key_remap_t mRemapKeys[MODE_COUNT]; diff --git a/indra/newview/skins/default/xui/en/control_table_contents_media.xml b/indra/newview/skins/default/xui/en/control_table_contents_media.xml index ce5d3556b6..a97c45dd6f 100644 --- a/indra/newview/skins/default/xui/en/control_table_contents_media.xml +++ b/indra/newview/skins/default/xui/en/control_table_contents_media.xml @@ -73,4 +73,14 @@ name="lst_action" value="Start Gesture" /> + + + -- cgit v1.2.3 From d5857b376f1da9ad4fe25ced1a4785a40a82a709 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 20 Jul 2021 21:51:43 +0300 Subject: DRTVWR-542 Generate placehodler triangles when face got optimized away like glod does --- indra/newview/llmodelpreview.cpp | 55 ++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 93186657ce..f21b05f9dc 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1860,12 +1860,13 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en face.mNumVertices); */ - S32 target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle + S32 target_indices = 0; F32 result_code = 0; // how far from original the model is, 1 == 100% S32 new_indices = 0; if (sloppy) { + target_indices = llfloor(num_indices * indices_ratio); new_indices = LLMeshOptimizer::simplifySloppy( output, face.mIndices, @@ -1877,11 +1878,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en lod_error_threshold, &result_code); } - - // todo: instead of checking (new_indices <= 0) - // create a dummy triangle if simplifySloppy returns nothing - if (new_indices <= 0) + else { + target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle new_indices = LLMeshOptimizer::simplify( output, face.mIndices, @@ -1903,28 +1902,46 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en << " new Indices: " << new_indices << " original count: " << num_indices << LL_ENDL; } - if (new_indices == 0) - { - LL_WARNS() << "No indices generated by meshoptimizer for face " << face_idx - << " of model " << target_model->mLabel - << " target Indices: " << target_indices - << " original count: " << num_indices << LL_ENDL; - } LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); // Copy old values new_face = face; - // Assign new values - new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output - S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); - ll_aligned_free_16(output); + if (new_indices == 0) + { + if (!sloppy) + { + // optimizeSloppy() can optimize triangles away even if target_indices is > 2, + // but optimize() isn't supposed to + LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " original count: " << num_indices << LL_ENDL; + } + + // Face got optimized away + // Generate empty triangle + new_face.resizeIndices(3); + new_face.resizeVertices(1); + memset(new_face.mIndices, 0, sizeof(U16) * 3); + new_face.mPositions[0].clear(); // set first vertice to 0 + new_face.mNormals[0].clear(); + new_face.mTexCoords[0].setZero(); + } + else + { + // Assign new values + new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output + S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); - // clear unused values - new_face.optimize(); + // clear unused values + new_face.optimize(); + } + + ll_aligned_free_16(output); } //blind copy skin weights and just take closest skin weight to point on -- cgit v1.2.3 From 9aaac1bb985f5bd65f9b0fe985c47cd30dcfd166 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 23 Jul 2021 21:30:13 +0300 Subject: DRTVWR-542 Attempt to simplify all faces of an object as a whole and split back into faces --- indra/newview/llfloatermodelpreview.cpp | 8 +- indra/newview/llmodelpreview.cpp | 323 +++++++++++++++------ indra/newview/llmodelpreview.h | 5 +- .../skins/default/xui/en/floater_model_preview.xml | 16 + 4 files changed, 265 insertions(+), 87 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d61311d610..3f2fcb148c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -730,10 +730,9 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit); break; case LLModelPreview::MESH_OPTIMIZER: - mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, false); - break; case LLModelPreview::MESH_OPTIMIZER_SLOPPY: - mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, true); + case LLModelPreview::MESH_OPTIMIZER_COMBINE: + mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode); break; default: LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL; @@ -1740,7 +1739,8 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) S32 index = lod_source_combo->getCurrentIndex(); if (index == LLModelPreview::GENERATE || index == LLModelPreview::MESH_OPTIMIZER - || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY) + || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY + || index == LLModelPreview::MESH_OPTIMIZER_COMBINE) { //rebuild LoD to update triangle counts onLODParamCommit(lod, true); } diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index f21b05f9dc..6542ac9090 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1706,7 +1706,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri } } -void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit, bool sloppy) +void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit) { LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL; // Allow LoD from -1 to LLModel::LOD_PHYSICS @@ -1840,108 +1840,269 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, U32 decimation, bool en LLModel* target_model = mModel[lod][mdl_idx]; - // Run meshoptimizer for each face - for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) - { - const LLVolumeFace &face = base->getVolumeFace(face_idx); - S32 num_indices = face.mNumIndices; - // todo: do not allocate per each face, add one large buffer somewhere - // faces have limited amount of indices - S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF; - U16* output = (U16*)ll_aligned_malloc_16(size); - - /* - generateShadowIndexBuffer appears to deform model - LLMeshOptimizer::generateShadowIndexBuffer( - &shadow[0], - face.mIndices, - num_indices, - &face.mPositions[0], - face.mNumVertices); - */ - - S32 target_indices = 0; - F32 result_code = 0; // how far from original the model is, 1 == 100% - S32 new_indices = 0; + if (meshopt_mode == MESH_OPTIMIZER_COMBINE) + { + // Figure out buffer size + S32 size_indices = 0; + S32 size_vertices = 0; - if (sloppy) + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - target_indices = llfloor(num_indices * indices_ratio); - new_indices = LLMeshOptimizer::simplifySloppy( - output, - face.mIndices, - num_indices, - face.mPositions, - face.mNumVertices, - LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], - target_indices, - lod_error_threshold, - &result_code); + const LLVolumeFace &face = base->getVolumeFace(face_idx); + size_indices += face.mNumIndices; + size_vertices += face.mNumVertices; } - else + + // Allocate buffers, note that we are using U32 buffer instead of U16 + U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); + U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); + + // extra space for normals and text coords, is it needed? + S32 size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF; + LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + size); + + // copy indices and vertices into new buffers + S32 vertices_copied = 0; + S32 indices_shift = 0; + S32 indices_copied = 0; + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle - new_indices = LLMeshOptimizer::simplify( - output, - face.mIndices, - num_indices, - face.mPositions, - face.mNumVertices, - LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], - target_indices, - lod_error_threshold, - &result_code); + const LLVolumeFace &face = base->getVolumeFace(face_idx); + + // vertices + S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); + LLVector4a* dest = combined_positions + vertices_copied; + LLVector4a::memcpyNonAliased16((F32*)dest, (F32*)face.mPositions, copy_bytes); + vertices_copied += face.mNumVertices; + + // todo: figure if need to copy normals and text coords + + // indices, sadly can't do dumb memcpy for indices, we need to adjust each value + for (S32 i = 0; i < face.mNumIndices; ++i) + { + U16 idx = face.mIndices[i]; + + combined_indices[indices_copied] = idx + indices_shift; + indices_copied++; + } + indices_shift += face.mNumVertices; } + // Now that we have buffers, optimize + S32 target_indices = 0; + F32 result_code = 0; // how far from original the model is, 1 == 100% + S32 new_indices = 0; + + target_indices = llmax(3, llfloor(size_indices * indices_ratio)); // leave at least one triangle + new_indices = LLMeshOptimizer::simplifyU32( + output_indices, + combined_indices, + size_indices, + combined_positions, + size_vertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], + target_indices, + lod_error_threshold, + &result_code); + if (result_code < 0) { - LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx - << " of model " << target_model->mLabel + LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel << " target Indices: " << target_indices << " new Indices: " << new_indices - << " original count: " << num_indices << LL_ENDL; + << " original count: " << size_indices << LL_ENDL; } - LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + // repack back into individual faces + indices_shift = 0; + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) + { + const LLVolumeFace &face = base->getVolumeFace(face_idx); + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + + S32 size = (face.mNumIndices * sizeof(U16) + 0xF) & ~0xF; + U16* output = (U16*)ll_aligned_malloc_16(size); - // Copy old values - new_face = face; + // Copy old values + new_face = face; + // Fow now crude method to copy indices back into face + // Should have been done in reverse - cycle by indices and figure out target face from id's size + // Experiment + S32 indices_copied = 0; + for (S32 i = 0; i < new_indices / 3; ++i) + { + U32 position = i * 3; + U32 idx1 = output_indices[position]; + U32 idx2 = output_indices[position+1]; + U32 idx3 = output_indices[position+2]; + + bool copy = false; + S32 range = indices_shift + face.mNumVertices; + + if (idx1 >= indices_shift && idx1 < range) + { + output[indices_copied] = idx1 - indices_shift; + copy = true; + } + if (copy) + { + if (idx2 >= indices_shift && idx2 < range) + { + output[indices_copied + 1] = idx2 - indices_shift; + } + else + { + // todo: extend size of face's vertices list and add new vertices + LL_WARNS_ONCE() << "incomplete code, dropped triangle" << LL_ENDL; + output[indices_copied + 1] = 0; + } - if (new_indices == 0) + if (idx3 < face.mNumVertices) + { + output[indices_copied + 2] = idx3 - indices_shift; + } + else + { + // todo: extend size of face's vertices list and add new vertices + LL_WARNS_ONCE() << "incomplete code, dropped triangle" << LL_ENDL; + output[indices_copied + 2] = 0; + } + } + if (copy) + { + indices_copied += 3; + } + + new_face.resizeIndices(indices_copied); + S32 idx_size = (indices_copied * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); + + } + indices_shift += face.mNumVertices; + + if (indices_copied == 0) + { + new_face.resizeIndices(3); + new_face.resizeVertices(1); + memset(new_face.mIndices, 0, sizeof(U16) * 3); + new_face.mPositions[0].clear(); // set first vertice to 0 + new_face.mNormals[0].clear(); + new_face.mTexCoords[0].setZero(); + } + } + + ll_aligned_free<64>(combined_positions); + ll_aligned_free_32(output_indices); + ll_aligned_free_32(combined_indices); + } + else + { + // Run meshoptimizer for each face + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - if (!sloppy) + const LLVolumeFace &face = base->getVolumeFace(face_idx); + S32 num_indices = face.mNumIndices; + // todo: do not allocate per each face, add one large buffer somewhere + // faces have limited amount of indices + S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF; + U16* output = (U16*)ll_aligned_malloc_16(size); + + /* + generateShadowIndexBuffer appears to deform model + LLMeshOptimizer::generateShadowIndexBuffer( + &shadow[0], + face.mIndices, + num_indices, + &face.mPositions[0], + face.mNumVertices); + */ + + S32 target_indices = 0; + F32 result_code = 0; // how far from original the model is, 1 == 100% + S32 new_indices = 0; + + if (meshopt_mode == MESH_OPTIMIZER_SLOPPY) + { + target_indices = llfloor(num_indices * indices_ratio); + new_indices = LLMeshOptimizer::simplifySloppy( + output, + face.mIndices, + num_indices, + face.mPositions, + face.mNumVertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], + target_indices, + lod_error_threshold, + &result_code); + } + + if (meshopt_mode == MESH_OPTIMIZER) { - // optimizeSloppy() can optimize triangles away even if target_indices is > 2, - // but optimize() isn't supposed to - LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx + target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle + new_indices = LLMeshOptimizer::simplify( + output, + face.mIndices, + num_indices, + face.mPositions, + face.mNumVertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], + target_indices, + lod_error_threshold, + &result_code); + } + + + if (result_code < 0) + { + LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx << " of model " << target_model->mLabel << " target Indices: " << target_indices + << " new Indices: " << new_indices << " original count: " << num_indices << LL_ENDL; } - // Face got optimized away - // Generate empty triangle - new_face.resizeIndices(3); - new_face.resizeVertices(1); - memset(new_face.mIndices, 0, sizeof(U16) * 3); - new_face.mPositions[0].clear(); // set first vertice to 0 - new_face.mNormals[0].clear(); - new_face.mTexCoords[0].setZero(); - } - else - { - // Assign new values - new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output - S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); - // clear unused values - new_face.optimize(); - } + // Copy old values + new_face = face; + + + if (new_indices == 0) + { + if (meshopt_mode != MESH_OPTIMIZER_SLOPPY) + { + // optimizeSloppy() can optimize triangles away even if target_indices is > 2, + // but optimize() isn't supposed to + LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " original count: " << num_indices << LL_ENDL; + } + + // Face got optimized away + // Generate empty triangle + new_face.resizeIndices(3); + new_face.resizeVertices(1); + memset(new_face.mIndices, 0, sizeof(U16) * 3); + new_face.mPositions[0].clear(); // set first vertice to 0 + new_face.mNormals[0].clear(); + new_face.mTexCoords[0].setZero(); + } + else + { + // Assign new values + new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output + S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); - ll_aligned_free_16(output); + // clear unused values + new_face.optimize(); + } + + ll_aligned_free_16(output); + } } //blind copy skin weights and just take closest skin weight to point on @@ -3833,7 +3994,7 @@ bool LLModelPreview::lodQueryCallback() { S32 lod = preview->mLodsQuery.back(); preview->mLodsQuery.pop_back(); - preview->genMeshOptimizerLODs(lod); + preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER); if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH)) { @@ -3857,11 +4018,11 @@ void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit) } } -void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, bool sloppy) +void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, S32 mode) { if (!mLODFrozen) { - genMeshOptimizerLODs(requested_lod, 3, enforce_tri_limit, sloppy); + genMeshOptimizerLODs(requested_lod, mode, 3, enforce_tri_limit); refresh(); } } diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 9f38156ca2..b784345b5a 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -127,6 +127,7 @@ public: GENERATE, MESH_OPTIMIZER, MESH_OPTIMIZER_SLOPPY, + MESH_OPTIMIZER_COMBINE, USE_LOD_ABOVE, } eLoDMode; @@ -164,7 +165,7 @@ public: bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } void queryLODs() { mGenLOD = true; }; void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); - void genMeshOptimizerLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false, bool sloppy = false); + void genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation = 3, bool enforce_tri_limit = false); void generateNormals(); void restoreNormals(); U32 calcResourceCost(); @@ -176,7 +177,7 @@ public: void updateLodControls(S32 lod); void clearGLODGroup(); void onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit); - void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, bool sloppy); + void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, S32 mode); void addEmptyFace(LLModel* pTarget); const bool getModelPivot(void) const { return mHasPivot; } diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 230284555c..5c78ef55d1 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -184,6 +184,10 @@ name="MeshOptSloppy" label="MeshOptSloppy" value="MeshOptSloppy" /> + + + + Date: Mon, 26 Jul 2021 21:20:53 +0300 Subject: DRTVWR-542 Attempt to simplify all faces of an object as a whole and split back into faces #2 --- indra/newview/llmodelpreview.cpp | 111 ++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 31 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 6542ac9090..b68162e374 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1857,12 +1857,14 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); - // extra space for normals and text coords, is it needed? - S32 size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF; - LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + size); + // extra space for normals and text coords + S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF; + LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); + LLVector4a* combined_normals = combined_positions + size_vertices; + LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices); // copy indices and vertices into new buffers - S32 vertices_copied = 0; + S32 positions_copied = 0; S32 indices_shift = 0; S32 indices_copied = 0; for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) @@ -1871,13 +1873,18 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // vertices S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); - LLVector4a* dest = combined_positions + vertices_copied; - LLVector4a::memcpyNonAliased16((F32*)dest, (F32*)face.mPositions, copy_bytes); - vertices_copied += face.mNumVertices; + LLVector4a::memcpyNonAliased16((F32*)(combined_positions + positions_copied), (F32*)face.mPositions, copy_bytes); - // todo: figure if need to copy normals and text coords + // normals + LLVector4a::memcpyNonAliased16((F32*)(combined_normals + positions_copied), (F32*)face.mNormals, copy_bytes); - // indices, sadly can't do dumb memcpy for indices, we need to adjust each value + // tex coords + copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + positions_copied), (F32*)face.mTexCoords, copy_bytes); + + positions_copied += face.mNumVertices; + + // indices, sadly can't do dumb memcpy for indices, need to adjust each value for (S32 i = 0; i < face.mNumIndices; ++i) { U16 idx = face.mIndices[i]; @@ -1916,20 +1923,31 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // repack back into individual faces indices_shift = 0; + + LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); + LLVector4a* buffer_normals = buffer_positions + size_vertices; + LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices); + S32 position_buffer_known_size = 0; + + U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16)); + + // Crude method to copy indices back into face + // Should have been done in reverse - cycle by indices and figure out target face from ids for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { const LLVolumeFace &face = base->getVolumeFace(face_idx); - LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); - S32 size = (face.mNumIndices * sizeof(U16) + 0xF) & ~0xF; - U16* output = (U16*)ll_aligned_malloc_16(size); + // copy face's original data + S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); + LLVector4a::memcpyNonAliased16((F32*)buffer_positions, (F32*)face.mPositions, copy_bytes); + LLVector4a::memcpyNonAliased16((F32*)buffer_normals, (F32*)face.mNormals, copy_bytes); - // Copy old values - new_face = face; + copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)buffer_tex_coords, (F32*)face.mTexCoords, copy_bytes); - // Fow now crude method to copy indices back into face - // Should have been done in reverse - cycle by indices and figure out target face from id's size - // Experiment + position_buffer_known_size = face.mNumVertices; + + // Copy indices S32 indices_copied = 0; for (S32 i = 0; i < new_indices / 3; ++i) { @@ -1941,49 +1959,60 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d bool copy = false; S32 range = indices_shift + face.mNumVertices; + // todo: we should not copy more than U16_MAX items per face if (idx1 >= indices_shift && idx1 < range) { - output[indices_copied] = idx1 - indices_shift; + buffer_indices[indices_copied] = idx1 - indices_shift; copy = true; } if (copy) { if (idx2 >= indices_shift && idx2 < range) { - output[indices_copied + 1] = idx2 - indices_shift; + buffer_indices[indices_copied + 1] = idx2 - indices_shift; } else { - // todo: extend size of face's vertices list and add new vertices - LL_WARNS_ONCE() << "incomplete code, dropped triangle" << LL_ENDL; - output[indices_copied + 1] = 0; + // Extend size of face's positions list + buffer_indices[indices_copied + 1] = (U16)position_buffer_known_size; + buffer_positions[position_buffer_known_size] = combined_positions[idx2]; + buffer_normals[position_buffer_known_size] = combined_normals[idx2]; + buffer_tex_coords[position_buffer_known_size] = combined_tex_coords[idx2]; + position_buffer_known_size++; + + LL_WARNS_ONCE() << "Merged triangle into different face" << LL_ENDL; } if (idx3 < face.mNumVertices) { - output[indices_copied + 2] = idx3 - indices_shift; + buffer_indices[indices_copied + 2] = idx3 - indices_shift; } else { - // todo: extend size of face's vertices list and add new vertices - LL_WARNS_ONCE() << "incomplete code, dropped triangle" << LL_ENDL; - output[indices_copied + 2] = 0; + // Extend size of face's positions list + buffer_indices[indices_copied + 2] = position_buffer_known_size; + buffer_positions[position_buffer_known_size] = combined_positions[idx3]; + buffer_normals[position_buffer_known_size] = combined_normals[idx3]; + buffer_tex_coords[position_buffer_known_size] = combined_tex_coords[idx3]; + position_buffer_known_size++; + + LL_WARNS_ONCE() << "Merged triangle into different face" << LL_ENDL; } } + if (copy) { indices_copied += 3; } - new_face.resizeIndices(indices_copied); - S32 idx_size = (indices_copied * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); - } - indices_shift += face.mNumVertices; + + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + //new_face = face; //temp if (indices_copied == 0) { + // face was optimized away new_face.resizeIndices(3); new_face.resizeVertices(1); memset(new_face.mIndices, 0, sizeof(U16) * 3); @@ -1991,10 +2020,30 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d new_face.mNormals[0].clear(); new_face.mTexCoords[0].setZero(); } + else + { + new_face.resizeIndices(indices_copied); + new_face.resizeVertices(position_buffer_known_size); + + S32 idx_size = (indices_copied * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size); + + LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, position_buffer_known_size * sizeof(LLVector4a)); + LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, position_buffer_known_size * sizeof(LLVector4a)); + + U32 tex_size = (position_buffer_known_size * sizeof(LLVector2) + 0xF)&~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size); + + new_face.optimize(); + } + + indices_shift += face.mNumVertices; } ll_aligned_free<64>(combined_positions); + ll_aligned_free<64>(buffer_positions); ll_aligned_free_32(output_indices); + ll_aligned_free_32(buffer_indices); ll_aligned_free_32(combined_indices); } else -- cgit v1.2.3 From 61d2717cfc58ade1f0a4647698603c146ee9e012 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 27 Jul 2021 18:54:44 +0300 Subject: DRTVWR-542 Attempt to simplify all faces of an object as a whole and split back into faces #3 --- indra/newview/llmodelpreview.cpp | 141 +++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 74 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index b68162e374..f005eb0436 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1864,35 +1864,35 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices); // copy indices and vertices into new buffers - S32 positions_copied = 0; - S32 indices_shift = 0; - S32 indices_copied = 0; + S32 combined_positions_shift = 0; + S32 indices_idx_shift = 0; + S32 combined_indices_shift = 0; for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { const LLVolumeFace &face = base->getVolumeFace(face_idx); // vertices S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); - LLVector4a::memcpyNonAliased16((F32*)(combined_positions + positions_copied), (F32*)face.mPositions, copy_bytes); + LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes); // normals - LLVector4a::memcpyNonAliased16((F32*)(combined_normals + positions_copied), (F32*)face.mNormals, copy_bytes); + LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes); // tex coords copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + positions_copied), (F32*)face.mTexCoords, copy_bytes); + LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + combined_positions_shift), (F32*)face.mTexCoords, copy_bytes); - positions_copied += face.mNumVertices; + combined_positions_shift += face.mNumVertices; // indices, sadly can't do dumb memcpy for indices, need to adjust each value for (S32 i = 0; i < face.mNumIndices; ++i) { U16 idx = face.mIndices[i]; - combined_indices[indices_copied] = idx + indices_shift; - indices_copied++; + combined_indices[combined_indices_shift] = idx + indices_idx_shift; + combined_indices_shift++; } - indices_shift += face.mNumVertices; + indices_idx_shift += face.mNumVertices; } // Now that we have buffers, optimize @@ -1922,95 +1922,87 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d } // repack back into individual faces - indices_shift = 0; LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); LLVector4a* buffer_normals = buffer_positions + size_vertices; LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices); - S32 position_buffer_known_size = 0; - U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16)); + S32* old_to_new_positions_map = new S32[size_vertices]; + + S32 buf_positions_copied = 0; + S32 buf_indices_copied = 0; + indices_idx_shift = 0; // Crude method to copy indices back into face - // Should have been done in reverse - cycle by indices and figure out target face from ids for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { const LLVolumeFace &face = base->getVolumeFace(face_idx); - // copy face's original data - S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); - LLVector4a::memcpyNonAliased16((F32*)buffer_positions, (F32*)face.mPositions, copy_bytes); - LLVector4a::memcpyNonAliased16((F32*)buffer_normals, (F32*)face.mNormals, copy_bytes); - - copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)buffer_tex_coords, (F32*)face.mTexCoords, copy_bytes); - - position_buffer_known_size = face.mNumVertices; + // reset data for new run + buf_positions_copied = 0; + buf_indices_copied = 0; + bool copy_triangle = false; + S32 range = indices_idx_shift + face.mNumVertices; - // Copy indices - S32 indices_copied = 0; - for (S32 i = 0; i < new_indices / 3; ++i) + for (S32 i = 0; i < size_vertices; i++) { - U32 position = i * 3; - U32 idx1 = output_indices[position]; - U32 idx2 = output_indices[position+1]; - U32 idx3 = output_indices[position+2]; + old_to_new_positions_map[i] = -1; + } - bool copy = false; - S32 range = indices_shift + face.mNumVertices; + // Copy relevant indices and vertices + for (S32 i = 0; i < new_indices; ++i) + { + U32 idx = output_indices[i]; - // todo: we should not copy more than U16_MAX items per face - if (idx1 >= indices_shift && idx1 < range) + if ((i % 3) == 0) { - buffer_indices[indices_copied] = idx1 - indices_shift; - copy = true; + copy_triangle = idx >= indices_idx_shift && idx < range; } - if (copy) + + if (copy_triangle) { - if (idx2 >= indices_shift && idx2 < range) + if (idx >= U16_MAX) { - buffer_indices[indices_copied + 1] = idx2 - indices_shift; - } - else - { - // Extend size of face's positions list - buffer_indices[indices_copied + 1] = (U16)position_buffer_known_size; - buffer_positions[position_buffer_known_size] = combined_positions[idx2]; - buffer_normals[position_buffer_known_size] = combined_normals[idx2]; - buffer_tex_coords[position_buffer_known_size] = combined_tex_coords[idx2]; - position_buffer_known_size++; - - LL_WARNS_ONCE() << "Merged triangle into different face" << LL_ENDL; + // Shouldn't happen due to simplification? + // Todo: add a fallback? + LL_ERRS() << "Over triangle limit" << LL_ENDL; + break; } - if (idx3 < face.mNumVertices) + if (old_to_new_positions_map[idx] == -1) { - buffer_indices[indices_copied + 2] = idx3 - indices_shift; + // New position, need to copy it + // Validate size + if (buf_positions_copied >= U16_MAX) + { + // Shouldn't happen due to simplification? + LL_ERRS() << "Over triangle limit" << LL_ENDL; + break; + } + + // Copy vertice, normals, tcs + buffer_positions[buf_positions_copied] = combined_positions[idx]; + buffer_normals[buf_positions_copied] = combined_normals[idx]; + buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx]; + + old_to_new_positions_map[idx] = buf_positions_copied; + + buffer_indices[buf_indices_copied] = (U16)buf_positions_copied; + buf_positions_copied++; } else { - // Extend size of face's positions list - buffer_indices[indices_copied + 2] = position_buffer_known_size; - buffer_positions[position_buffer_known_size] = combined_positions[idx3]; - buffer_normals[position_buffer_known_size] = combined_normals[idx3]; - buffer_tex_coords[position_buffer_known_size] = combined_tex_coords[idx3]; - position_buffer_known_size++; - - LL_WARNS_ONCE() << "Merged triangle into different face" << LL_ENDL; + // existing position + buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx]; } + buf_indices_copied++; } - - if (copy) - { - indices_copied += 3; - } - } LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); //new_face = face; //temp - if (indices_copied == 0) + if (buf_indices_copied < 3) { // face was optimized away new_face.resizeIndices(3); @@ -2022,24 +2014,25 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d } else { - new_face.resizeIndices(indices_copied); - new_face.resizeVertices(position_buffer_known_size); + new_face.resizeIndices(buf_indices_copied); + new_face.resizeVertices(buf_positions_copied); - S32 idx_size = (indices_copied * sizeof(U16) + 0xF) & ~0xF; + S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF; LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size); - LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, position_buffer_known_size * sizeof(LLVector4a)); - LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, position_buffer_known_size * sizeof(LLVector4a)); + LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a)); + LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a)); - U32 tex_size = (position_buffer_known_size * sizeof(LLVector2) + 0xF)&~0xF; + U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF; LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size); new_face.optimize(); } - indices_shift += face.mNumVertices; + indices_idx_shift += face.mNumVertices; } + delete []old_to_new_positions_map; ll_aligned_free<64>(combined_positions); ll_aligned_free<64>(buffer_positions); ll_aligned_free_32(output_indices); -- cgit v1.2.3 From d64b1bded9a0ff05d90f00d72b031a8c04715af7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 27 Jul 2021 20:14:39 +0300 Subject: DRTVWR-542 Already optimized --- indra/newview/llmodelpreview.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index f005eb0436..3704cc2ea5 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2025,8 +2025,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF; LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size); - - new_face.optimize(); } indices_idx_shift += face.mNumVertices; -- cgit v1.2.3 From 1531a31cd9907e5294df5cedbda2b9d1e3adb68b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 28 Jul 2021 21:25:18 +0300 Subject: DRTVWR-542 Rename simplification methods in UI and add a fallback --- indra/newview/llmodelpreview.cpp | 56 ++++++++++++---------- .../skins/default/xui/en/floater_model_preview.xml | 24 +++++----- 2 files changed, 42 insertions(+), 38 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 3704cc2ea5..96eb9340f5 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1840,7 +1840,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d LLModel* target_model = mModel[lod][mdl_idx]; - if (meshopt_mode == MESH_OPTIMIZER_COMBINE) + S32 model_meshopt_mode = meshopt_mode; + + if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE) { // Figure out buffer size S32 size_indices = 0; @@ -1961,22 +1963,23 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d if (copy_triangle) { - if (idx >= U16_MAX) - { - // Shouldn't happen due to simplification? - // Todo: add a fallback? - LL_ERRS() << "Over triangle limit" << LL_ENDL; - break; - } - if (old_to_new_positions_map[idx] == -1) { // New position, need to copy it // Validate size if (buf_positions_copied >= U16_MAX) { - // Shouldn't happen due to simplification? - LL_ERRS() << "Over triangle limit" << LL_ENDL; + // Normally this shouldn't happen since the whole point is to reduce amount of vertices + // but it might happen if user tries to run optimization with too large triangle or error value + // so fallback to 'per face' mode or verify requested limits and copy base model as is. + LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for" + << " model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << size_indices + << " error treshold: " << lod_error_threshold + << LL_ENDL; + model_meshopt_mode = MESH_OPTIMIZER; break; } @@ -1999,6 +2002,11 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d } } + if (buf_positions_copied >= U16_MAX) + { + break; + } + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); //new_face = face; //temp @@ -2037,7 +2045,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d ll_aligned_free_32(buffer_indices); ll_aligned_free_32(combined_indices); } - else + + if (model_meshopt_mode == MESH_OPTIMIZER + || model_meshopt_mode == MESH_OPTIMIZER_SLOPPY) { // Run meshoptimizer for each face for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) @@ -2049,21 +2059,11 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF; U16* output = (U16*)ll_aligned_malloc_16(size); - /* - generateShadowIndexBuffer appears to deform model - LLMeshOptimizer::generateShadowIndexBuffer( - &shadow[0], - face.mIndices, - num_indices, - &face.mPositions[0], - face.mNumVertices); - */ - S32 target_indices = 0; F32 result_code = 0; // how far from original the model is, 1 == 100% S32 new_indices = 0; - if (meshopt_mode == MESH_OPTIMIZER_SLOPPY) + if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY) { target_indices = llfloor(num_indices * indices_ratio); new_indices = LLMeshOptimizer::simplifySloppy( @@ -2078,7 +2078,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d &result_code); } - if (meshopt_mode == MESH_OPTIMIZER) + if (model_meshopt_mode == MESH_OPTIMIZER) { target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle new_indices = LLMeshOptimizer::simplify( @@ -2100,7 +2100,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d << " of model " << target_model->mLabel << " target Indices: " << target_indices << " new Indices: " << new_indices - << " original count: " << num_indices << LL_ENDL; + << " original count: " << num_indices + << " error treshold: " << lod_error_threshold + << LL_ENDL; } LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); @@ -2118,7 +2120,9 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx << " of model " << target_model->mLabel << " target Indices: " << target_indices - << " original count: " << num_indices << LL_ENDL; + << " original count: " << num_indices + << " error treshold: " << lod_error_threshold + << LL_ENDL; } // Face got optimized away diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 5c78ef55d1..cd67adf42a 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -178,15 +178,15 @@ value="Generate" /> Date: Wed, 4 Aug 2021 00:15:49 +0300 Subject: DRTVWR-542 Fix incorect dropbox state --- indra/newview/llfloatermodelpreview.cpp | 2 +- indra/newview/llfloatermodelpreview.h | 4 +--- indra/newview/llmodelpreview.cpp | 8 +++++--- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3f2fcb148c..e5d451e909 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -136,7 +136,7 @@ mAvatarTabIndex(0) mStatusLock = new LLMutex(); mModelPreview = NULL; - mLODMode[LLModel::LOD_HIGH] = 0; + mLODMode[LLModel::LOD_HIGH] = LLModelPreview::LOD_FROM_FILE; for (U32 i = 0; i < LLModel::LOD_HIGH; i++) { mLODMode[i] = LLModelPreview::MESH_OPTIMIZER; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 8a01b0c307..51f9b3a0e2 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -196,9 +196,7 @@ protected: std::map mViewOptionDisabled; //store which lod mode each LOD is using - // 0 - load from file - // 1 - auto generate - // 2 - use LoD above + // See eLoDMode S32 mLODMode[4]; LLMutex* mStatusLock; diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 96eb9340f5..11a536473c 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1842,6 +1842,8 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d S32 model_meshopt_mode = meshopt_mode; + // Ideally this should run not per model, + // but combine all submodels with origin model as well if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE) { // Figure out buffer size @@ -2758,7 +2760,7 @@ void LLModelPreview::updateLodControls(S32 lod) S32 lod_mode = lod_combo->getCurrentIndex(); if (lod_mode == LOD_FROM_FILE) // LoD from file { - fmp->mLODMode[lod] = 0; + fmp->mLODMode[lod] = LOD_FROM_FILE; for (U32 i = 0; i < num_file_controls; ++i) { mFMP->childSetVisible(file_controls[i] + lod_name[lod], true); @@ -2771,7 +2773,7 @@ void LLModelPreview::updateLodControls(S32 lod) } else if (lod_mode == USE_LOD_ABOVE) // use LoD above { - fmp->mLODMode[lod] = 2; + fmp->mLODMode[lod] = USE_LOD_ABOVE; for (U32 i = 0; i < num_file_controls; ++i) { mFMP->childSetVisible(file_controls[i] + lod_name[lod], false); @@ -2797,7 +2799,7 @@ void LLModelPreview::updateLodControls(S32 lod) } else // auto generate, the default case for all LoDs except High { - fmp->mLODMode[lod] = 1; + fmp->mLODMode[lod] = MESH_OPTIMIZER; //don't actually regenerate lod when refreshing UI mLODFrozen = true; -- cgit v1.2.3 From 1a1793244002effe46cedf63180de60f4bc69a9a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 4 Aug 2021 21:14:00 +0300 Subject: DRTVWR-542 Automated method selection Normally simplification methods apply for whole upload, but this one selects methods per model or per face. --- indra/newview/llfloatermodelpreview.cpp | 6 +- indra/newview/llmodelpreview.cpp | 631 +++++++++++---------- indra/newview/llmodelpreview.h | 7 +- .../skins/default/xui/en/floater_model_preview.xml | 48 +- 4 files changed, 386 insertions(+), 306 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e5d451e909..6795ea8f53 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -139,7 +139,7 @@ mAvatarTabIndex(0) mLODMode[LLModel::LOD_HIGH] = LLModelPreview::LOD_FROM_FILE; for (U32 i = 0; i < LLModel::LOD_HIGH; i++) { - mLODMode[i] = LLModelPreview::MESH_OPTIMIZER; + mLODMode[i] = LLModelPreview::MESH_OPTIMIZER_AUTO; } } @@ -729,6 +729,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) case LLModelPreview::GENERATE: mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit); break; + case LLModelPreview::MESH_OPTIMIZER_AUTO: case LLModelPreview::MESH_OPTIMIZER: case LLModelPreview::MESH_OPTIMIZER_SLOPPY: case LLModelPreview::MESH_OPTIMIZER_COMBINE: @@ -1738,6 +1739,7 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[lod]); S32 index = lod_source_combo->getCurrentIndex(); if (index == LLModelPreview::GENERATE + || index == LLModelPreview::MESH_OPTIMIZER_AUTO || index == LLModelPreview::MESH_OPTIMIZER || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY || index == LLModelPreview::MESH_OPTIMIZER_COMBINE) @@ -1771,7 +1773,7 @@ void LLFloaterModelPreview::resetUploadOptions() getChild("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE); for (S32 lod = 0; lod < NUM_LOD - 1; ++lod) { - getChild("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER); + getChild("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER_AUTO); childSetValue("lod_file_" + lod_name[lod], ""); } diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 11a536473c..3a8676d7b9 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1706,6 +1706,307 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri } } +// Runs per object, but likely it is a better way to run per model+submodels +// returns a ratio of base model indices to resulting indices +F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy) +{ + // Figure out buffer size + S32 size_indices = 0; + S32 size_vertices = 0; + + for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx) + { + const LLVolumeFace &face = base_model->getVolumeFace(face_idx); + size_indices += face.mNumIndices; + size_vertices += face.mNumVertices; + } + + // Allocate buffers, note that we are using U32 buffer instead of U16 + U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); + U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); + + // extra space for normals and text coords + S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF; + LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); + LLVector4a* combined_normals = combined_positions + size_vertices; + LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices); + + // copy indices and vertices into new buffers + S32 combined_positions_shift = 0; + S32 indices_idx_shift = 0; + S32 combined_indices_shift = 0; + for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx) + { + const LLVolumeFace &face = base_model->getVolumeFace(face_idx); + + // vertices + S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); + LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes); + + // normals + LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes); + + // tex coords + copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + combined_positions_shift), (F32*)face.mTexCoords, copy_bytes); + + combined_positions_shift += face.mNumVertices; + + // indices, sadly can't do dumb memcpy for indices, need to adjust each value + for (S32 i = 0; i < face.mNumIndices; ++i) + { + U16 idx = face.mIndices[i]; + + combined_indices[combined_indices_shift] = idx + indices_idx_shift; + combined_indices_shift++; + } + indices_idx_shift += face.mNumVertices; + } + + // Now that we have buffers, optimize + S32 target_indices = 0; + F32 result_code = 0; // how far from original the model is, 1 == 100% + S32 new_indices = 0; + + target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle + new_indices = LLMeshOptimizer::simplifyU32( + output_indices, + combined_indices, + size_indices, + combined_positions, + size_vertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], + target_indices, + error_threshold, + sloppy, + &result_code); + + + if (result_code < 0) + { + LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << size_indices << LL_ENDL; + } + + // repack back into individual faces + + LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); + LLVector4a* buffer_normals = buffer_positions + size_vertices; + LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices); + U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16)); + S32* old_to_new_positions_map = new S32[size_vertices]; + + S32 buf_positions_copied = 0; + S32 buf_indices_copied = 0; + indices_idx_shift = 0; + + // Crude method to copy indices back into face + for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx) + { + const LLVolumeFace &face = base_model->getVolumeFace(face_idx); + + // reset data for new run + buf_positions_copied = 0; + buf_indices_copied = 0; + bool copy_triangle = false; + S32 range = indices_idx_shift + face.mNumVertices; + + for (S32 i = 0; i < size_vertices; i++) + { + old_to_new_positions_map[i] = -1; + } + + // Copy relevant indices and vertices + for (S32 i = 0; i < new_indices; ++i) + { + U32 idx = output_indices[i]; + + if ((i % 3) == 0) + { + copy_triangle = idx >= indices_idx_shift && idx < range; + } + + if (copy_triangle) + { + if (old_to_new_positions_map[idx] == -1) + { + // New position, need to copy it + // Validate size + if (buf_positions_copied >= U16_MAX) + { + // Normally this shouldn't happen since the whole point is to reduce amount of vertices + // but it might happen if user tries to run optimization with too large triangle or error value + // so fallback to 'per face' mode or verify requested limits and copy base model as is. + LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for" + << " model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << size_indices + << " error treshold: " << error_threshold + << LL_ENDL; + return -1; + } + + // Copy vertice, normals, tcs + buffer_positions[buf_positions_copied] = combined_positions[idx]; + buffer_normals[buf_positions_copied] = combined_normals[idx]; + buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx]; + + old_to_new_positions_map[idx] = buf_positions_copied; + + buffer_indices[buf_indices_copied] = (U16)buf_positions_copied; + buf_positions_copied++; + } + else + { + // existing position + buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx]; + } + buf_indices_copied++; + } + } + + if (buf_positions_copied >= U16_MAX) + { + break; + } + + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + //new_face = face; //temp + + if (buf_indices_copied < 3) + { + // face was optimized away + new_face.resizeIndices(3); + new_face.resizeVertices(1); + memset(new_face.mIndices, 0, sizeof(U16) * 3); + new_face.mPositions[0].clear(); // set first vertice to 0 + new_face.mNormals[0].clear(); + new_face.mTexCoords[0].setZero(); + } + else + { + new_face.resizeIndices(buf_indices_copied); + new_face.resizeVertices(buf_positions_copied); + + S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size); + + LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a)); + LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a)); + + U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size); + } + + indices_idx_shift += face.mNumVertices; + } + + delete[]old_to_new_positions_map; + ll_aligned_free<64>(combined_positions); + ll_aligned_free<64>(buffer_positions); + ll_aligned_free_32(output_indices); + ll_aligned_free_32(buffer_indices); + ll_aligned_free_32(combined_indices); + + if (new_indices <= 0) + { + return -1; + } + + return (F32)size_indices / (F32)new_indices; +} + +F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, bool sloppy) +{ + const LLVolumeFace &face = base_model->getVolumeFace(face_idx); + S32 size_indices = face.mNumIndices; + // todo: do not allocate per each face, add one large buffer somewhere + // faces have limited amount of indices + S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF; + U16* output = (U16*)ll_aligned_malloc_16(size); + + S32 target_indices = 0; + F32 result_code = 0; // how far from original the model is, 1 == 100% + S32 new_indices = 0; + + target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle + new_indices = LLMeshOptimizer::simplify( + output, + face.mIndices, + size_indices, + face.mPositions, + face.mNumVertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], + target_indices, + error_threshold, + sloppy, + &result_code); + + + if (result_code < 0) + { + LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << size_indices + << " error treshold: " << error_threshold + << LL_ENDL; + } + + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + + // Copy old values + new_face = face; + + + if (new_indices == 0) + { + if (!sloppy) + { + // meshopt_optimizeSloppy() can optimize triangles away even if target_indices is > 2, + // but optimize() isn't supposed to + LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " original count: " << size_indices + << " error treshold: " << error_threshold + << LL_ENDL; + } + + // Face got optimized away + // Generate empty triangle + new_face.resizeIndices(3); + new_face.resizeVertices(1); + memset(new_face.mIndices, 0, sizeof(U16) * 3); + new_face.mPositions[0].clear(); // set first vertice to 0 + new_face.mNormals[0].clear(); + new_face.mTexCoords[0].setZero(); + } + else + { + // Assign new values + new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output + S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); + + // clear unused values + new_face.optimize(); + } + + ll_aligned_free_16(output); + + if (new_indices <= 0) + { + return -1; + } + + return (F32)size_indices / (F32)new_indices; +} + void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit) { LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL; @@ -1736,7 +2037,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview // We should not be accesing views from other class! U32 lod_mode = LIMIT_TRIANGLES; - F32 indices_ratio = 0; + F32 indices_decimator = 0; F32 triangle_limit = 0; F32 lod_error_threshold = 1; //100% @@ -1767,7 +2068,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d } // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio - indices_ratio = triangle_limit / (F32)base_triangle_count; + indices_decimator = (F32)base_triangle_count / triangle_limit; } else { @@ -1776,8 +2077,8 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d } else { - // we are genrating all lods and each lod will get own indices_ratio - indices_ratio = 1; + // we are genrating all lods and each lod will get own indices_decimator + indices_decimator = 1; triangle_limit = base_triangle_count; } @@ -1810,7 +2111,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // we are genrating all lods and each lod gets own indices_ratio if (lod < start) { - indices_ratio /= decimation; + indices_decimator *= decimation; triangle_limit /= decimation; } } @@ -1846,308 +2147,64 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // but combine all submodels with origin model as well if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE) { - // Figure out buffer size - S32 size_indices = 0; - S32 size_vertices = 0; + // Run meshoptimizer for each model/object, up to 8 faces in one model + // Ideally this should run not per model, + // but combine all submodels with origin model as well + genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + } + + if (model_meshopt_mode == MESH_OPTIMIZER) + { + // Run meshoptimizer for each face for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - const LLVolumeFace &face = base->getVolumeFace(face_idx); - size_indices += face.mNumIndices; - size_vertices += face.mNumVertices; + genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); } + } - // Allocate buffers, note that we are using U32 buffer instead of U16 - U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); - U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); - - // extra space for normals and text coords - S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF; - LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); - LLVector4a* combined_normals = combined_positions + size_vertices; - LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices); - - // copy indices and vertices into new buffers - S32 combined_positions_shift = 0; - S32 indices_idx_shift = 0; - S32 combined_indices_shift = 0; + if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY) + { + // Run meshoptimizer for each face for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - const LLVolumeFace &face = base->getVolumeFace(face_idx); - - // vertices - S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); - LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes); - - // normals - LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes); - - // tex coords - copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + combined_positions_shift), (F32*)face.mTexCoords, copy_bytes); - - combined_positions_shift += face.mNumVertices; - - // indices, sadly can't do dumb memcpy for indices, need to adjust each value - for (S32 i = 0; i < face.mNumIndices; ++i) - { - U16 idx = face.mIndices[i]; - - combined_indices[combined_indices_shift] = idx + indices_idx_shift; - combined_indices_shift++; - } - indices_idx_shift += face.mNumVertices; - } - - // Now that we have buffers, optimize - S32 target_indices = 0; - F32 result_code = 0; // how far from original the model is, 1 == 100% - S32 new_indices = 0; - - target_indices = llmax(3, llfloor(size_indices * indices_ratio)); // leave at least one triangle - new_indices = LLMeshOptimizer::simplifyU32( - output_indices, - combined_indices, - size_indices, - combined_positions, - size_vertices, - LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], - target_indices, - lod_error_threshold, - &result_code); - - - if (result_code < 0) - { - LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel - << " target Indices: " << target_indices - << " new Indices: " << new_indices - << " original count: " << size_indices << LL_ENDL; + genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true); } + } - // repack back into individual faces - - LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); - LLVector4a* buffer_normals = buffer_positions + size_vertices; - LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices); - U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16)); - S32* old_to_new_positions_map = new S32[size_vertices]; - - S32 buf_positions_copied = 0; - S32 buf_indices_copied = 0; - indices_idx_shift = 0; - - // Crude method to copy indices back into face - for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) + if (model_meshopt_mode == MESH_OPTIMIZER_AUTO) + { + F32 allowed_ratio_drift = 2.f; + S32 res = 0; + if (base->mHasGeneratedFaces) { - const LLVolumeFace &face = base->getVolumeFace(face_idx); - - // reset data for new run - buf_positions_copied = 0; - buf_indices_copied = 0; - bool copy_triangle = false; - S32 range = indices_idx_shift + face.mNumVertices; - - for (S32 i = 0; i < size_vertices; i++) - { - old_to_new_positions_map[i] = -1; - } - - // Copy relevant indices and vertices - for (S32 i = 0; i < new_indices; ++i) - { - U32 idx = output_indices[i]; - - if ((i % 3) == 0) - { - copy_triangle = idx >= indices_idx_shift && idx < range; - } - - if (copy_triangle) - { - if (old_to_new_positions_map[idx] == -1) - { - // New position, need to copy it - // Validate size - if (buf_positions_copied >= U16_MAX) - { - // Normally this shouldn't happen since the whole point is to reduce amount of vertices - // but it might happen if user tries to run optimization with too large triangle or error value - // so fallback to 'per face' mode or verify requested limits and copy base model as is. - LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for" - << " model " << target_model->mLabel - << " target Indices: " << target_indices - << " new Indices: " << new_indices - << " original count: " << size_indices - << " error treshold: " << lod_error_threshold - << LL_ENDL; - model_meshopt_mode = MESH_OPTIMIZER; - break; - } - - // Copy vertice, normals, tcs - buffer_positions[buf_positions_copied] = combined_positions[idx]; - buffer_normals[buf_positions_copied] = combined_normals[idx]; - buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx]; - - old_to_new_positions_map[idx] = buf_positions_copied; - - buffer_indices[buf_indices_copied] = (U16)buf_positions_copied; - buf_positions_copied++; - } - else - { - // existing position - buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx]; - } - buf_indices_copied++; - } - } - - if (buf_positions_copied >= U16_MAX) - { - break; - } - - LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); - //new_face = face; //temp + res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); - if (buf_indices_copied < 3) + if (res * allowed_ratio_drift < indices_decimator) { - // face was optimized away - new_face.resizeIndices(3); - new_face.resizeVertices(1); - memset(new_face.mIndices, 0, sizeof(U16) * 3); - new_face.mPositions[0].clear(); // set first vertice to 0 - new_face.mNormals[0].clear(); - new_face.mTexCoords[0].setZero(); + res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " sloppily simplified using per model method." << LL_ENDL; } else { - new_face.resizeIndices(buf_indices_copied); - new_face.resizeVertices(buf_positions_copied); - - S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size); - - LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a)); - LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a)); - - U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size); + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " simplified using per model method." << LL_ENDL; } - - indices_idx_shift += face.mNumVertices; } - - delete []old_to_new_positions_map; - ll_aligned_free<64>(combined_positions); - ll_aligned_free<64>(buffer_positions); - ll_aligned_free_32(output_indices); - ll_aligned_free_32(buffer_indices); - ll_aligned_free_32(combined_indices); - } - - if (model_meshopt_mode == MESH_OPTIMIZER - || model_meshopt_mode == MESH_OPTIMIZER_SLOPPY) - { - // Run meshoptimizer for each face - for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) + else { - const LLVolumeFace &face = base->getVolumeFace(face_idx); - S32 num_indices = face.mNumIndices; - // todo: do not allocate per each face, add one large buffer somewhere - // faces have limited amount of indices - S32 size = (num_indices * sizeof(U16) + 0xF) & ~0xF; - U16* output = (U16*)ll_aligned_malloc_16(size); - - S32 target_indices = 0; - F32 result_code = 0; // how far from original the model is, 1 == 100% - S32 new_indices = 0; - - if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY) - { - target_indices = llfloor(num_indices * indices_ratio); - new_indices = LLMeshOptimizer::simplifySloppy( - output, - face.mIndices, - num_indices, - face.mPositions, - face.mNumVertices, - LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], - target_indices, - lod_error_threshold, - &result_code); - } - - if (model_meshopt_mode == MESH_OPTIMIZER) - { - target_indices = llmax(3, llfloor(num_indices * indices_ratio)); // leave at least one triangle - new_indices = LLMeshOptimizer::simplify( - output, - face.mIndices, - num_indices, - face.mPositions, - face.mNumVertices, - LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], - target_indices, - lod_error_threshold, - &result_code); - } - - - if (result_code < 0) + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx - << " of model " << target_model->mLabel - << " target Indices: " << target_indices - << " new Indices: " << new_indices - << " original count: " << num_indices - << " error treshold: " << lod_error_threshold - << LL_ENDL; - } - - LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); - - // Copy old values - new_face = face; - - - if (new_indices == 0) - { - if (meshopt_mode != MESH_OPTIMIZER_SLOPPY) + res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); + + if (res * allowed_ratio_drift < indices_decimator) { - // optimizeSloppy() can optimize triangles away even if target_indices is > 2, - // but optimize() isn't supposed to - LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx - << " of model " << target_model->mLabel - << " target Indices: " << target_indices - << " original count: " << num_indices - << " error treshold: " << lod_error_threshold - << LL_ENDL; + res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true); } - - // Face got optimized away - // Generate empty triangle - new_face.resizeIndices(3); - new_face.resizeVertices(1); - memset(new_face.mIndices, 0, sizeof(U16) * 3); - new_face.mPositions[0].clear(); // set first vertice to 0 - new_face.mNormals[0].clear(); - new_face.mTexCoords[0].setZero(); } - else - { - // Assign new values - new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output - S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); - - // clear unused values - new_face.optimize(); - } - - ll_aligned_free_16(output); } } @@ -2799,7 +2856,7 @@ void LLModelPreview::updateLodControls(S32 lod) } else // auto generate, the default case for all LoDs except High { - fmp->mLODMode[lod] = MESH_OPTIMIZER; + fmp->mLODMode[lod] = MESH_OPTIMIZER_AUTO; //don't actually regenerate lod when refreshing UI mLODFrozen = true; @@ -4040,7 +4097,7 @@ bool LLModelPreview::lodQueryCallback() { S32 lod = preview->mLodsQuery.back(); preview->mLodsQuery.pop_back(); - preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER); + preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER_AUTO); if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH)) { diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index b784345b5a..b3296fecf6 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -125,9 +125,10 @@ public: { LOD_FROM_FILE = 0, GENERATE, + MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face + MESH_OPTIMIZER_COMBINE, MESH_OPTIMIZER, MESH_OPTIMIZER_SLOPPY, - MESH_OPTIMIZER_COMBINE, USE_LOD_ABOVE, } eLoDMode; @@ -229,6 +230,10 @@ private: // Count amount of original models, excluding sub-models static U32 countRootModels(LLModelLoader::model_list models); + // functions for meshoptimizer, return reached simplification ratio + F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, bool sloppy); + F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, bool sloppy); + protected: friend class LLModelLoader; friend class LLFloaterModelPreview; diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index cd67adf42a..db9d296fa5 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -176,6 +176,14 @@ name="Generate" label="Generate" value="Generate" /> + + - + + - + + - + + - Date: Fri, 6 Aug 2021 09:46:11 +0300 Subject: DRTVWR-542 Automated method selection #2 --- indra/newview/llmodelpreview.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 3a8676d7b9..3ee435fb5f 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2151,7 +2151,15 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // Ideally this should run not per model, // but combine all submodels with origin model as well - genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + F32 res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + if (res < 0) + { + // U16 vertices overflow, shouldn't happen, but just in case + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) + { + genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); + } + } } if (model_meshopt_mode == MESH_OPTIMIZER) @@ -2175,12 +2183,23 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d if (model_meshopt_mode == MESH_OPTIMIZER_AUTO) { F32 allowed_ratio_drift = 2.f; - S32 res = 0; + F32 res = 0; if (base->mHasGeneratedFaces) { res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); - if (res * allowed_ratio_drift < indices_decimator) + if (res < 0) + { + // U16 vertices overflow, shouldn't happen, but just in case + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) + { + genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); + } + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " per model method overflow, defaulting to per face." << LL_ENDL; + } + else if (res * allowed_ratio_drift < indices_decimator) { res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); LL_INFOS() << "Model " << target_model->getName() -- cgit v1.2.3 From 3772249c2f1fd101e06c1be8c1601b58fd6f04ba Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 2 Sep 2021 21:55:06 +0300 Subject: SL-15756 Falback in case no triangles were generated --- indra/newview/llmodelpreview.cpp | 60 ++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 3ee435fb5f..e54045d811 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1708,6 +1708,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri // Runs per object, but likely it is a better way to run per model+submodels // returns a ratio of base model indices to resulting indices +// returns -1 in case of failure F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy) { // Figure out buffer size @@ -1911,8 +1912,23 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe ll_aligned_free_32(buffer_indices); ll_aligned_free_32(combined_indices); - if (new_indices <= 0) + if (new_indices < 3) { + // Model should have at least one visible triangle + + if (!sloppy) + { + // Should only happen with sloppy + // non sloppy shouldn't be capable of optimizing mesh away + LL_WARNS() << "Failed to generate triangles" + << " model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << size_indices + << " error treshold: " << error_threshold + << LL_ENDL; + } + return -1; } @@ -1963,7 +1979,7 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target new_face = face; - if (new_indices == 0) + if (new_indices < 3) { if (!sloppy) { @@ -1999,8 +2015,9 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target ll_aligned_free_16(output); - if (new_indices <= 0) + if (new_indices < 3) { + // At least one triangle is needed return -1; } @@ -2183,12 +2200,12 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d if (model_meshopt_mode == MESH_OPTIMIZER_AUTO) { F32 allowed_ratio_drift = 2.f; - F32 res = 0; + F32 res_ratio = 0; if (base->mHasGeneratedFaces) { - res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); - if (res < 0) + if (res_ratio < 0) { // U16 vertices overflow, shouldn't happen, but just in case for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) @@ -2199,12 +2216,22 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d << " lod " << which_lod << " per model method overflow, defaulting to per face." << LL_ENDL; } - else if (res * allowed_ratio_drift < indices_decimator) + else if (res_ratio * allowed_ratio_drift < indices_decimator) { - res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); + // Try sloppy variant if normal one failed to simplify model enough. + res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); LL_INFOS() << "Model " << target_model->getName() << " lod " << which_lod << " sloppily simplified using per model method." << LL_ENDL; + + + if (res_ratio < 0) + { + // Sloppy variant failed to generate triangles. + // Can happen with models that are too simple as is. + // Fallback to normal method. + genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + } } else { @@ -2217,13 +2244,24 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d { for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); + res_ratio = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); - if (res * allowed_ratio_drift < indices_decimator) + if (res_ratio * allowed_ratio_drift < indices_decimator) { - res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true); + // normal method failed to sufficiently simplify, try sloppy + res_ratio = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true); + if (res_ratio < 0) + { + // Sloppy failed to generate triangles. + // Can happen with models that are too simple as is. + // Fallback to normal method. + genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); + } } } + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " simplified using per face methods." << LL_ENDL; } } -- cgit v1.2.3 From bac30c9ba5fc9f947788b4fbb468d3259a20fc2e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 3 Sep 2021 21:15:00 +0300 Subject: SL-15940 Limit wasn't adjusting for a model with less than 30 triangles --- indra/newview/llmodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index e54045d811..bf661d39b2 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2945,7 +2945,7 @@ void LLModelPreview::updateLodControls(S32 lod) threshold->setVisible(false); limit->setMaxValue(mMaxTriangleLimit); - limit->setIncrement(mMaxTriangleLimit / 32); + limit->setIncrement(llmax((U32)1, mMaxTriangleLimit / 32)); } else { -- cgit v1.2.3 From b45c0e3ed926270e100271f33885b8d31085a858 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 6 Sep 2021 21:29:51 +0300 Subject: SL-15940 Remove ability to set zero triangle limit Setting lod to zero triangles doesn't work and shouldn't work, so UI shouldn't allow setting less then one triangle per model as well. --- indra/newview/llmodelpreview.cpp | 10 ++++++++-- indra/newview/llmodelpreview.h | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index bf661d39b2..b17aa960ce 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -194,6 +194,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mPreviewLOD = 0; mModelLoader = NULL; mMaxTriangleLimit = 0; + mMinTriangleLimit = 0; mDirty = false; mGenLOD = false; mLoading = false; @@ -1508,6 +1509,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri } mMaxTriangleLimit = base_triangle_count; + mMinTriangleLimit = mBaseModel.size(); for (S32 lod = start; lod >= end; --lod) { @@ -1541,7 +1543,7 @@ void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri U32 actual_verts = 0; U32 submeshes = 0; - mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio); + mRequestedTriangleCount[lod] = llmax(mMinTriangleLimit, (S32)((F32)triangle_count / triangle_ratio)); mRequestedErrorThreshold[lod] = lod_error_threshold; glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); @@ -2100,6 +2102,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d } mMaxTriangleLimit = base_triangle_count; + mMinTriangleLimit = mBaseModel.size(); // TODO: Glod regenerates vertex buffer at this stage // check why, it might be needed to regenerate buffer as well @@ -2133,7 +2136,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d } } - mRequestedTriangleCount[lod] = triangle_limit; + mRequestedTriangleCount[lod] = llmax(mMinTriangleLimit, (S32)triangle_limit); mRequestedErrorThreshold[lod] = lod_error_threshold; mRequestedLoDMode[lod] = lod_mode; @@ -2431,6 +2434,7 @@ void LLModelPreview::updateStatusMessages() if (mMaxTriangleLimit == 0) { mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; + mMinTriangleLimit = mUploadData.size(); } mHasDegenerate = false; @@ -2933,6 +2937,7 @@ void LLModelPreview::updateLodControls(S32 lod) LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit_" + lod_name[lod]); limit->setMaxValue(mMaxTriangleLimit); + limit->setMinValue(mMinTriangleLimit); limit->forceSetValue(mRequestedTriangleCount[lod]); threshold->forceSetValue(mRequestedErrorThreshold[lod]); @@ -2945,6 +2950,7 @@ void LLModelPreview::updateLodControls(S32 lod) threshold->setVisible(false); limit->setMaxValue(mMaxTriangleLimit); + limit->setMinValue(mMinTriangleLimit); limit->setIncrement(llmax((U32)1, mMaxTriangleLimit / 32)); } else diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index b3296fecf6..49032f0dbf 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -296,8 +296,14 @@ protected: U32 mGroup; std::map, U32> mObject; + + // Amount of triangles in original(base) model U32 mMaxTriangleLimit; + // Minimum amount of allowed triangles in lod for spin cntrl. + // Leave at least one triangle per model. + S32 mMinTriangleLimit; + LLMeshUploadThread::instance_list mUploadData; std::set mTextureSet; -- cgit v1.2.3 From 396c8bb9fe52e86a857a49020bc0feb33503a6a1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 6 Sep 2021 23:48:04 +0300 Subject: Revert "SL-443 Keybindings: Support reassigment of script interaction button" This reverts commit a5675bedbb2bd34ce03dd16651dc74d8078efea9. Commit slipped in by accident --- indra/newview/app_settings/key_bindings.xml | 8 --- indra/newview/llkeyconflict.cpp | 58 ++-------------- indra/newview/llkeyconflict.h | 4 +- indra/newview/lltoolcomp.cpp | 10 +-- indra/newview/lltoolpie.cpp | 2 +- indra/newview/llviewerinput.cpp | 81 +++------------------- indra/newview/llviewerinput.h | 5 +- .../xui/en/control_table_contents_media.xml | 10 --- 8 files changed, 20 insertions(+), 158 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml index ffc1b2e7cc..4f6deb1f98 100644 --- a/indra/newview/app_settings/key_bindings.xml +++ b/indra/newview/app_settings/key_bindings.xml @@ -33,8 +33,6 @@ - - @@ -129,8 +127,6 @@ - - @@ -228,8 +224,6 @@ - - @@ -257,7 +251,5 @@ - - diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index 58a740e16a..d7a17b237e 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -868,7 +868,7 @@ void LLKeyConflictHandler::resetKeyboardBindings() void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode) { - // These placeholds are meant to cause conflict resolution when user tries to assign same control somewhere else + // These controls are meant to cause conflicts when user tries to assign same control somewhere else // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks if (load_mode == MODE_FIRST_PERSON) @@ -928,73 +928,25 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode) registerTemporaryControl("spin_around_ccw_sitting"); registerTemporaryControl("spin_around_cw_sitting"); } - - - // Special case, mouse clicks passed to scripts have 'lowest' piority - // thus do not conflict, everything else has a chance before them - // also in ML they have highest priority, but only when script-grabbed, - // thus do not conflict - // (see AGENT_CONTROL_ML_LBUTTON_DOWN and CONTROL_LBUTTON_DOWN_INDEX) - LLKeyConflict *type_data = &mControlsMap[script_mouse_handler_name]; - type_data->mAssignable = true; - type_data->mConflictMask = U32_MAX - CONFLICT_LMOUSE; } -bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, U32 conlict_mask) +bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask) { if (conlict_mask == CONFLICT_NOTHING) { // Can't conflict return true; } - - if (data.mMouse == CLICK_LEFT - && data.mMask == MASK_NONE - && data.mKey == KEY_NONE) - { - if ((conlict_mask & CONFLICT_LMOUSE) == 0) - { - // Can't conflict - return true; - } - else - { - // simplify conflict mask - conlict_mask = CONFLICT_LMOUSE; - } - } - else - { - // simplify conflict mask - conlict_mask &= ~CONFLICT_LMOUSE; - } - std::map conflict_list; control_map_t::iterator cntrl_iter = mControlsMap.begin(); control_map_t::iterator cntrl_end = mControlsMap.end(); for (; cntrl_iter != cntrl_end; ++cntrl_iter) { - const U32 cmp_mask = cntrl_iter->second.mConflictMask; - if ((cmp_mask & conlict_mask) == 0) - { - // can't conflict - continue; - } S32 index = cntrl_iter->second.mKeyBind.findKeyData(data); - if (index >= 0) + if (index >= 0 + && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING + && (cntrl_iter->second.mConflictMask & conlict_mask) != 0) { - if (cmp_mask != U32_MAX) - { - const LLKeyData cmp_data = cntrl_iter->second.mKeyBind.getKeyData(index); - if ((cmp_mask & CONFLICT_LMOUSE) == 0 - && cmp_data.mMouse == CLICK_LEFT - && cmp_data.mMask == MASK_NONE - && cmp_data.mKey == KEY_NONE) - { - // Does not conflict - continue; - } - } if (cntrl_iter->second.mAssignable) { // Potentially we can have multiple conflict flags conflicting diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h index e78d2fa33b..2926ca3aeb 100644 --- a/indra/newview/llkeyconflict.h +++ b/indra/newview/llkeyconflict.h @@ -66,7 +66,6 @@ public: }; const U32 CONFLICT_NOTHING = 0; - const U32 CONFLICT_LMOUSE = 0x1 << 1; // at the moment this just means that key will conflict with everything that is identical const U32 CONFLICT_ANY = U32_MAX; @@ -146,7 +145,6 @@ private: // at the moment these kind of control is not savable, but takes part in conflict resolution void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask); - // conflict mask 0 means that any conflicts will be ignored void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0); typedef std::map control_map_t; @@ -154,7 +152,7 @@ private: bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination); void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values // returns false in case user is trying to reuse control that can't be reassigned - bool removeConflicts(const LLKeyData &data, U32 conlict_mask); + bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask); // removes flags and removes temporary file, returns 'true' if file was removed bool clearUnsavedChanges(); diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp index 9ac1810964..f9c327b46e 100644 --- a/indra/newview/lltoolcomp.cpp +++ b/indra/newview/lltoolcomp.cpp @@ -44,7 +44,6 @@ #include "lltoolmgr.h" #include "lltoolselectrect.h" #include "lltoolplacer.h" -#include "llviewerinput.h" #include "llviewermenu.h" #include "llviewerobject.h" #include "llviewerwindow.h" @@ -744,7 +743,7 @@ BOOL LLToolCompGun::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask) { // if the left button is grabbed, don't put up the pie menu - if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON)) + if (gAgent.leftButtonGrabbed()) { gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); return FALSE; @@ -761,7 +760,7 @@ BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLToolCompGun::handleDoubleClick(S32 x, S32 y, MASK mask) { // if the left button is grabbed, don't put up the pie menu - if (gAgent.leftButtonGrabbed() && gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON)) + if (gAgent.leftButtonGrabbed()) { gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); return FALSE; @@ -795,10 +794,7 @@ BOOL LLToolCompGun::handleRightMouseDown(S32 x, S32 y, MASK mask) BOOL LLToolCompGun::handleMouseUp(S32 x, S32 y, MASK mask) { - if (gViewerInput.isLMouseHandlingDefault(MODE_FIRST_PERSON)) - { - gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP); - } + gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP); setCurrentTool( (LLTool*) mGun ); return TRUE; } diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 0693775622..75a5fabdc2 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -746,7 +746,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) else if (!mMouseOutsideSlop && mMouseButtonDown // disable camera steering if click on land is not used for moving - && gViewerInput.isMouseBindUsed(CLICK_LEFT, MASK_NONE, MODE_THIRD_PERSON)) + && gViewerInput.isMouseBindUsed(CLICK_LEFT)) { S32 delta_x = x - mMouseDownX; S32 delta_y = y - mMouseDownY; diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 8b3d406b78..c0eaa88f54 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -61,7 +61,7 @@ const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true); struct LLKeyboardActionRegistry -: public LLRegistrySingleton, LLKeyboardActionRegistry> +: public LLRegistrySingleton, LLKeyboardActionRegistry> { LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry); }; @@ -836,49 +836,7 @@ bool voice_follow_key(EKeystate s) return false; } -bool sript_trigger_lbutton(EKeystate s) -{ - // Check for script overriding/expecting left mouse button. - // Note that this does not pass event further and depends onto mouselook. - // Checks CONTROL_ML_LBUTTON_DOWN_INDEX for mouselook, - // CONTROL_LBUTTON_DOWN_INDEX for normal camera - if (gAgent.leftButtonGrabbed()) - { - bool mouselook = gAgentCamera.cameraMouselook(); - switch (s) - { - case KEYSTATE_DOWN: - // at the moment sript_trigger_lbutton is only intended for mouselook - // but handling other modes just in case - if (mouselook) - { - gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); - } - else - { - gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN); - } - return true; - case KEYSTATE_UP: - if (mouselook) - { - gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP); - } - else - { - gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP); - } - return true; - default: - break; - } - } - return false; -} - -// Used by scripts, for overriding/handling left mouse button -// see mControlsTakenCount -bool agent_control_lbutton_handle(EKeystate s) +bool agen_control_lbutton_handle(EKeystate s) { switch (s) { @@ -947,7 +905,6 @@ REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to); REGISTER_KEYBOARD_ACTION("walk_to", walk_to); REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice); REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key); -REGISTER_KEYBOARD_ACTION(script_mouse_handler_name, sript_trigger_lbutton); #undef REGISTER_KEYBOARD_ACTION LLViewerInput::LLViewerInput() @@ -1147,20 +1104,6 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const typedef boost::function function_t; function_t function = NULL; - if (mouse == CLICK_LEFT - && mask == MASK_NONE - && function_name == script_mouse_handler_name) - { - // Special case - // Left click has script overrides and by default - // is handled via agent_control_lbutton as last option - // In case of mouselook and present overrides it has highest - // priority even over UI and is handled in LLToolCompGun::handleMouseDown - // so just mark it as having default handler - mLMouseDefaultHandling[mode] = true; - return TRUE; - } - function_t* result = LLKeyboardActionRegistry::getValue(function_name); if (result) { @@ -1221,7 +1164,6 @@ void LLViewerInput::resetBindings() { mKeyBindings[i].clear(); mMouseBindings[i].clear(); - mLMouseDefaultHandling[i] = false; } } @@ -1413,14 +1355,13 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask)) { - // pass mouse left button press to script if (key_down && !repeat) { - res = agent_control_lbutton_handle(KEYSTATE_DOWN); + res = agen_control_lbutton_handle(KEYSTATE_DOWN); } if (key_up) { - res = agent_control_lbutton_handle(KEYSTATE_UP); + res = agen_control_lbutton_handle(KEYSTATE_UP); } } return res; @@ -1540,28 +1481,24 @@ bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const S32 mode = getMode(); MASK mask = gKeyboard->currentMask(TRUE); res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state); - // no user defined actions found or those actions can't handle the key/button, handle control if nessesary - // This will pass AGENT_CONTROL_LBUTTON_DOWN to server, no idea why it doesn't do mouselook variant _ML_ - // but it was set this way forever (moved as is from LLTool::handleMouseDown) so lots of scripts probably - // rely on this. - if (!res && mLMouseDefaultHandling[mode] && agent_control_lbutton.canHandle(click, KEY_NONE, mask)) + if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask)) { switch (state) { case MOUSE_STATE_DOWN: - agent_control_lbutton_handle(KEYSTATE_DOWN); + agen_control_lbutton_handle(KEYSTATE_DOWN); res = true; break; case MOUSE_STATE_CLICK: // might not work best with some functions, // but some function need specific states too specifically - agent_control_lbutton_handle(KEYSTATE_DOWN); - agent_control_lbutton_handle(KEYSTATE_UP); + agen_control_lbutton_handle(KEYSTATE_DOWN); + agen_control_lbutton_handle(KEYSTATE_UP); res = true; break; case MOUSE_STATE_UP: - agent_control_lbutton_handle(KEYSTATE_UP); + agen_control_lbutton_handle(KEYSTATE_UP); res = true; break; default: diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h index 32dd3c0e28..281a209896 100644 --- a/indra/newview/llviewerinput.h +++ b/indra/newview/llviewerinput.h @@ -31,7 +31,6 @@ #include "llinitparam.h" const S32 MAX_KEY_BINDINGS = 128; // was 60 -const std::string script_mouse_handler_name = "sript_trigger_lbutton"; class LLNamedFunction { @@ -125,8 +124,7 @@ public: BOOL handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); void scanMouse(); - bool isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode); - bool isLMouseHandlingDefault(const S32 mode) { return mLMouseDefaultHandling[mode]; } + bool isMouseBindUsed(const EMouseClickType mouse, const MASK mask = MASK_NONE, const S32 mode = MODE_THIRD_PERSON); private: bool scanKey(const std::vector &binding, @@ -165,7 +163,6 @@ private: // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown) std::vector mKeyBindings[MODE_COUNT]; std::vector mMouseBindings[MODE_COUNT]; - bool mLMouseDefaultHandling[MODE_COUNT]; // Due to having special priority typedef std::map key_remap_t; key_remap_t mRemapKeys[MODE_COUNT]; diff --git a/indra/newview/skins/default/xui/en/control_table_contents_media.xml b/indra/newview/skins/default/xui/en/control_table_contents_media.xml index a97c45dd6f..ce5d3556b6 100644 --- a/indra/newview/skins/default/xui/en/control_table_contents_media.xml +++ b/indra/newview/skins/default/xui/en/control_table_contents_media.xml @@ -73,14 +73,4 @@ name="lst_action" value="Start Gesture" /> - - - -- cgit v1.2.3 From 0bcf150d4e25f701fbed7ea0141fb580d698ee4d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 15 Jul 2021 18:37:02 +0300 Subject: SL-443 keybindings: Do not error on unknown function It is likely be from newer viewer / Preparations for SL-443 deloyment. --- indra/newview/llviewerinput.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index c0eaa88f54..f269be035e 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1070,7 +1070,7 @@ BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, cons if (!function) { - LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + LL_WARNS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; return FALSE; } @@ -1112,7 +1112,7 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const if (!function) { - LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; + LL_WARNS() << "Can't bind mouse key to function " << function_name << ", no function with this name found" << LL_ENDL; return FALSE; } -- cgit v1.2.3 From e7373ff2f52f375ba9b6ffbf4d3b9f1996d2007e Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 2 Aug 2021 23:56:24 +0300 Subject: SL-15201 Increased the viewer version to 6.5 for new-feature viewer --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 4c8366c864..f22d756da3 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.4.23 +6.5.0 -- cgit v1.2.3 From ca629c362c5ed248547f9df057703079c95331e7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 9 Sep 2021 20:59:21 +0300 Subject: SL-15965 Support wider range of parsing errors --- .../newview/skins/default/xui/en/floater_model_preview.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index db9d296fa5..05990e28d8 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -45,7 +45,21 @@ Rigged to unrecognized joint name [NAME] Skinning disabled due to [COUNT] unknown joints Model [MODEL_NAME] loaded + Texture coordinates data is not complete. + Found NaN while loading position data from DAE-Model, invalid model. + Found NaN while loading normals from DAE-Model, invalid model. + Negative scale detected, unsupported transform. domInstance_geometry: [LABEL] + Negative scale detected, unsupported post-normalization transform. domInstance_geometry: [LABEL] + Unable to resolve geometry URL. + Bad element + Scene could not be parsed + Error with dae - traditionally indicates a corrupt file. + Could not verify controller + Can't find internal doc + Document has no root + Document has no visual_scene + Unable to process mesh without position data. Invalid model. Date: Thu, 21 Oct 2021 18:46:06 +0300 Subject: SL-16226 Crash at genMeshOptimizerPerModel --- indra/newview/llmodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index b17aa960ce..4f759446f1 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1911,7 +1911,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe ll_aligned_free<64>(combined_positions); ll_aligned_free<64>(buffer_positions); ll_aligned_free_32(output_indices); - ll_aligned_free_32(buffer_indices); + ll_aligned_free_16(buffer_indices); ll_aligned_free_32(combined_indices); if (new_indices < 3) -- cgit v1.2.3 From fd5e1f0b97adf17469023d81908554890af5d24b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 21 Oct 2021 18:54:35 +0300 Subject: SL-15521 Fix license file not mentioning meshoptimizer --- indra/newview/licenses-mac.txt | 26 ++++++++++++++++++++++++++ indra/newview/licenses-win32.txt | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt index af80bff5d9..1a3a59d2f5 100644 --- a/indra/newview/licenses-mac.txt +++ b/indra/newview/licenses-mac.txt @@ -693,3 +693,29 @@ From Vivox: Attn: customer support 40 Speen Street Suite 402 Framingham, MA 01701 + + +============= +meshoptimizer +============= +MIT License + +Copyright (c) 2016-2021 Arseny Kapoulkine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt index 8736626907..3e337851d7 100644 --- a/indra/newview/licenses-win32.txt +++ b/indra/newview/licenses-win32.txt @@ -838,3 +838,29 @@ Although NOT REQUIRED, we would appreciate it if active users of GLOD put a link on their web site to the GLOD web site when possible. +============= +meshoptimizer +============= +MIT License + +Copyright (c) 2016-2021 Arseny Kapoulkine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + -- cgit v1.2.3 From 33f52ee51dad85802d124e987aa6ee9b7faf0cb2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 10 Nov 2021 17:48:55 +0200 Subject: SL-14403 Removed glod --- indra/newview/CMakeLists.txt | 6 - indra/newview/licenses-win32.txt | 68 ---- indra/newview/llfloatermodelpreview.cpp | 6 +- indra/newview/llmodelpreview.cpp | 438 --------------------- indra/newview/llmodelpreview.h | 14 +- .../newview/skins/default/xui/en/floater_about.xml | 1 - .../skins/default/xui/en/floater_model_preview.xml | 64 ++- indra/newview/viewer_manifest.py | 10 - 8 files changed, 26 insertions(+), 581 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 4c237c5ef3..75935ff56a 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -16,7 +16,6 @@ include(DBusGlib) include(DragDrop) include(EXPAT) include(FMODSTUDIO) -include(GLOD) include(Hunspell) include(JsonCpp) include(LLAppearance) @@ -68,7 +67,6 @@ endif(FMODSTUDIO) include_directories( ${DBUSGLIB_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} - ${GLOD_INCLUDE_DIR} ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} @@ -1815,9 +1813,6 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapriconv-1.dll - ${SHARED_LIB_STAGING_DIR}/Release/glod.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/glod.dll - ${SHARED_LIB_STAGING_DIR}/Debug/glod.dll ${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom22.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom22.dll ${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom22-d.dll @@ -2053,7 +2048,6 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} ${FMODWRAPPER_LIBRARY} # must come after LLAudio - ${GLOD_LIBRARIES} ${OPENGL_LIBRARIES} ${JSONCPP_LIBRARIES} ${SDL_LIBRARY} diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt index 3e337851d7..749ca1c21d 100644 --- a/indra/newview/licenses-win32.txt +++ b/indra/newview/licenses-win32.txt @@ -770,74 +770,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============= -GLOD license -============= -The GLOD Open-Source License Version 1.0 June 16, 2004 - -Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns -Hopkins University and David Luebke, Brenden Schubert, University of -Virginia. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, is permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer and - request. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer and - request in the documentation and/or other materials provided with - the distribution. - -3. The name "GLOD" must not be used to endorse or promote products - derived from this software without prior written permission. - -4. Redistributions of any modified version of this source, whether in - source or binary form , must include a form of the following - acknowledgment: "This product is derived from the GLOD library, - which is available from http://www.cs.jhu.edu/~graphics/GLOD." - -5. Redistributions of any modified version of this source in binary - form must provide, free of charge, access to the modified version - of the code. - -6. This license shall be governed by and construed and enforced in - accordance with the laws of the State of Maryland, without - reference to its conflicts of law provisions. The exclusive - jurisdiction and venue for all legal actions relating to this - license shall be in courts of competent subject matter jurisdiction - located in the State of Maryland. - -TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED -UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES -THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR -PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH -YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE -COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY -NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY -CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS -AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY -SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF -PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS. - -YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE -COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS, -DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM -YOUR ACCEPTANCE AND USE OF GLOD. - -Although NOT REQUIRED, we would appreciate it if active users of GLOD -put a link on their web site to the GLOD web site when possible. - - ============= meshoptimizer ============= diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6795ea8f53..de89d776df 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -726,9 +726,6 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) S32 mode = lod_source_combo->getCurrentIndex(); switch (mode) { - case LLModelPreview::GENERATE: - mModelPreview->onLODGenerateParamCommit(lod, enforce_tri_limit); - break; case LLModelPreview::MESH_OPTIMIZER_AUTO: case LLModelPreview::MESH_OPTIMIZER: case LLModelPreview::MESH_OPTIMIZER_SLOPPY: @@ -1738,8 +1735,7 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[lod]); S32 index = lod_source_combo->getCurrentIndex(); - if (index == LLModelPreview::GENERATE - || index == LLModelPreview::MESH_OPTIMIZER_AUTO + if (index == LLModelPreview::MESH_OPTIMIZER_AUTO || index == LLModelPreview::MESH_OPTIMIZER || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY || index == LLModelPreview::MESH_OPTIMIZER_COMBINE) diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 4f759446f1..d629358355 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -67,7 +67,6 @@ #include "lltabcontainer.h" #include "lltextbox.h" -#include "glod/glod.h" #include bool LLModelPreview::sIgnoreLoadedCallback = false; @@ -90,19 +89,6 @@ static const F32 PREVIEW_ZOOM_LIMIT(10.f); const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f; -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; - return TRUE; - } - - return FALSE; -} - LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) { LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); @@ -202,10 +188,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mLoadState = LLModelLoader::STARTING; mGroup = 0; mLODFrozen = false; - mBuildShareTolerance = 0.f; - mBuildQueueMode = GLOD_QUEUE_GREEDY; - mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; for (U32 i = 0; i < LLModel::NUM_LODS; ++i) { @@ -213,10 +195,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mRequestedCreaseAngle[i] = -1.f; mRequestedLoDMode[i] = 0; mRequestedErrorThreshold[i] = 0.f; - mRequestedBuildOperator[i] = 0; - mRequestedQueueMode[i] = 0; - mRequestedBorderMode[i] = 0; - mRequestedShareTolerance[i] = 0.f; } mViewOption["show_textures"] = false; @@ -226,23 +204,11 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mHasPivot = false; mModelPivot = LLVector3(0.0f, 0.0f, 0.0f); - glodInit(); - createPreviewAvatar(); } LLModelPreview::~LLModelPreview() { - // glod apparently has internal mem alignment issues that are angering - // the heap-check code in windows, these should be hunted down in that - // TP code, if possible - // - // kernel32.dll!HeapFree() + 0x14 bytes - // msvcr100.dll!free(void * pBlock) Line 51 C - // glod.dll!glodGetGroupParameteriv() + 0x119 bytes - // glod.dll!glodShutdown() + 0x77 bytes - // - //glodShutdown(); if (mModelLoader) { mModelLoader->shutdown(); @@ -828,11 +794,6 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable mLODFile[lod] = filename; - if (lod == LLModel::LOD_HIGH) - { - clearGLODGroup(); - } - std::map joint_alias_map; getJointAliases(joint_alias_map); @@ -933,7 +894,6 @@ void LLModelPreview::clearIncompatible(S32 lod) if (i == LLModel::LOD_HIGH) { mBaseModel = mModel[lod]; - clearGLODGroup(); mBaseScene = mScene[lod]; mVertexBuffer[5].clear(); } @@ -942,23 +902,6 @@ void LLModelPreview::clearIncompatible(S32 lod) } } -void LLModelPreview::clearGLODGroup() -{ - if (mGroup) - { - for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - mObject.clear(); - - glodDeleteGroup(mGroup); - stop_gloderror(); - mGroup = 0; - } -} - void LLModelPreview::loadModelCallback(S32 loaded_lod) { assert_main_thread(); @@ -1110,7 +1053,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) } mBaseModel = mModel[loaded_lod]; - clearGLODGroup(); mBaseScene = mScene[loaded_lod]; mVertexBuffer[5].clear(); @@ -1341,373 +1283,6 @@ void LLModelPreview::restoreNormals() updateStatusMessages(); } -void LLModelPreview::genGlodLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) -{ - LL_INFOS() << "Generating lod " << which_lod << " using glod" << LL_ENDL; - // Allow LoD from -1 to LLModel::LOD_PHYSICS - if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) - { - std::ostringstream out; - out << "Invalid level of detail: " << which_lod; - LL_WARNS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, false); - assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS); - return; - } - - if (mBaseModel.empty()) - { - return; - } - - LLVertexBuffer::unbind(); - - bool no_ff = LLGLSLShader::sNoFixedFunction; - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - LLGLSLShader::sNoFixedFunction = false; - - if (shader) - { - shader->unbind(); - } - - stop_gloderror(); - static U32 cur_name = 1; - - S32 limit = -1; - - U32 triangle_count = 0; - - U32 instanced_triangle_count = 0; - - //get the triangle count for the whole scene - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter) - { - for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) - { - LLModel* mdl = instance->mModel; - if (mdl) - { - instanced_triangle_count += mdl->getNumTriangles(); - } - } - } - - //get the triangle count for the non-instanced set of models - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - triangle_count += mBaseModel[i]->getNumTriangles(); - } - - //get ratio of uninstanced triangles to instanced triangles - F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count; - - U32 base_triangle_count = triangle_count; - - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - U32 lod_mode = LIMIT_TRIANGLES; - - F32 lod_error_threshold = 0; - - // The LoD should be in range from Lowest to High - if (which_lod > -1 && which_lod < NUM_LOD) - { - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal(); - } - - if (which_lod != -1) - { - mRequestedLoDMode[which_lod] = lod_mode; - } - - if (lod_mode == LIMIT_TRIANGLES) - { - lod_mode = GLOD_TRIANGLE_BUDGET; - - // The LoD should be in range from Lowest to High - if (which_lod > -1 && which_lod < NUM_LOD) - { - limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger(); - //convert from "scene wide" to "non-instanced" triangle limit - limit = (S32)((F32)limit*triangle_ratio); - } - } - else - { - lod_mode = GLOD_ERROR_THRESHOLD; - } - - bool object_dirty = false; - - if (mGroup == 0) - { - object_dirty = true; - mGroup = cur_name++; - glodNewGroup(mGroup); - } - - if (object_dirty) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - - if (mObject[mdl] != 0) - { - glodDeleteObject(mObject[mdl]); - } - - mObject[mdl] = cur_name++; - - glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); - stop_gloderror(); - - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } - - if (mVertexBuffer[5].empty()) - { - genBuffers(5, false); - } - - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) - { - LLVertexBuffer* buff = mVertexBuffer[5][mdl][i]; - buff->setBuffer(type_mask & buff->getTypeMask()); - - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*)mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices / 3; - stop_gloderror(); - } - - glodBuildObject(mObject[mdl]); - stop_gloderror(); - } - } - - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (which_lod != -1) - { - start = end = which_lod; - } - - mMaxTriangleLimit = base_triangle_count; - mMinTriangleLimit = mBaseModel.size(); - - for (S32 lod = start; lod >= end; --lod) - { - if (which_lod == -1) - { - if (lod < start) - { - triangle_count /= decimation; - } - } - else - { - if (enforce_tri_limit) - { - triangle_count = limit; - } - else - { - for (S32 j = LLModel::LOD_HIGH; j>which_lod; --j) - { - triangle_count /= decimation; - } - } - } - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - mRequestedTriangleCount[lod] = llmax(mMinTriangleLimit, (S32)((F32)triangle_count / triangle_ratio)); - mRequestedErrorThreshold[lod] = lod_error_threshold; - - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); - stop_gloderror(); - - if (lod_mode != GLOD_TRIANGLE_BUDGET) - { - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); - } - else - { - //SH-632: always add 1 to desired amount to avoid decimating below desired amount - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count + 1); - } - - stop_gloderror(); - glodAdaptGroup(mGroup); - stop_gloderror(); - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - - std::string name = base->mLabel + getLodSuffix(lod); - - mModel[lod][mdl_idx]->mLabel = name; - mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; - - GLint* sizes = new GLint[patch_count * 2]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); - stop_gloderror(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - - LLModel* target_model = mModel[lod][mdl_idx]; - - for (GLint i = 0; i < patch_count; ++i) - { - type_mask = mVertexBuffer[5][base][i]->getTypeMask(); - - LLPointer buff = new LLVertexBuffer(type_mask, 0); - - if (sizes[i * 2 + 1] > 0 && sizes[i * 2] > 0) - { - if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true)) - { - // Todo: find a way to stop preview in this case instead of crashing - LL_ERRS() << "Failed buffer allocation during preview LOD generation." - << " Vertices: " << sizes[i * 2 + 1] - << " Indices: " << sizes[i * 2] << LL_ENDL; - } - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*)buff->getIndicesPointer()); - stop_gloderror(); - } - else - { - // This face was eliminated or we failed to allocate buffer, - // attempt to create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset((U8*)buff->getMappedData(), 0, buff->getSize()); - memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } - - buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0); - - LLStrider pos; - LLStrider norm; - LLStrider tc; - LLStrider index; - - buff->getVertexStrider(pos); - if (type_mask & LLVertexBuffer::MAP_NORMAL) - { - buff->getNormalStrider(norm); - } - if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) - { - buff->getTexCoord0Strider(tc); - } - - buff->getIndexStrider(index); - - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices() / 3; - actual_verts += buff->getNumVerts(); - ++submeshes; - - if (!validate_face(target_model->getVolumeFace(names[i]))) - { - LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL; - } - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mSkinInfo = base->mSkinInfo; - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; - } - - delete[] sizes; - delete[] names; - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - LLVertexBuffer::unbind(); - LLGLSLShader::sNoFixedFunction = no_ff; - if (shader) - { - shader->bind(); - } -} - // Runs per object, but likely it is a better way to run per model+submodels // returns a ratio of base model indices to resulting indices // returns -1 in case of failure @@ -2104,9 +1679,6 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d mMaxTriangleLimit = base_triangle_count; mMinTriangleLimit = mBaseModel.size(); - // TODO: Glod regenerates vertex buffer at this stage - // check why, it might be needed to regenerate buffer as well - // Build models S32 start = LLModel::LOD_HIGH; @@ -3573,7 +3145,6 @@ BOOL LLModelPreview::render() { genBuffers(-1, skin_weight); //genBuffers(3); - //genGlodLODs(); } if (!mModel[mPreviewLOD].empty()) @@ -4175,15 +3746,6 @@ bool LLModelPreview::lodQueryCallback() return true; } -void LLModelPreview::onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit) -{ - if (!mLODFrozen) - { - genGlodLODs(lod, 3, enforce_tri_limit); - refresh(); - } -} - void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, S32 mode) { if (!mLODFrozen) diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 49032f0dbf..7d4507ccf2 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -124,7 +124,6 @@ public: typedef enum { LOD_FROM_FILE = 0, - GENERATE, MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face MESH_OPTIMIZER_COMBINE, MESH_OPTIMIZER, @@ -165,7 +164,6 @@ public: void loadModelCallback(S32 lod); bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } void queryLODs() { mGenLOD = true; }; - void genGlodLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); void genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation = 3, bool enforce_tri_limit = false); void generateNormals(); void restoreNormals(); @@ -176,8 +174,6 @@ public: void clearIncompatible(S32 lod); void updateStatusMessages(); void updateLodControls(S32 lod); - void clearGLODGroup(); - void onLODGenerateParamCommit(S32 lod, bool enforce_tri_limit); void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, S32 mode); void addEmptyFace(LLModel* pTarget); @@ -265,19 +261,11 @@ protected: std::map mViewOption; - //GLOD object parameters (must rebuild object if these change) + // Model generation 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; diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 71f4d81195..bde7aec672 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -101,7 +101,6 @@ Dummy Name replaced at run time expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. - GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 05990e28d8..d08bc92e5d 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -187,24 +187,20 @@ label="Load from file" value="Load from file" /> - + name="MeshOpt Auto" + label="Generate Auto" + value="MeshOpt Auto" /> - + name="MeshOpt Auto" + label="Generate Auto" + value="MeshOpt Auto" /> - + name="MeshOpt Auto" + label="Generate Auto" + value="MeshOpt Auto" /> - + name="MeshOpt Auto" + label="Generate Auto" + value="MeshOpt Auto" /> Date: Wed, 10 Nov 2021 18:00:49 +0200 Subject: SL-15521 Fix debian license file not mentioning meshoptimizer Just in case --- indra/newview/skins/default/xui/en/floater_about.xml | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview') diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index bde7aec672..eb07425dfe 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -105,6 +105,7 @@ Dummy Name replaced at run time Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) jpeglib Copyright (C) 1991-1998, Thomas G. Lane. + meshoptimizer Copyright (c) 2016-2021 Arseny Kapoulkine ogg/vorbis Copyright (C) 2002, Xiphophorus OpenSSL Copyright (C) 1998-2008 The OpenSSL Project. PCRE Copyright (c) 1997-2012 University of Cambridge -- cgit v1.2.3 From 3641541c6cc7f33f0e0dc2e1eb2cfdfcec23322b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 15 Nov 2021 23:23:09 +0200 Subject: SL-15756 Removed mHasGeneratedFaces mHasGeneratedFaces is always true for some types of models and glod was treating faces as one mesh by default, so meshoptimizer should do the same regardles of mHasGeneratedFaces --- indra/newview/llmodelpreview.cpp | 73 +++++++++++++--------------------------- 1 file changed, 23 insertions(+), 50 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index d629358355..f6edbf6bc6 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1775,68 +1775,41 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d if (model_meshopt_mode == MESH_OPTIMIZER_AUTO) { F32 allowed_ratio_drift = 2.f; - F32 res_ratio = 0; - if (base->mHasGeneratedFaces) - { - res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + F32 res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); - if (res_ratio < 0) + if (res_ratio < 0) + { + // U16 vertices overflow, shouldn't happen, but just in case + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - // U16 vertices overflow, shouldn't happen, but just in case - for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) - { - genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); - } - LL_INFOS() << "Model " << target_model->getName() - << " lod " << which_lod - << " per model method overflow, defaulting to per face." << LL_ENDL; + genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); } - else if (res_ratio * allowed_ratio_drift < indices_decimator) - { - // Try sloppy variant if normal one failed to simplify model enough. - res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); - LL_INFOS() << "Model " << target_model->getName() - << " lod " << which_lod - << " sloppily simplified using per model method." << LL_ENDL; + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " per model method overflow, defaulting to per face." << LL_ENDL; + } + else if (res_ratio * allowed_ratio_drift < indices_decimator) + { + // Try sloppy variant if normal one failed to simplify model enough. + res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " sloppily simplified using per model method." << LL_ENDL; - if (res_ratio < 0) - { - // Sloppy variant failed to generate triangles. - // Can happen with models that are too simple as is. - // Fallback to normal method. - genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); - } - } - else + if (res_ratio < 0) { - LL_INFOS() << "Model " << target_model->getName() - << " lod " << which_lod - << " simplified using per model method." << LL_ENDL; + // Sloppy variant failed to generate triangles. + // Can happen with models that are too simple as is. + // Fallback to normal method. + genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); } } else { - for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) - { - res_ratio = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); - - if (res_ratio * allowed_ratio_drift < indices_decimator) - { - // normal method failed to sufficiently simplify, try sloppy - res_ratio = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true); - if (res_ratio < 0) - { - // Sloppy failed to generate triangles. - // Can happen with models that are too simple as is. - // Fallback to normal method. - genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); - } - } - } LL_INFOS() << "Model " << target_model->getName() << " lod " << which_lod - << " simplified using per face methods." << LL_ENDL; + << " simplified using per model method." << LL_ENDL; } } -- cgit v1.2.3 From cba1daaf6be4dfd031cd10d9aea07c7124d32726 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 17 Nov 2021 21:46:43 +0200 Subject: SL-16226 Fix crash with extra large faces --- indra/newview/llmodelpreview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index f6edbf6bc6..6a827207ae 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1373,7 +1373,8 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); LLVector4a* buffer_normals = buffer_positions + size_vertices; LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices); - U16* buffer_indices = (U16*)ll_aligned_malloc_16(U16_MAX * sizeof(U16)); + S32 buffer_idx_size = (size_indices * sizeof(U16) + 0xF) & ~0xF; + U16* buffer_indices = (U16*)ll_aligned_malloc_16(buffer_idx_size); S32* old_to_new_positions_map = new S32[size_vertices]; S32 buf_positions_copied = 0; -- cgit v1.2.3