diff --git a/doc/contributions.txt b/doc/contributions.txt
index 97c7ff1098a630d16eabdeceeae86e4142255833..bb910aa8384686b4d40e91909517b6fe0f3ea9de 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -256,6 +256,8 @@ Benja Kepler
 	VWR-746
 Benjamin Bigdipper
 Beth Walcher
+Beq Janus
+	SL-10288
 Bezilon Kasei
 Biancaluce Robbiani
 	CT-225
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 0eef5120eb295ef497072938d94781b599ffae63..1abddc80cb3f942e8d4cd5d3c59e4df90918ed53 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -6628,8 +6628,189 @@
     <key>Value</key>
     <integer>600</integer>
   </map>
-  <key>MigrateCacheDirectory</key>
-    <map>
+  <key>MeshPreviewCanvasColor</key>
+  <map>
+    <key>Comment</key>
+    <string>Canvas colour for the Mesh uploader</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color4</string>
+    <key>Value</key>
+    <array>
+      <real>0.169</real>
+      <real>0.169</real>
+      <real>0.169</real>
+      <real>1.0</real>
+    </array>
+  </map>
+  <key>MeshPreviewEdgeColor</key>
+  <map>
+    <key>Comment</key>
+    <string>Edge colour for the Mesh uploader preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color4</string>
+    <key>Value</key>
+    <array>
+      <real>0.4</real>
+      <real>0.4</real>
+      <real>0.4</real>
+      <real>1.0</real>
+    </array>
+  </map>
+  <key>MeshPreviewBaseColor</key>
+  <map>
+    <key>Comment</key>
+    <string>base diffuse colour for the Mesh uploader</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color4</string>
+    <key>Value</key>
+    <array>
+      <real>1.0</real>
+      <real>1.0</real>
+      <real>1.0</real>
+      <real>1.0</real>
+    </array>
+  </map>
+  <key>MeshPreviewBrightnessColor</key>
+  <map>
+    <key>Comment</key>
+    <string>Brightness modifier</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color3</string>
+    <key>Value</key>
+    <array>
+      <real>0.9</real>
+      <real>0.9</real>
+      <real>0.9</real>
+    </array>
+  </map>
+  <key>MeshPreviewEdgeWidth</key>
+  <map>
+    <key>Comment</key>
+    <string>line thickness used when display edges is selected in mesh preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+      <real>1.0</real>
+  </map>
+  <key>MeshPreviewPhysicsEdgeColor</key>
+  <map>
+    <key>Comment</key>
+    <string>Edge colour for the Mesh uploader physics preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color4</string>
+    <key>Value</key>
+    <array>
+      <real>0.0</real>
+      <real>0.25</real>
+      <real>0.5</real>
+      <real>0.25</real>
+    </array>
+  </map>
+  <key>MeshPreviewPhysicsFillColor</key>
+  <map>
+    <key>Comment</key>
+    <string>Fill colour for the Mesh uploader physics preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color4</string>
+    <key>Value</key>
+    <array>
+      <real>0.0</real>
+      <real>0.5</real>
+      <real>1.0</real>
+      <real>0.5</real>
+    </array>
+  </map>
+  <key>MeshPreviewPhysicsEdgeWidth</key>
+  <map>
+    <key>Comment</key>
+    <string>line thickness used when display physics is selected in mesh preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>1.0</real>
+  </map>
+  <key>MeshPreviewDegenerateEdgeColor</key>
+  <map>
+    <key>Comment</key>
+    <string>Edge colour for the Mesh uploader Degenerate preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color4</string>
+    <key>Value</key>
+    <array>
+      <real>1.0</real>
+      <real>0.0</real>
+      <real>0.0</real>
+      <real>1.0</real>
+    </array>
+  </map>
+  <key>MeshPreviewDegenerateFillColor</key>
+  <map>
+    <key>Comment</key>
+    <string>Fill colour for the Mesh uploader Degenerate preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color4</string>
+    <key>Value</key>
+    <array>
+      <real>1.0</real>
+      <real>0.0</real>
+      <real>0.0</real>
+      <real>0.5</real>
+    </array>
+  </map>
+  <key>MeshPreviewDegenerateEdgeWidth</key>
+  <map>
+    <key>Comment</key>
+    <string>line thickness used when display Degenerate is selected in mesh preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>3.0</real>
+  </map>
+  <key>MeshPreviewDegeneratePointSize</key>
+  <map>
+    <key>Comment</key>
+    <string>Large point size used to highlight degenerate triangle vertices in Mesh preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>8.0</real>
+  </map>
+  <key>MeshPreviewZoomLimit</key>
+  <map>
+    <key>Comment</key>
+    <string>Maximum Zoom level in preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>10.0</real>
+  </map>
+  <map>
       <key>Comment</key>
       <string>Check for old version of disk cache to migrate to current location</string>
       <key>Persist</key>
@@ -7868,7 +8049,17 @@
       <key>Value</key>
 	  <integer>13</integer>
     </map>
-
+  <key>PreviewRenderSize</key>  
+  <map>
+    <key>Comment</key>
+    <string>Resolution of the image rendered for the mesh upload preview</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>S32</string>
+    <key>Value</key>
+    <integer>1024</integer>
+  </map>
   <key>PreviewAmbientColor</key>
   <map>
     <key>Comment</key>
@@ -7885,8 +8076,6 @@
       <real>1.0</real>
     </array>
   </map>
-
-
   <key>PreviewDiffuse0</key>
   <map>
     <key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
index 7f3f84398b102ab07dd68c2106a67fc2a9509408..3424613e948fd120e63a10ca111f1bfa556b80a9 100644
--- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl
@@ -91,8 +91,10 @@ void main()
 
 	// Collect normal lights (need to be divided by two, as we later multiply by 2)
 	col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz);
-	col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z);
-	col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z);
-		
+//	col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z);
+	col.rgb += light_diffuse[2].rgb * calcDirectionalLight(norm, light_position[2].xyz);
+//	col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z);
+	col.rgb += light_diffuse[3].rgb * calcDirectionalLight(norm, light_position[3].xyz);
+	col /= 2.0;
 	vertex_color = col*color;
 }
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index fa9a0712fa4185cdbb2f0164ae77cec76370e008..af6977d3cd689912e8768a35ab10a9a4f1eb7eef 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -125,11 +125,17 @@ BOOL LLViewerDynamicTexture::render()
 //-----------------------------------------------------------------------------
 void LLViewerDynamicTexture::preRender(BOOL clear_depth)
 {
-	//only images up to 512x512 are supported
-	llassert(mFullHeight <= 512);
-	llassert(mFullWidth <= 512);
+	// <FS:Beq> changes to support higher resolution rendering in the preview
+	////only images up to 512x512 are supported
+	//llassert(mFullHeight <= 512);
+	//llassert(mFullWidth <= 512);
+	gPipeline.allocatePhysicsBuffer();
+	llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth()));
+	llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
 
-	if (gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI)
+//	if (gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI)
+	if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI)
+// </FS:Beq>
 	{ //using offscreen render target, just use the bottom left corner
 		mOrigin.set(0, 0);
 	}
@@ -215,14 +221,15 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
 	{
 		return TRUE;
 	}
-
-	bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI;
-
+	// <FS:Beq> changes to support higher resolution rendering in the preview
+	//	bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI;
+	bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI;
 	if (use_fbo)
 	{
-		gPipeline.mWaterDis.bindTarget();
+//		gPipeline.mWaterDis.bindTarget();
+		gPipeline.mPhysicsDisplay.bindTarget();
 	}
-
+	// </FS:Beq>
 	LLGLSLShader::bindNoShader();
 	LLVertexBuffer::unbind();
 	
@@ -258,7 +265,10 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
 
 	if (use_fbo)
 	{
-		gPipeline.mWaterDis.flush();
+		// <FS:Beq> changes to support higher resolution rendering in the preview
+		// gPipeline.mWaterDis.flush();
+		gPipeline.mPhysicsDisplay.flush();
+		// </FS:Beq>
 	}
 
 	return ret;
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 818d364c3e260bac8d42adf249abfdaa1ba72ced..01f0a5197d64a6d4e84c3cb48974f508575c6470 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -427,8 +427,11 @@ void LLFloaterModelPreview::initModelPreview()
 	{
 		delete mModelPreview;
 	}
-
-	mModelPreview = new LLModelPreview(512, 512, this );
+	// <FS:Beq> mesh uploader changes to allow higher resolution render
+	//	mModelPreview = new LLModelPreview(512, 512, this);
+	auto size = gSavedSettings.getS32("PreviewRenderSize");
+	mModelPreview = new LLModelPreview(size, size, this );
+	// </FS:Beq>
 	mModelPreview->setPreviewTarget(16.f);
 	mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5));
 	mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1));
@@ -438,8 +441,16 @@ void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl)
 {
 	if (mModelPreview)
 	{
-		mModelPreview->mViewOption[ctrl->getName()] = !mModelPreview->mViewOption[ctrl->getName()];
-		
+		// <FS:Beq> only show explode when phsyics is on
+		//		mModelPreview->mViewOption[ctrl->getName()] = !mModelPreview->mViewOption[ctrl->getName()];
+		auto name = ctrl->getName();
+		mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name];
+		if (name == "show_physics")
+		{
+			auto enabled = mModelPreview->mViewOption[name];
+			childSetEnabled("physics_explode", enabled);
+			childSetVisible("physics_explode", enabled);
+		}
 		mModelPreview->refresh();
 	}
 }
@@ -653,6 +664,43 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
 	}
 }
 
+// <FS:Beq> extracted method to simplify changes in layout
+void LLFloaterModelPreview::draw3dPreview()
+{
+	gGL.color3f(1.f, 1.f, 1.f);
+
+	gGL.getTexUnit(0)->bind(mModelPreview);
+
+
+	LLView* preview_panel = getChild<LLView>("preview_panel");
+
+	if (!preview_panel)
+	{
+		LL_WARNS() << "preview_panel not found in floater definition" << LL_ENDL;
+	}
+	LLRect rect = preview_panel->getRect();
+
+	if (rect != mPreviewRect)
+	{
+		mModelPreview->refresh();
+		mPreviewRect = preview_panel->getRect();
+	}
+
+	gGL.begin( LLRender::QUADS );
+	{
+		gGL.texCoord2f(0.f, 1.f);
+		gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop-1);
+		gGL.texCoord2f(0.f, 0.f);
+		gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom);
+		gGL.texCoord2f(1.f, 0.f);
+		gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom);
+		gGL.texCoord2f(1.f, 1.f);
+		gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1);
+	}
+	gGL.end();
+
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+}
 
 //-----------------------------------------------------------------------------
 // draw()
@@ -1218,6 +1266,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
 , mResetJoints( false )
 , mModelNoErrors( true )
 , mLastJointUpdate( false )
+, mHasDegenerate( false ) // <FS:Beq>
 {
 	mNeedsUpdate = TRUE;
 	mCameraDistance = 0.f;
@@ -2707,8 +2756,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 
 void LLModelPreview::updateStatusMessages()
 {
+// <FS:Beq> bit mask values for physics errors. used to prevent overwrite of single line status
+// TODO: use this to provied multiline status
+	enum PhysicsError
+	{
+		NONE=0,
+		NOHAVOK=1,
+		DEGENERATE=2,
+		TOOMANYHULLS=4,
+		TOOMANYVERTSINHULL=8
+	};
+// </FS:Beq>
 	assert_main_thread();
 
+	U32 has_physics_error{ PhysicsError::NONE }; // <FS:Beq> physics error bitmap
 	//triangle/vertex/submesh count for each mesh asset for each lod
 	std::vector<S32> tris[LLModel::NUM_LODS];
 	std::vector<S32> verts[LLModel::NUM_LODS];
@@ -2797,44 +2858,72 @@ void LLModelPreview::updateStatusMessages()
 	{
 		mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
 	}
-
-	bool has_degenerate = false;
-
+	// <FS:Beq> make has_degenerate a member so that we can use it in the render method
+	// has_degenerate = false
+	mHasDegenerate = false;
 	{//check for degenerate triangles in physics mesh
 		U32 lod = LLModel::LOD_PHYSICS;
 		const LLVector4a scale(0.5f);
-		for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i)
+		for (U32 i = 0; i < mModel[lod].size() && !mHasDegenerate; ++i)// <FS:Beq> make has_degenerate a member 
 		{ //for each model in the lod
 			if (mModel[lod][i] && mModel[lod][i]->mPhysics.mHull.empty())
 			{ //no decomp exists
 				S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
-				for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j)
+				for (S32 j = 0; j < cur_submeshes && !mHasDegenerate; ++j)// <FS:Beq> make has_degenerate a member 
 				{ //for each submesh (face), add triangles and vertices to current total
 					LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
-					for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; )
+					for (S32 k = 0; (k < face.mNumIndices) && !mHasDegenerate; )// <FS:Beq> make has_degenerate a member 
 					{
-						U16 index_a = face.mIndices[k+0];
-						U16 index_b = face.mIndices[k+1];
-						U16 index_c = face.mIndices[k+2];
-
-						LLVector4a v1; v1.setMul(face.mPositions[index_a], scale);
-						LLVector4a v2; v2.setMul(face.mPositions[index_b], scale);
-						LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);
-
-						if (ll_is_degenerate(v1,v2,v3))
+						U16 index_a = face.mIndices[k + 0];
+						U16 index_b = face.mIndices[k + 1];
+						U16 index_c = face.mIndices[k + 2];
+						// <FS:Beq> FIRE-23367/23387 - Allow forced empty triangle placeholders created by the LOD processing.
+						//	LLVector4a v1; v1.setMul(face.mPositions[index_a], scale);
+						//	LLVector4a v2; v2.setMul(face.mPositions[index_b], scale);
+						//	LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);
+
+						//	if (ll_is_degenerate(v1, v2, v3))
+						//	{
+						//		mHasDegenerate = true;// <FS:Beq> make has_degenerate a member 
+						//	}
+						//	else
+						//	{
+						//		k += 3;
+						//	}
+						if (index_c == 0 && index_b == 0 && index_a == 0) // test in reverse as 3rd index is less likely to be 0 in a normal case
 						{
-							has_degenerate = true;
+							LL_DEBUGS("MeshValidation") << "Empty placeholder triangle (3 identical index 0 verts) ignored" << LL_ENDL;
 						}
 						else
 						{
-							k += 3;
+							LLVector4a v1; v1.setMul(face.mPositions[index_a], scale);
+							LLVector4a v2; v2.setMul(face.mPositions[index_b], scale);
+							LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);
+							if (ll_is_degenerate(v1, v2, v3))
+							{
+								mHasDegenerate = true;// <FS:Beq> make has_degenerate a member 
+							}
 						}
+						k += 3;
 					}
 				}
 			}
 		}
 	}
 
