diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 523ea8a3949ba714f40375484c3e5811cd247bad..c4018cd79c6a5744c32a4f72c9070b666d360aa6 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -204,6 +204,7 @@ set(viewer_SOURCE_FILES
     llfloatermediasettings.cpp
     llfloatermemleak.cpp
     llfloatermodelpreview.cpp
+    llfloatermodeluploadbase.cpp
     llfloatermodelwizard.cpp
     llfloaternamedesc.cpp
     llfloaternotificationsconsole.cpp
@@ -496,6 +497,7 @@ set(viewer_SOURCE_FILES
     lltranslate.cpp
     lluilistener.cpp
     lluploaddialog.cpp
+    lluploadfloaterobservers.cpp
     llurl.cpp
     llurldispatcher.cpp
     llurldispatcherlistener.cpp
@@ -758,6 +760,7 @@ set(viewer_HEADER_FILES
     llfloatermediasettings.h
     llfloatermemleak.h
     llfloatermodelpreview.h
+    llfloatermodeluploadbase.h
     llfloatermodelwizard.h
     llfloaternamedesc.h
     llfloaternotificationsconsole.h
@@ -1047,6 +1050,7 @@ set(viewer_HEADER_FILES
     lluiconstants.h
     lluilistener.h
     lluploaddialog.h
+    lluploadfloaterobservers.h
     llurl.h
     llurldispatcher.h
     llurldispatcherlistener.h
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index d000248e8ed2cdd1fa5b65040e590c7621330008..ea85dc0052bfe2ce3cd90e4db2f35182244c5aed 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -71,6 +71,7 @@
 #include "llmatrix4a.h"
 #include "llmenubutton.h"
 #include "llmeshrepository.h"
+#include "llnotificationsutil.h"
 #include "llsdutil_math.h"
 #include "lltextbox.h"
 #include "lltoolmgr.h"
@@ -353,7 +354,9 @@ void LLMeshFilePicker::notify(const std::string& filename)
 // LLFloaterModelPreview()
 //-----------------------------------------------------------------------------
 LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) :
-LLFloater(key)
+LLFloaterModelUploadBase(key),
+mUploadBtn(NULL),
+mCalculateBtn(NULL)
 {
 	sInstance = this;
 	mLastMouseX = 0;
@@ -422,8 +425,6 @@ BOOL LLFloaterModelPreview::postBuild()
 	
 	childDisable("ok_btn");
 
-	childSetCommitCallback("confirm_checkbox", refresh, this);
-
 	mViewOptionMenuButton = getChild<LLMenuButton>("options_gear_btn");
 
 	mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2));
@@ -473,6 +474,13 @@ BOOL LLFloaterModelPreview::postBuild()
 		}
 	}
 
+	mUploadBtn = getChild<LLButton>("ok_btn");
+	mCalculateBtn = getChild<LLButton>("calculate_btn");
+
+	mCalculateBtn->setClickedCallback(boost::bind(&LLFloaterModelPreview::onClickCalculateBtn, this));
+
+	toggleCalculateButton(true);
+
 	return TRUE;
 }
 
@@ -551,6 +559,26 @@ void LLFloaterModelPreview::loadModel(S32 lod, const std::string& file_name)
 	mModelPreview->loadModel(file_name, lod);
 }
 
+void LLFloaterModelPreview::onClickCalculateBtn()
+{
+	childSetTextArg("weights", "[EQ]", llformat("%d", mModelPreview->mResourceCost));
+
+	mModelPreview->rebuildUploadData();
+
+	bool upload_skinweights = childGetValue("upload_skin").asBoolean();
+	bool upload_joint_positions = childGetValue("upload_joints").asBoolean();
+
+	mUploadModelUrl.clear();
+	LLMeshUploadThread* thread = new LLMeshUploadThread(mModelPreview->mUploadData, mModelPreview->mPreviewScale,
+			childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mUploadModelUrl, false);
+
+	thread->setObserverHandle(getWholeModelFeeObserverHandle());
+
+	gMeshRepo.mUploadWaitList.push_back(thread);
+
+	toggleCalculateButton(false);
+}
+
 //static
 void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata)
 {
@@ -561,7 +589,8 @@ void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata)
 		return;
 	}
 
-	fp->mModelPreview->calcResourceCost();
+	fp->toggleCalculateButton(true);
+
 	fp->mModelPreview->refresh();
 }
 //static
@@ -573,7 +602,9 @@ void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata )
 	{
 		return;
 	}
-	fp->mModelPreview->calcResourceCost();
+
+	fp->toggleCalculateButton(true);
+
 	fp->mModelPreview->refresh();
 }
 
@@ -623,7 +654,8 @@ void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata)
 		return;
 	}
 	
-	fp->mModelPreview->calcResourceCost();
+	fp->toggleCalculateButton(true);
+
 	fp->mModelPreview->refresh();
 	fp->mModelPreview->resetPreviewTarget();
 	fp->mModelPreview->clearBuffers();
@@ -653,6 +685,7 @@ void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userda
 {
 	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
 
+	fp->toggleCalculateButton(true);
 	fp->mModelPreview->generateNormals();
 }
 
@@ -676,6 +709,8 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
 void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata)
 {
 	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+
+	fp->toggleCalculateButton(true);
 	fp->mModelPreview->onLODParamCommit(false);
 }
 
@@ -683,6 +718,7 @@ void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata)
 void LLFloaterModelPreview::onLODParamCommitTriangleLimit(LLUICtrl* ctrl, void* userdata)
 {
 	LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata;
+	fp->toggleCalculateButton(true);
 	fp->mModelPreview->onLODParamCommit(true);
 }
 
@@ -714,6 +750,8 @@ void LLFloaterModelPreview::draw()
 		}
 	}
 
+	childSetEnabled("ok_btn", mHasUploadPerm);
+
 	childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost));
 	childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size()));
 
@@ -871,6 +909,12 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return TRUE;
 }
 
+/*virtual*/
+void LLFloaterModelPreview::onOpen(const LLSD& key)
+{
+	requestAgentUploadPermissions();
+}
+
 //static
 void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)
 {
@@ -2926,8 +2970,7 @@ U32 LLModelPreview::calcResourceCost()
 
 	if (mFMP && mModelLoader)
 	{
-		const BOOL confirmed_checkbox = mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean();
-		if ( getLoadState() < LLModelLoader::ERROR_PARSING && confirmed_checkbox )
+		if ( getLoadState() < LLModelLoader::ERROR_PARSING)
 		{
 			mFMP->childEnable("ok_btn");
 		}
@@ -3038,8 +3081,6 @@ void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost,
 	childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x));
 	childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", y));
 	childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z));
-	childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost));
-	childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost));	
 }
 
 
@@ -3069,8 +3110,7 @@ void LLModelPreview::rebuildUploadData()
 
 	F32 max_scale = 0.f;
 
-	const BOOL confirmed_checkbox = mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean();
-	if ( mBaseScene.size() > 0 && confirmed_checkbox )
+	if ( mBaseScene.size() > 0)
 	{
 		mFMP->childEnable("ok_btn");
 	}
@@ -3476,8 +3516,7 @@ void LLModelPreview::loadModelCallback(S32 lod)
 	}
 
 	mLoading = false;
-	if (mFMP)
-		mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->set(FALSE);
+
 	refresh();
 
 	mModelLoadedSignal();
@@ -4185,8 +4224,7 @@ void LLModelPreview::updateStatusMessages()
 		}
 	}
 
-	const BOOL confirmed_checkbox = mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean();
-	if ( upload_ok && !errorStateFromLoader && skinAndRigOk && !has_degenerate && confirmed_checkbox)
+	if ( upload_ok && !errorStateFromLoader && skinAndRigOk && !has_degenerate)
 	{
 		mFMP->childEnable("ok_btn");
 	}
@@ -5314,7 +5352,7 @@ void LLFloaterModelPreview::onUpload(void* user_data)
 	mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions);
 
 	gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale,
-						  mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions);
+						  mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mp->mUploadModelUrl);
 
 	mp->closeFloater(false);
 }
@@ -5330,6 +5368,7 @@ void LLFloaterModelPreview::onClearMaterials(void* user_data)
 //static
 void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data)
 {
+	sInstance->toggleCalculateButton(true);
 	sInstance->mModelPreview->mDirty = true;
 }
 
@@ -5382,6 +5421,34 @@ void LLFloaterModelPreview::setStatusMessage(const std::string& msg)
 	mStatusMessage = msg;
 }
 
+void LLFloaterModelPreview::toggleCalculateButton(bool visible)
+{
+	mCalculateBtn->setVisible(visible);
+	mUploadBtn->setVisible(!visible);
+	mUploadBtn->setEnabled(mHasUploadPerm);
+
+	if (visible)
+	{
+		std::string tbd = getString("tbd");
+		childSetTextArg("weights", "[EQ]", tbd);
+		childSetTextArg("weights", "[PH]", tbd);
+		childSetTextArg("weights", "[FEE]", tbd);
+	}
+}
+
+void LLFloaterModelPreview::onModelPhysicsFeeReceived(F64 physics, S32 fee, std::string upload_url)
+{
+	mUploadModelUrl = upload_url;
+	childSetTextArg("weights", "[PH]", llformat("%.3f", physics));
+	childSetTextArg("weights", "[FEE]", llformat("%d", fee));
+	childSetVisible("weights", true);
+}
+
+void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason)
+{
+	llwarns << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << llendl;
+}
+
 S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)
 {
 	if (mContinue)
@@ -5421,3 +5488,20 @@ void LLFloaterModelPreview::DecompRequest::completed()
 		llassert(sInstance->mCurRequest.find(this) == sInstance->mCurRequest.end());
 	}
 }
+
+void LLFloaterModelPreview::onPermReceived(const LLSD& result)
+{
+	std::string upload_status = result["mesh_upload_status"].asString();
+	mHasUploadPerm = "valid" == upload_status;
+
+	mUploadBtn->setEnabled(mHasUploadPerm);
+	getChild<LLTextBox>("warning_title")->setVisible(mHasUploadPerm);
+	getChild<LLTextBox>("warning_message")->setVisible(mHasUploadPerm);
+}
+
+void LLFloaterModelPreview::setPermErrorStatus(U32 status, const std::string& reason)
+{
+	llwarns << "LLFloaterModelPreview::setPermErrors(" << status << " : " << reason << ")" << llendl;
+
+	LLNotificationsUtil::add("MeshUploadPermError");
+}
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index ab50890fb9a1b9ef268022471cb47f0fb588bb4b..62878812c355ddd0ec3885e7f59ef62b3e5caddd 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -140,7 +140,7 @@ class LLModelLoader : public LLThread
 	static bool isAlive(LLModelLoader* loader) ;
 };
 
-class LLFloaterModelPreview : public LLFloater
+class LLFloaterModelPreview : public LLFloaterModelUploadBase
 {
 public:
 	
@@ -167,6 +167,8 @@ class LLFloaterModelPreview : public LLFloater
 	BOOL handleHover(S32 x, S32 y, MASK mask);
 	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); 
 	
+	/*virtual*/ void onOpen(const LLSD& key);
+
 	static void onMouseCaptureLostModelPreview(LLMouseHandler*);
 	static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
 
@@ -194,6 +196,16 @@ class LLFloaterModelPreview : public LLFloater
 	void enableViewOption(const std::string& option);
 	void disableViewOption(const std::string& option);
 
+	// shows warning message if agent has no permissions to upload model
+	/*virtual*/ void onPermReceived(const LLSD& result);
+
+	// called when error occurs during permissions request
+	/*virtual*/ void setPermErrorStatus(U32 status, const std::string& reason);
+
+	/*virtual*/ void onModelPhysicsFeeReceived(F64 physics, S32 fee, std::string upload_url);
+
+	/*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason);
+
 protected:
 	friend class LLModelPreview;
 	friend class LLMeshFilePicker;
@@ -259,6 +271,14 @@ class LLFloaterModelPreview : public LLFloater
 	LLToggleableMenu* mViewOptionMenu;
 	LLMutex* mStatusLock;
 
+private:
+	void onClickCalculateBtn();
+
+	// Toggles between "Calculate weights & fee" and "Upload" buttons.
+	void toggleCalculateButton(bool visible);
+
+	LLButton* mUploadBtn;
+	LLButton* mCalculateBtn;
 };
 
 class LLMeshFilePicker : public LLFilePickerThread
diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..56c6447792e82edd3256348b5cf7d7b3213ffe56
--- /dev/null
+++ b/indra/newview/llfloatermodeluploadbase.cpp
@@ -0,0 +1,56 @@
+/**
+ * @file llfloatermodeluploadbase.cpp
+ * @brief LLFloaterUploadModelBase class definition
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloatermodeluploadbase.h"
+#include "llagent.h"
+#include "llviewerregion.h"
+#include "llnotificationsutil.h"
+
+LLFloaterModelUploadBase::LLFloaterModelUploadBase(const LLSD& key)
+:LLFloater(key),
+ mHasUploadPerm(false)
+{
+}
+
+void LLFloaterModelUploadBase::requestAgentUploadPermissions()
+{
+	std::string capability = "MeshUploadFlag";
+	std::string url = gAgent.getRegion()->getCapability(capability);
+
+	if (!url.empty())
+	{
+		llinfos<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <<llendl;
+		LLHTTPClient::get(url, new LLUploadModelPremissionsResponder(getPermObserverHandle()));
+	}
+	else
+	{
+		LLSD args;
+		args["CAPABILITY"] = capability;
+		LLNotificationsUtil::add("RegionCapabilityRequestError", args);
+	}
+}
diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4e300563dc1582984453955bf418da4a2a5c26d
--- /dev/null
+++ b/indra/newview/llfloatermodeluploadbase.h
@@ -0,0 +1,57 @@
+/**
+ * @file llfloatermodeluploadbase.h
+ * @brief LLFloaterUploadModelBase class declaration
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LLFLOATERMODELUPLOADBASE_H_
+#define LLFLOATERMODELUPLOADBASE_H_
+
+#include "lluploadfloaterobservers.h"
+
+class LLFloaterModelUploadBase : public LLFloater, public LLUploadPermissionsObserver, public LLWholeModelFeeObserver
+{
+public:
+
+	LLFloaterModelUploadBase(const LLSD& key);
+
+	virtual ~LLFloaterModelUploadBase(){};
+
+	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason){};
+
+	virtual void onPermissionsReceived(const LLSD& result){};
+
+	virtual void onModelPhysicsFeeReceived(F64 physics, S32 fee, std::string upload_url){};
+
+	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason){};
+
+protected:
+
+	// requests agent's permissions to upload model
+	void requestAgentUploadPermissions();
+
+	std::string mUploadModelUrl;
+	bool mHasUploadPerm;
+};
+
+#endif /* LLFLOATERMODELUPLOADBASE_H_ */
diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp
index 97b54c4c748c94a7b0db2b1a6f76ab2df9c5fde3..3c0ce96864bfa1aad6a22f262e0968b14e25f7a1 100644
--- a/indra/newview/llfloatermodelwizard.cpp
+++ b/indra/newview/llfloatermodelwizard.cpp
@@ -52,7 +52,7 @@ static	const std::string stateNames[]={
 static void swap_controls(LLUICtrl* first_ctrl, LLUICtrl* second_ctrl, bool first_ctr_visible);
 
 LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key)
