diff options
Diffstat (limited to 'indra/newview')
| -rw-r--r-- | indra/newview/llface.cpp | 67 | ||||
| -rw-r--r-- | indra/newview/llface.h | 3 | ||||
| -rw-r--r-- | indra/newview/llpanelface.cpp | 162 | ||||
| -rw-r--r-- | indra/newview/llpanelface.h | 1 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_tools.xml | 26 | 
5 files changed, 250 insertions, 9 deletions
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index defd882fe4..d22950cad3 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -827,6 +827,73 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position,  	return tc;  } +// Returns scale compared to default texgen, and face orientation as calculated +// by planarProjection(). This is needed to match planar texgen parameters. +void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_pos, F32* scale) const +{ +	const LLMatrix4& vol_mat = getWorldMatrix(); +	const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset); +	LLVector3 normal = vf.mVertices[0].mNormal; +	LLVector3 binormal = vf.mVertices[0].mBinormal; +	LLVector2 projected_binormal; +	planarProjection(projected_binormal, normal, vf.mCenter, binormal); +	projected_binormal -= LLVector2(0.5f, 0.5f); // this normally happens in xform() +	*scale = projected_binormal.length(); +	// rotate binormal to match what planarProjection() thinks it is, +	// then find rotation from that: +	projected_binormal.normalize(); +	F32 ang = acos(projected_binormal.mV[VY]); +	ang = (projected_binormal.mV[VX] < 0.f) ? -ang : ang; +	binormal.rotVec(ang, normal); +	LLQuaternion local_rot( binormal % normal, binormal, normal ); +	*face_rot = local_rot * vol_mat.quaternion(); +	*face_pos = vol_mat.getTranslation(); +} + +// Returns the necessary texture transform to align this face's TE to align_to's TE +bool LLFace::calcAlignedPlanarTE(const LLFace* align_to,  LLVector2* res_st_offset,  +								 LLVector2* res_st_scale, F32* res_st_rot) const +{ +	if (!align_to) +	{ +		return false; +	} +	const LLTextureEntry *orig_tep = align_to->getTextureEntry(); +	if ((orig_tep->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR) || +		(getTextureEntry()->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR)) +	{ +		return false; +	} + +	LLVector3 orig_pos, this_pos; +	LLQuaternion orig_face_rot, this_face_rot; +	F32 orig_proj_scale, this_proj_scale; +	align_to->getPlanarProjectedParams(&orig_face_rot, &orig_pos, &orig_proj_scale); +	getPlanarProjectedParams(&this_face_rot, &this_pos, &this_proj_scale); + +	// The rotation of "this face's" texture: +	LLQuaternion orig_st_rot = LLQuaternion(orig_tep->getRotation(), LLVector3::z_axis) * orig_face_rot; +	LLQuaternion this_st_rot = orig_st_rot * ~this_face_rot; +	F32 x_ang, y_ang, z_ang; +	this_st_rot.getEulerAngles(&x_ang, &y_ang, &z_ang); +	*res_st_rot = z_ang; + +	// Offset and scale of "this face's" texture: +	LLVector3 centers_dist = (this_pos - orig_pos) * ~orig_st_rot; +	LLVector3 st_scale(orig_tep->mScaleS, orig_tep->mScaleT, 1.f); +	st_scale *= orig_proj_scale; +	centers_dist.scaleVec(st_scale); +	LLVector2 orig_st_offset(orig_tep->mOffsetS, orig_tep->mOffsetT); + +	*res_st_offset = orig_st_offset + (LLVector2)centers_dist; +	res_st_offset->mV[VX] -= (S32)res_st_offset->mV[VX]; +	res_st_offset->mV[VY] -= (S32)res_st_offset->mV[VY]; + +	st_scale /= this_proj_scale; +	*res_st_scale = (LLVector2)st_scale; +	return true; +} +  void LLFace::updateRebuildFlags()  {  	if (!mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) diff --git a/indra/newview/llface.h b/indra/newview/llface.h index d95057f3ef..0166e45bee 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -89,6 +89,9 @@ public:  	BOOL			hasGeometry()		const	{ return mGeomCount > 0; }  	LLVector3		getPositionAgent()	const;  	LLVector2       surfaceToTexture(LLVector2 surface_coord, LLVector3 position, LLVector3 normal); +	void 			getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_pos, F32* scale) const; +	bool			calcAlignedPlanarTE(const LLFace* align_to, LLVector2* st_offset, +										LLVector2* st_scale, F32* st_rot) const;  	U32				getState()			const	{ return mState; }  	void			setState(U32 state)			{ mState |= state; } diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 572e7a6212..bce496cbad 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -42,6 +42,7 @@  #include "llcolorswatch.h"  #include "llcombobox.h"  #include "lldrawpoolbump.h" +#include "llface.h"  #include "lllineeditor.h"  #include "llmediaentry.h"  #include "llresmgr.h" @@ -75,6 +76,7 @@ BOOL	LLPanelFace::postBuild()  	childSetCommitCallback("checkbox flip t",&LLPanelFace::onCommitTextureInfo, this);  	childSetCommitCallback("TexRot",&LLPanelFace::onCommitTextureInfo, this);  	childSetAction("button apply",&LLPanelFace::onClickApply,this); +	childSetCommitCallback("checkbox planar align",&LLPanelFace::onCommitPlanarAlign, this);  	childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureInfo, this);  	childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureInfo, this);  	childSetAction("button align",&LLPanelFace::onClickAutoFix,this); @@ -359,6 +361,93 @@ private:  	LLPanelFace* mPanel;  }; +// Functor that aligns a face to mCenterFace +struct LLPanelFaceSetAlignedTEFunctor : public LLSelectedTEFunctor +{ +	LLPanelFaceSetAlignedTEFunctor(LLPanelFace* panel, LLFace* center_face) : +		mPanel(panel), +		mCenterFace(center_face) {} + +	virtual bool apply(LLViewerObject* object, S32 te) +	{ +		LLFace* facep = object->mDrawable->getFace(te); +		if (!facep) +		{ +			return true; +		} + +		bool set_aligned = true; +		if (facep == mCenterFace) +		{ +			set_aligned = false; +		} +		if (set_aligned) +		{ +			LLVector2 uv_offset, uv_scale; +			F32 uv_rot; +			set_aligned = facep->calcAlignedPlanarTE(mCenterFace, &uv_offset, &uv_scale, &uv_rot); +			if (set_aligned) +			{ +				object->setTEOffset(te, uv_offset.mV[VX], uv_offset.mV[VY]); +				object->setTEScale(te, uv_scale.mV[VX], uv_scale.mV[VY]); +				object->setTERotation(te, uv_rot); +			} +		} +		if (!set_aligned) +		{ +			LLPanelFaceSetTEFunctor setfunc(mPanel); +			setfunc.apply(object, te); +		} +		return true; +	} +private: +	LLPanelFace* mPanel; +	LLFace* mCenterFace; +}; + +// Functor that tests if a face is aligned to mCenterFace +struct LLPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor +{ +	LLPanelFaceGetIsAlignedTEFunctor(LLFace* center_face) : +		mCenterFace(center_face) {} + +	virtual bool apply(LLViewerObject* object, S32 te) +	{ +		LLFace* facep = object->mDrawable->getFace(te); +		if (!facep) +		{ +			return false; +		} +		if (facep == mCenterFace) +		{ +			return true; +		} +		 +		LLVector2 aligned_st_offset, aligned_st_scale; +		F32 aligned_st_rot; +		if ( facep->calcAlignedPlanarTE(mCenterFace, &aligned_st_offset, &aligned_st_scale, &aligned_st_rot) ) +		{ +			const LLTextureEntry* tep = facep->getTextureEntry(); +			LLVector2 st_offset, st_scale; +			tep->getOffset(&st_offset.mV[VX], &st_offset.mV[VY]); +			tep->getScale(&st_scale.mV[VX], &st_scale.mV[VY]); +			F32 st_rot = tep->getRotation(); +			// needs a fuzzy comparison, because of fp errors +			if (is_approx_equal_fraction(st_offset.mV[VX], aligned_st_offset.mV[VX], 12) &&  +				is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 12) &&  +				is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 12) && +				is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 12) && +				is_approx_equal_fraction(st_rot, aligned_st_rot, 14)) +			{ +				return true; +			} +		} +		return false; +	} +private: +	LLFace* mCenterFace; +}; +  struct LLPanelFaceSendFunctor : public LLSelectedObjectFunctor  {  	virtual bool apply(LLViewerObject* object) @@ -370,8 +459,26 @@ struct LLPanelFaceSendFunctor : public LLSelectedObjectFunctor  void LLPanelFace::sendTextureInfo()  { -	LLPanelFaceSetTEFunctor setfunc(this); -	LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); +	if ((bool)childGetValue("checkbox planar align").asBoolean()) +	{ +		struct f1 : public LLSelectedTEGetFunctor<LLFace *> +		{ +			LLFace* get(LLViewerObject* object, S32 te) +			{ +				return (object->mDrawable) ? object->mDrawable->getFace(te): NULL; +			} +		} get_last_face_func; +		LLFace* last_face; +		LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_last_face_func, last_face); + +		LLPanelFaceSetAlignedTEFunctor setfunc(this, last_face); +		LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); +	} +	else +	{ +		LLPanelFaceSetTEFunctor setfunc(this); +		LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); +	}  	LLPanelFaceSendFunctor sendfunc;  	LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc); @@ -497,6 +604,44 @@ void LLPanelFace::getState()  			}  		} + +		// planar align +		bool align_planar = false; +		bool identical_planar_aligned = false; +		bool is_planar = false; +		{ +			LLCheckBoxCtrl*	cb_planar_align = getChild<LLCheckBoxCtrl>("checkbox planar align"); +			align_planar = (cb_planar_align && cb_planar_align->get()); +			struct f1 : public LLSelectedTEGetFunctor<bool> +			{ +				bool get(LLViewerObject* object, S32 face) +				{ +					return (object->getTE(face)->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR); +				} +			} func; + +			bool texgens_identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, is_planar ); +			bool enabled = (editable && texgens_identical && is_planar); +			childSetValue("checkbox planar align", align_planar && enabled); +			childSetEnabled("checkbox planar align", enabled); + +			if (align_planar && enabled) +			{ +				struct f2 : public LLSelectedTEGetFunctor<LLFace *> +				{ +					LLFace* get(LLViewerObject* object, S32 te) +					{ +						return (object->mDrawable) ? object->mDrawable->getFace(te): NULL; +					} +				} get_te_face_func; +				LLFace* last_face; +				LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, last_face); +				LLPanelFaceGetIsAlignedTEFunctor get_is_aligend_func(last_face); +				// this will determine if the texture param controls are tentative: +				identical_planar_aligned = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&get_is_aligend_func); +			} +		} +		  		// Texture scale  		{  			F32 scale_s = 1.f; @@ -508,6 +653,7 @@ void LLPanelFace::getState()  				}  			} func;  			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, scale_s ); +			identical = align_planar ? identical_planar_aligned : identical;  			getChild<LLUICtrl>("TexScaleU")->setValue(editable ? llabs(scale_s) : 0);  			getChild<LLUICtrl>("TexScaleU")->setTentative(LLSD((BOOL)(!identical)));  			getChildView("TexScaleU")->setEnabled(editable); @@ -526,6 +672,7 @@ void LLPanelFace::getState()  				}  			} func;  			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, scale_t ); +			identical = align_planar ? identical_planar_aligned : identical;  			getChild<LLUICtrl>("TexScaleV")->setValue(llabs(editable ? llabs(scale_t) : 0));  			getChild<LLUICtrl>("TexScaleV")->setTentative(LLSD((BOOL)(!identical))); @@ -547,6 +694,7 @@ void LLPanelFace::getState()  				}  			} func;  			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, offset_s ); +			identical = align_planar ? identical_planar_aligned : identical;  			getChild<LLUICtrl>("TexOffsetU")->setValue(editable ? offset_s : 0);  			getChild<LLUICtrl>("TexOffsetU")->setTentative(!identical);  			getChildView("TexOffsetU")->setEnabled(editable); @@ -562,6 +710,7 @@ void LLPanelFace::getState()  				}  			} func;  			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, offset_t ); +			identical = align_planar ? identical_planar_aligned : identical;  			getChild<LLUICtrl>("TexOffsetV")->setValue(editable ? offset_t : 0);  			getChild<LLUICtrl>("TexOffsetV")->setTentative(!identical);  			getChildView("TexOffsetV")->setEnabled(editable); @@ -578,6 +727,7 @@ void LLPanelFace::getState()  				}  			} func;  			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, rotation ); +			identical = align_planar ? identical_planar_aligned : identical;  			getChild<LLUICtrl>("TexRot")->setValue(editable ? rotation * RAD_TO_DEG : 0);  			getChild<LLUICtrl>("TexRot")->setTentative(!identical);  			getChildView("TexRot")->setEnabled(editable); @@ -993,3 +1143,11 @@ void LLPanelFace::setMediaType(const std::string& mime_type)  {  } +// static +void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata) +{ +	LLPanelFace* self = (LLPanelFace*) userdata; +	self->getState(); +	self->sendTextureInfo(); +} + diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 94c354cf02..42be9b257f 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -85,6 +85,7 @@ protected:  	static void		onCommitShiny(			LLUICtrl* ctrl, void* userdata);  	static void		onCommitFullbright(		LLUICtrl* ctrl, void* userdata);  	static void     onCommitGlow(           LLUICtrl* ctrl, void *userdata); +	static void		onCommitPlanarAlign(	LLUICtrl* ctrl, void* userdata);  	static void		onClickApply(void*);  	static void		onClickAutoFix(void*); diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 514b0a501b..1d58e7a540 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2408,7 +2408,7 @@ even though the user gets a free copy.               name="label shininess"               left_pad="4"               text_readonly_color="LabelDisabledColor" -             top_pad="-36" +             top_pad="-37"               width="90">                  Shininess              </text> @@ -2445,7 +2445,7 @@ even though the user gets a free copy.               left_pad="4"               name="label bumpiness"               text_readonly_color="LabelDisabledColor" -             top_pad="-36" +             top_pad="-37"               width="90">                  Bumpiness              </text> @@ -2563,6 +2563,17 @@ even though the user gets a free copy.               top_delta="-4"               width="120" />  --> +            <check_box +             follows="top|left" +             height="16" +             initial_value="false" +             label="Align planar faces" +             layout="topleft" +             left="17" +             name="checkbox planar align" +             tool_tip="Align textures on all selected faces with the last selected face. Requires Planar texture mapping." +             top_delta="26" +             width="140" />              <text               type="string"               length="1" @@ -2572,8 +2583,8 @@ even though the user gets a free copy.               left="10"               name="rpt"               text_readonly_color="LabelDisabledColor" -             top_pad="4" -             width="200"> +             top_pad="2" +             width="140">                  Repeats / Face              </text>              <spinner @@ -2586,7 +2597,7 @@ even though the user gets a free copy.               left="20"               max_val="100"               name="TexScaleU" -             top_pad="6" +             top_pad="5"               width="185" />              <check_box               height="19" @@ -2696,7 +2707,7 @@ even though the user gets a free copy.           bg_alpha_color="DkGray"           name="Add_Media"           left="0" -         height="63" +         height="47"           width="290">              <text               type="string" @@ -2782,8 +2793,9 @@ even though the user gets a free copy.  			 label="Align"  			 label_selected="Align Media"  			 layout="topleft" -			 right="-10" +			 right="-16"  			 name="button align" +			 top_delta="-4"  			 tool_tip="Align media texture (must load first)"  			 width="80" />  		</panel>  | 