+	// <FS:Beq> flag degenerates here rather than deferring to a MAV error later
+	mFMP->childSetVisible("physics_status_message_text", mHasDegenerate); //display or clear
+	auto degenerateIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
+	degenerateIcon->setVisible(mHasDegenerate);
+	if (mHasDegenerate)
+	{
+		has_physics_error |= PhysicsError::DEGENERATE;
+		mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_degenerate_triangles"));
+		LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Error");
+		degenerateIcon->setImage(img);
+	}
+	// </FS:Beq>
+
 	mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
 
 	std::string mesh_status_na = mFMP->getString("mesh_status_na");
@@ -2959,14 +3048,22 @@ void LLModelPreview::updateStatusMessages()
 			}
 		}
 	}
-	mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit);
-	LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
-	physStatusIcon->setVisible(physExceededVertexLimit);
+
 	if (physExceededVertexLimit)
 	{
-		mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded"));
-		LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning");
-		physStatusIcon->setImage(img);
+		has_physics_error |= PhysicsError::TOOMANYVERTSINHULL;
+	}
+
+	if (!(has_physics_error & PhysicsError::DEGENERATE)){ // only update this field (incluides clearing it) if it is not already in use.
+		mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit);
+		LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
+		physStatusIcon->setVisible(physExceededVertexLimit);
+		if (physExceededVertexLimit)
+		{
+			mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded"));
+			LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning");
+			physStatusIcon->setImage(img);
+		}
 	}
 
 	if (getLoadState() >= LLModelLoader::ERROR_PARSING)
@@ -2995,12 +3092,21 @@ void LLModelPreview::updateStatusMessages()
 			mModelNoErrors = false;
 		}
 	}
-
-	// Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics
-	// current use of has_degenerate won't block upload permanently - later checks will restore the button
-	if (!mModelNoErrors || has_degenerate)
+	// <FS:Beq> Improve the error checking the TO DO here is no longer applicable but not an FS comment so edited to stop it being picked up
+	//// To do investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics
+	//// current use of has_degenerate won't block upload permanently - later checks will restore the button
+	//if (!mModelNoErrors || mHasDegenerate)
+	//{
+	//	mFMP->childDisable("ok_btn");
+	if (!mModelNoErrors || mHasDegenerate)
 	{
 		mFMP->childDisable("ok_btn");
+		mFMP->childDisable("calculate_btn");
+	}
+	else
+	{
+		mFMP->childEnable("ok_btn");
+		mFMP->childEnable("calculate_btn");
 	}
 	
 	//add up physics triangles etc
@@ -3616,11 +3722,30 @@ BOOL LLModelPreview::render()
 	bool textures = mViewOption["show_textures"];
 	bool physics = mViewOption["show_physics"];
 
+	// <FS:Beq> Extra configurability, to be exposed later as controls?
+	static LLCachedControl<LLColor4> canvas_col(gSavedSettings, "MeshPreviewCanvasColor");
+	static LLCachedControl<LLColor4> edge_col(gSavedSettings, "MeshPreviewEdgeColor");
+	static LLCachedControl<LLColor4> base_col(gSavedSettings, "MeshPreviewBaseColor");
+	static LLCachedControl<LLColor3> brightness(gSavedSettings, "MeshPreviewBrightnessColor");
+	static LLCachedControl<F32> edge_width(gSavedSettings, "MeshPreviewEdgeWidth");
+	static LLCachedControl<LLColor4> phys_edge_col(gSavedSettings, "MeshPreviewPhysicsEdgeColor");
+	static LLCachedControl<LLColor4> phys_fill_col(gSavedSettings, "MeshPreviewPhysicsFillColor");
+	static LLCachedControl<F32> phys_edge_width(gSavedSettings, "MeshPreviewPhysicsEdgeWidth");
+	static LLCachedControl<LLColor4> deg_edge_col(gSavedSettings, "MeshPreviewDegenerateEdgeColor");
+	static LLCachedControl<LLColor4> deg_fill_col(gSavedSettings, "MeshPreviewDegenerateFillColor");	
+	static LLCachedControl<F32> deg_edge_width(gSavedSettings, "MeshPreviewDegenerateEdgeWidth");
+	static LLCachedControl<F32> deg_point_size(gSavedSettings, "MeshPreviewDegeneratePointSize");
+	// </FS:Beq>
 	S32 width = getWidth();
 	S32 height = getHeight();
 
 	LLGLSUIDefault def;
 	LLGLDisable no_blend(GL_BLEND);
+// <FS:Beq> Clean up render of mesh preview
+//	LLGLEnable blend(GL_BLEND);
+//	gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+// </FS:Beq> 
+
 	LLGLEnable cull(GL_CULL_FACE);
 	LLGLDepthTest depth(GL_TRUE);
 	LLGLDisable fog(GL_FOG);
@@ -3639,9 +3764,9 @@ BOOL LLModelPreview::render()
 		gGL.matrixMode(LLRender::MM_MODELVIEW);
 		gGL.pushMatrix();
 		gGL.loadIdentity();
-
-		gGL.color4f(0.169f, 0.169f, 0.169f, 1.f);
-
+		// <FS:Beq> uploader improvements
+		//gGL.color4f(0.169f, 0.169f, 0.169f, 1.f);
+		gGL.color4fv(static_cast<LLColor4>(canvas_col).mV);
 		gl_rect_2d_simple( width, height );
 
 		gGL.matrixMode(LLRender::MM_PROJECTION);
@@ -3789,8 +3914,11 @@ BOOL LLModelPreview::render()
 	stop_glerror();
 
 	gGL.pushMatrix();
-	const F32 BRIGHTNESS = 0.9f;
-	gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
+	// <FS:Beq> mesh uploader improvements configurable brightness
+	//const F32 BRIGHTNESS = 0.9f;
+	//gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
+	gGL.color4fv(edge_col().mV);
+	// </FS:Beq>
 
 	const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
 
@@ -3875,16 +4003,22 @@ BOOL LLModelPreview::render()
 						}
 						else
 						{
-							gGL.diffuseColor4f(1,1,1,1);
+						// <FS:Beq> improved mesh uploader
+						//	gGL.diffuseColor4f(1,1,1,1);
+							gGL.diffuseColor4fv(static_cast<LLColor4>(base_col).mV);
+						// </FS:Beq>
+
 						}
 
 						buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 						gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-						gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
-
+						// <FS:Beq> improved mesh uploader
+						//gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
+						gGL.diffuseColor4fv(static_cast<LLColor4>(edge_col).mV);
+						// </FS:Beq> 
 						if (edges)
 						{
-							glLineWidth(3.f);
+							glLineWidth(edge_width);
 							glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 							glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@@ -3896,11 +4030,25 @@ BOOL LLModelPreview::render()
 
 			if (physics)
 			{
+				// <FS:Beq> model upload improvements - use the settings
+				////Vector4a physicsFillColour(0.4, 0.4, 0.4, 0.4);
+				//const LLColor4 physicsFillColour(0.0, 0.5, 1.0, 0.5);
+				////LLVector4a physicsEdgeColour(1.0, 1.0, 0.0, 1.0);
+				//const LLColor4 physicsEdgeColour=physicsFillColour*0.5;
+				//const LLColor4 degenerateFill(1.0, 0.0, 0.0, 0.5);
+				//const LLColor4 degenerateEdge(1.0,0.0,0.0,1.0);
+				// </FS:Beq> 
+
 				glClear(GL_DEPTH_BUFFER_BIT);
-				
-				for (U32 i = 0; i < 2; i++)
+				//<FS:Beq> refactor to remove silly variable names
+				//				for (U32 i = 0; i < 2; i++)
+				for (U32 pass = 0; pass < 2; pass++)
+				//</FS:Beq>
 				{
-					if (i == 0)
+					//<FS:Beq> refactor to remove silly variable names
+					//if (i == 0)
+					if (pass == 0)
+					//</FS:Beq>
 					{ //depth only pass
 						gGL.setColorMask(false, false);
 					}
@@ -3910,8 +4058,11 @@ BOOL LLModelPreview::render()
 					}
 
 					//enable alpha blending on second pass but not first pass
-					LLGLState blend(GL_BLEND, i); 
-					
+					//<FS:Beq> refactor to remove silly variable names
+					//LLGLState blend(GL_BLEND, i);
+					LLGLState blend(GL_BLEND, pass);
+					//</FS:Beq>
+
 					gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
 
 					for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
@@ -3920,175 +4071,196 @@ BOOL LLModelPreview::render()
 
 						LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
 
-							if (!model)
-							{
-								continue;
-							}
+						if (!model)
+						{
+							continue;
+						}
 
-							gGL.pushMatrix();
-							LLMatrix4 mat = instance.mTransform;
+						gGL.pushMatrix();
+						LLMatrix4 mat = instance.mTransform;
 
-						gGL.multMatrix((GLfloat*) mat.mMatrix);
+						gGL.multMatrix((GLfloat*)mat.mMatrix);
 
 
-							bool render_mesh = true;
+						bool render_mesh = true;
+						LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
+						if (decomp)
+						{
+							LLMutexLock(decomp->mMutex);
+
+							LLModel::Decomposition& physics = model->mPhysics;
 
-							LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
-							if (decomp)
+							if (!physics.mHull.empty())
 							{
-								LLMutexLock(decomp->mMutex);
-
-								LLModel::Decomposition& physics = model->mPhysics;
+								render_mesh = false;
 
-								if (!physics.mHull.empty())
-								{
-									render_mesh = false;
+								if (physics.mMesh.empty())
+								{ //build vertex buffer for physics mesh
+									gMeshRepo.buildPhysicsMesh(physics);
+								}
 
-									if (physics.mMesh.empty())
-									{ //build vertex buffer for physics mesh
-										gMeshRepo.buildPhysicsMesh(physics);
-									}
-						
-									if (!physics.mMesh.empty())
-									{ //render hull instead of mesh
-										for (U32 i = 0; i < physics.mMesh.size(); ++i)
+								if (!physics.mMesh.empty())
+								{ //render hull instead of mesh
+									for (U32 i = 0; i < physics.mMesh.size(); ++i)
+									{
+										if (explode > 0.f)
 										{
-											if (explode > 0.f)
-											{
-												gGL.pushMatrix();
+											gGL.pushMatrix();
 
-												LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
-												offset *= explode;
+											LLVector3 offset = model->mHullCenter[i] - model->mCenterOfHullCenters;
+											offset *= explode;
 
-												gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
-											}
+											gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
+										}
 
-											static std::vector<LLColor4U> hull_colors;
+										static std::vector<LLColor4U> hull_colors;
 
-											if (i+1 >= hull_colors.size())
-											{
-												hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128));
-											}
+										if (i + 1 >= hull_colors.size())
+										{
+											hull_colors.push_back(LLColor4U(rand() % 128 + 127, rand() % 128 + 127, rand() % 128 + 127, 128));
+										}
 
-											gGL.diffuseColor4ubv(hull_colors[i].mV);
-											LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+										gGL.diffuseColor4ubv(hull_colors[i].mV);
+										LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
 
-											if (explode > 0.f)
-											{
-												gGL.popMatrix();
-											}
+										if (explode > 0.f)
+										{
+											gGL.popMatrix();
 										}
 									}
 								}
 							}
-						
-							if (render_mesh)
+						}
+
+						if (render_mesh)
+						{
+							if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
 							{
-								if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
-								{
-									genBuffers(LLModel::LOD_PHYSICS, false);
-								}
+								genBuffers(LLModel::LOD_PHYSICS, false);
+							}
 
-								U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
+							U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
+							if (pass > 0){
 								for (U32 i = 0; i < num_models; ++i)
 								{
 									LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
 
 									gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-									gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f);
+									gGL.diffuseColor4fv(phys_fill_col().mV);
 
 									buffer->setBuffer(type_mask & buffer->getTypeMask());
-									buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
-
-									gGL.diffuseColor3f(1.f, 1.f, 0.f);
+									buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0);
 
-									glLineWidth(2.f);
+									gGL.diffuseColor4fv(phys_edge_col().mV);
+									glLineWidth(phys_edge_width);
 									glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-									buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+									buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0);
 
 									glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 									glLineWidth(1.f);
 								}
 							}
-
-							gGL.popMatrix();
 						}
 
-					glLineWidth(3.f);
-					glPointSize(8.f);
-					gPipeline.enableLightsFullbright(LLColor4::white);
-					//show degenerate triangles
-					LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
-					LLGLDisable cull(GL_CULL_FACE);
-					gGL.diffuseColor4f(1.f,0.f,0.f,1.f);
-					const LLVector4a scale(0.5f);
+						gGL.popMatrix();
+					}
 
-					for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
+					//<FS:Beq> refactor to remove silly variable names
+					// also only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks]
+					//if (i > 0)
+					if (pass > 0 && mHasDegenerate)
+					//</FS:Beq>
 					{
-						LLModelInstance& instance = *iter;
-
-						LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
-
-						if (!model)
+						glLineWidth(deg_edge_width);
+						glPointSize(deg_point_size);
+// <FS:Beq> This single line is why the degenerate triangles display has been crap forever. 
+// 						gPipeline.enableLightsFullbright(LLColor4::white);
+						//show degenerate triangles
+						LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
+						LLGLDisable cull(GL_CULL_FACE);
+						const LLVector4a scale(0.5f);
+
+						for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
 						{
-							continue;
-						}
+							LLModelInstance& instance = *iter;
 
-						gGL.pushMatrix();
-						LLMatrix4 mat = instance.mTransform;
+							LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
 
-						gGL.multMatrix((GLfloat*) mat.mMatrix);
+							if (!model)
+							{
+								continue;
+							}
 
+							gGL.pushMatrix();
+							LLMatrix4 mat = instance.mTransform;
 
-						LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
-						if (decomp)
-						{
-							LLMutexLock(decomp->mMutex);
+							gGL.multMatrix((GLfloat*)mat.mMatrix);
 
-							LLModel::Decomposition& physics = model->mPhysics;
 
-							if (physics.mHull.empty())
+							LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
+							if (decomp)
 							{
-								if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
-								{
-									genBuffers(LLModel::LOD_PHYSICS, false);
-								}
-							
-								for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i)
-								{
-									LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
+								LLMutexLock(decomp->mMutex);
 
-									buffer->setBuffer(type_mask & buffer->getTypeMask());
+								LLModel::Decomposition& physics = model->mPhysics;
 
-									LLStrider<LLVector3> pos_strider; 
-									buffer->getVertexStrider(pos_strider, 0);
-									LLVector4a* pos = (LLVector4a*) pos_strider.get();
-							
-									LLStrider<U16> idx;
-									buffer->getIndexStrider(idx, 0);
+								if (physics.mHull.empty())
+								{
+									if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
+									{
+										genBuffers(LLModel::LOD_PHYSICS, false);
+									}
 
-									for (U32 i = 0; i < buffer->getNumIndices(); i += 3)
+									auto num_degenerate = 0;
+									//<FS:Beq> More nested i variable silliness
+									//									for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i)
+									auto num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
+									for (U32 v = 0; v < num_models; ++v)
 									{
-										LLVector4a v1; v1.setMul(pos[*idx++], scale);
-										LLVector4a v2; v2.setMul(pos[*idx++], scale);
-										LLVector4a v3; v3.setMul(pos[*idx++], scale);
+										LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v];
+									//</FS:Beq>
+										if(buffer->getNumVerts() < 3)continue;
+
+										buffer->setBuffer(type_mask & buffer->getTypeMask());
+
+										LLStrider<LLVector3> pos_strider;
+										buffer->getVertexStrider(pos_strider, 0);
+										LLVector4a* pos = (LLVector4a*)pos_strider.get();
+
+										LLStrider<U16> idx;
+										buffer->getIndexStrider(idx, 0);
 
-										if (ll_is_degenerate(v1,v2,v3))
+										LLVector4a v1, v2, v3;
+										//<FS:Beq> rename inner most i to avoid merge confusion
+										for (U32 indices_offset = 0; indices_offset < buffer->getNumIndices(); indices_offset += 3)
 										{
-											buffer->draw(LLRender::LINE_LOOP, 3, i);
-											buffer->draw(LLRender::POINTS, 3, i);
+											v1.setMul(pos[*idx++], scale);
+											v2.setMul(pos[*idx++], scale);
+											v3.setMul(pos[*idx++], scale);
+
+											if (ll_is_degenerate(v1, v2, v3))
+											{
+												num_degenerate++;
+												glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+												gGL.diffuseColor3fv(deg_edge_col().mV);
+												buffer->drawRange(LLRender::TRIANGLES, 0, 2, 3, indices_offset);
+												buffer->drawRange(LLRender::POINTS, 0, 2, 3, indices_offset);
+												glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+												gGL.diffuseColor3fv(deg_fill_col().mV);
+												buffer->drawRange(LLRender::TRIANGLES, 0, 2, 3, indices_offset);
+											}
 										}
 									}
 								}
 							}
-						}
 
-						gGL.popMatrix();
+							gGL.popMatrix();
+						}
+						glLineWidth(1.f);
+						glPointSize(1.f);
+						gPipeline.enableLightsPreview();
+						gGL.setSceneBlendType(LLRender::BT_ALPHA);
 					}
-					glLineWidth(1.f);
-					glPointSize(1.f);
-					gPipeline.enableLightsPreview();
-					gGL.setSceneBlendType(LLRender::BT_ALPHA);
 				}
 			}
 		}
@@ -4170,16 +4342,19 @@ BOOL LLModelPreview::render()
 							}
 						
 							buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
-							gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
+							// <FS:Beq> configurable colour and width
+							//gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
 
 							if (edges)
 							{
-								glLineWidth(3.f);
+								gGL.diffuseColor4fv(edge_col().mV);
+								glLineWidth(edge_width);
 								glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 								buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
 								glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 								glLineWidth(1.f);
 							}
