re-merge change from Thickbrick (minor collisions with changes from viewer-public merge)
commit
838c01e87d
|
|
@ -212,6 +212,8 @@ Dzonatas Sol
|
|||
VWR-1705
|
||||
VWR-1729
|
||||
VWR-1812
|
||||
Eddi Decosta
|
||||
SNOW-586
|
||||
Eddy Stryker
|
||||
VWR-15
|
||||
VWR-23
|
||||
|
|
@ -632,6 +634,7 @@ Tharax Ferraris
|
|||
VWR-605
|
||||
Thickbrick Sleaford
|
||||
SNOW-207
|
||||
SNOW-586
|
||||
SNOW-743
|
||||
VWR-7109
|
||||
VWR-9287
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue