Tagteam Texture Editor Commit Night!

Update 1: Align Planar Textures.
Update 2: Copy/Paste buttons for texture params now work.

Sorry about another two-in-one patch, but y'can't really change one without the other on this.

Signed-off-by: Beeks <HgDelirium@gmail.com>
This commit is contained in:
Beeks
2010-09-15 20:38:33 -04:00
parent b215b405ea
commit 24f3101629
5 changed files with 340 additions and 10 deletions

View File

@@ -801,6 +801,72 @@ 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 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 face's rotation from normal and rotated binormal:
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 * mXform->getWorldRotation();
*face_pos = mXform->getWorldPosition();
}
// 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))
@@ -1212,7 +1278,9 @@ F32 LLFace::getTextureVirtualSize()
{
//apply texel area to face area to get accurate ratio
//face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
face_area = mPixelArea / llclamp(texel_area, 0.015625f, 1024.f);
//face_area = mPixelArea / llclamp(texel_area, 0.015625f, 1024.f);
face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f); // see SNOW-207
}
if(face_area > LLViewerImage::sMaxSmallImageSize)

View File

@@ -93,6 +93,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; }

View File

@@ -36,6 +36,7 @@
#include "llpanelface.h"
// library includes
#include "llcalc.h"
#include "llerror.h"
#include "llfocusmgr.h"
#include "llrect.h"
@@ -43,11 +44,13 @@
#include "llfontgl.h"
// project includes
#include "llagent.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcolorswatch.h"
#include "llcombobox.h"
#include "lldrawpoolbump.h"
#include "llface.h"
#include "lllineeditor.h"
#include "llresmgr.h"
#include "llselectmgr.h"
@@ -60,6 +63,7 @@
#include "llviewercontrol.h"
#include "llviewermedia.h"
#include "llviewerobject.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "lluictrlfactory.h"
#include "llpluginclassmedia.h"
@@ -169,6 +173,7 @@ BOOL LLPanelFace::postBuild()
childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this);
childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this);
childSetCommitCallback("checkbox planar align",&LLPanelFace::onCommitPlanarAlign, this);
childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureInfo, this);
childSetCommitCallback("checkbox flip s",&LLPanelFace::onCommitTextureInfo, this);
childSetCommitCallback("TexScaleV",&LLPanelFace::onCommitTextureInfo, this);
@@ -178,6 +183,8 @@ BOOL LLPanelFace::postBuild()
childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureInfo, this);
childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureInfo, this);
childSetAction("button align",onClickAutoFix,this);
childSetAction("copytextures",onClickCopy,this);
childSetAction("pastetextures",onClickPaste,this);
clearCtrls();
@@ -359,6 +366,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], 16) &&
is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 16) &&
is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 16) &&
is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 16) &&
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 +464,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);
@@ -380,7 +492,7 @@ void LLPanelFace::sendTextureInfo()
void LLPanelFace::getState()
{
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
LLCalc* calcp = LLCalc::getInstance();
if( objectp
&& objectp->getPCode() == LL_PCODE_VOLUME
&& objectp->permModify())
@@ -402,6 +514,13 @@ void LLPanelFace::getState()
//
// //mBtnAutoFix->setEnabled ( editable );
// }
S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ))
&& (selected_count == 1);
childSetEnabled("copytextures", single_volume && editable);
childSetEnabled("pastetextures", single_volume && editable);
childSetEnabled("textbox params", single_volume && editable);
childSetEnabled("button apply",editable);
bool identical;
@@ -481,6 +600,43 @@ void LLPanelFace::getState()
}
}
// planar align
bool align_planar = false;
bool identical_planar_aligned = 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 is_planar;
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
{
childSetEnabled("tex scale",editable);
@@ -494,6 +650,7 @@ void LLPanelFace::getState()
}
} func;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, scale_s );
identical = align_planar ? identical_planar_aligned : identical;
childSetValue("TexScaleU",editable ? llabs(scale_s) : 0);
childSetTentative("TexScaleU",LLSD((BOOL)(!identical)));
childSetEnabled("TexScaleU",editable);
@@ -512,6 +669,7 @@ void LLPanelFace::getState()
}
} func;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, scale_t );
identical = align_planar ? identical_planar_aligned : identical;
childSetValue("TexScaleV",llabs(editable ? llabs(scale_t) : 0));
childSetTentative("TexScaleV",LLSD((BOOL)(!identical)));
@@ -533,6 +691,7 @@ void LLPanelFace::getState()
}
} func;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, offset_s );
identical = align_planar ? identical_planar_aligned : identical;
childSetValue("TexOffsetU", editable ? offset_s : 0);
childSetTentative("TexOffsetU",!identical);
childSetEnabled("TexOffsetU",editable);
@@ -548,6 +707,7 @@ void LLPanelFace::getState()
}
} func;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, offset_t );
identical = align_planar ? identical_planar_aligned : identical;
childSetValue("TexOffsetV", editable ? offset_t : 0);
childSetTentative("TexOffsetV",!identical);
childSetEnabled("TexOffsetV",editable);
@@ -565,6 +725,7 @@ void LLPanelFace::getState()
}
} func;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, rotation );
identical = align_planar ? identical_planar_aligned : identical;
childSetValue("TexRot", editable ? rotation * RAD_TO_DEG : 0);
childSetTentative("TexRot",!identical);
childSetEnabled("TexRot",editable);
@@ -757,6 +918,15 @@ void LLPanelFace::getState()
childSetEnabled("button apply",enabled);
}
}
// Set variable values for numeric expressions
calcp->setVar(LLCalc::TEX_U_SCALE, childGetValue("TexScaleU").asReal());
calcp->setVar(LLCalc::TEX_V_SCALE, childGetValue("TexScaleV").asReal());
calcp->setVar(LLCalc::TEX_U_OFFSET, childGetValue("TexOffsetU").asReal());
calcp->setVar(LLCalc::TEX_V_OFFSET, childGetValue("TexOffsetV").asReal());
calcp->setVar(LLCalc::TEX_ROTATION, childGetValue("TexRot").asReal());
calcp->setVar(LLCalc::TEX_TRANSPARENCY, childGetValue("ColorTrans").asReal());
calcp->setVar(LLCalc::TEX_GLOW, childGetValue("glow").asReal());
}
else
{
@@ -792,6 +962,16 @@ void LLPanelFace::getState()
childSetEnabled("button align",FALSE);
childSetEnabled("button apply",FALSE);
// Set variable values for numeric expressions
calcp->clearVar(LLCalc::TEX_U_SCALE);
calcp->clearVar(LLCalc::TEX_V_SCALE);
calcp->clearVar(LLCalc::TEX_U_OFFSET);
calcp->clearVar(LLCalc::TEX_V_OFFSET);
calcp->clearVar(LLCalc::TEX_ROTATION);
calcp->clearVar(LLCalc::TEX_TRANSPARENCY);
calcp->clearVar(LLCalc::TEX_GLOW);
}
}
@@ -978,3 +1158,69 @@ void LLPanelFace::onClickAutoFix(void* userdata)
LLPanelFaceSendFunctor sendfunc;
LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc);
}
// static
void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
self->getState();
self->sendTextureInfo();
}
static LLSD textures;
void LLPanelFace::onClickCopy(void* userdata)
{
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
if(!objectp)
{
objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
if (!objectp)
{
return;
}
}
S32 te_count = objectp->getNumFaces();
textures.clear();
for (S32 i = 0; i < te_count; i++)
{
llinfos << "Copying params on face " << i << "." << llendl;
textures.append(objectp->getTE(i)->asLLSD());
}
}
void LLPanelFace::onClickPaste(void* userdata)
{
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
if(!objectp)
{
objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
if (!objectp)
{
return;
}
}
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_ObjectImage);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
msg->nextBlockFast(_PREHASH_ObjectData);
msg->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
msg->addStringFast(_PREHASH_MediaURL, NULL);
LLPrimitive obj;
obj.setNumTEs(U8(textures.size()));
for (int i = 0; i < textures.size(); i++)
{
llinfos << "Pasting params on face " << i << "." << llendl;
LLTextureEntry tex;
tex.fromLLSD(textures[i]);
obj.setTE(U8(i), tex);
}
obj.packTEMessage(gMessageSystem);
msg->sendReliable(gAgent.getRegion()->getHost());
}