+							// </FS:Beq>
 						}
 					}
 				}
@@ -4237,8 +4412,11 @@ void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians)
 void LLModelPreview::zoom(F32 zoom_amt)
 {
 	F32 new_zoom = mCameraZoom+zoom_amt;
-
-	mCameraZoom	= llclamp(new_zoom, 1.f, 10.f);
+	// <FS:Beq> add configurable zoom TODO: stop clamping in render
+	// mCameraZoom = llclamp(new_zoom, 1.f, 10.f);
+	static LLCachedControl<F32> zoom_limit(gSavedSettings, "MeshPreviewZoomLimit");
+	mCameraZoom	= llclamp(new_zoom, 1.f, zoom_limit());
+	// </FS:Beq>
 }
 
 void LLModelPreview::pan(F32 right, F32 up)
@@ -4444,11 +4622,22 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)
 		childSetTextArg("server_weight", "[SIM]", tbd);
 		childSetTextArg("physics_weight", "[PH]", tbd);
 		childSetTextArg("upload_fee", "[FEE]", tbd);
-		childSetTextArg("price_breakdown", "[STREAMING]", tbd);
-		childSetTextArg("price_breakdown", "[PHYSICS]", tbd);
-		childSetTextArg("price_breakdown", "[INSTANCES]", tbd);
-		childSetTextArg("price_breakdown", "[TEXTURES]", tbd);
-		childSetTextArg("price_breakdown", "[MODEL]", tbd);
+		// <FS:Beq> add extended info fields
+		//childSetTextArg("price_breakdown", "[STREAMING]", dashes);
+		//childSetTextArg("price_breakdown", "[PHYSICS]", dashes);
+		//childSetTextArg("price_breakdown", "[INSTANCES]", dashes);
+		//childSetTextArg("price_breakdown", "[TEXTURES]", dashes);
+		//childSetTextArg("price_breakdown", "[MODEL]", dashes);
+		std::string dashes = hasString("--") ? getString("--") : "--";
+		childSetTextArg("price_breakdown", "[STREAMING]", dashes);
+		childSetTextArg("price_breakdown", "[PHYSICS]", dashes);
+		childSetTextArg("price_breakdown", "[INSTANCES]", dashes);
+		childSetTextArg("price_breakdown", "[TEXTURES]", dashes);
+		childSetTextArg("price_breakdown", "[MODEL]", dashes);
+		childSetTextArg("physics_breakdown", "[PCH]", dashes);
+		childSetTextArg("physics_breakdown", "[PM]", dashes);
+		childSetTextArg("physics_breakdown", "[PHU]", dashes);
+		// </FS:Beq>
 	}
 }
 
@@ -4498,6 +4687,16 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()
 	childSetTextArg("price_breakdown", "[INSTANCES]", llformat("%d", result["upload_price_breakdown"]["mesh_instance"].asInteger()));
 	childSetTextArg("price_breakdown", "[TEXTURES]", llformat("%d", result["upload_price_breakdown"]["texture"].asInteger()));
 	childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger()));
+//<FS:Beq> Updates for enhanced Mesh feedback at upload
+	childSetTextArg("physics_breakdown", "[PCH]", llformat("%0.3f", result["model_physics_cost"]["hull"].asReal()));
+	childSetTextArg("physics_breakdown", "[PM]", llformat("%0.3f", result["model_physics_cost"]["mesh"].asReal()));
+	childSetTextArg("physics_breakdown", "[PHU]", llformat("%0.3f", result["model_physics_cost"]["decomposition"].asReal()));
+	childSetTextArg("streaming_breakdown", "[STR_TOTAL]", llformat("%d", result["streaming_cost"].asInteger()));
+	childSetTextArg("streaming_breakdown", "[STR_HIGH]", llformat("%d", result["streaming_params"]["high_lod"].asInteger()));
+	childSetTextArg("streaming_breakdown", "[STR_MED]", llformat("%d", result["streaming_params"]["medium_lod"].asInteger()));
+	childSetTextArg("streaming_breakdown", "[STR_LOW]", llformat("%d", result["streaming_params"]["low_lod"].asInteger()));
+	childSetTextArg("streaming_breakdown", "[STR_LOWEST]", llformat("%d", result["streaming_params"]["lowest_lod"].asInteger()));
+//</FS:Beq>
 	childSetVisible("upload_fee", true);
 	childSetVisible("price_breakdown", true);
 	mUploadBtn->setEnabled(isModelUploadAllowed());
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 7ec6a58ac76de31e44812a630f19edbc3b961307..564f4c39ded5aef29d0d012e1e0202c2df7d62e1 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -152,6 +152,7 @@ protected:
 	static void		onAutoFillCommit(LLUICtrl*,void*);
 	
 	void onLODParamCommit(S32 lod, bool enforce_tri_limit);
+	void draw3dPreview();
 
 	static void		onExplodeCommit(LLUICtrl*, void*);
 	
@@ -310,6 +311,7 @@ public:
 	static bool 		sIgnoreLoadedCallback;
     std::vector<S32> mLodsQuery;
     std::vector<S32> mLodsWithParsingError;
+	bool mHasDegenerate;
 
 protected:
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 40d6d325badbcc9383f47c1a0b0b68e34514820b..c7626304edf532fe100af9fd9e8217df4a1de3d0 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -6582,7 +6582,7 @@ void LLPipeline::enableLightsPreview()
 	light->enable();
 	light->setPosition(light_pos);
 	light->setDiffuse(diffuse0);
-	light->setAmbient(LLColor4::black);
+	light->setAmbient(ambient);
 	light->setSpecular(specular0);
 	light->setSpotExponent(0.f);
 	light->setSpotCutoff(180.f);
@@ -6593,7 +6593,7 @@ void LLPipeline::enableLightsPreview()
 	light->enable();
 	light->setPosition(light_pos);
 	light->setDiffuse(diffuse1);
-	light->setAmbient(LLColor4::black);
+	light->setAmbient(ambient);
 	light->setSpecular(specular1);
 	light->setSpotExponent(0.f);
 	light->setSpotCutoff(180.f);
@@ -6603,7 +6603,7 @@ void LLPipeline::enableLightsPreview()
 	light->enable();
 	light->setPosition(light_pos);
 	light->setDiffuse(diffuse2);
-	light->setAmbient(LLColor4::black);
+	light->setAmbient(ambient);
 	light->setSpecular(specular2);
 	light->setSpotExponent(0.f);
 	light->setSpotCutoff(180.f);
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 5a86eb06fbf018858912c5cda924c3ed24ab8978..e073268b0ae6e2d838e994134610914a471d199d 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -2,12 +2,12 @@
 <floater
  can_close="true"
  can_drag_on_left="false"
