Merge branch 'master' into DRTVWR-507-maint

# Conflicts:
#	indra/newview/llfloatermodelpreview.cpp
master
Andrey Lihatskiy 2020-10-14 21:58:43 +03:00
commit 35708568d6
32 changed files with 5211 additions and 3782 deletions

View File

@ -264,6 +264,9 @@ Benjamin Bigdipper
Beq Janus
BUG-227094
Beth Walcher
Beq Janus
SL-10288
SL-13583
Bezilon Kasei
Biancaluce Robbiani
CT-225

View File

@ -408,7 +408,7 @@ void showJointScaleOverrides( const LLJoint& joint, const std::string& note, con
bool LLJoint::aboveJointPosThreshold(const LLVector3& pos) const
{
LLVector3 diff = pos - getDefaultPosition();
const F32 max_joint_pos_offset = 0.0001f; // 0.1 mm
const F32 max_joint_pos_offset = LL_JOINT_TRESHOLD_POS_OFFSET; // 0.1 mm
return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset;
}
@ -511,7 +511,7 @@ void LLJoint::clearAttachmentPosOverrides()
// getAllAttachmentPosOverrides()
//--------------------------------------------------------------------
void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides,
std::set<LLVector3>& distinct_pos_overrides)
std::set<LLVector3>& distinct_pos_overrides) const
{
num_pos_overrides = m_attachmentPosOverrides.count();
LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin();
@ -525,7 +525,7 @@ void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides,
// getAllAttachmentScaleOverrides()
//--------------------------------------------------------------------
void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides,
std::set<LLVector3>& distinct_scale_overrides)
std::set<LLVector3>& distinct_scale_overrides) const
{
num_scale_overrides = m_attachmentScaleOverrides.count();
LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin();

View File

@ -53,6 +53,8 @@ const U32 LL_FACE_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-2);
const S32 LL_CHARACTER_MAX_PRIORITY = 7;
const F32 LL_MAX_PELVIS_OFFSET = 5.f;
const F32 LL_JOINT_TRESHOLD_POS_OFFSET = 0.0001f; //0.1 mm
class LLVector3OverrideMap
{
public:
@ -287,9 +289,9 @@ public:
void showAttachmentScaleOverrides(const std::string& av_info) const;
void getAllAttachmentPosOverrides(S32& num_pos_overrides,
std::set<LLVector3>& distinct_pos_overrides);
std::set<LLVector3>& distinct_pos_overrides) const;
void getAllAttachmentScaleOverrides(S32& num_scale_overrides,
std::set<LLVector3>& distinct_scale_overrides);
std::set<LLVector3>& distinct_scale_overrides) const;
// These are used in checks of whether a pos/scale override is considered significant.
bool aboveJointPosThreshold(const LLVector3& pos) const;

View File

@ -343,7 +343,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
return LLModel::NO_ERRORS ;
}
LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly)
LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg)
{
domPRef p = poly->getP();
domListOfUInts& idx = p->getValue();
@ -403,6 +403,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
LLVolumeFace::VertexMapData::PointMap point_map;
U32 cur_idx = 0;
bool log_tc_msg = true;
for (U32 i = 0; i < vcount.getCount(); ++i)
{ //for each polygon
U32 first_index = 0;
@ -426,8 +427,21 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
if (tc_source)
{
cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0],
tc[idx[cur_idx+tc_offset]*2+1]);
U64 idx_x = idx[cur_idx + tc_offset] * 2 + 0;
U64 idx_y = idx[cur_idx + tc_offset] * 2 + 1;
if (idx_y < tc.getCount())
{
cv.mTexCoord.setVec(tc[idx_x], tc[idx_y]);
}
else if (log_tc_msg)
{
log_tc_msg = false;
LL_WARNS() << "Texture coordinates data is not complete." << LL_ENDL;
LLSD args;
args["Message"] = "IncompleteTC";
log_msg.append(args);
}
}
if (norm_source)
@ -1215,7 +1229,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
for (S32 i = 0; i < childCount; ++i)
{
domNode* pNode = daeSafeCast<domNode>(children[i]);
if ( isNodeAJoint( pNode ) )
if (pNode)
{
processJointNode( pNode, mJointList );
}
@ -1470,6 +1484,12 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
}
}
U32 bind_count = model->mSkinInfo.mAlternateBindMatrix.size();
if (bind_count > 0 && bind_count != jointCnt)
{
LL_WARNS("Mesh") << "Model " << model->mLabel << " has invalid joint bind matrix list." << LL_ENDL;
}
//grab raw position array
domVertices* verts = mesh->getVertices();
@ -1834,59 +1854,61 @@ void LLDAELoader::processJointNode( domNode* pNode, JointTransformMap& jointTran
//LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL;
//1. handle the incoming node - extract out translation via SID or element
if (isNodeAJoint(pNode))
{
LLMatrix4 workingTransform;
LLMatrix4 workingTransform;
//Pull out the translate id and store it in the jointTranslations map
daeSIDResolver jointResolverA(pNode, "./translate");
domTranslate* pTranslateA = daeSafeCast<domTranslate>(jointResolverA.getElement());
daeSIDResolver jointResolverB(pNode, "./location");
domTranslate* pTranslateB = daeSafeCast<domTranslate>(jointResolverB.getElement());
//Pull out the translate id and store it in the jointTranslations map
daeSIDResolver jointResolverA( pNode, "./translate" );
domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() );
daeSIDResolver jointResolverB( pNode, "./location" );
domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() );
//Translation via SID was successful
if (pTranslateA)
{
extractTranslation(pTranslateA, workingTransform);
}
else
if (pTranslateB)
{
extractTranslation(pTranslateB, workingTransform);
}
else
{
//Translation via child from element
daeElement* pTranslateElement = getChildFromElement(pNode, "translate");
if (!pTranslateElement || pTranslateElement->typeID() != domTranslate::ID())
{
//LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
daeSIDResolver jointResolver(pNode, "./matrix");
domMatrix* pMatrix = daeSafeCast<domMatrix>(jointResolver.getElement());
if (pMatrix)
{
//LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL;
domFloat4x4 domArray = pMatrix->getValue();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
workingTransform.mMatrix[i][j] = domArray[i + j * 4];
}
}
}
else
{
LL_WARNS() << "The found element is not translate or matrix node - most likely a corrupt export!" << LL_ENDL;
}
}
else
{
extractTranslationViaElement(pTranslateElement, workingTransform);
}
}
//Translation via SID was successful
if ( pTranslateA )
{
extractTranslation( pTranslateA, workingTransform );
}
else
if ( pTranslateB )
{
extractTranslation( pTranslateB, workingTransform );
}
else
{
//Translation via child from element
daeElement* pTranslateElement = getChildFromElement( pNode, "translate" );
if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() )
{
//LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL;
daeSIDResolver jointResolver( pNode, "./matrix" );
domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() );
if ( pMatrix )
{
//LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL;
domFloat4x4 domArray = pMatrix->getValue();
for ( int i = 0; i < 4; i++ )
{
for( int j = 0; j < 4; j++ )
{
workingTransform.mMatrix[i][j] = domArray[i + j*4];
}
}
}
else
{
LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL;
}
}
else
{
extractTranslationViaElement( pTranslateElement, workingTransform );
}
}
//Store the working transform relative to the nodes name.
jointTransforms[ pNode->getName() ] = workingTransform;
//Store the working transform relative to the nodes name.
jointTransforms[pNode->getName()] = workingTransform;
}
//2. handle the nodes children
@ -2356,7 +2378,7 @@ LLColor4 LLDAELoader::getDaeColor(daeElement* element)
return value;
}
bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh)
bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD& log_msg)
{
LLModel::EModelStatus status = LLModel::NO_ERRORS;
domTriangles_Array& tris = mesh->getTriangles_array();
@ -2378,7 +2400,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh)
for (U32 i = 0; i < polys.getCount(); ++i)
{
domPolylistRef& poly = polys.get(i);
status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly);
status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, log_msg);
if(status != LLModel::NO_ERRORS)
{
@ -2442,7 +2464,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
// Get the whole set of volume faces
//
addVolumeFacesFromDomMesh(ret, mesh);
addVolumeFacesFromDomMesh(ret, mesh, mWarningsArray);
U32 volume_faces = ret->getNumVolumeFaces();
@ -2515,7 +2537,8 @@ bool LLDAELoader::createVolumeFacesFromDomMesh(LLModel* pModel, domMesh* mesh)
{
pModel->ClearFacesAndMaterials();
addVolumeFacesFromDomMesh(pModel, mesh);
LLSD placeholder;
addVolumeFacesFromDomMesh(pModel, mesh, placeholder);
if (pModel->getNumVolumeFaces() > 0)
{

View File

@ -89,7 +89,7 @@ protected:
//Verify that a controller matches vertex counts
bool verifyController( domController* pController );
static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh);
static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg);
static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh);
static LLModel* loadModelFromDomMesh(domMesh* mesh);