View File

@@ -86,9 +86,12 @@ 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*);
static void onClickCopy(void*);
static void onClickPaste(void*);
static F32 valueGlow(LLViewerObject* object, S32 face);
};

View File

@@ -1227,6 +1227,10 @@
weave
</combo_item>
</combo_box>
<check_box bottom="-148" follows="left|top" font="SansSerifSmall" height="16"
initial_value="false" enabled="false" label="Align planar textures"
left="8" mouse_opaque="true" name="checkbox planar align" width="160"
tool_tip="Aligns textures on all selected faces to the last selected face. Requires Planar texture mapping." />
<text bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom="-158" drop_shadow_visible="true" follows="left|top"
font="SansSerifSmall" h_pad="0" halign="left" height="10" left="10"
@@ -1295,12 +1299,18 @@
<button bottom="-360" follows="left|top" font="SansSerifSmall" halign="center"
height="20" label="Align" label_selected="Align" left="112"
mouse_opaque="true" name="button align" scale_image="TRUE" width="68" />
<button bottom="-360" follows="top|right" font="SansSerifSmall" halign="center"
height="16" label="Copy" left="80" mouse_opaque="true" name="copytextures" enabled="true"
tool_tip="Copy Testure Params from Clipboard" width="50" />
<button bottom_delta="0" follows="top|right" font="SansSerifSmall" halign="center"
height="16" label="Paste" left_delta="50" mouse_opaque="true" name="pastetextures" enabled="true"
tool_tip="Paste Texture Params from Clipboard" width="50" />
<text bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom="-322" drop_shadow_visible="true" follows="left|top"
font="SansSerifSmall" h_pad="0" halign="left" height="20" left="185"
mouse_opaque="true" name="textbox params" v_pad="0" width="160">
Texture Params
</text>
<button bottom_delta="-18" follows="top|right" font="SansSerifSmall" halign="center"
height="20" label="Copy" left_delta="5" mouse_opaque="true" name="copytextures" enabled="true"
tool_tip="Copy Testure Params from Clipboard" width="68" />
<button bottom_delta="-20" follows="top|right" font="SansSerifSmall" halign="center"
height="20" label="Paste" left_delta="0" mouse_opaque="true" name="pastetextures" enabled="true"
tool_tip="Paste Texture Params from Clipboard" width="68" />
</panel>
<panel border="true" bottom="-383" follows="left|top|right|bottom" height="367"
label="Content" left="1" mouse_opaque="false" name="Contents" width="270">