-	: LLFloater(key)
+	: LLFloaterModelUploadBase(key)
 	 ,mRecalculateGeometryBtn(NULL)
 	 ,mRecalculatePhysicsBtn(NULL)
 	 ,mRecalculatingPhysicsBtn(NULL)
@@ -396,6 +396,13 @@ BOOL LLFloaterModelWizard::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return TRUE;
 }
 
+
+/*virtual*/
+void LLFloaterModelWizard::onOpen(const LLSD& key)
+{
+	requestAgentUploadPermissions();
+}
+
 void LLFloaterModelWizard::initDecompControls()
 {
 	LLSD key;
@@ -453,6 +460,15 @@ void LLFloaterModelWizard::initDecompControls()
 	mDecompParams["Simplify Method"] = 0; // set it to retain %
 }
 
+void LLFloaterModelWizard::onPermReceived(const LLSD& result)
+{
+}
+
+void LLFloaterModelWizard::setPermErrorStatus(U32 status, const std::string& reason)
+{
+	llwarns << "LLFloaterModelWizard::setPermErrors(" << status << " : " << reason << ")" << llendl;
+}
+
 //static
 void LLFloaterModelWizard::executePhysicsStage(std::string stage_name)
 {
@@ -623,7 +639,7 @@ void LLFloaterModelWizard::onUpload()
 	mModelPreview->rebuildUploadData();
 	
 	gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, 
-						  true, false, false);
+						  true, false, false, mUploadModelUrl, true);
 	
 	setState(UPLOAD);
 	
diff --git a/indra/newview/llfloatermodelwizard.h b/indra/newview/llfloatermodelwizard.h
index 409451e1b6a2fc69d1ee324a5e1e89ce70f04292..9930e0c4e64551c134d2abfff209c2abb62b5a00 100644
--- a/indra/newview/llfloatermodelwizard.h
+++ b/indra/newview/llfloatermodelwizard.h
@@ -30,12 +30,13 @@
 #include "llmeshrepository.h"
 #include "llmodel.h"
 #include "llthread.h"
+#include "llfloatermodeluploadbase.h"
 
 
 class LLModelPreview;
 
 
-class LLFloaterModelWizard : public LLFloater
+class LLFloaterModelWizard : public LLFloaterModelUploadBase
 {
 public:
 	
@@ -62,12 +63,20 @@ class LLFloaterModelWizard : public LLFloater
 	BOOL handleMouseDown(S32 x, S32 y, MASK mask);
 	BOOL handleMouseUp(S32 x, S32 y, MASK mask);
 	BOOL handleHover(S32 x, S32 y, MASK mask);
-	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); 
+	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+
+	/*virtual*/ void onOpen(const LLSD& key);
 
 	void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost);
 	void modelLoadedCallback();
 	void initDecompControls();
 	