- can_minimize="false"
- can_resize="false"
- height="480"
- min_height="480"
- width="980"
- min_width="980"
+ can_minimize="true"
+ can_resize="true"
+ height="600"
+ min_height="600"
+ width="1024"
+ min_width="1024"
  name="Model Preview"
  title="UPLOAD MODEL"
  help_topic="upload_model" >
@@ -33,19 +33,21 @@
   <string name="mesh_status_missing_lod">Missing required level of detail.</string>
   <string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string>
   <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string>
+  <string name="phys_status_degenerate_triangles">The physics mesh too dense remove the small thin triangles (see preview)</string>
+  <string name="phys_status_no_havok">The Firestorm OpenSim build is not supported for physics upload in SL.</string>
   <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->
   <string name="decomposing">Analyzing...</string>
   <string name="simplifying">Simplifying...</string>
   <string name="tbd">TBD</string>
 
-<panel
-  follows="top|left"
-  height="455"
-  layout="topleft"
-  left="3"
-  name="left_panel"
-  top_pad="10"
-  width="630">
+  <panel
+    follows="top|left"
+    height="580"
+    layout="topleft"
+    left="3"
+    name="left_panel"
+    top_pad="0"
+    width="630">
     <panel
       follows="all"
       height="50"
@@ -755,8 +757,9 @@
                       name="first_step_name"
                       text_color="White"
                       top_pad="0"
-                      width="210">
-                      Step 1: Level of Detail
+                      width="210"
+                      valign="center">
+                      Step 1: Pick a physics model :
                     </text>
                     <combo_box
                       follows="left|top"
@@ -798,7 +801,7 @@
               layout="topleft"
               left="18"
               name="physics_tab_border"
-              top_pad="15"
+              top_pad="10"
               width="589"/>
                 <panel
                   bg_alpha_color="0 0 0 0"
@@ -807,7 +810,7 @@
                   follows="top|left"
                   left="18"
                   name="physics analysis"
-                  top_pad="15"
+                  top_pad="10"
                   visible="true"
                   width="589">
                     <text
@@ -819,7 +822,7 @@
                       name="method_label"
                       text_color="White"
                       top_pad="0">
-                      Step 2: Analyze
+                      Step 2: Convert to hulls (optional)
                     </text>
                     <text
                       follows="top|left"
@@ -905,7 +908,7 @@
               layout="topleft"
               left="18"
               name="physics_tab_border"
-              top_pad="15"
+              top_pad="10"
               width="589"/>
                 <panel
                   bg_alpha_color="0 0 0 0"
@@ -914,7 +917,7 @@
                   height="66"
                   left="18"
                   name="physics simplification"
-                  top_pad="15"
+                  top_pad="10"
                   width="589">
                     <text
                       text_color="White"
@@ -1013,7 +1016,7 @@
               layout="topleft"
               left="18"
               name="physics_tab_border"
-              top_pad="15"
+              top_pad="10"
               width="589"/>
                 <panel
                   bg_alpha_color="0 0 0 0"
@@ -1075,10 +1078,9 @@
                  follows="left|top"
                  height="19"
                  layout="topleft"
-                 left_pad="5"
-                 top_delta="0"
+                 top_pad="5"
                  name="physics message"
-                 width="270">
+                 width="589">
                      <icon
                       follows="left|top"
                       height="16"
@@ -1093,7 +1095,7 @@
                       layout="topleft"
                       left_pad="2"
                       name="physics_status_message_text"
-                      width="252"
+                      width="573"
                       top_delta="3"/>
                 </panel>
         </panel>
@@ -1219,13 +1221,14 @@
      </panel>
     </tab_container>
     <panel
-     follows="top|left"
-     height="80"
-     layout="top|left"
-     left="0"
+     follows="top|left|bottom"
+     layout="topleft"
+     height="184"
+     left="4"
+     border="true"
      name="weights_and_warning_panel"
      top_pad="3"
-     width="625">
+     width="629">
        <button
          follows="top|left"
          label="Calculate weights &amp; fee"
@@ -1265,10 +1268,10 @@
          label_color="White"
          layout="topleft"
          name="reset_btn"
-         right="-2"
+         right="-5"
          top="3"
          height="20"
-         width="275"/>
+         width="265"/>
        <!-- ========== WEIGHTS ==========-->
        <text
          follows="top|left"
@@ -1287,7 +1290,7 @@
          left_pad="0"
          name="prim_weight"
          top_delta="0"
-         width="120"
+         width="130"
          word_wrap="true">
          Land impact: [EQ]
        </text>
@@ -1297,7 +1300,7 @@
          left_pad="0"
          name="download_weight"
          top_delta="0"
-         width="100"
+         width="130"
          word_wrap="true">
          Download: [ST]
        </text>
@@ -1307,7 +1310,7 @@
          layout="topleft"
          left_pad="0"
          name="physics_weight"
-         width="90"
+         width="130"
          word_wrap="true">
          Physics: [PH]
        </text>
@@ -1317,17 +1320,148 @@
          layout="topleft"
          left_pad="0"
          name="server_weight"
-         width="83"
+         width="130"
          word_wrap="true">
          Server: [SIM]
        </text>
-       <!-- ========== NOTE MESSAGE ========== -->
+       <!-- =========== Cost breakdown ======== -->
+      <panel
+        border="true"
+        top_pad="5"
+        layout="topleft"
+        left="6"
+        name="price_breakdown_panel"
+        width="120"
+        height="100">
+        <text
+          layout="topleft"
+          left="3">
+          Price Breakdown
+        </text>
+        <view_border
+          bevel_style="none"
+          follows="top|left"
+          height="0"
+          layout="topleft"
+          left="3"
+          name="price_breakdown_border"
+          top_pad="5"
+          width="110"/>
+        <text
+          height="80"
+          top_pad="5"
+          layout="topleft"
+          left="3"
+          name="price_breakdown_labels"
+          width="70"
+          word_wrap="false">
+Download:
+Physics:
+Instances:
+Textures:
+Model:
+        </text>
+        <text
+          height="80"
+          top_delta="0"
+          layout="topleft"
+          halign="right"
+          left_pad="0"
+          name="price_breakdown"
+          width="40"
+          word_wrap="false">
+[STREAMING]
+[PHYSICS]
+[INSTANCES]
+[TEXTURES]
+[MODEL]
+        </text>
+      </panel>
+       <!-- 
+       Streaming breakdown numbers are available but not fully understood
+       uncommenting the following sections will display the numbers for debugging purposes
+       <text
+        height="80"
+        top_delta="0"
+        layout="topleft"
+        left="130"
+        name="streaming_breakdown_labels"
+        width="65"
+        word_wrap="true">
+Streaming/Download:
+High:
+Medium:
+Low:
+Lowest:
+      </text>
        <text
