diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index b45ead92d30b1bd99b93090b6b1c9d9e8bedaa24..703584ed62c178d268c292c369182df6bb103fa3 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -404,11 +404,6 @@ S32  LLPrimitive::setTEFullbright(const U8 index, const U8 fullbright)
 	return mTextureList.setFullbright(index, fullbright);
 }
 
-S32 LLPrimitive::setTERenderableTarget(const U8 te, const LLTextureEntry::eRenderableTarget target)
-{
-    return mTextureList.setRenderableTarget(te, target);
-}
-
 S32  LLPrimitive::setTEMediaFlags(const U8 index, const U8 media_flags)
 {
 	return mTextureList.setMediaFlags(index, media_flags);
@@ -1828,6 +1823,40 @@ bool LLLightParams::fromLLSD(LLSD& sd)
 
 //============================================================================
 
+LLMirrorParams::LLMirrorParams()
+{
+    mType = PARAMS_MIRROR;
+}
+
+BOOL LLMirrorParams::pack(LLDataPacker &dp) const
+{
+    return TRUE;
+}
+
+BOOL LLMirrorParams::unpack(LLDataPacker &dp)
+{
+    return TRUE;
+}
+
+bool LLMirrorParams::operator==(const LLNetworkData& data) const
+{
+    if (data.mType != PARAMS_REFLECTION_PROBE)
+    {
+        return false;
+    }
+    return true;
+}
+
+void LLMirrorParams::copy(const LLNetworkData& data)
+{
+    const LLMirrorParams *param = (LLMirrorParams*)&data;
+    mType = param->mType;
+}
+
+//============================================================================
+
+//============================================================================
+
 LLReflectionProbeParams::LLReflectionProbeParams()
 {
     mType = PARAMS_REFLECTION_PROBE;
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 520c7c7ac8348d7f6360903d9ceb0fccedeaa394..1af9bca42ebd9b403df581518851008da2a287bd 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -109,6 +109,7 @@ class LLNetworkData
         PARAMS_EXTENDED_MESH = 0x70,
         PARAMS_RENDER_MATERIAL = 0x80,
         PARAMS_REFLECTION_PROBE = 0x90,
+        PARAMS_MIRROR = 0x100,
 	};
 	
 public:
@@ -172,6 +173,16 @@ class LLLightParams : public LLNetworkData
 	F32 getCutoff() const					{ return mCutoff; }
 };
 
+class LLMirrorParams : public LLNetworkData
+{
+public:
+    LLMirrorParams();
+    /*virtual*/ BOOL pack(LLDataPacker &dp) const;
+    /*virtual*/ BOOL unpack(LLDataPacker &dp);
+    /*virtual*/ bool operator==(const LLNetworkData& data) const;
+    /*virtual*/ void copy(const LLNetworkData& data);
+};
+
 extern const F32 REFLECTION_PROBE_MIN_AMBIANCE;
 extern const F32 REFLECTION_PROBE_MAX_AMBIANCE;
 extern const F32 REFLECTION_PROBE_DEFAULT_AMBIANCE;
@@ -485,7 +496,6 @@ class LLPrimitive : public LLXform
 	virtual S32 setTETexGen(const U8 te, const U8 texgen);
 	virtual S32 setTEShiny(const U8 te, const U8 shiny);
 	virtual S32 setTEFullbright(const U8 te, const U8 fullbright);
-    virtual S32 setTERenderableTarget(const U8 te, const LLTextureEntry::eRenderableTarget target);
 	virtual S32 setTEMediaFlags(const U8 te, const U8 flags);
 	virtual S32 setTEGlow(const U8 te, const F32 glow);
 	virtual S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp
index 49b59e35cbfe6fe4619f8e958467b952d0ffb21c..f4f08248b82dde355796be88bd2abce6c72abc59 100644
--- a/indra/llprimitive/llprimtexturelist.cpp
+++ b/indra/llprimitive/llprimtexturelist.cpp
@@ -341,16 +341,6 @@ S32 LLPrimTextureList::setFullbright(const U8 index, const U8 fullbright)
 	return TEM_CHANGE_NONE;
 }
 