+	// shows warning message if agent has no permissions to upload model
+	void onPermReceived(const LLSD& result);
+
+	// called when error occurs during permissions request
+	void setPermErrorStatus(U32 status, const std::string& reason);
+
 	const LLRect& getPreviewRect() const { return mPreviewRect; }
 
 	LLPhysicsDecomp::decomp_params mDecompParams;
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 4da5da94934d550dabd8b6f4647502f5158d2e78..49bcbf860a59cc4b02b3d65d57d1657b1fe10507 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -62,6 +62,7 @@
 #include "llinventorymodel.h"
 #include "llfoldertype.h"
 #include "llviewerparcelmgr.h"
+#include "lluploadfloaterobservers.h"
 
 #include "boost/lexical_cast.hpp"
 
@@ -554,10 +555,12 @@ class LLWholeModelFeeResponder: public LLCurl::Responder
 {
 	LLMeshUploadThread* mThread;
 	LLSD mModelData;
+	LLHandle<LLWholeModelFeeObserver> mObserverHandle;
 public:
-	LLWholeModelFeeResponder(LLMeshUploadThread* thread, LLSD& model_data):
+	LLWholeModelFeeResponder(LLMeshUploadThread* thread, LLSD& model_data, LLHandle<LLWholeModelFeeObserver> observer_handle):
 		mThread(thread),
-		mModelData(model_data)
+		mModelData(model_data),
+		mObserverHandle(observer_handle)
 	{
 	}
 	virtual void completed(U32 status,
@@ -573,11 +576,21 @@ class LLWholeModelFeeResponder: public LLCurl::Responder
 		llinfos << "completed" << llendl;
 		mThread->mPendingUploads--;
 		dump_llsd_to_file(cc,make_dump_name("whole_model_fee_response_",dump_num));
+
 		if (isGoodStatus(status) &&
 			cc["state"].asString() == "upload")
 		{
 			llinfos << "fee request succeeded" << llendl;
-			mThread->mWholeModelUploadURL = cc["uploader"].asString(); 
+			mThread->mWholeModelUploadURL = cc["uploader"].asString();
+
+			LLWholeModelFeeObserver* observer = mObserverHandle.get();
+			if (observer)
+			{
+				S32 fee = cc["upload_price"].asInteger();
+				F64 phys = cc["data"]["physics_cost"].asReal();
+
+				observer->onModelPhysicsFeeReceived(phys, fee, mThread->mWholeModelUploadURL);
+			}
 		}
 		else
 		{
@@ -1376,9 +1389,11 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32
 }
 
 LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures,
-										bool upload_skin, bool upload_joints)
+										bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload)
 : LLThread("mesh upload"),
-	mDiscarded(FALSE)
+	mDiscarded(FALSE),
+	mDoUpload(do_upload),
+	mWholeModelUploadURL(upload_url)
 {
 	mInstanceList = data;
 	mUploadTextures = upload_textures;
@@ -1456,7 +1471,14 @@ BOOL LLMeshUploadThread::isDiscarded()
 
 void LLMeshUploadThread::run()
 {
-	doWholeModelUpload();
+	if (mDoUpload)
+	{
+		doWholeModelUpload();
+	}
+	else
+	{
+		requestWholeModelFee();
+	}
 }
 
 void dump_llsd_to_file(const LLSD& content, std::string filename)
@@ -1650,69 +1672,54 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
 	dest = result;
 }
 
-void LLMeshUploadThread::doWholeModelUpload()
+void LLMeshUploadThread::queueUpModels()
 {
-	dump_num++;
-	
-	mCurlRequest = new LLCurlRequest();	
-
-	// Queue up models for hull generation (viewer-side)
 	for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
-	{
-		LLMeshUploadData data;
-		data.mBaseModel = iter->first;
-
-		LLModelInstance& instance = *(iter->second.begin());
-
-		for (S32 i = 0; i < 5; i++)
 		{
-			data.mModel[i] = instance.mLOD[i];
-		}
+			LLMeshUploadData data;
+			data.mBaseModel = iter->first;
 
-		//queue up models for hull generation
-		LLModel* physics = NULL;
+			LLModelInstance& instance = *(iter->second.begin());
 
-		if (data.mModel[LLModel::LOD_PHYSICS].notNull())
-		{
-			physics = data.mModel[LLModel::LOD_PHYSICS];
-		}
-		else if (data.mModel[LLModel::LOD_MEDIUM].notNull())
-		{
-			physics = data.mModel[LLModel::LOD_MEDIUM];
-		}
-		else
-		{
-			physics = data.mModel[LLModel::LOD_HIGH];
-		}
+			for (S32 i = 0; i < 5; i++)
+			{
+				data.mModel[i] = instance.mLOD[i];
+			}
 
-		llassert(physics != NULL);
-		
-		DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this);
-		if(request->isValid())
-		{
-			gMeshRepo.mDecompThread->submitRequest(request);
-		}		
-	}
+			//queue up models for hull generation
+			LLModel* physics = NULL;
 
