diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 8097a05511a08c278a43188f57a86623f6a7f832..a879389c5adec63666535769e9ec40097709ea9a 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -67,19 +67,36 @@ U64 LLMeshOptimizer::simplifyU32(U32 *destination,
     U64 vertex_positions_stride,
     U64 target_index_count,
     F32 target_error,
+    bool sloppy,
     F32* result_error
 )
 {
-    return meshopt_simplify<unsigned int>(destination,
-        indices,
-        index_count,
-        (const float*)vertex_positions,
-        vertex_count,
-        vertex_positions_stride,
-        target_index_count,
-        target_error,
-        result_error
-        );
+    if (sloppy)
+    {
+        return meshopt_simplifySloppy<unsigned int>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
+    else
+    {
+        return meshopt_simplify<unsigned int>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
 }
 
 //static
@@ -91,41 +108,35 @@ U64 LLMeshOptimizer::simplify(U16 *destination,
                               U64 vertex_positions_stride,
                               U64 target_index_count,
                               F32 target_error,
+                              bool sloppy,
                               F32* result_error
     )
 {
-    return meshopt_simplify<unsigned short>(destination,
-                                 indices,
-                                 index_count,
-                                 (const float*)vertex_positions,
-                                 vertex_count,
-                                 vertex_positions_stride, 
-                                 target_index_count,
-                                 target_error,
-                                 result_error
-                                 );
+    if (sloppy)
+    {
+        return meshopt_simplifySloppy<unsigned short>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
+    else
+    {
+        return meshopt_simplify<unsigned short>(destination,
+            indices,
+            index_count,
+            (const float*)vertex_positions,
+            vertex_count,
+            vertex_positions_stride,
+            target_index_count,
+            target_error,
+            result_error
+            );
+    }
 }
 
-//static
-U64 LLMeshOptimizer::simplifySloppy(U16 *destination,
-                              const U16 *indices,
-                              U64 index_count,
-                              const LLVector4a *vertex_positions,
-                              U64 vertex_count,
-    U64 vertex_positions_stride,
-                              U64 target_index_count,
-                              F32 target_error,
-                              F32* result_error
-    )
-{
-    return meshopt_simplifySloppy<unsigned short>(destination,
-                                 indices,
-                                 index_count,
-                                 (const float*)vertex_positions,
-                                 vertex_count,
-                                 vertex_positions_stride, 
-                                 target_index_count,
-                                 target_error,
-                                 result_error
-                                 );
-}
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index e881ec26c55a421a604170806432972ce56b437d..e8dd16dae967593e7aec99522bdba81de9cedc85 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -45,6 +45,8 @@ class LLMeshOptimizer
         U64 vertex_positions_stride);
 
     // returns amount of indices in destiantion
+    // sloppy engages a variant of a mechanizm that does not respect topology as much
+    // but is much more efective for simpler models
     // result_error returns how far from original the model is in % if not NULL
     // Works with U32 indices (LLFace uses U16 indices)
     static U64 simplifyU32(
@@ -56,10 +58,13 @@ class LLMeshOptimizer
         U64 vertex_positions_stride,
         U64 target_index_count,
         F32 target_error,
+        bool sloppy,
         F32* result_error);
 
     // Returns amount of indices in destiantion
-    // Result_error returns how far from original the model is in % if not NULL
+    // sloppy engages a variant of a mechanizm that does not respect topology as much
+    // but is much better for simpler models
+    // result_error returns how far from original the model is in % if not NULL
     // Meant for U16 indices (LLFace uses U16 indices)
     static U64 simplify(
         U16 *destination,
@@ -70,19 +75,7 @@ class LLMeshOptimizer
         U64 vertex_positions_stride,
         U64 target_index_count,
         F32 target_error,
-        F32* result_error);
-
-    // returns amount of indices in destiantion
-    // result_error returns how far from original the model is in % if not NULL
-    static U64 simplifySloppy(
-        U16 *destination,
-        const U16 *indices,
-        U64 index_count,
-        const LLVector4a *vertex_positions,
-        U64 vertex_count,
-        U64 vertex_positions_stride,
-        U64 target_index_count,
-        F32 target_error,
+        bool sloppy,
         F32* result_error);
 private:
 };
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index 17e9e05edd2f5d6b0a4e4f4e53fa01290477e5e0..dcf3b5fa0eaffb7c50e190b01f775a761d944cb7 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -149,7 +149,11 @@ bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S
 	return true;
 }
 
-LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri)
+LLModel::EModelStatus load_face_from_dom_triangles(
+    std::vector<LLVolumeFace>& face_list,
+    std::vector<std::string>& materials,
+    domTrianglesRef& tri,
+    bool &generated_additional_faces)
 {
 	LLVolumeFace face;
 	std::vector<LLVolumeFace::VertexData> verts;
@@ -282,6 +286,8 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 
 		if (indices.size()%3 == 0 && verts.size() >= 65532)
 		{
+            generated_additional_faces = true;
+
 			std::string material;
 
 			if (tri->getMaterial())
@@ -289,7 +295,6 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 				material = std::string(tri->getMaterial());
 			}
 
-            // Todo: mark model in some way as having generated(split) faces  
 			materials.push_back(material);
 			face_list.push_back(face);
 			face_list.rbegin()->fillFromLegacyData(verts, indices);
@@ -344,7 +349,12 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
 	return LLModel::NO_ERRORS ;
 }
 
-LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg)
+LLModel::EModelStatus load_face_from_dom_polylist(
+    std::vector<LLVolumeFace>& face_list,
+    std::vector<std::string>& materials,
+    domPolylistRef& poly,
+    bool& generated_additional_faces,
+    LLSD& log_msg)
 {
 	domPRef p = poly->getP();
 	domListOfUInts& idx = p->getValue();
@@ -546,6 +556,8 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
 
 			if (indices.size()%3 == 0 && indices.size() >= 65532)
 			{
+                generated_additional_faces = true;
+
 				std::string material;
 
 				if (poly->getMaterial())
@@ -771,6 +783,9 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
 		}
 	}
 
+    // Viewer can only fit U16 vertices, shouldn't we do some checks here and return overflow if result has more?
+    llassert(vert_idx.size() < U16_MAX);
+
 	//build vertex array from map
 	std::vector<LLVolumeFace::VertexData> new_verts;
 	new_verts.resize(vert_idx.size());
@@ -2390,11 +2405,13 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	LLModel::EModelStatus status = LLModel::NO_ERRORS;
 	domTriangles_Array& tris = mesh->getTriangles_array();
 