View File

@ -127,7 +127,7 @@ LLModelLoader::LLModelLoader(
, mStateCallback(state_cb)
, mOpaqueData(opaque_userdata)
, mRigValidJointUpload(true)
, mLegacyRigValid(true)
, mLegacyRigFlags(0)
, mNoNormalize(false)
, mNoOptimize(false)
, mCacheOnlyHitIfRigged(false)
@ -136,6 +136,7 @@ LLModelLoader::LLModelLoader(
{
assert_main_thread();
sActiveLoaderList.push_back(this) ;
mWarningsArray = LLSD::emptyArray();
}
LLModelLoader::~LLModelLoader()
@ -146,6 +147,7 @@ LLModelLoader::~LLModelLoader()
void LLModelLoader::run()
{
mWarningsArray.clear();
doLoadModel();
doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
}
@ -387,7 +389,7 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st
//2. It is suitable for upload as standard av with just skin weights
bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
U32 legacy_rig_flags = determineRigLegacyFlags( jointListFromAsset );
// It's OK that both could end up being true.
@ -401,19 +403,16 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st
setRigValidForJointPositionUpload( false );
}
if ( !isRigLegacyOK)
{
// This starts out true, becomes false if false for any loaded
// mesh.
setLegacyRigValid( false );
}
legacy_rig_flags |= getLegacyRigFlags();
// This starts as 0, changes if any loaded mesh has issues
setLegacyRigFlags(legacy_rig_flags);
}
//-----------------------------------------------------------------------------
// isRigLegacy()
// determineRigLegacyFlags()
//-----------------------------------------------------------------------------
bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
U32 LLModelLoader::determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset )
{
//No joints in asset
if ( jointListFromAsset.size() == 0 )
@ -426,7 +425,12 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs
{
LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL;
LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL;
return false;
LLSD args;
args["Message"] = "TooManyJoint";
args["[JOINTS]"] = LLSD::Integer(jointListFromAsset.size());
args["[MAX]"] = LLSD::Integer(mMaxJointsPerMesh);
mWarningsArray.append(args);
return LEGACY_RIG_FLAG_TOO_MANY_JOINTS;
}
// Unknown joints in asset
@ -437,16 +441,24 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs
if (mJointMap.find(*it)==mJointMap.end())
{
LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL;
LLSD args;
args["Message"] = "UnrecognizedJoint";
args["[NAME]"] = *it;
mWarningsArray.append(args);
unknown_joint_count++;
}
}
if (unknown_joint_count>0)
{
LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL;
return false;
LLSD args;
args["Message"] = "UnknownJoints";
args["[COUNT]"] = LLSD::Integer(unknown_joint_count);
mWarningsArray.append(args);
return LEGACY_RIG_FLAG_UNKNOWN_JOINT;
}
return true;
return LEGACY_RIG_OK;
}
//-----------------------------------------------------------------------------
// isRigSuitableForJointPositionUpload()

View File

@ -42,6 +42,10 @@ typedef std::deque<std::string> JointNameSet;
const S32 SLM_SUPPORTED_VERSION = 3;
const S32 NUM_LOD = 4;
const U32 LEGACY_RIG_OK = 0;
const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1;
const U32 LEGACY_RIG_FLAG_UNKNOWN_JOINT = 2;
class LLModelLoader : public LLThread
{
public:
@ -166,7 +170,7 @@ public:
void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
//Determines if a rig is a legacy from the joint list
bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
U32 determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset );
//Determines if a rig is suitable for upload
bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
@ -174,8 +178,9 @@ public:
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
const bool isLegacyRigValid(void) const { return mLegacyRigFlags == 0; }
U32 getLegacyRigFlags() const { return mLegacyRigFlags; }
void setLegacyRigFlags( U32 rigFlags ) { mLegacyRigFlags = rigFlags; }
//-----------------------------------------------------------------------------
// isNodeAJoint()
@ -185,6 +190,9 @@ public:
return name != NULL && mJointMap.find(name) != mJointMap.end();
}
const LLSD logOut() const { return mWarningsArray; }
void clearLog() { mWarningsArray.clear(); }
protected:
LLModelLoader::load_callback_t mLoadCallback;
@ -194,13 +202,15 @@ protected:
void* mOpaqueData;
bool mRigValidJointUpload;
bool mLegacyRigValid;
U32 mLegacyRigFlags;
bool mNoNormalize;
bool mNoOptimize;
JointTransformMap mJointTransformMap;
LLSD mWarningsArray; // preview floater will pull logs from here
static std::list<LLModelLoader*> sActiveLoaderList;
static bool isAlive(LLModelLoader* loader) ;
};

View File

@ -643,7 +643,8 @@ void LLButton::draw()
LLColor4 highlighting_color = LLColor4::white;
LLColor4 glow_color = LLColor4::white;
LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
LLUIImage* imagep = NULL;
LLUIImage* imagep = NULL;
LLUIImage* image_glow = NULL;
// Cancel sticking of color, if the button is pressed,
// or when a flashing of the previously selected button is ended
@ -710,17 +711,18 @@ void LLButton::draw()
imagep = mImageDisabled;
}
image_glow = imagep;
if (mFlashing)
{
// if button should flash and we have icon for flashing, use it as image for button
if(flash && mImageFlash)
if (flash && mImageFlash)
{
// setting flash to false to avoid its further influence on glow
flash = false;
imagep = mImageFlash;
// if button should flash and we have icon for flashing, use it as image for button
image_glow = mImageFlash;
}
// else use usual flashing via flash_color
else if (mFlashingTimer)
// provide fade-in and fade-out via flash_color
if (mFlashingTimer)
{
LLColor4 flash_color = mFlashBgColor.get();
use_glow_effect = TRUE;
@ -734,6 +736,11 @@ void LLButton::draw()
{
glow_color = highlighting_color;
}
else
{
// will fade from highlight color
glow_color = flash_color;
}
}
}
@ -806,7 +813,7 @@ void LLButton::draw()
if (mCurGlowStrength > 0.01f)
{
gGL.setSceneBlendType(glow_type);
imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha));
gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
}
@ -817,7 +824,7 @@ void LLButton::draw()
if (mCurGlowStrength > 0.01f)
{
gGL.setSceneBlendType(glow_type);
imagep->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha));
image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha));
gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
}

View File

@ -205,6 +205,7 @@ public:
void setFlashing( bool b, bool force_flashing = false );
BOOL getFlashing() const { return mFlashing; }
LLFlashTimer* getFlashTimer() {return mFlashingTimer;}
void setFlashColor(const LLUIColor &color) { mFlashBgColor = color; };
void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
LLFontGL::HAlign getHAlign() const { return mHAlign; }

View File