-	while (!mPhysicsComplete)
-	{
-		apr_sleep(100);
-	}
+			if (data.mModel[LLModel::LOD_PHYSICS].notNull())
+			{
+				physics = data.mModel[LLModel::LOD_PHYSICS];
+			}
+			else if (data.mModel[LLModel::LOD_MEDIUM].notNull())
+			{
+				physics = data.mModel[LLModel::LOD_MEDIUM];
+			}
+			else
+			{
+				physics = data.mModel[LLModel::LOD_HIGH];
+			}
 
-	LLSD model_data;
-	wholeModelToLLSD(model_data,false);
-	dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num));
+			llassert(physics != NULL);
 
-	mPendingUploads++;
-	LLCurlRequest::headers_t headers;
-	mCurlRequest->post(mWholeModelFeeCapability, headers, model_data,
-					   new LLWholeModelFeeResponder(this,model_data), mMeshUploadTimeOut);
+			DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this);
+			if(request->isValid())
+			{
+				gMeshRepo.mDecompThread->submitRequest(request);
+			}
+		}
 
-	do
-	{
-		mCurlRequest->process();
-	} while (mCurlRequest->getQueued() > 0);
+		while (!mPhysicsComplete)
+		{
+			apr_sleep(100);
+		}
+}
 
+void LLMeshUploadThread::doWholeModelUpload()
+{
+	mCurlRequest = new LLCurlRequest();
 
 	if (mWholeModelUploadURL.empty())
 	{
@@ -1720,12 +1727,15 @@ void LLMeshUploadThread::doWholeModelUpload()
 	}
 	else
 	{
+		queueUpModels();
+
 		LLSD full_model_data;
 		wholeModelToLLSD(full_model_data, true);
 		LLSD body = full_model_data["asset_resources"];
 		dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num));
+		LLCurlRequest::headers_t headers;
 		mCurlRequest->post(mWholeModelUploadURL, headers, body,
-						   new LLWholeModelUploadResponder(this, model_data), mMeshUploadTimeOut);
+						   new LLWholeModelUploadResponder(this, full_model_data), mMeshUploadTimeOut);
 		do
 		{
 			mCurlRequest->process();
@@ -1739,6 +1749,35 @@ void LLMeshUploadThread::doWholeModelUpload()
 	mFinished = true;
 }
 
+void LLMeshUploadThread::requestWholeModelFee()
+{
+	dump_num++;
+
+	mCurlRequest = new LLCurlRequest();
+
+	queueUpModels();
+
+	LLSD model_data;
+	wholeModelToLLSD(model_data,false);
+	dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num));
+
+	mPendingUploads++;
+	LLCurlRequest::headers_t headers;
+	mCurlRequest->post(mWholeModelFeeCapability, headers, model_data,
+					   new LLWholeModelFeeResponder(this,model_data, mObserverHandle), mMeshUploadTimeOut);
+
+	do
+	{
+		mCurlRequest->process();
+	} while (mCurlRequest->getQueued() > 0);
+
+	delete mCurlRequest;
+	mCurlRequest = NULL;
+
+	// Currently a no-op.
+	mFinished = true;
+}
+
 void LLMeshUploadThread::uploadModel(LLMeshUploadData& data)
 { //called from arbitrary thread
 	{
@@ -2836,9 +2875,9 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
 
 
 void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
-									bool upload_skin, bool upload_joints)
+									bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload)
 {
-	LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints);
+	LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url, do_upload);
 	mUploadWaitList.push_back(thread);
 }
 
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index f56734a7de4c83df1cb2a9489c6f341d84521420..03993c6f2cfd00a9e0120c20f0324679887d329f 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -36,6 +36,7 @@
 #define LLCONVEXDECOMPINTER_STATIC 1
 
 #include "llconvexdecomposition.h"
+#include "lluploadfloaterobservers.h"
 
 class LLVOVolume;
 class LLMeshResponder;
@@ -412,7 +413,7 @@ class LLMeshUploadThread : public LLThread
 	std::map<LLViewerFetchedTexture*, LLTextureUploadData> mTextureMap;
 
 	LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures,