+        height="80"
+        top_delta="0"
+        layout="topleft"
+        left_pad="0"
+        name="streaming_breakdown"
+        width="95"
+        word_wrap="true">
+[STR_TOTAL]
+[STR_HIGH]
+[STR_MED]
+[STR_LOW]
+[STR_LOWEST]
+      </text>-->
+      <panel
+        border="true"
+        layout="topleft"
+        left_pad="265"
+        name="price_breakdown_panel"
+        width="120"
+        height="100">
+        <text
+          layout="topleft"
+          left="3">
+          Physics Costs
+        </text>
+        <view_border
+          bevel_style="none"
+          follows="top|left"
+          height="0"
+          layout="topleft"
+          left="3"
+          name="price_breakdown_border"
+          top_pad="5"
+          width="110"/>
+        <text
+         height="80"
+         top_pad="5"
+         layout="topleft"
+         left="5"
+         name="physics_breakdown_labels"
+         width="65">
+Base Hull:
+Mesh:
+Analysed:
+        </text>
+        <text
+         height="80"
+         top_delta="0"
+         layout="topleft"
+         left_pad="0"
+         name="physics_breakdown"
+         width="40"
+         halign="right"
+         word_wrap="false"
+         visible="true">
+[PCH]
+[PM]
+[PHU]
+        </text>-->
+      </panel>
+      <!-- ========== NOTE MESSAGE ========== -->
+      <text
          font="SansSerif"
          layout="topleft"
          left="6"
          name="warning_title"
-         top_pad="10"
+         top_pad="5"
          text_color="DrYellow"
          visible="false"
          width="40">
@@ -1346,104 +1480,110 @@
          visible="false">
          You dont have rights to upload mesh models. [[VURL] Find out how] to get certified.
        </text>
-       <text text_color="Yellow" layout="topleft" top_delta="20" left="6" name="status">[STATUS]</text>
-  
+       <text text_color="Yellow" layout="topleft" top_delta="5" left="6" name="status">
+[STATUS]
+       </text>
     </panel>
-</panel>
-
-<text 
- follows="left|top"
- layout="topleft"
- left="640"
- name="lod_label"
- text_color="White"
- top="13"
- height="15"
- width="290">
- Preview:
- </text>
-<panel
- border="true"
- bevel_style="none"
- follows="top|left"
- name="preview_panel"
- top_pad="4"
- width="290"
- height="290"/>
-
-<panel
-  follows="all"
-  height="130"
-  layout="topleft"
-  name="right_panel"
-  top_pad="5"
-  width="340">
-    <combo_box
-      top_pad="3"
+  </panel>
+  <panel
+    follows="top|left|bottom|right"
+    can_resize="true"
+    name="right_panel"
+    top="0"
+    left="640"
+    background_visible="true"
+    width="375">
+    <text
       follows="left|top"
-      height="18"
       layout="topleft"
-      name="preview_lod_combo"
-      width="150"
-      tool_tip="LOD to view in preview render">
+      left="0"
+      name="lod_label"
+      text_color="White"
+      top="13"
+      height="15"
+      width="290">
+      Preview:
+    </text>
+    <panel
+      can_resize="false"
+      follows="top|left"
+      height="20"
+      name="right_upper_panel"
+      top="8"
+      left="60"
+      background_visible="true"
+      width="315">
+      <combo_box
+        top_pad="3"
+        can_resize="false"
+        follows="top|left"
+        height="18"
+        layout="topleft"
+        name="preview_lod_combo"
+        width="75"
+        tool_tip="LOD to view in preview render">
         <combo_item name="high">   High   </combo_item>
         <combo_item name="medium"> Medium </combo_item>
         <combo_item name="low">    Low    </combo_item>
         <combo_item name="lowest"> Lowest </combo_item>
-    </combo_box>
-    <text
-      follows="top|left"
-      layout="topleft"
-      text_color="White"
-      top="5"
-      left_pad="20"
-      name="label_display"
-      width="50">
-      Display...
-    </text>
-    <check_box
-      follows="top|left"
-      label="Edges"
+      </combo_box>
+    </panel>
+  </panel>
+  <panel
+     border="true"
+     bevel_style="none"
+     follows="top|left|right|bottom"
+     layout="topleft"
+     name="preview_panel"
+     top="30"
+     width="375"
+     height="525"/>
+
+   <panel
+     follows="left|right|bottom"
+     layout="topleft"
+     height="40"
+     name="lower_right_panel"
+     top_pad="5"
+     width="375">
+     <check_box
+       follows="right|bottom"
+       label="Edges"
       label_text.text_color="White"
       layout="topleft"
-      left_delta="0"
       name="show_edges"
-      top_pad="8">
-    </check_box>
+      width="70"
+      left="0"
+      top_pad="8"/>
     <check_box
-      follows="top|left"
+      follows="right|bottom"
+      left_pad="8"
       label="Physics"
       label_text.text_color="White"
-      layout="topleft"
-      name="show_physics"
-      top_pad="8">
-    </check_box>
+      name="show_physics"/>
     <check_box
-      follows="top|left"
+      follows="right|bottom"
       label="Textures"
       label_text.text_color="White"
       layout="topleft"
       name="show_textures"
-      top_pad="8">
-    </check_box>
+      left_pad="0"/>
     <check_box
-      follows="top|left"
-      label="Skin weights"
+      follows="right|bottom"
+      label="Weights"
       label_text.text_color="White"
       layout="topleft"
       name="show_skin_weight"
-      top_pad="8">
-    </check_box>
+      left_pad="0"/>
     <check_box
-      follows="top|left"
+      follows="right|bottom"
       label="Joints"
       label_text.text_color="White"
       layout="topleft"
       name="show_joint_positions"
-      top_pad="8">
-    </check_box>
+      left_pad="0"/>
     <text
-      follows="top|left"
+      follows="right|bottom"
       layout="topleft"
       left="2"
       name="physics_explode_label"
@@ -1453,12 +1593,13 @@
     </text>
     <slider
       name="physics_explode"
-      follows="top|left"
-      top="100"
-      left="0"
+      follows="right|bottom"
+      valign="center"
+      top="15"
+      left="80"
       min_val="0.0"
       max_val="3.0"
       height="20"
-      width="150"/>
-</panel>
+      width="120"/>
+  </panel>
 </floater>