-S32 LLPrimTextureList::setRenderableTarget(const U8 index, const U8 target)
-{
-    if (index < mEntryList.size())
-    {
-        return mEntryList[index]->setRenderableTarget((LLTextureEntry::eRenderableTarget)target);
-    }
-    
-    return TEM_CHANGE_NONE;
-}
-
 S32 LLPrimTextureList::setMediaFlags(const U8 index, const U8 media_flags)
 {
 	if (index < mEntryList.size())
diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h
index 34b87d879f6ad2adb36a4c3ba06ec49a190ac677..49c636e40f1866004e0831facd4a2f4d7f7cfc5d 100644
--- a/indra/llprimitive/llprimtexturelist.h
+++ b/indra/llprimitive/llprimtexturelist.h
@@ -102,7 +102,6 @@ class LLPrimTextureList
 	S32 setTexGen(const U8 index, const U8 texgen);
 	S32 setShiny(const U8 index, const U8 shiny);
 	S32 setFullbright(const U8 index, const U8 t);
-    S32 setRenderableTarget(const U8 index, const U8 target);
 	S32 setMediaFlags(const U8 index, const U8 media_flags);
 	S32 setGlow(const U8 index, const F32 glow);
 	S32 setMaterialID(const U8 index, const LLMaterialID& pMaterialID);
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index fdf3774bfaf3375a6128ee7972717d7480037d7f..ee2a4c769ae4a64afe718a4f90471f49d4383b07 100644
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -504,16 +504,6 @@ S32 LLTextureEntry::setFullbright(U8 fullbright)
 	return TEM_CHANGE_NONE;
 }
 
-S32 LLTextureEntry::setRenderableTarget(eRenderableTarget target)
-{
-    if (getRenderableTarget() != target) {
-        mRenderableTarget = target;
-        return TEM_CHANGE_TEXTURE;
-    }
-    
-    return TEM_CHANGE_NONE;
-}
-
 S32 LLTextureEntry::setShiny(U8 shiny)
 {
 	shiny &= TEM_SHINY_MASK;
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
index 2c0832e1d46543ce03ff8cb5142e0ce3ca6f3de6..0935147688193897bae14f4498b83236e088a9f4 100644
--- a/indra/llprimitive/lltextureentry.h
+++ b/indra/llprimitive/lltextureentry.h
@@ -80,12 +80,6 @@ class LLTextureEntry
 		TEX_GEN_SPHERICAL		= 0x04,
 		TEX_GEN_CYLINDRICAL		= 0x06
 	} eTexGen;
-    
-    
-    typedef enum e_renderable_target {
-        RT_DISABLED = 0x00,
-        RT_MIRROR = 0x02
-    } eRenderableTarget;
 
 	LLTextureEntry();
 	LLTextureEntry(const LLUUID& tex_id);
@@ -141,8 +135,6 @@ class LLTextureEntry
 	S32  setMaterialID(const LLMaterialID& pMaterialID);
 	S32  setMaterialParams(const LLMaterialPtr pMaterialParams);
     
-    S32  setRenderableTarget(eRenderableTarget target);
-    
 	virtual const LLUUID &getID() const { return mID; }
 	const LLColor4 &getColor() const { return mColor; }
     const F32 getAlpha() const { return mColor.mV[VALPHA]; }
@@ -160,7 +152,6 @@ class LLTextureEntry
 
 	U8	 getBumpmap() const { return mBump & TEM_BUMP_MASK; }
 	U8	 getFullbright() const { return (mBump>>TEM_FULLBRIGHT_SHIFT) & TEM_FULLBRIGHT_MASK; }
-    eRenderableTarget getRenderableTarget() const { return mRenderableTarget; }
 	U8	 getShiny() const { return (mBump>>TEM_SHINY_SHIFT) & TEM_SHINY_MASK; }
 	U8	 getBumpShiny() const { return mBump & TEM_BUMP_SHINY_MASK; }
  	U8	 getBumpShinyFullbright() const { return mBump; }