-			bool upload_skin, bool upload_joints);
+			bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true);
 	~LLMeshUploadThread();
 
 	void uploadTexture(LLTextureUploadData& data);
@@ -433,7 +434,11 @@ class LLMeshUploadThread : public LLThread
 	void discard() ;
 	BOOL isDiscarded();
 
+	// Queue up models for hull generation (viewer-side)
+	void queueUpModels();
+
 	void doWholeModelUpload();
+	void requestWholeModelFee();
 
 	void wholeModelToLLSD(LLSD& dest, bool include_textures);
 
@@ -441,6 +446,12 @@ class LLMeshUploadThread : public LLThread
 							 LLVector3& result_pos,
 							 LLQuaternion& result_rot,
 							 LLVector3& result_scale);
+
+	void setObserverHandle(LLHandle<LLWholeModelFeeObserver> observer_handle) { mObserverHandle = observer_handle; }
+
+private:
+	LLHandle<LLWholeModelFeeObserver> mObserverHandle;
+	bool mDoUpload; // if FALSE only model data will be requested, otherwise the model will be uploaded
 };
 
 class LLMeshRepository
@@ -491,7 +502,7 @@ class LLMeshRepository
 	LLSD& getMeshHeader(const LLUUID& mesh_id);
 
 	void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
-			bool upload_skin, bool upload_joints);
+			bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true);
 
 	S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
 
diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2d418ee00de77402fdfcbdc52bc8fd9fa4c75533
--- /dev/null
+++ b/indra/newview/lluploadfloaterobservers.cpp
@@ -0,0 +1,56 @@
+/**
+ * @file lluploadfloaterobservers.cpp
+ * @brief LLUploadModelPremissionsResponder definition
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lluploadfloaterobservers.h"
+
+LLUploadModelPremissionsResponder::LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer)
+:mObserverHandle(observer)
+{
+}
+
+void LLUploadModelPremissionsResponder::error(U32 status, const std::string& reason)
+{
+	llwarns << "LLUploadModelPremissionsResponder::error("<< status << ": " << reason << ")" << llendl;
+
+	LLUploadPermissionsObserver* observer = mObserverHandle.get();
+
+	if (observer)
+	{
+		observer->setPermErrorStatus(status, reason);
+	}
+}
+
+void LLUploadModelPremissionsResponder::result(const LLSD& content)
+{
+	LLUploadPermissionsObserver* observer = mObserverHandle.get();
+
+	if (observer)
+	{
+		observer->onPermReceived(content);
+	}
+}
diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h
new file mode 100644
index 0000000000000000000000000000000000000000..f27687e12e4f0c433ec5041d74d120a7cce935df
--- /dev/null
+++ b/indra/newview/lluploadfloaterobservers.h
@@ -0,0 +1,79 @@
+/**
+ * @file lluploadfloaterobservers.h
+ * @brief LLUploadModelPremissionsResponder declaration
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LLUPLOADFLOATEROBSERVERS_H_
+#define LLUPLOADFLOATEROBSERVERS_H_
+
+#include "llfloater.h"
+#include "llhttpclient.h"
+#include "llhandle.h"
+
+class LLUploadPermissionsObserver
+{
+public:
+
+	LLUploadPermissionsObserver(){mUploadPermObserverHandle.bind(this);}
+	virtual ~LLUploadPermissionsObserver() {}
+
+	virtual void onPermReceived(const LLSD& result) = 0;
+	virtual void setPermErrorStatus(U32 status, const std::string& reason) = 0;
+
+	LLHandle<LLUploadPermissionsObserver> getPermObserverHandle() const {return mUploadPermObserverHandle;}
+
+protected:
+	LLRootHandle<LLUploadPermissionsObserver> mUploadPermObserverHandle;
+};
+
+class LLWholeModelFeeObserver
+{
+public:
+	LLWholeModelFeeObserver() { mWholeModelFeeObserverHandle.bind(this); }
+	virtual ~LLWholeModelFeeObserver() {}
+
+	virtual void onModelPhysicsFeeReceived(F64 physics, S32 fee, std::string upload_url) = 0;
+	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0;
+
+	LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; }
+
+protected:
+	LLRootHandle<LLWholeModelFeeObserver> mWholeModelFeeObserverHandle;
+};
+
+class LLUploadModelPremissionsResponder : public LLHTTPClient::Responder
+{
+public:
+
+	LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer);
+
+	void error(U32 status, const std::string& reason);
+
+	void result(const LLSD& content);
+
+private:
+	LLHandle<LLUploadPermissionsObserver> mObserverHandle;
+};
+
+#endif /* LLUPLOADFLOATEROBSERVERS_H_ */
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 f58595b3c57246ce86a918f1f1b570477b9bc2f3..ab46a13098dd9e2e95b5799faf72d8b30850fcf4 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -23,6 +23,7 @@
   <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>
   
 
   <text left="15" bottom="25" follows="top|left" height="15" name="name_label">