+    pModel->mHasGeneratedFaces = false;
+
 	for (U32 i = 0; i < tris.getCount(); ++i)
 	{
 		domTrianglesRef& tri = tris.get(i);
 
-		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri);
+		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, pModel->mHasGeneratedFaces);
 		pModel->mStatus = status;
 		if(status != LLModel::NO_ERRORS)
 		{
@@ -2407,7 +2424,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	for (U32 i = 0; i < polys.getCount(); ++i)
 	{
 		domPolylistRef& poly = polys.get(i);
-		status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, log_msg);
+		status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, pModel->mHasGeneratedFaces, log_msg);
 
 		if(status != LLModel::NO_ERRORS)
 		{
@@ -2421,6 +2438,10 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
 	for (U32 i = 0; i < polygons.getCount(); ++i)
 	{
 		domPolygonsRef& poly = polygons.get(i);
+
+        // Due to how poligons work, assume that face was 'generated' by default
+        pModel->mHasGeneratedFaces = true;
+
 		status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly);
 
 		if(status != LLModel::NO_ERRORS)
@@ -2520,6 +2541,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
 		{
 			LLModel* next = new LLModel(volume_params, 0.f);
 			next->mSubmodelID = ++submodelID;
+			next->mHasGeneratedFaces = ret->mHasGeneratedFaces;
 			next->mLabel = model_name + (char)((int)'a' + next->mSubmodelID) + lod_suffix[mLod];
 			next->getVolumeFaces() = remainder;
 			next->mNormalizedScale = ret->mNormalizedScale;
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 702a1b523843864d24d1f88690aed0cabfe5008d..8b8fde0ea0980e521cde3e87da38131445902a44 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -55,7 +55,8 @@ LLModel::LLModel(LLVolumeParams& params, F32 detail)
       mNormalizedTranslation(0,0,0), 
       mPelvisOffset( 0.0f ), 
       mStatus(NO_ERRORS), 
-      mSubmodelID(0)
+      mSubmodelID(0),
+      mHasGeneratedFaces(false)
 {
 	mDecompID = -1;
 	mLocalID = -1;
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 96368d64e505ed5f22eec5b1bbccbcea40f50028..87a47dcb3678044ac95e3a1088bcd76433bb7a2a 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -284,6 +284,11 @@ class LLModel : public LLVolume
     // A model/object can only have 8 faces, spillover faces will
     // be moved to new model/object and assigned a submodel id.
 	int mSubmodelID;
+    // A .dae face can have more than 65K vertices, but viewer
+    // is limited to U16 for indices, in such case spilower will
+    // be moved into new face and this will be set to true.
+    // Also true in case faces were generated from polygons
+    bool mHasGeneratedFaces;
 };
 
 typedef std::vector<LLPointer<LLModel> >	model_list;
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index e5d451e90939b4a42803a8db01e99d15fe097017..6795ea8f538efed7598736923885d77d28f43549 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<LLComboBox>("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<LLComboBox>("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE);
 	for (S32 lod = 0; lod < NUM_LOD - 1; ++lod)
 	{
-		getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER);
+		getChild<LLComboBox>("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 11a536473cf4e3d482c53fc07e0b843cbe5e9f03..3a8676d7b963bf90e2c2e03a0f900a44ca82fb5a 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 b784345b5a52d220f8dc8dc801f82598e07d9d3a..b3296fecf6c0090be468bcf1e9be6047bdc17be8 100644
--- a/indra/newview/llmodelpreview.h
+++ b/indra/newview/llmodelpreview.h
@@ -125,9 +125,10 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     {
         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 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
     // 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 cd67adf42afcd3b6032a5f5678aa3675f4c6a248..db9d296fa5590e8f766228e475e34e511e736e78 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" />
+                <item
+                 name="MeshOpt"
+                 label="Simplify (auto)"
+                 value="MeshOpt" />
+                <item
+                 name="MeshOptCombine"
+                 label="Simplify per object"
+                 value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
                  label="Simplify per face"
@@ -184,10 +192,6 @@
                  name="MeshOptSloppy"
                  label="Simplify sloppy"
                  value="MeshOptSloppy" />
-                <item
-                 name="MeshOptCombine"
-                 label="Simplify per object"
-                 value="MeshOptCombine" />
             </combo_box>
             <line_editor
              follows="left|top"
@@ -317,6 +321,14 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="Simplify (auto)"
+                 value="MeshOpt" />
+                <item
+                 name="MeshOptCombine"
+                 label="Simplify per object"
+                 value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
                  label="Simplify per face"
@@ -325,10 +337,6 @@
                  name="MeshOptSloppy"
                  label="Simplify sloppy"
                  value="MeshOptSloppy" />
-                <item
-                 name="MeshOptCombine"
-                 label="Simplify per object"
-                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -462,6 +470,14 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="Simplify (auto)"
+                 value="MeshOpt" />
+                <item
+                 name="MeshOptCombine"
+                 label="Simplify per object"
+                 value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
                  label="Simplify per face"
@@ -470,10 +486,6 @@
                  name="MeshOptSloppy"
                  label="Simplify sloppy"
                  value="MeshOptSloppy" />
-                <item
-                 name="MeshOptCombine"
-                 label="Simplify per object"
-                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"
@@ -607,6 +619,14 @@
                  name="Generate"
                  label="Generate"
                  value="Generate" />
+                <item
+                 name="MeshOpt"
+                 label="Simplify (auto)"
+                 value="MeshOpt" />
+                <item
+                 name="MeshOptCombine"
+                 label="Simplify per object"
+                 value="MeshOptCombine" />
                 <item
                  name="MeshOpt"
                  label="Simplify per face"
@@ -615,10 +635,6 @@
                  name="MeshOptSloppy"
                  label="Simplify sloppy"
                  value="MeshOptSloppy" />
-                <item
-                 name="MeshOptCombine"
-                 label="Simplify per object"
-                 value="MeshOptCombine" />
                 <item
                  name="Use LoD above"
                  label="Use LoD above"