@@ -242,7 +233,6 @@ class LLTextureEntry
 	LLColor4			mColor;
 	U8					mBump;					// Bump map, shiny, and fullbright
 	U8					mMediaFlags;			// replace with web page, movie, etc.
-    eRenderableTarget   mRenderableTarget;
 	F32                 mGlow;
 	bool                mMaterialUpdatePending;
 	LLMaterialID        mMaterialID;
diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp
index 729603e960f4ec75c2f8e74ef17d44737f590f11..6374b10823e2e0bbc429229b59d628da94605b0c 100644
--- a/indra/newview/llheroprobemanager.cpp
+++ b/indra/newview/llheroprobemanager.cpp
@@ -103,53 +103,71 @@ void LLHeroProbeManager::update()
 
     llassert(mProbes[0] == mDefaultProbe);
     
-    LLVector3 camera_pos = LLViewerCamera::instance().getOrigin();
-    
     LLVector4a probe_pos;
     
-    LLVector3 focus_point;
-    
-    LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject();
-    if (obj && obj->mDrawable && obj->isSelected())
-    { // focus on selected media object
-        S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace();
-        if (obj && obj->mDrawable)
+    if (mHeroList.empty())
+    {
+        LLVector3 focus_point;
+        
+        LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject();
+        if (obj && obj->mDrawable && obj->isSelected())
+        { // focus on selected media object
+            S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace();
+            if (obj && obj->mDrawable)
+            {
+                LLFace* face = obj->mDrawable->getFace(face_idx);
+                if (face)
+                {
+                    focus_point = face->getPositionAgent();
+                }
+            }
+        }
+        
+        if (focus_point.isExactlyZero())
         {
-            LLFace* face = obj->mDrawable->getFace(face_idx);
-            if (face)
+            if (LLViewerJoystick::getInstance()->getOverrideCamera())
+            { // focus on point under cursor
+                focus_point.set(gDebugRaycastIntersection.getF32ptr());
+            }
+            else if (gAgentCamera.cameraMouselook())
+            { // focus on point under mouselook crosshairs
+                LLVector4a result;
+                result.clear();
+                
+                gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, NULL, &result);
+                
+                focus_point.set(result.getF32ptr());
+            }
+            else
             {
-                focus_point = face->getPositionAgent();
+                // focus on alt-zoom target
+                LLViewerRegion* region = gAgent.getRegion();
+                if (region)
+                {
+                    focus_point = LLVector3(gAgentCamera.getFocusGlobal() - region->getOriginGlobal());
+                }
             }
         }
+        
+        probe_pos.load3(((focus_point)).mV);
     }
-
-    if (focus_point.isExactlyZero())
+    else
     {
-        if (LLViewerJoystick::getInstance()->getOverrideCamera())
-        { // focus on point under cursor
-            focus_point.set(gDebugRaycastIntersection.getF32ptr());
-        }
-        else if (gAgentCamera.cameraMouselook())
-        { // focus on point under mouselook crosshairs
-            LLVector4a result;
-            result.clear();
-
-            gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, NULL, &result);
-
-            focus_point.set(result.getF32ptr());
-        }
-        else
+        // Get the nearest hero.
+        float distance = F32_MAX;
+        
+        for (auto drawable : mHeroList)
         {
-            // focus on alt-zoom target
-            LLViewerRegion* region = gAgent.getRegion();
-            if (region)
+            if (drawable.notNull())
             {
-                focus_point = LLVector3(gAgentCamera.getFocusGlobal() - region->getOriginGlobal());
+                if (drawable->mDistanceWRTCamera < distance)
+                {
+                    probe_pos.load3(drawable->mXform.getPosition().mV);
+                }
             }
         }
     }
     
-    probe_pos.load3(((focus_point + camera_pos) / 2).mV);
     static LLCachedControl<S32> sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1);
     static LLCachedControl<S32> sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3);
 
@@ -464,7 +482,7 @@ void LLHeroProbeManager::initReflectionMaps()
         
         mDefaultProbe->mCubeIndex = 0;
         mDefaultProbe->mCubeArray = mTexture;
-        mDefaultProbe->mDistance = 64.f;
+        mDefaultProbe->mDistance = 12.f;
         mDefaultProbe->mRadius = 4096.f;
         mDefaultProbe->mProbeIndex = 0;
         touch_default_probe(mDefaultProbe);
@@ -536,6 +554,7 @@ void LLHeroProbeManager::registerHeroDrawable(LLDrawable* drawablep)
     if (mHeroList.find(drawablep) == mHeroList.end())
     {
         mHeroList.insert(drawablep);
+        LL_INFOS() << "Added hero drawable." << LL_ENDL;
     }
 }
 
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 9233ec6277ac4db9ef40f86feb832e3c03856004..25f42e6daebde5ff495eab96f13b2913ea9dc380 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -596,17 +596,6 @@ void LLPanelFace::sendFullbright()
 	LLSelectMgr::getInstance()->selectionSetFullbright( fullbright );
 }
 
-void LLPanelFace::sendMirror()
-{
-    LLCheckBoxCtrl* mCheckMirror = getChild<LLCheckBoxCtrl>("checkbox mirror");
-    
-    if (!mCheckMirror)
-        return;
-    
-    LLTextureEntry::eRenderableTarget target = mCheckMirror->get() ? LLTextureEntry::RT_MIRROR : LLTextureEntry::RT_DISABLED;
-    LLSelectMgr::getInstance()->selectionSetRenderableTarget(target);
-}
-
 void LLPanelFace::sendColor()
 {
 	
@@ -3007,12 +2996,6 @@ void LLPanelFace::onCommitFullbright(LLUICtrl* ctrl, void* userdata)
 	self->sendFullbright();
 }
 
-void LLPanelFace::onCommitMirror(LLUICtrl* ctrl, void* userdata)
-{
-    LLPanelFace* self = (LLPanelFace*) userdata;
-    self->sendMirror();
-}
-
 // static
 void LLPanelFace::onCommitGlow(LLUICtrl* ctrl, void* userdata)
 {
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 0b7486232d9cb2ccd875af8ee8e55d4f698c5c1a..5cad8cefcf87e06941479fe51e9df78cc2671af9 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -139,7 +139,6 @@ class LLPanelFace : public LLPanel
 	void			sendShiny(U32 shininess);			// applies and sends shininess
 	void			sendFullbright();		// applies and sends full bright
 
-    void            sendMirror();
 	void			sendGlow();
     void            alignTestureLayer();
 
@@ -229,7 +228,6 @@ class LLPanelFace : public LLPanel
 	static void		onCommitShiny(				LLUICtrl* ctrl, void* userdata);
 	static void		onCommitAlphaMode(		LLUICtrl* ctrl, void* userdata);
 	static void		onCommitFullbright(		LLUICtrl* ctrl, void* userdata);
-    static void     onCommitMirror(LLUICtrl* ctrl, void* userdata);
 	static void     onCommitGlow(				LLUICtrl* ctrl, void *userdata);
 	static void		onCommitPlanarAlign(		LLUICtrl* ctrl, void* userdata);
 	static void		onCommitRepeatsPerMeter(	LLUICtrl* ctrl, void* userinfo);
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index ed244f773c6511014aa3bb1a9b83efd68b5f418b..d62a640b5ca7faac92fa0d047df75ebf6ff521f6 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -114,6 +114,11 @@ BOOL	LLPanelVolume::postBuild()
 		getChild<LLUICtrl>("FlexForceZ")->setValidateBeforeCommit(precommitValidate);
 	}
 
+    // Mirror Parameters
+    {
+        childSetCommitCallback("Mirror Checkbox Ctrl", onCommitIsMirror, this);
+    }
+    
 	// LIGHT Parameters
 	{
 		childSetCommitCallback("Light Checkbox Ctrl",onCommitIsLight,this);
@@ -305,6 +310,10 @@ void LLPanelVolume::getState( )
 		getChildView("select_single")->setEnabled(true);
 	}
 	
+    BOOL is_mirror = volobjp && volobjp->isMirror();
+    getChild<LLUICtrl>("Mirror Checkbox Ctrl")->setValue(is_mirror);
+    getChildView("Mirror Checkbox Ctrl")->setEnabled(editable && single_volume && volobjp);
+    
 	// Light properties
 	BOOL is_light = volobjp && volobjp->getIsLight();
 	getChild<LLUICtrl>("Light Checkbox Ctrl")->setValue(is_light);
@@ -737,6 +746,25 @@ void LLPanelVolume::sendIsLight()
 	LL_INFOS() << "update light sent" << LL_ENDL;
 }
 
+void LLPanelVolume::sendIsMirror()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
+    {
+        return;
+    }
+    LLVOVolume *volobjp = (LLVOVolume *)objectp;
+    
+    // Quick hack to set the mirror locally.
+    
+    gPipeline.mHeroProbeManager.registerHeroDrawable(volobjp->mDrawable);
+    
+    BOOL value = getChild<LLUICtrl>("Mirror Checkbox Ctrl")->getValue();
+    volobjp->setIsMirror(value);
+    LL_INFOS() << "update mirror sent" << LL_ENDL;
+}
+
+
 void LLPanelVolume::sendIsReflectionProbe()
 {
     LLViewerObject* objectp = mObject;
@@ -1403,6 +1431,12 @@ void LLPanelVolume::onCommitIsLight( LLUICtrl* ctrl, void* userdata )
 	self->sendIsLight();
 }
 
+void LLPanelVolume::onCommitIsMirror( LLUICtrl* ctrl, void* userdata )
+{
+    LLPanelVolume* self = (LLPanelVolume*) userdata;
+    self->sendIsMirror();
+}
+
 // static
 void LLPanelVolume::setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp)
 {
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index 01b7ebb75c5dc908f18f9a939413e5ab12630a01..a6583516248d74bc14b800a70fe6e2e778f692e0 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -58,6 +58,7 @@ class LLPanelVolume : public LLPanel
 
 	void			sendIsLight();
     
+    void            sendIsMirror();
     // when an object is becoming a refleciton probe, present a dialog asking for confirmation
     // otherwise, send the reflection probe update immediately
     void            sendIsReflectionProbe();
@@ -71,6 +72,7 @@ class LLPanelVolume : public LLPanel
 	
 	static void 	onCommitIsLight(		LLUICtrl* ctrl, void* userdata);
 	static void 	onCommitLight(			LLUICtrl* ctrl, void* userdata);
+    static void     onCommitIsMirror(       LLUICtrl* ctrl, void* userdata);
     static void 	onCommitIsReflectionProbe(LLUICtrl* ctrl, void* userdata);
     static void     onCommitProbe(LLUICtrl* ctrl, void* userdata);
 	void 			onCommitIsFlexible(		LLUICtrl* ctrl, void* userdata);
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 2b1b4b79b2e814468ed3392108976549ddafe65d..5c1a339570004177ae43bbde6920a1a54e3c6d55 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2355,47 +2355,6 @@ void LLSelectMgr::selectionSetFullbright(U8 fullbright)
 	getSelection()->applyToObjects(&sendfunc);
 }
 
-void LLSelectMgr::selectionSetRenderableTarget(LLTextureEntry::eRenderableTarget target)
-{
-    struct f : public LLSelectedTEFunctor
-    {
-        LLTextureEntry::eRenderableTarget mRenderableTarget;
-        
-        f(const LLTextureEntry::eRenderableTarget& t) : mRenderableTarget(t) {}
-        
-        bool apply(LLViewerObject* object, S32 te)
-        {
-            if (object->permModify())
-            {
-                object->setTERenderableTarget(te, mRenderableTarget);
-            }
-            
-            return true;
-        }
-    } setfunc(target);
-    
-    getSelection()->applyToTEs(&setfunc);
-    
-    struct g : public LLSelectedObjectFunctor
-    {
-        LLTextureEntry::eRenderableTarget mRenderableTarget;
-        
-        g(const LLTextureEntry::eRenderableTarget& t) : mRenderableTarget(t) {}
-        
-        virtual bool apply(LLViewerObject* object)
-        {
-            if (object->permModify())
-            {
-                object->sendTEUpdate();
-            }
-            
-            return true;
-        }
-    } sendfunc(target);
-    
-    getSelection()->applyToObjects(&sendfunc);
-}
-
 // This function expects media_data to be a map containing relevant
 // media data name/value pairs (e.g. home_url, etc.)
 void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data)
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 8ce59c6654af085ad3736c000fb64aaf48b93440..327134a4875110868870d3af071173053723d44c 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -653,7 +653,6 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton<LLSelectMgr>
 	void selectionSetGlow(const F32 glow);
 	void selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func, int specific_te = -1);
 	void selectionRemoveMaterial();