@ -132,6 +132,7 @@ LLScrollListCtrl::Params::Params()
sort_ascending("sort_ascending", true),
mouse_wheel_opaque("mouse_wheel_opaque", false),
commit_on_keyboard_movement("commit_on_keyboard_movement", true),
commit_on_selection_change("commit_on_selection_change", false),
heading_height("heading_height"),
page_lines("page_lines", 0),
background_visible("background_visible"),
@ -162,7 +163,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
mMaxSelectable(0),
mAllowKeyboardMovement(true),
mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
mCommitOnSelectionChange(false),
mCommitOnSelectionChange(p.commit_on_selection_change),
mSelectionChanged(false),
mNeedsScroll(false),
mCanSelect(true),

View File

@ -97,6 +97,7 @@ public:
// behavioral flags
Optional<bool> multi_select,
commit_on_keyboard_movement,
commit_on_selection_change,
mouse_wheel_opaque;
// display flags

View File

@ -220,6 +220,8 @@ LLTabContainer::Params::Params()
last_tab("last_tab"),
use_custom_icon_ctrl("use_custom_icon_ctrl", false),
open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false),
enable_tabs_flashing("enable_tabs_flashing", false),
tabs_flashing_color("tabs_flashing_color"),
tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0),
use_ellipses("use_ellipses"),
font_halign("halign")
@ -259,6 +261,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mCustomIconCtrlUsed(p.use_custom_icon_ctrl),
mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop),
mTabIconCtrlPad(p.tab_icon_ctrl_pad),
mEnableTabsFlashing(p.enable_tabs_flashing),
mTabsFlashingColor(p.tabs_flashing_color),
mUseTabEllipses(p.use_ellipses)
{
static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
@ -280,6 +284,11 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mMinTabWidth = tabcntr_vert_tab_min_width;
}
if (p.tabs_flashing_color.isProvided())
{
mEnableTabsFlashing = true;
}
initButtons( );
}
@ -1102,6 +1111,10 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.pad_left( mLabelPadLeft );
p.pad_right(2);
}
// inits flash timer
p.button_flash_enable = mEnableTabsFlashing;
p.flash_color = mTabsFlashingColor;
// *TODO : It seems wrong not to use p in both cases considering the way p is initialized
if (mCustomIconCtrlUsed)

View File

@ -109,6 +109,12 @@ public:
* Open tabs on hover in drag and drop situations
*/
Optional<bool> open_tabs_on_drag_and_drop;
/**
* Enable tab flashing
*/
Optional<bool> enable_tabs_flashing;
Optional<LLUIColor> tabs_flashing_color;
/**
* Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true)
@ -310,6 +316,8 @@ private:
bool mCustomIconCtrlUsed;
bool mOpenTabsOnDragAndDrop;
bool mEnableTabsFlashing;
LLUIColor mTabsFlashingColor;
S32 mTabIconCtrlPad;
bool mUseTabEllipses;
};

View File

@ -2259,6 +2259,18 @@ void LLTextBase::needsReflow(S32 index)
mReflowIndex = llmin(mReflowIndex, index);
}
S32 LLTextBase::removeFirstLine()
{
if (!mLineInfoList.empty())
{
S32 length = getLineEnd(0);
deselect();
removeStringNoUndo(0, length);
return length;
}
return 0;
}
void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params)
{
segment_vec_t segments;

View File

@ -404,6 +404,7 @@ public:
virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style
virtual std::string getText() const;
void setMaxTextLength(S32 length) { mMaxTextByteLength = length; }
S32 getMaxTextLength() { return mMaxTextByteLength; }
// wide-char versions
void setWText(const LLWString& text);
@ -432,6 +433,7 @@ public:
S32 getLength() const { return getWText().length(); }
S32 getLineCount() const { return mLineInfoList.size(); }
S32 removeFirstLine(); // returns removed length
void addDocumentChild(LLView* view);
void removeDocumentChild(LLView* view);

View File

@ -401,6 +401,7 @@ set(viewer_SOURCE_FILES
llmenuoptionpathfindingrebakenavmesh.cpp
llmeshrepository.cpp
llmimetypes.cpp
llmodelpreview.cpp
llmorphview.cpp
llmoveview.cpp
llmutelist.cpp
@ -1032,6 +1033,7 @@ set(viewer_HEADER_FILES
llmenuoptionpathfindingrebakenavmesh.h
llmeshrepository.h
llmimetypes.h
llmodelpreview.h
llmorphview.h
llmoveview.h
llmutelist.h

View File

@ -1 +1 @@
6.4.10
6.4.11

View File

@ -6708,7 +6708,7 @@
<integer>600</integer>
</map>
<key>MigrateCacheDirectory</key>
<map>
<map>
<key>Comment</key>
<string>Check for old version of disk cache to migrate to current location</string>
<key>Persist</key>
@ -7958,7 +7958,6 @@
<key>Value</key>
<integer>13</integer>
</map>
<key>PreviewAmbientColor</key>
<map>
<key>Comment</key>
@ -7975,8 +7974,6 @@
<real>1.0</real>
</array>
</map>
<key>PreviewDiffuse0</key>
<map>
<key>Comment</key>
@ -16607,3 +16604,4 @@
</map>
</llsd>

View File

@ -93,6 +93,5 @@ void main()
col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz);
col.rgb += light_diffuse[2].rgb*calcLocalLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z);
col.rgb += light_diffuse[3].rgb*calcLocalLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z);
vertex_color = col*color;
}

View File

@ -125,11 +125,11 @@ BOOL LLViewerDynamicTexture::render()
//-----------------------------------------------------------------------------
void LLViewerDynamicTexture::preRender(BOOL clear_depth)
{
//only images up to 1024*1024 are supported
llassert(mFullHeight <= 512);
llassert(mFullWidth <= 512);
gPipeline.allocatePhysicsBuffer();
llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth()));
llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight()));
if (gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete())
if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI)
{ //using offscreen render target, just use the bottom left corner
mOrigin.set(0, 0);
}
@ -216,7 +216,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
return TRUE;
}
bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete();
bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete() && !gGLManager.mIsATI;
if (use_fbo)
{

File diff suppressed because it is too large Load Diff

View File

@ -28,36 +28,26 @@
#define LL_LLFLOATERMODELPREVIEW_H
#include "llfloaternamedesc.h"
#include "lldynamictexture.h"
#include "llquaternion.h"
#include "llmeshrepository.h"
#include "llmodel.h"
#include "llthread.h"
#include "llviewermenufile.h"
#include "llfloatermodeluploadbase.h"
#include "lldaeloader.h"
#include "llmeshrepository.h"
class LLComboBox;
class LLJoint;
class LLViewerJointMesh;
class LLVOAvatar;
class LLTextBox;
class LLVertexBuffer;
class LLMeshFilePicker;
class LLModelPreview;
class LLFloaterModelPreview;
class DAE;
class daeElement;
class domProfile_COMMON;
class domInstance_geometry;
class domNode;
class domTranslate;
class domController;
class domSkin;
class domMesh;
class LLMenuButton;
class LLToggleableMenu;
class LLTabContainer;
class LLViewerTextEditor;
class LLJointOverrideData
{
public:
LLJointOverrideData() : mHasConflicts(false) {};
std::map<std::string, LLVector3> mPosOverrides; // models with overrides
std::set<std::string> mModelsNoOverrides; // models without defined overrides
bool mHasConflicts;
};
typedef std::map<std::string, LLJointOverrideData> joint_override_data_map_t;
class LLFloaterModelPreview : public LLFloaterModelUploadBase
{
@ -80,6 +70,7 @@ public:
virtual ~LLFloaterModelPreview();
virtual BOOL postBuild();
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
void initModelPreview();
@ -93,6 +84,11 @@ public:
static void onMouseCaptureLostModelPreview(LLMouseHandler*);
static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
static void addStringToLog(const std::string& message, const LLSD& args, bool flash, S32 lod = -1);
static void addStringToLog(const std::string& str, bool flash);
static void addStringToLog(const std::ostringstream& strm, bool flash);
void clearAvatarTab(); // clears table
void updateAvatarTab(bool highlight_overrides); // populates table and data as nessesary
void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost);
void setPreviewLOD(S32 lod);
@ -107,13 +103,17 @@ public:
void loadModel(S32 lod);
void loadModel(S32 lod, const std::string& file_name, bool force_disable_slm = false);
void loadHighLodModel();
void onViewOptionChecked(LLUICtrl* ctrl);
void onUploadOptionChecked(LLUICtrl* ctrl);
bool isViewOptionChecked(const LLSD& userdata);
bool isViewOptionEnabled(const LLSD& userdata);
void setViewOptionEnabled(const std::string& option, bool enabled);
void enableViewOption(const std::string& option);
void disableViewOption(const std::string& option);
void onShowSkinWeightChecked(LLUICtrl* ctrl);
bool isModelLoading();
@ -142,8 +142,6 @@ protected:
static void onImportScaleCommit(LLUICtrl*, void*);
static void onPelvisOffsetCommit(LLUICtrl*, void*);
static void onUploadJointsCommit(LLUICtrl*,void*);
static void onUploadSkinCommit(LLUICtrl*,void*);
static void onPreviewLODCommit(LLUICtrl*,void*);
@ -154,6 +152,7 @@ protected:
static void onAutoFillCommit(LLUICtrl*,void*);
void onLODParamCommit(S32 lod, bool enforce_tri_limit);
void draw3dPreview();
static void onExplodeCommit(LLUICtrl*, void*);
@ -175,11 +174,15 @@ protected:
// FIXME - this function and mStatusMessage have no visible effect, and the
// actual status messages are managed by directly manipulation of
// the UI element.
void setStatusMessage(const std::string& msg);
void setStatusMessage(const std::string& msg);
void addStringToLogTab(const std::string& str, bool flash);
void setCtrlLoadFromFile(S32 lod);
LLModelPreview* mModelPreview;
LLPhysicsDecomp::decomp_params mDecompParams;
LLPhysicsDecomp::decomp_params mDefaultDecompParams;
S32 mLastMouseX;
S32 mLastMouseY;
@ -203,223 +206,34 @@ protected:
LLSD mModelPhysicsFee;
private:
void onClickCalculateBtn();
void toggleCalculateButton();
void onClickCalculateBtn();
void onJointListSelection();
void onLoDSourceCommit(S32 lod);
void modelUpdated(bool calculate_visible);
// Toggles between "Calculate weights & fee" and "Upload" buttons.
void toggleCalculateButton();
void toggleCalculateButton(bool visible);
// resets display options of model preview to their defaults.
void resetDisplayOptions();
void resetUploadOptions();
void clearLogTab();
void createSmoothComboBox(LLComboBox* combo_box, float min, float max);
LLButton* mUploadBtn;
LLButton* mCalculateBtn;
};
LLViewerTextEditor* mUploadLogText;
LLTabContainer* mTabContainer;
class LLMeshFilePicker : public LLFilePickerThread
{
public:
LLMeshFilePicker(LLModelPreview* mp, S32 lod);
virtual void notify(const std::vector<std::string>& filenames);
S32 mAvatarTabIndex; // just to avoid any issues in case of xml changes
std::string mSelectedJointName;
private:
LLModelPreview* mMP;
S32 mLOD;
};
class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
{
typedef boost::signals2::signal<void (F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)> details_signal_t;
typedef boost::signals2::signal<void (void)> model_loaded_signal_t;
typedef boost::signals2::signal<void (bool)> model_updated_signal_t;
public:
typedef enum
{
LOD_FROM_FILE = 0,
GENERATE,
USE_LOD_ABOVE,
} eLoDMode;
public:
LLModelPreview(S32 width, S32 height, LLFloater* fmp);
virtual ~LLModelPreview();
void resetPreviewTarget();
void setPreviewTarget(F32 distance);
void setTexture(U32 name) { mTextureName = name; }
void setPhysicsFromLOD(S32 lod);
BOOL render();
void update();
void genBuffers(S32 lod, bool skinned);
void clearBuffers();
void refresh();
void rotate(F32 yaw_radians, F32 pitch_radians);
void zoom(F32 zoom_amt);
void pan(F32 right, F32 up);
virtual BOOL needsRender() { return mNeedsUpdate; }
void setPreviewLOD(S32 lod);
void clearModel(S32 lod);
void getJointAliases(JointMap& joint_map);
void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);
void loadModelCallback(S32 lod);
bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
void queryLODs() { mGenLOD = true; };
void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
void generateNormals();
void restoreNormals();
U32 calcResourceCost();
void rebuildUploadData();
void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position);
void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position);
void clearIncompatible(S32 lod);
void updateStatusMessages();
void updateLodControls(S32 lod);
void clearGLODGroup();
void onLODParamCommit(S32 lod, bool enforce_tri_limit);
void addEmptyFace( LLModel* pTarget );
const bool getModelPivot( void ) const { return mHasPivot; }
void setHasPivot( bool val ) { mHasPivot = val; }
void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; }
//Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions
//Accessors for joint position upload friendly rigs
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
//Accessors for the legacy rigs
const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
static bool lodQueryCallback();
boost::signals2::connection setDetailsCallback( const details_signal_t::slot_type& cb ){ return mDetailsSignal.connect(cb); }
boost::signals2::connection setModelLoadedCallback( const model_loaded_signal_t::slot_type& cb ){ return mModelLoadedSignal.connect(cb); }
boost::signals2::connection setModelUpdatedCallback( const model_updated_signal_t::slot_type& cb ){ return mModelUpdatedSignal.connect(cb); }
void setLoadState( U32 state ) { mLoadState = state; }
U32 getLoadState() { return mLoadState; }
static bool sIgnoreLoadedCallback;
std::vector<S32> mLodsQuery;
std::vector<S32> mLodsWithParsingError;
protected:
static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque);
static void stateChangedCallback(U32 state, void* opaque);
static LLJoint* lookupJointByName(const std::string&, void* opaque);
static U32 loadTextures(LLImportMaterial& material, void* opaque);
private:
//Utility function for controller vertex compare
bool verifyCount( int expected, int result );
//Creates the dummy avatar for the preview window
void createPreviewAvatar( void );
//Accessor for the dummy avatar
LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; }
// Count amount of original models, excluding sub-models
static U32 countRootModels(LLModelLoader::model_list models);
protected:
friend class LLModelLoader;
friend class LLFloaterModelPreview;
friend class LLFloaterModelPreview::DecompRequest;
friend class LLPhysicsDecomp;
LLFloater* mFMP;
BOOL mNeedsUpdate;
bool mDirty;
bool mGenLOD;
U32 mTextureName;
F32 mCameraDistance;
F32 mCameraYaw;
F32 mCameraPitch;
F32 mCameraZoom;
LLVector3 mCameraOffset;
LLVector3 mPreviewTarget;
LLVector3 mPreviewScale;
S32 mPreviewLOD;
S32 mPhysicsSearchLOD;
U32 mResourceCost;
std::string mLODFile[LLModel::NUM_LODS];
bool mLoading;
U32 mLoadState;
bool mResetJoints;
bool mModelNoErrors;
std::map<std::string, bool> mViewOption;
//GLOD object parameters (must rebuild object if these change)
bool mLODFrozen;
F32 mBuildShareTolerance;
U32 mBuildQueueMode;
U32 mBuildOperator;
U32 mBuildBorderMode;
U32 mRequestedLoDMode[LLModel::NUM_LODS];
S32 mRequestedTriangleCount[LLModel::NUM_LODS];
F32 mRequestedErrorThreshold[LLModel::NUM_LODS];
U32 mRequestedBuildOperator[LLModel::NUM_LODS];
U32 mRequestedQueueMode[LLModel::NUM_LODS];
U32 mRequestedBorderMode[LLModel::NUM_LODS];
F32 mRequestedShareTolerance[LLModel::NUM_LODS];
F32 mRequestedCreaseAngle[LLModel::NUM_LODS];
LLModelLoader* mModelLoader;
LLModelLoader::scene mScene[LLModel::NUM_LODS];
LLModelLoader::scene mBaseScene;
LLModelLoader::model_list mModel[LLModel::NUM_LODS];
LLModelLoader::model_list mBaseModel;
typedef std::vector<LLVolumeFace> v_LLVolumeFace_t;
typedef std::vector<v_LLVolumeFace_t> vv_LLVolumeFace_t;
vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS];
vv_LLVolumeFace_t mBaseModelFacesCopy;
U32 mGroup;
std::map<LLPointer<LLModel>, U32> mObject;
U32 mMaxTriangleLimit;
LLMeshUploadThread::instance_list mUploadData;
std::set<LLViewerFetchedTexture * > mTextureSet;
//map of vertex buffers to models (one vertex buffer in vector per face in model
std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1];
details_signal_t mDetailsSignal;
model_loaded_signal_t mModelLoadedSignal;
model_updated_signal_t mModelUpdatedSignal;
LLVector3 mModelPivot;
bool mHasPivot;
float mPelvisZOffset;
bool mRigValidJointUpload;
bool mLegacyRigValid;
bool mLastJointUpdate;
JointNameSet mJointsFromNode;
JointTransformMap mJointTransformMap;
LLPointer<LLVOAvatar> mPreviewAvatar;
joint_override_data_map_t mJointOverrides[LLModel::NUM_LODS];
};
#endif // LL_LLFLOATERMODELPREVIEW_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,313 @@
/**
* @file llmodelpreview.h
* @brief LLModelPreview class definition, class
* responsible for model preview inside LLFloaterModelPreview
*
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2020, 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 LL_LLMODELPREVIEW_H
#define LL_LLMODELPREVIEW_H
#include "lldynamictexture.h"
#include "llfloatermodelpreview.h"
#include "llmeshrepository.h"
#include "llmodelloader.h" //NUM_LOD
#include "llmodel.h"
class LLJoint;
class LLVOAvatar;
class LLTextBox;
class LLVertexBuffer;
class DAE;
class daeElement;
class domProfile_COMMON;
class domInstance_geometry;
class domNode;
class domTranslate;
class domController;
class domSkin;
class domMesh;
// const strings needed by classes that use model preivew
static const std::string lod_name[NUM_LOD + 1] =
{
"lowest",
"low",
"medium",
"high",
"I went off the end of the lod_name array. Me so smart."
};
static const std::string lod_triangles_name[NUM_LOD + 1] =
{
"lowest_triangles",
"low_triangles",
"medium_triangles",
"high_triangles",
"I went off the end of the lod_triangles_name array. Me so smart."
};
static const std::string lod_vertices_name[NUM_LOD + 1] =
{
"lowest_vertices",
"low_vertices",
"medium_vertices",
"high_vertices",
"I went off the end of the lod_vertices_name array. Me so smart."
};
static const std::string lod_status_name[NUM_LOD + 1] =
{
"lowest_status",
"low_status",
"medium_status",
"high_status",
"I went off the end of the lod_status_name array. Me so smart."
};
static const std::string lod_icon_name[NUM_LOD + 1] =
{
"status_icon_lowest",
"status_icon_low",
"status_icon_medium",
"status_icon_high",
"I went off the end of the lod_status_name array. Me so smart."
};
static const std::string lod_status_image[NUM_LOD + 1] =
{
"ModelImport_Status_Good",
"ModelImport_Status_Warning",
"ModelImport_Status_Error",
"I went off the end of the lod_status_image array. Me so smart."
};
static const std::string lod_label_name[NUM_LOD + 1] =
{
"lowest_label",
"low_label",
"medium_label",
"high_label",
"I went off the end of the lod_label_name array. Me so smart."
};
class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
{
LOG_CLASS(LLModelPreview);
typedef boost::signals2::signal<void(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)> details_signal_t;
typedef boost::signals2::signal<void(void)> model_loaded_signal_t;
typedef boost::signals2::signal<void(bool)> model_updated_signal_t;
public:
typedef enum
{
LOD_FROM_FILE = 0,
GENERATE,
USE_LOD_ABOVE,
} eLoDMode;
public:
// Todo: model preview shouldn't need floater dependency, it
// should just expose data to floater, not control flaoter like it does
LLModelPreview(S32 width, S32 height, LLFloater* fmp);
virtual ~LLModelPreview();
void resetPreviewTarget();
void setPreviewTarget(F32 distance);
void setTexture(U32 name) { mTextureName = name; }
void setPhysicsFromLOD(S32 lod);
BOOL render();
void update();
void genBuffers(S32 lod, bool skinned);
void clearBuffers();
void refresh();
void rotate(F32 yaw_radians, F32 pitch_radians);
void zoom(F32 zoom_amt);
void pan(F32 right, F32 up);
virtual BOOL needsRender() { return mNeedsUpdate; }
void setPreviewLOD(S32 lod);
void clearModel(S32 lod);
void getJointAliases(JointMap& joint_map);
void loadModel(std::string filename, S32 lod, bool force_disable_slm = false);
void loadModelCallback(S32 lod);
bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
void queryLODs() { mGenLOD = true; };
void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
void generateNormals();
void restoreNormals();
U32 calcResourceCost();
void rebuildUploadData();
void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position);
void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position);
void clearIncompatible(S32 lod);
void updateStatusMessages();
void updateLodControls(S32 lod);
void clearGLODGroup();
void onLODParamCommit(S32 lod, bool enforce_tri_limit);
void addEmptyFace(LLModel* pTarget);
const bool getModelPivot(void) const { return mHasPivot; }
void setHasPivot(bool val) { mHasPivot = val; }
void setModelPivot(const LLVector3& pivot) { mModelPivot = pivot; }
//Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions
//Accessors for joint position upload friendly rigs
const bool isRigValidForJointPositionUpload(void) const { return mRigValidJointUpload; }
void setRigValidForJointPositionUpload(bool rigValid) { mRigValidJointUpload = rigValid; }
//Accessors for the legacy rigs
const bool isLegacyRigValid(void) const { return mLegacyRigFlags == 0; }
U32 getLegacyRigFlags() const { return mLegacyRigFlags; }
void setLegacyRigFlags(U32 rigFlags) { mLegacyRigFlags = rigFlags; }
static void textureLoadedCallback(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata);
static bool lodQueryCallback();
boost::signals2::connection setDetailsCallback(const details_signal_t::slot_type& cb){ return mDetailsSignal.connect(cb); }
boost::signals2::connection setModelLoadedCallback(const model_loaded_signal_t::slot_type& cb){ return mModelLoadedSignal.connect(cb); }
boost::signals2::connection setModelUpdatedCallback(const model_updated_signal_t::slot_type& cb){ return mModelUpdatedSignal.connect(cb); }
void setLoadState(U32 state) { mLoadState = state; }
U32 getLoadState() { return mLoadState; }
static bool sIgnoreLoadedCallback;
std::vector<S32> mLodsQuery;
std::vector<S32> mLodsWithParsingError;
bool mHasDegenerate;
protected:
static void loadedCallback(LLModelLoader::scene& scene, LLModelLoader::model_list& model_list, S32 lod, void* opaque);
static void stateChangedCallback(U32 state, void* opaque);
static LLJoint* lookupJointByName(const std::string&, void* opaque);
static U32 loadTextures(LLImportMaterial& material, void* opaque);
void lookupLODModelFiles(S32 lod);
private:
//Utility function for controller vertex compare
bool verifyCount(int expected, int result);
//Creates the dummy avatar for the preview window
void createPreviewAvatar(void);
//Accessor for the dummy avatar
LLVOAvatar* getPreviewAvatar(void) { return mPreviewAvatar; }
// Count amount of original models, excluding sub-models
static U32 countRootModels(LLModelLoader::model_list models);
protected:
friend class LLModelLoader;
friend class LLFloaterModelPreview;
friend class LLFloaterModelPreview::DecompRequest;
friend class LLPhysicsDecomp;
LLFloater* mFMP;
BOOL mNeedsUpdate;
bool mDirty;
bool mGenLOD;
U32 mTextureName;
F32 mCameraDistance;
F32 mCameraYaw;
F32 mCameraPitch;
F32 mCameraZoom;
LLVector3 mCameraOffset;
LLVector3 mPreviewTarget;
LLVector3 mPreviewScale;
S32 mPreviewLOD;
S32 mPhysicsSearchLOD;
U32 mResourceCost;
std::string mLODFile[LLModel::NUM_LODS];
bool mLoading;
U32 mLoadState;
bool mResetJoints;
bool mModelNoErrors;
bool mLookUpLodFiles;
std::map<std::string, bool> mViewOption;
//GLOD object parameters (must rebuild object if these change)
bool mLODFrozen;
F32 mBuildShareTolerance;
U32 mBuildQueueMode;
U32 mBuildOperator;
U32 mBuildBorderMode;
U32 mRequestedLoDMode[LLModel::NUM_LODS];
S32 mRequestedTriangleCount[LLModel::NUM_LODS];
F32 mRequestedErrorThreshold[LLModel::NUM_LODS];
U32 mRequestedBuildOperator[LLModel::NUM_LODS];
U32 mRequestedQueueMode[LLModel::NUM_LODS];
U32 mRequestedBorderMode[LLModel::NUM_LODS];
F32 mRequestedShareTolerance[LLModel::NUM_LODS];
F32 mRequestedCreaseAngle[LLModel::NUM_LODS];
LLModelLoader* mModelLoader;
LLModelLoader::scene mScene[LLModel::NUM_LODS];
LLModelLoader::scene mBaseScene;
LLModelLoader::model_list mModel[LLModel::NUM_LODS];
LLModelLoader::model_list mBaseModel;
typedef std::vector<LLVolumeFace> v_LLVolumeFace_t;
typedef std::vector<v_LLVolumeFace_t> vv_LLVolumeFace_t;
vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS];
vv_LLVolumeFace_t mBaseModelFacesCopy;
U32 mGroup;
std::map<LLPointer<LLModel>, U32> mObject;
U32 mMaxTriangleLimit;
LLMeshUploadThread::instance_list mUploadData;
std::set<LLViewerFetchedTexture * > mTextureSet;
//map of vertex buffers to models (one vertex buffer in vector per face in model
std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS + 1];
details_signal_t mDetailsSignal;
model_loaded_signal_t mModelLoadedSignal;
model_updated_signal_t mModelUpdatedSignal;
LLVector3 mModelPivot;
bool mHasPivot;
float mPelvisZOffset;
bool mRigValidJointUpload;
U32 mLegacyRigFlags;
bool mLastJointUpdate;
bool mFirstSkinUpdate;
JointNameSet mJointsFromNode;
JointTransformMap mJointTransformMap;
LLPointer<LLVOAvatar> mPreviewAvatar;
LLCachedControl<bool> mImporterDebug;
};
#endif // LL_LLMODELPREVIEW_H

View File

@ -552,7 +552,7 @@ class LLFileUploadModel : public view_listener_t
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model");
if (fmp && !fmp->isModelLoading())
{
fmp->loadModel(3);
fmp->loadHighLodModel();
}
return TRUE;

View File

@ -1578,13 +1578,16 @@ void LLVOAvatar::renderCollisionVolumes()
}
}
void LLVOAvatar::renderBones()
void LLVOAvatar::renderBones(const std::string &selected_joint)
{
LLGLEnable blend(GL_BLEND);
avatar_joint_list_t::iterator iter = mSkeleton.begin();
avatar_joint_list_t::iterator end = mSkeleton.end();
avatar_joint_list_t::iterator end = mSkeleton.end();
// For selected joints
static LLVector3 SELECTED_COLOR_OCCLUDED(1.0f, 1.0f, 0.0f);
static LLVector3 SELECTED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f);
// For bones with position overrides defined
static LLVector3 OVERRIDE_COLOR_OCCLUDED(1.0f, 0.0f, 0.0f);
static LLVector3 OVERRIDE_COLOR_VISIBLE(0.5f, 0.5f, 0.5f);
@ -1611,7 +1614,18 @@ void LLVOAvatar::renderBones()
LLVector3 pos;
LLUUID mesh_id;
if (jointp->hasAttachmentPosOverride(pos,mesh_id))
F32 sphere_scale = SPHERE_SCALEF;
// We are in render, so it is preferable to implement selection
// in a different way, but since this is for debug/preview, this
// is low priority
if (jointp->getName() == selected_joint)
{
sphere_scale *= 16;
occ_color = SELECTED_COLOR_OCCLUDED;
visible_color = SELECTED_COLOR_VISIBLE;
}
else if (jointp->hasAttachmentPosOverride(pos,mesh_id))
{
occ_color = OVERRIDE_COLOR_OCCLUDED;
visible_color = OVERRIDE_COLOR_VISIBLE;
@ -1632,7 +1646,6 @@ void LLVOAvatar::renderBones()
LLVector3 begin_pos(0,0,0);
LLVector3 end_pos(jointp->getEnd());
F32 sphere_scale = SPHERE_SCALEF;
gGL.pushMatrix();
gGL.multMatrix( &jointp->getXform()->getWorldMatrix().mMatrix[0][0] );

View File

@ -444,7 +444,7 @@ public:
F32 getLastSkinTime() { return mLastSkinTime; }
U32 renderTransparent(BOOL first_pass);
void renderCollisionVolumes();
void renderBones();
void renderBones(const std::string &selected_joint = std::string());
void renderJoints();
static void deleteCachedImages(bool clearAll=true);
static void destroyGL();

View File

@ -6610,7 +6610,7 @@ void LLPipeline::enableLightsPreview()
light->enable();
light->setPosition(light_pos);
light->setDiffuse(diffuse0);
light->setAmbient(LLColor4::black);
light->setAmbient(ambient);
light->setSpecular(specular0);
light->setSpotExponent(0.f);
light->setSpotCutoff(180.f);
@ -6621,7 +6621,7 @@ void LLPipeline::enableLightsPreview()
light->enable();
light->setPosition(light_pos);
light->setDiffuse(diffuse1);
light->setAmbient(LLColor4::black);
light->setAmbient(ambient);
light->setSpecular(specular1);
light->setSpotExponent(0.f);
light->setSpotCutoff(180.f);
@ -6631,7 +6631,7 @@ void LLPipeline::enableLightsPreview()
light->enable();
light->setPosition(light_pos);
light->setDiffuse(diffuse2);
light->setAmbient(LLColor4::black);
light->setAmbient(ambient);
light->setSpecular(specular2);
light->setSpotExponent(0.f);
light->setSpotCutoff(180.f);

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

View File

@ -634,6 +634,7 @@ with the same filename but different name
<texture name="TabTop_Right_Off" file_name="containers/TabTop_Right_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
<texture name="TabTop_Right_Selected" file_name="containers/TabTop_Right_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
<texture name="TabTop_Right_Flashing" file_name="containers/TabTop_Right_Flashing.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" />
<texture name="TabTop_Middle_Off" file_name="containers/TabTop_Middle_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="120" scale.bottom="9" />
<texture name="TabTop_Middle_Selected" file_name="containers/TabTop_Middle_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="96" scale.bottom="9" />
<texture name="TabTop_Left_Off" file_name="containers/TabTop_Left_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="120" scale.bottom="9" />

View File

@ -2,15 +2,16 @@
<floater
can_close="true"
can_drag_on_left="false"
can_minimize="false"
can_resize="false"
height="480"
min_height="480"
can_minimize="true"
can_resize="true"
height="625"
min_height="625"
width="980"
min_width="980"
name="Model Preview"
title="UPLOAD MODEL"
help_topic="upload_model" >
help_topic="upload_model"
legacy_header_height="25">
<string name="status_idle"></string>
<string name="status_parse_error">Error: Dae parsing issue - see log for details.</string>
@ -33,19 +34,27 @@
<string name="mesh_status_missing_lod">Missing required level of detail.</string>
<string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string>
<string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string>
<string name="phys_status_degenerate_triangles">The physics mesh too dense remove the small thin triangles (see preview)</string>
<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>
<!-- Warnings and info from model loader-->
<string name="TooManyJoint">Skinning disabled due to too many joints: [JOINTS], maximum: [MAX]</string>
<string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>
<string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string>
<string name="ModelLoaded">Model [MODEL_NAME] loaded</string>
<string name="IncompleteTC">Texture coordinates data is not complete.</string>
<panel
follows="top|left"
height="455"
layout="topleft"
left="3"
name="left_panel"
top_pad="10"
width="630">
<panel
follows="top|left"
height="595"
layout="topleft"
left="3"
name="left_panel"
top_pad="25"
width="635">
<panel
follows="all"
height="50"
@ -76,12 +85,16 @@
</panel>
<tab_container
follows="top|left"
top_pad="15"
top_pad="10"
left="0"
height="300"
height="330"
width="635"
name="import_tab"
tab_position="top">
tab_position="top"
enable_tabs_flashing="true"
tabs_flashing_color="MenuItemFlashBgColor">
<last_tab
tab_top_image_flash="TabTop_Right_Flashing"/> <!-- for log tab -->
<!-- LOD PANEL -->
<panel
help_topic="upload_model_lod"
@ -92,12 +105,12 @@
<view_border
bevel_style="none"
follows="top|left"
height="275"
height="306"
layout="topleft"
left="3"
name="lod_tab_border"
top_pad="0"
width="629" />
width="628" />
<text
follows="left|top"
height="18"
@ -688,7 +701,7 @@
left="10"
name="lod_tab_border"
top_pad="20"
width="605" />
width="614" />
<check_box
follows="top|left"
height="15"
@ -730,12 +743,12 @@
<view_border
bevel_style="none"
follows="top|left"
height="275"
height="306"
layout="topleft"
left="3"
name="physics_tab_border"
top_pad="0"
width="619"/>
width="628"/>
<panel
bg_alpha_color="0 0 0 0"
bg_opaque_color="0 0 0 0.3"
@ -755,8 +768,9 @@
name="first_step_name"
text_color="White"
top_pad="0"
width="210">
Step 1: Level of Detail
width="210"
valign="center">
Step 1: Pick a physics model :
</text>
<combo_box
follows="left|top"
@ -798,7 +812,7 @@
layout="topleft"
left="18"
name="physics_tab_border"
top_pad="15"
top_pad="10"
width="589"/>
<panel
bg_alpha_color="0 0 0 0"
@ -807,7 +821,7 @@
follows="top|left"
left="18"
name="physics analysis"
top_pad="15"
top_pad="10"
visible="true"
width="589">
<text
@ -819,7 +833,7 @@
name="method_label"
text_color="White"
top_pad="0">
Step 2: Analyze
Step 2: Convert to hulls (optional)
</text>
<text
follows="top|left"
@ -905,7 +919,7 @@
layout="topleft"
left="18"
name="physics_tab_border"
top_pad="15"
top_pad="10"
width="589"/>
<panel
bg_alpha_color="0 0 0 0"
@ -914,7 +928,7 @@
height="66"
left="18"
name="physics simplification"
top_pad="15"
top_pad="10"
width="589">
<text
text_color="White"
@ -1013,7 +1027,7 @@
layout="topleft"
left="18"
name="physics_tab_border"
top_pad="15"
top_pad="10"
width="589"/>
<panel
bg_alpha_color="0 0 0 0"
@ -1075,10 +1089,9 @@
follows="left|top"
height="19"
layout="topleft"
left_pad="5"
top_delta="0"
top_pad="5"
name="physics message"
width="270">
width="589">
<icon
follows="left|top"
height="16"
@ -1093,7 +1106,7 @@
layout="topleft"
left_pad="2"
name="physics_status_message_text"
width="252"
width="573"
top_delta="3"/>
</panel>
</panel>
@ -1105,12 +1118,12 @@
<view_border
bevel_style="none"
follows="top|left"
height="275"
height="306"
layout="topleft"
left="3"
name="border"
top_pad="0"
width="619"/>
width="628"/>
<text
follows="top|left"
height="16"
@ -1157,75 +1170,211 @@
label_text.text_color="White"
left="20"
top_pad="20"/>
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
name="border"
top_pad="20"
width="579"/>
<text
follows="top|left"
height="15"
left="20"
name="include_label"
text_color="White"
top_pad="20"
width="150">
For avatar models only:
</text>
<check_box
follows="top|left"
height="15"
label="Include skin weight"
label_text.text_color="White"
name="upload_skin"
top_pad="15"/>
<check_box
follows="top|left"
height="15"
label="Include joint positions"
label_text.text_color="White"
name="upload_joints"
top_pad="15"/>
<check_box
follows="top|left"
height="15"
label="Lock scale if joint position defined"
label_text.text_color="White"
name="lock_scale_if_joint_position"
top_pad="15"/>
<text
follows="top|left"
height="15"
layout="topleft"
left="220"
name="pelvis_offset_label"
text_color="White"
top="134"
width="200">
Z offset (raise or lower avatar):
</text>
<spinner
follows="top|left"
height="20"
min_val="-3.00"
max_val="3.0"
name="pelvis_offset"
top_pad="10"
value="0.0"
width="80"/>
</panel>
<panel
label="Overrides"
layout="topleft"
name="rigging_panel"
title="Rigging">
<view_border
bevel_style="none"
follows="top|left"
height="306"
layout="topleft"
left="3"
name="avatar_tab_border"
top_pad="0"
width="628" />
<check_box
follows="top|left"
height="15"
label="Include skin weight"
label_text.text_color="White"
name="upload_skin"
top="8"
left="20"/>
<check_box
follows="top|left"
height="15"
label="Include joint positions"
label_text.text_color="White"
name="upload_joints"
left_delta="0"
top_pad="7"/>
<check_box
follows="top|left"
height="15"
label="Lock scale if joint position defined"
label_text.text_color="White"
name="lock_scale_if_joint_position"
top_pad="7"/>
<text
follows="top|left"
height="15"
layout="topleft"
left="220"
name="pelvis_offset_label"
text_color="White"
top="8"
width="200">
Z offset (raise or lower avatar):
</text>
<spinner
follows="top|left"
height="20"
min_val="-3.00"
max_val="3.0"
name="pelvis_offset"
top_pad="10"
value="0.0"
width="80"/>
<text
follows="top|left"
height="17"
left="425"
name="skin_too_many_joints"
text_color="Orange"
top="7"
width="195"
word_wrap="true">
Too many skinned joints
</text>
<text
follows="top|left"
height="32"
left="425"
name="skin_unknown_joint"
text_color="Orange"
top="8"
width="195"
word_wrap="true">
Model has an unknown joint(s)
</text>
<text
layout="topleft"
follows="top|left"
height="15"
left="20"
name="joints_descr"
top="73"
width="150">
Joints:
</text>
<scroll_list
layout="topleft"
follows="top|left"
name="joints_list"
column_padding="0"
draw_heading="false"
draw_stripes="false"
commit_on_selection_change="true"
heading_height="23"
height="199"
left_delta="0"
top_pad="0"
width="200"/>
<text
layout="topleft"
follows="top|left"
height="15"
left_delta="0"
name="conflicts_description"
top_pad="2"
width="200">
[CONFLICTS] conflicts in [JOINTS_COUNT] joints
</text>
<text
layout="topleft"
follows="top|left"
height="15"
left_pad="5"
name="pos_overrides_descr"
top="73"
width="300">
Position overrides for joint '[JOINT]':
</text>
<scroll_list
layout="topleft"
follows="top|left"
name="pos_overrides_list"
column_padding="0"
draw_heading="true"
draw_stripes="false"
heading_height="23"
height="100"
left_delta="0"
top_pad="0"
width="385">
<scroll_list.columns
label="Model"
name="model_name"
relative_width="0.49" />
<scroll_list.columns
label="X"
name="axis_x"
relative_width="0.17" />
<scroll_list.columns
label="Y"
name="axis_y"
relative_width="0.17" />
<scroll_list.columns
label="Z"
name="axis_z"
relative_width="0.17" />
</scroll_list>
</panel>
<panel
label="Log"
layout="topleft"
name="logs_panel"
title="Log">
<view_border
bevel_style="none"
follows="top|left"
height="289"
layout="topleft"
left="3"
name="log_tab_border"
top_pad="0"
width="628" />
<text_editor
type="string"
length="1"
embedded_items="false"
follows="top|left"
font="SansSerif"
ignore_tab="false"
layout="topleft"
height="289"
left="4"
top="0"
right="-1"
max_length="65536"
name="log_text"
parse_urls="true"
spellcheck="false"
read_only="true"
word_wrap="true">
</text_editor>
<check_box
control_name="ImporterDebug"
follows="top|left"
top_pad="9"
left="6"
width="70"
label="Enable detailed logging"
name="verbose_logging"/>
</panel>
</tab_container>
<panel
follows="top|left"
height="80"
layout="top|left"
left="0"
follows="top|left|bottom"
layout="topleft"
height="195"
left="4"
border="true"
name="weights_and_warning_panel"
top_pad="3"
width="625">
width="629">
<button
follows="top|left"
label="Calculate weights &amp; fee"
@ -1265,10 +1414,10 @@
label_color="White"
layout="topleft"
name="reset_btn"
right="-2"
right="-5"
top="3"
height="20"
width="275"/>
width="265"/>
<!-- ========== WEIGHTS ==========-->
<text
follows="top|left"
@ -1287,7 +1436,7 @@
left_pad="0"
name="prim_weight"
top_delta="0"
width="120"
width="130"
word_wrap="true">
Land impact: [EQ]
</text>
@ -1297,7 +1446,7 @@
left_pad="0"
name="download_weight"
top_delta="0"
width="100"
width="130"
word_wrap="true">
Download: [ST]
</text>
@ -1307,7 +1456,7 @@
layout="topleft"
left_pad="0"
name="physics_weight"
width="90"
width="130"
word_wrap="true">
Physics: [PH]
</text>
@ -1317,19 +1466,150 @@
layout="topleft"
left_pad="0"
name="server_weight"
width="83"
width="130"
word_wrap="true">
Server: [SIM]
</text>
<!-- ========== NOTE MESSAGE ========== -->
<!-- =========== Cost breakdown ======== -->
<panel
border="true"
top_pad="5"
layout="topleft"
left="6"
name="price_breakdown_panel"
width="120"
height="100">
<text
layout="topleft"
left="3">
Price Breakdown
</text>
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="3"
name="price_breakdown_border"
top_pad="5"
width="110"/>
<text
height="80"
top_pad="5"
layout="topleft"
left="3"
name="price_breakdown_labels"
width="70"
word_wrap="false">
Download:
Physics:
Instances:
Textures:
Model:
</text>
<text
height="80"
top_delta="0"
layout="topleft"
halign="right"
left_pad="0"
name="price_breakdown"
width="40"
word_wrap="false">
[STREAMING]
[PHYSICS]
[INSTANCES]
[TEXTURES]
[MODEL]
</text>
</panel>
<!--
Streaming breakdown numbers are available but not fully understood
uncommenting the following sections will display the numbers for debugging purposes
<text
height="80"
top_delta="0"
layout="topleft"
left="130"
name="streaming_breakdown_labels"
width="65"
word_wrap="true">
Streaming/Download:
High:
Medium:
Low:
Lowest:
</text>
<text
height="80"
top_delta="0"
layout="topleft"
left_pad="0"
name="streaming_breakdown"
width="95"
word_wrap="true">
[STR_TOTAL]
[STR_HIGH]
[STR_MED]
[STR_LOW]
[STR_LOWEST]
</text>-->
<panel
border="true"
layout="topleft"
left_pad="265"
name="physics_costs_panel"
width="120"
height="100">
<text
layout="topleft"
left="3">
Physics Costs
</text>
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="3"
name="price_breakdown_border"
top_pad="5"
width="110"/>
<text
height="80"
top_pad="5"
layout="topleft"
left="5"
name="physics_breakdown_labels"
width="65">
Base Hull:
Mesh:
Analysed:
</text>
<text
height="80"
top_delta="0"
layout="topleft"
left_pad="0"
name="physics_breakdown"
width="40"
halign="right"
word_wrap="false"
visible="true">
[PCH]
[PM]
[PHU]
</text>-->
</panel>
<!-- ========== NOTE MESSAGE ========== -->
<text
font="SansSerif"
layout="topleft"
left="6"
name="warning_title"
top_pad="10"
top_pad="5"
text_color="DrYellow"
visible="false"
visible="true"
width="40">
NOTE:
</text>
@ -1340,44 +1620,51 @@
left_pad="1"
name="warning_message"
parse_urls="true"
top_delta="2"
top_delta="1"
wrap="true"
width="462"
visible="false">
visible="true">
You dont have rights to upload mesh models. [[VURL] Find out how] to get certified.
</text>
<text
text_color="Yellow"
layout="topleft"
top_pad="-2"
left="6"
name="status">
[STATUS]
</text>
<text text_color="Yellow" layout="topleft" top_delta="20" left="6" name="status">[STATUS]</text>
</panel>
</panel>
<text
follows="left|top"
layout="topleft"
left="640"
name="lod_label"
text_color="White"
top="13"
height="15"
width="290">
Preview:
</text>
<panel
border="true"
bevel_style="none"
follows="top|left"
name="preview_panel"
top_pad="4"
width="290"
height="290"/>
<panel
follows="all"
height="130"
layout="topleft"
name="right_panel"
top_pad="5"
width="340">
</panel>
<text
follows="left|top"
layout="topleft"
left="640"
name="lod_label"
text_color="White"
top="29"
height="15"
width="290">
Preview:
</text>
<panel
follows="all"
layout="topleft"
border="true"
bevel_style="none"
name="preview_panel"
top_pad="4"
width="325"
height="408"/>
<panel
follows="right|bottom"
can_resize="false"
height="140"
layout="topleft"
name="right_panel"
top_pad="5"
width="340">
<combo_box
top_pad="3"
follows="left|top"
@ -1386,10 +1673,10 @@
name="preview_lod_combo"
width="150"
tool_tip="LOD to view in preview render">
<combo_item name="high"> High </combo_item>
<combo_item name="medium"> Medium </combo_item>
<combo_item name="low"> Low </combo_item>
<combo_item name="lowest"> Lowest </combo_item>
<combo_item name="high"> High </combo_item>
<combo_item name="medium"> Medium </combo_item>
<combo_item name="low"> Low </combo_item>
<combo_item name="lowest"> Lowest </combo_item>
</combo_box>
<text
follows="top|left"
@ -1434,13 +1721,23 @@
name="show_skin_weight"
top_pad="8">
</check_box>
<check_box
follows="top|left"
label="Joint position overrides"
label_text.text_color="White"
word_wrap="down"
width="130"
layout="topleft"
name="show_joint_overrides"
top_pad="8">
</check_box>
<check_box
follows="top|left"
label="Joints"
label_text.text_color="White"
layout="topleft"
name="show_joint_positions"
top_pad="8">
top_pad="17">
</check_box>
<text
follows="top|left"
@ -1460,5 +1757,5 @@
max_val="3.0"
height="20"
width="150"/>
</panel>
</panel>
</floater>

View File

@ -17,5 +17,6 @@
name="Preview Tabs"
tab_position="bottom"
top="16"
width="448" />
width="448"
enable_tabs_flashing="true"/>
</multi_floater>