@@ -70,43 +71,29 @@
     width="290"
     height="290"
     follows="all"/>
-
-  <text bottom_delta="25" left="25" width="100" follows="bottom|left">Upload Details</text>
-  <panel top_pad="5" border="true" left="15" width="290" height="70" follows="bottom|left"
-          bevel_style="none" bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3">
-    <text left="25" follows="bottom|left" width="140" height="15" name="streaming cost">
-      Resource Cost: [COST]
-    </text>
-    <text left="25" top_pad="5" width="140" follows="bottom|left" height="15" name="physics cost">
-      Physics Cost: [COST]
+    
+    <text
+     follows="top|left"
+     font="SansSerif"
+     left_delta="0"
+     name="warning_title"
+     text_color="Yellow"
+     top_pad="10"
+     visible="false">
+     WARNING:
     </text>
-    <text left="25" top_pad="5" follows="bottom|left" height="15" name="upload fee">
-      Upload Fee: N/A
+    <text
+     follows="top|left"
+     text_color="White"
+     height="50"
+     left_delta="0"
+     name="warning_message"
+     parse_urls="true"
+     top_pad="5"
+     wrap="true"
+     visible="false">
+     You will not be able to complete the final upload of this model to the Second Life servers. Find out how to get certifed for mesh model uploads.
     </text>
-  </panel>
-
-  <check_box
-	height="16"
-	left_delta="0"
-	name="confirm_checkbox"
-	top_pad="15"
-	follows="bottom|left"
-	width="16" />
-
-  <text
-	height="30"
-	width="570"
-	word_wrap="true" 
-	left_delta="25"
-	top_delta="0">I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more]</text>
-  <text left="10" bottom="540" width="290" height="15" follows="bottom|left|right" name="status">[STATUS]</text>
-
-  
-  <button bottom="540" left="300"  follows="bottom|right" height="20" label="Defaults"
-	     width="80" name="reset_btn" tool_tip="Reset to defaults"/>
-  <button bottom="540" left="430"  follows="bottom|right" height="20" label="Upload"
-	     width="80" name="ok_btn" tool_tip="Upload to simulator"/>
-  <button left_pad="10" follows="right|bottom" height="20" width="80" label="Cancel" name="cancel_btn"/>
 
   <tab_container
     follows="right|top|bottom"
@@ -416,6 +403,24 @@
 
     </panel>
   </tab_container>
+
+  <text
+	height="16"
+	left="310"
+	name="weights"
+	width="300"
+	word_wrap="true" 
+	top_pad="7">
+	    Prim equivs: [EQ] Physics: [PH] Upload fee: [FEE] L$
+  </text>
+  
+  <button bottom="540" left="10"  follows="bottom|left" height="20" label="Set to defaults"
+	     width="100" name="reset_btn" tool_tip="Set to defaults"/>
+  <button left="310"  follows="bottom|right" height="20" label="Calculate weights &amp; fee"
+	     width="150" name="calculate_btn" tool_tip="Calculate weights &amp; fee" top_delta="0"/>
+  <button bottom="540" left="310"  follows="bottom|right" height="20" label="Upload"
+	     width="80" name="ok_btn" tool_tip="Upload to simulator" visible="false"/>
+  <button right="-10" follows="right|bottom" height="20" width="80" label="Cancel" name="cancel_btn" top_delta="0"/>
   
   <!--
   <button bottom_delta="0" left="10" width="120" name="auto fill" label="Generate LOD" tool_tip="Automatically generate levels of detail"/>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 09105c1d287129f95ab51e7142c152b26336d9a0..d3d78e63b06528a389b93f093f5cb0308004078e 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6828,6 +6828,20 @@ Select residents to share with.
 See the log file for details.
   </notification>
    
+   <notification
+    name="MeshUploadPermError"
+    icon="alert.tga"
+    type="alert">
+    Error while requesting mesh upload permissons.
+  </notification>
+  
+  <notification
+    name="RegionCapabilityRequestError"
+    icon="alert.tga"
+    type="alert">
+    Could not get region capability &apos;[CAPABILITY]&apos;.
+  </notification>
+   
   <notification
    icon="notifytip.tga"
    name="ShareItemsConfirmation"