-    void selectionSetRenderableTarget(LLTextureEntry::eRenderableTarget target);
 
 	void selectionSetObjectPermissions(U8 perm_field, BOOL set, U32 perm_mask, BOOL override = FALSE);
 	void selectionSetObjectName(const std::string& name);
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 7871815fda629c2a8a20eb4806760e9cc1598573..68162f83c0cb88c01b669be5e110a57715fb354d 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -5296,29 +5296,6 @@ S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright)
 	return retval;
 }
 
-S32 LLViewerObject::setTERenderableTarget(const U8 te, const LLTextureEntry::eRenderableTarget target)
-{
-    S32 retval = 0;
-    
-    const LLTextureEntry *tep = getTE(te);
-    if (!tep)
-    {
-        LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL;
-    }
-    else if (target != tep->getRenderableTarget())
-    {
-        retval = LLPrimitive::setTERenderableTarget(te, target);
-        setChanged(TEXTURE);
-        if (mDrawable.notNull() && retval)
-        {
-            //gPipeline.markMirror(mDrawable);
-        }
-    }
-    
-    return retval;
-}
-
-
 S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags)
 {
 	// this might need work for media type
@@ -6251,6 +6228,11 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
       {
           new_block = new LLReflectionProbeParams();
           break;
+      }
+      case LLNetworkData::PARAMS_MIRROR:
+      {
+          new_block = new LLMirrorParams();
+          break;
       }
 	  default:
 	  {
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index fe33047218b71916b08351a12a2fcbc1f98e34b1..a87644476fa46421fb3af1c57b17584ac25fb9cb 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -360,7 +360,6 @@ class LLViewerObject
 	/*virtual*/	S32		setTEMediaTexGen(const U8 te, const U8 media ); // *FIXME: this confusingly acts upon a superset of setTETexGen's flags without absorbing its semantics
 	/*virtual*/	S32		setTEShiny(const U8 te, const U8 shiny );
 	/*virtual*/	S32		setTEFullbright(const U8 te, const U8 fullbright );
-    /*virtual*/ S32     setTERenderableTarget(const U8 te, const LLTextureEntry::eRenderableTarget target);
 	/*virtual*/	S32		setTEMediaFlags(const U8 te, const U8 media_flags );
 	/*virtual*/ S32     setTEGlow(const U8 te, const F32 glow);
 	/*virtual*/ S32     setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 2589beefe91a4da94649ef795338dcdfe4282f6f..175ce93b14410413b2fd8be02b577b5c7474a977 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1045,7 +1045,10 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
         updateReflectionProbePtr();
     }
     
-    gPipeline.mHeroProbeManager.registerHeroDrawable(mDrawable);
+    if (isMirror())
+    {
+        gPipeline.mHeroProbeManager.registerHeroDrawable(mDrawable);
+    }
     
 	updateRadius();
 	bool force_update = true; // avoid non-alpha mDistance update being optimized away
@@ -2369,16 +2372,6 @@ S32 LLVOVolume::setTEFullbright(const U8 te, const U8 fullbright)
 	return  res;
 }
 
-S32 LLVOVolume::setTERenderableTarget(const U8 te, const LLTextureEntry::eRenderableTarget mirror)
-{
-    S32 res = LLViewerObject::setTERenderableTarget(te, mirror);
-    if (res)
-    {
-        //gPipeline.markMirror(mDrawable);
-    }
-    return res;
-}
-
 S32 LLVOVolume::setTEBumpShinyFullbright(const U8 te, const U8 bump)
 {
 	S32 res = LLViewerObject::setTEBumpShinyFullbright(te, bump);
@@ -3379,28 +3372,41 @@ F32 LLVOVolume::getLightCutoff() const
 	}
 }
 
-BOOL LLVOVolume::isMirror() const
+bool LLVOVolume::setIsMirror(BOOL is_mirror)
 {
-    S32 faceCount = getNumFaces();
-    
-    // Temporary hack to set the object to mirror.
-    for (int i = 0; i < faceCount; i++)
+    BOOL was_mirror = isMirror();
+    if (is_mirror != was_mirror)
     {
-        const LLTextureEntry* te = getTE(i);
-        
-        if (te->getMaterialParams().notNull())
+        if (is_mirror)
         {
-            LLViewerTexture* specularp = getTESpecularMap(0);
-            
-            if (specularp && specularp->getID() == "da7ecda1-e780-423f-ce27-26df7dc69cb6")
-            {
-                LL_INFOS() << "BELLADONNA OF SADNESS" << LL_ENDL;
-                return TRUE;
-            }
+            setParameterEntryInUse(LLNetworkData::PARAMS_MIRROR, TRUE, true);
+        }
+        else
+        {
+            setParameterEntryInUse(LLNetworkData::PARAMS_MIRROR, FALSE, true);
         }
     }
     
-    return FALSE;
+    updateMirrorDrawable();
+    
+    return was_mirror != is_mirror;
+}
+
+void LLVOVolume::updateMirrorDrawable()
+{
+    if (isMirror())
+    {
+        gPipeline.mHeroProbeManager.registerHeroDrawable(mDrawable);
+    }
+    else
+    {
+        gPipeline.mHeroProbeManager.unregisterHeroDrawable(mDrawable);
+    }
+}
+
+BOOL LLVOVolume::isMirror() const
+{
+    return getParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE);
 }
 
 BOOL LLVOVolume::isReflectionProbe() const
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index cecf726763795d0044b7f624adc4722fd4077276..32c89ddae2e824dcd953ce2ab1349a32608fa8a2 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -209,7 +209,6 @@ class LLVOVolume : public LLViewerObject
 	/*virtual*/ S32		setTEBumpmap(const U8 te, const U8 bump) override;
 	/*virtual*/ S32		setTEShiny(const U8 te, const U8 shiny) override;
 	/*virtual*/ S32		setTEFullbright(const U8 te, const U8 fullbright) override;
-    /*virtual*/ S32     setTERenderableTarget(const U8 te, const LLTextureEntry::eRenderableTarget target) override;
 	/*virtual*/ S32		setTEBumpShinyFullbright(const U8 te, const U8 bump) override;
 	/*virtual*/ S32		setTEMediaFlags(const U8 te, const U8 media_flags) override;
 	/*virtual*/ S32		setTEGlow(const U8 te, const F32 glow) override;
@@ -295,6 +294,10 @@ class LLVOVolume : public LLViewerObject
 	F32 getLightRadius() const;
 	F32 getLightFalloff(const F32 fudge_factor = 1.f) const;
 	F32 getLightCutoff() const;
+    
+    // Mirrors
+    bool setIsMirror(BOOL is_mirror);
+    void updateMirrorDrawable();
 
     // Reflection Probes
     bool setIsReflectionProbe(BOOL is_probe);
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 5e999ed24536fbaa82b2144c558b96abf7eb532f..4094a487a9fea8132e9f64d47c59577879f2b987 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2406,7 +2406,15 @@ even though the user gets a free copy.
              name="object_horizontal"
              top_pad="10"
              width="278" />
-
+            <check_box
+             height="16"
+             label="Mirror"
+             layout="topleft"
+             left="10"
+             name="Mirror Checkbox Ctrl"
+             tool_tip="Causes object to be a mirror"
+             top_pad="8"
+             width="60" />
             <check_box
              height="16"
              label="Light"