Merge remote-tracking branch 'origin/master' into DRTVWR-559

master
Brad Kittenbrink 2022-08-04 10:59:26 -07:00
commit 38208441db
73 changed files with 3368 additions and 485 deletions

View File

@ -4,12 +4,14 @@ project(llmath)
include(00-Common)
include(LLCommon)
include(LLMeshOptimizer)
include(bugsplat)
include(Boost)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
${LLMESHOPTIMIZER_INCLUDE_DIRS}
)
set(llmath_SOURCE_FILES
@ -109,6 +111,7 @@ add_library (llmath ${llmath_SOURCE_FILES})
target_link_libraries(llmath
${LLCOMMON_LIBRARIES}
${LLMESHOPTIMIZER_LIBRARIES}
)
# Add tests

View File

@ -49,6 +49,7 @@
#include "llsdserialize.h"
#include "llvector4a.h"
#include "llmatrix4a.h"
#include "llmeshoptimizer.h"
#include "lltimer.h"
#define DEBUG_SILHOUETTE_BINORMALS 0
@ -4952,6 +4953,50 @@ bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a
return a.mV[2] < b.mV[2];
}
void LLVolumeFace::remap()
{
// Generate a remap buffer
std::vector<unsigned int> remap(mNumVertices);
S32 remap_vertices_count = LLMeshOptimizer::generateRemapMultiU16(&remap[0],
mIndices,
mNumIndices,
mPositions,
mNormals,
mTexCoords,
mNumVertices);
// Allocate new buffers
S32 size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF;
U16* remap_indices = (U16*)ll_aligned_malloc_16(size);
S32 tc_bytes_size = ((remap_vertices_count * sizeof(LLVector2)) + 0xF) & ~0xF;
LLVector4a* remap_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * remap_vertices_count + tc_bytes_size);
LLVector4a* remap_normals = remap_positions + remap_vertices_count;
LLVector2* remap_tex_coords = (LLVector2*)(remap_normals + remap_vertices_count);
// Fill the buffers
LLMeshOptimizer::remapIndexBufferU16(remap_indices, mIndices, mNumIndices, &remap[0]);
LLMeshOptimizer::remapPositionsBuffer(remap_positions, mPositions, mNumVertices, &remap[0]);
LLMeshOptimizer::remapNormalsBuffer(remap_normals, mNormals, mNumVertices, &remap[0]);
LLMeshOptimizer::remapUVBuffer(remap_tex_coords, mTexCoords, mNumVertices, &remap[0]);
// Free unused buffers
ll_aligned_free_16(mIndices);
ll_aligned_free<64>(mPositions);
// Tangets are now invalid
ll_aligned_free_16(mTangents);
mTangents = NULL;
// Assign new values
mIndices = remap_indices;
mPositions = remap_positions;
mNormals = remap_normals;
mTexCoords = remap_tex_coords;
mNumVertices = remap_vertices_count;
mNumAllocatedVertices = remap_vertices_count;
}
void LLVolumeFace::optimize(F32 angle_cutoff)
{
LLVolumeFace new_face;

View File

@ -902,6 +902,10 @@ public:
typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
};
// Eliminates non unique triangles, takes positions,
// normals and texture coordinates into account.
void remap();
void optimize(F32 angle_cutoff = 2.f);
bool cacheOptimize();

View File

@ -28,6 +28,9 @@
#include "meshoptimizer.h"
#include "llmath.h"
#include "v2math.h"
LLMeshOptimizer::LLMeshOptimizer()
{
// Todo: Looks like for memory management, we can add allocator and deallocator callbacks
@ -40,24 +43,218 @@ LLMeshOptimizer::~LLMeshOptimizer()
}
//static
void LLMeshOptimizer::generateShadowIndexBuffer(U16 *destination,
const U16 *indices,
void LLMeshOptimizer::generateShadowIndexBufferU32(U32 *destination,
const U32 *indices,
U64 index_count,
const LLVector4a *vertex_positions,
U64 vertex_count,
U64 vertex_positions_stride
const LLVector4a * vertex_positions,
const LLVector4a * normals,
const LLVector2 * text_coords,
U64 vertex_count
)
{
meshopt_generateShadowIndexBuffer<unsigned short>(destination,
meshopt_Stream streams[3];
S32 index = 0;
if (vertex_positions)
{
streams[index].data = (const float*)vertex_positions;
// Despite being LLVector4a, only x, y and z are in use
streams[index].size = sizeof(F32) * 3;
streams[index].stride = sizeof(F32) * 4;
index++;
}
if (normals)
{
streams[index].data = (const float*)normals;
streams[index].size = sizeof(F32) * 3;
streams[index].stride = sizeof(F32) * 4;
index++;
}
if (text_coords)
{
streams[index].data = (const float*)text_coords;
streams[index].size = sizeof(F32) * 2;
streams[index].stride = sizeof(F32) * 2;
index++;
}
if (index == 0)
{
// invalid
return;
}
meshopt_generateShadowIndexBufferMulti<unsigned int>(destination,
indices,
index_count,
(const float*)vertex_positions, // verify that it is correct to convert to float
vertex_count,
sizeof(LLVector4a),
vertex_positions_stride
streams,
index
);
}
//static
void LLMeshOptimizer::generateShadowIndexBufferU16(U16 *destination,
const U16 *indices,
U64 index_count,
const LLVector4a * vertex_positions,
const LLVector4a * normals,
const LLVector2 * text_coords,
U64 vertex_count
)
{
meshopt_Stream streams[3];
S32 index = 0;
if (vertex_positions)
{
streams[index].data = (const float*)vertex_positions;
streams[index].size = sizeof(F32) * 3;
streams[index].stride = sizeof(F32) * 4;
index++;
}
if (normals)
{
streams[index].data = (const float*)normals;
streams[index].size = sizeof(F32) * 3;
streams[index].stride = sizeof(F32) * 4;
index++;
}
if (text_coords)
{
streams[index].data = (const float*)text_coords;
streams[index].size = sizeof(F32) * 2;
streams[index].stride = sizeof(F32) * 2;
index++;
}
if (index == 0)
{
// invalid
return;
}
meshopt_generateShadowIndexBufferMulti<unsigned short>(destination,
indices,
index_count,
vertex_count,
streams,
index);
}
void LLMeshOptimizer::optimizeVertexCacheU32(U32 * destination, const U32 * indices, U64 index_count, U64 vertex_count)
{
meshopt_optimizeVertexCache<unsigned int>(destination, indices, index_count, vertex_count);
}
void LLMeshOptimizer::optimizeVertexCacheU16(U16 * destination, const U16 * indices, U64 index_count, U64 vertex_count)
{
meshopt_optimizeVertexCache<unsigned short>(destination, indices, index_count, vertex_count);
}
size_t LLMeshOptimizer::generateRemapMultiU32(
unsigned int* remap,
const U32 * indices,
U64 index_count,
const LLVector4a * vertex_positions,
const LLVector4a * normals,
const LLVector2 * text_coords,
U64 vertex_count)
{
meshopt_Stream streams[] = {
{(const float*)vertex_positions, sizeof(F32) * 3, sizeof(F32) * 4},
{(const float*)normals, sizeof(F32) * 3, sizeof(F32) * 4},
{(const float*)text_coords, sizeof(F32) * 2, sizeof(F32) * 2},
};
// Remap can function without indices,
// but providing indices helps with removing unused vertices
U64 indeces_cmp = indices ? index_count : vertex_count;
// meshopt_generateVertexRemapMulti will throw an assert if (indices[i] >= vertex_count)
return meshopt_generateVertexRemapMulti(&remap[0], indices, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
}
size_t LLMeshOptimizer::generateRemapMultiU16(
unsigned int* remap,
const U16 * indices,
U64 index_count,
const LLVector4a * vertex_positions,
const LLVector4a * normals,
const LLVector2 * text_coords,
U64 vertex_count)
{
S32 out_of_range_count = 0;
U32* indices_u32 = NULL;
if (indices)
{
indices_u32 = (U32*)ll_aligned_malloc_32(index_count * sizeof(U32));
for (U64 i = 0; i < index_count; i++)
{
if (indices[i] < vertex_count)
{
indices_u32[i] = (U32)indices[i];
}
else
{
out_of_range_count++;
indices_u32[i] = 0;
}
}
}
if (out_of_range_count)
{
LL_WARNS() << out_of_range_count << " indices are out of range." << LL_ENDL;
}
size_t unique = generateRemapMultiU32(remap, indices_u32, index_count, vertex_positions, normals, text_coords, vertex_count);
ll_aligned_free_32(indices_u32);
return unique;
}
void LLMeshOptimizer::remapIndexBufferU32(U32 * destination_indices,
const U32 * indices,
U64 index_count,
const unsigned int* remap)
{
meshopt_remapIndexBuffer<unsigned int>(destination_indices, indices, index_count, remap);
}
void LLMeshOptimizer::remapIndexBufferU16(U16 * destination_indices,
const U16 * indices,
U64 index_count,
const unsigned int* remap)
{
meshopt_remapIndexBuffer<unsigned short>(destination_indices, indices, index_count, remap);
}
void LLMeshOptimizer::remapPositionsBuffer(LLVector4a * destination_vertices,
const LLVector4a * vertex_positions,
U64 vertex_count,
const unsigned int* remap)
{
meshopt_remapVertexBuffer((float*)destination_vertices, (const float*)vertex_positions, vertex_count, sizeof(LLVector4a), remap);
}
void LLMeshOptimizer::remapNormalsBuffer(LLVector4a * destination_normalss,
const LLVector4a * normals,
U64 mormals_count,
const unsigned int* remap)
{
meshopt_remapVertexBuffer((float*)destination_normalss, (const float*)normals, mormals_count, sizeof(LLVector4a), remap);
}
void LLMeshOptimizer::remapUVBuffer(LLVector2 * destination_uvs,
const LLVector2 * uv_positions,
U64 uv_count,
const unsigned int* remap)
{
meshopt_remapVertexBuffer((float*)destination_uvs, (const float*)uv_positions, uv_count, sizeof(LLVector2), remap);
}
//static
U64 LLMeshOptimizer::simplifyU32(U32 *destination,
const U32 *indices,

View File

@ -28,7 +28,8 @@
#include "linden_common.h"
#include "llmath.h"
class LLVector4a;
class LLVector2;
class LLMeshOptimizer
{
@ -36,13 +37,85 @@ public:
LLMeshOptimizer();
~LLMeshOptimizer();
static void generateShadowIndexBuffer(
static void generateShadowIndexBufferU32(
U32 *destination,
const U32 *indices,
U64 index_count,
const LLVector4a * vertex_positions,
const LLVector4a * normals,
const LLVector2 * text_coords,
U64 vertex_count);
static void generateShadowIndexBufferU16(
U16 *destination,
const U16 *indices,
U64 index_count,
const LLVector4a *vertex_positions,
const LLVector4a * vertex_positions,
const LLVector4a * normals,
const LLVector2 * text_coords,
U64 vertex_count);
static void optimizeVertexCacheU32(
U32 *destination,
const U32 *indices,
U64 index_count,
U64 vertex_count);
static void optimizeVertexCacheU16(
U16 *destination,
const U16 *indices,
U64 index_count,
U64 vertex_count);
// Remap functions
// Welds indentical vertexes together.
// Removes unused vertices if indices were provided.
static size_t generateRemapMultiU32(
unsigned int* remap,
const U32 * indices,
U64 index_count,
const LLVector4a * vertex_positions,
const LLVector4a * normals,
const LLVector2 * text_coords,
U64 vertex_count);
static size_t generateRemapMultiU16(
unsigned int* remap,
const U16 * indices,
U64 index_count,
const LLVector4a * vertex_positions,
const LLVector4a * normals,
const LLVector2 * text_coords,
U64 vertex_count);
static void remapIndexBufferU32(U32 * destination_indices,
const U32 * indices,
U64 index_count,
const unsigned int* remap);
static void remapIndexBufferU16(U16 * destination_indices,
const U16 * indices,
U64 index_count,
const unsigned int* remap);
static void remapPositionsBuffer(LLVector4a * destination_vertices,
const LLVector4a * vertex_positions,
U64 vertex_count,
U64 vertex_positions_stride);
const unsigned int* remap);
static void remapNormalsBuffer(LLVector4a * destination_normalss,
const LLVector4a * normals,
U64 mormals_count,
const unsigned int* remap);
static void remapUVBuffer(LLVector2 * destination_uvs,
const LLVector2 * uv_positions,
U64 uv_count,
const unsigned int* remap);
// Simplification
// returns amount of indices in destiantion
// sloppy engages a variant of a mechanizm that does not respect topology as much

View File

@ -2563,7 +2563,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
if (!mNoOptimize)
{
ret->optimizeVolumeFaces();
ret->remapVolumeFaces();
}
volume_faces = remainder.size();

View File

@ -107,6 +107,14 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint )
}
}
void LLModel::remapVolumeFaces()
{
for (U32 i = 0; i < getNumVolumeFaces(); ++i)
{
mVolumeFaces[i].remap();
}
}
void LLModel::optimizeVolumeFaces()
{
for (U32 i = 0; i < getNumVolumeFaces(); ++i)

View File

@ -184,6 +184,7 @@ public:
void sortVolumeFacesByMaterialName();
void normalizeVolumeFaces();
void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
void remapVolumeFaces();
void optimizeVolumeFaces();
void offsetMesh( const LLVector3& pivotPoint );
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);

View File

@ -102,6 +102,7 @@ LLButton::Params::Params()
scale_image("scale_image", true),
hover_glow_amount("hover_glow_amount"),
commit_on_return("commit_on_return", true),
commit_on_capture_lost("commit_on_capture_lost", false),
display_pressed_state("display_pressed_state", true),
use_draw_context_alpha("use_draw_context_alpha", true),
badge("badge"),
@ -165,6 +166,7 @@ LLButton::LLButton(const LLButton::Params& p)
mBottomVPad(p.pad_bottom),
mHoverGlowStrength(p.hover_glow_amount),
mCommitOnReturn(p.commit_on_return),
mCommitOnCaptureLost(p.commit_on_capture_lost),
mFadeWhenDisabled(FALSE),
mForcePressedState(false),
mDisplayPressedState(p.display_pressed_state),
@ -475,6 +477,10 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
// We only handle the click if the click both started and ended within us
if( hasMouseCapture() )
{
// reset timers before focus change, to not cause
// additional commits if mCommitOnCaptureLost.
resetMouseDownTimer();
// Always release the mouse
gFocusMgr.setMouseCapture( NULL );
@ -489,8 +495,6 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
// Regardless of where mouseup occurs, handle callback
if(mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
resetMouseDownTimer();
// DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
// If mouseup in the widget, it's been clicked
if (pointInView(x, y))
@ -1195,6 +1199,18 @@ void LLButton::setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignmen
void LLButton::onMouseCaptureLost()
{
if (mCommitOnCaptureLost
&& mMouseDownTimer.getStarted())
{
if (mMouseUpSignal) (*mMouseUpSignal)(this, LLSD());
if (mIsToggle)
{
toggleState();
}
LLUICtrl::onCommit();
}
resetMouseDownTimer();
}

View File

@ -124,6 +124,7 @@ public:
Optional<bool> is_toggle,
scale_image,
commit_on_return,
commit_on_capture_lost,
display_pressed_state;
Optional<F32> hover_glow_amount;
@ -374,6 +375,7 @@ protected:
F32 mCurGlowStrength;
bool mCommitOnReturn;
bool mCommitOnCaptureLost;
bool mFadeWhenDisabled;
bool mForcePressedState;
bool mDisplayPressedState;

View File

@ -69,16 +69,22 @@ void LLProgressBar::draw()
static LLTimer timer;
F32 alpha = getDrawContext().mAlpha;
LLColor4 image_bar_color = mColorBackground.get();
image_bar_color.setAlpha(alpha);
mImageBar->draw(getLocalRect(), image_bar_color);
if (mImageBar) // optional according to parameters
{
LLColor4 image_bar_color = mColorBackground.get();
image_bar_color.setAlpha(alpha);
mImageBar->draw(getLocalRect(), image_bar_color);
}
alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
LLColor4 bar_color = mColorBar.get();
bar_color.mV[VALPHA] *= alpha; // modulate alpha
LLRect progress_rect = getLocalRect();
progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f));
mImageFill->draw(progress_rect, bar_color);
if (mImageFill)
{
alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
LLColor4 bar_color = mColorBar.get();
bar_color.mV[VALPHA] *= alpha; // modulate alpha
LLRect progress_rect = getLocalRect();
progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f));
mImageFill->draw(progress_rect, bar_color);
}
}
void LLProgressBar::setValue(const LLSD& value)

View File

@ -103,6 +103,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height);
up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
up_button_params.commit_on_capture_lost = true;
mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
addChild(mUpBtn);
@ -111,6 +112,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height);
down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
down_button_params.commit_on_capture_lost = true;
mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
addChild(mDownBtn);

View File

@ -1 +1 @@
6.6.2
6.6.3

View File

@ -2717,19 +2717,14 @@ bool LLAppViewer::initConfiguration()
if (clp.hasOption("graphicslevel"))
{
// User explicitly requested --graphicslevel on the command line. We
// expect this switch has already set RenderQualityPerformance. Check
// that value for validity.
U32 graphicslevel = gSavedSettings.getU32("RenderQualityPerformance");
if (LLFeatureManager::instance().isValidGraphicsLevel(graphicslevel))
{
// graphicslevel is valid: save it and engage it later. Capture
// the requested value separately from the settings variable
// because, if this is the first run, LLViewerWindow's constructor
// will call LLFeatureManager::applyRecommendedSettings(), which
// overwrites this settings variable!
mForceGraphicsLevel = graphicslevel;
}
// User explicitly requested --graphicslevel on the command line. We
// expect this switch has already set RenderQualityPerformance. Check
// that value for validity later.
// Capture the requested value separately from the settings variable
// because, if this is the first run, LLViewerWindow's constructor
// will call LLFeatureManager::applyRecommendedSettings(), which
// overwrites this settings variable!
mForceGraphicsLevel = gSavedSettings.getU32("RenderQualityPerformance");
}
LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance");
@ -3087,7 +3082,7 @@ bool LLAppViewer::initWindow()
// Initialize GL stuff
//
if (mForceGraphicsLevel)
if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel)))
{
LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false);
gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel);

View File

@ -272,9 +272,9 @@ BOOL LLConversationViewSession::postBuild()
default:
break;
}
}
refresh();
refresh(); // requires vmi
}
return TRUE;
}
@ -490,17 +490,20 @@ void LLConversationViewSession::refresh()
{
// Refresh the session view from its model data
LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem());
vmi->resetRefresh();
if (vmi)
{
vmi->resetRefresh();
if (mSessionTitle)
{
if (!highlightFriendTitle(vmi))
{
LLStyle::Params title_style;
title_style.color = LLUIColorTable::instance().getColor("LabelTextColor");
mSessionTitle->setText(vmi->getDisplayName(), title_style);
}
}
if (mSessionTitle)
{
if (!highlightFriendTitle(vmi))
{
LLStyle::Params title_style;
title_style.color = LLUIColorTable::instance().getColor("LabelTextColor");
mSessionTitle->setText(vmi->getDisplayName(), title_style);
}
}
}
// Update all speaking indicators
LLSpeakingIndicatorManager::updateSpeakingIndicators();
@ -524,8 +527,11 @@ void LLConversationViewSession::refresh()
}
requestArrange();
// Do the regular upstream refresh
LLFolderViewFolder::refresh();
if (vmi)
{
// Do the regular upstream refresh
LLFolderViewFolder::refresh();
}
}
void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& session_id)
@ -627,8 +633,11 @@ BOOL LLConversationViewParticipant::postBuild()
}
updateChildren();
LLFolderViewItem::postBuild();
refresh();
if (getViewModelItem())
{
LLFolderViewItem::postBuild();
refresh();
}
return TRUE;
}
@ -712,10 +721,10 @@ void LLConversationViewParticipant::refresh()
// *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat
mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted());
// Do the regular upstream refresh
LLFolderViewItem::refresh();
}
// Do the regular upstream refresh
LLFolderViewItem::refresh();
}
void LLConversationViewParticipant::addToFolder(LLFolderViewFolder* folder)

View File

@ -551,7 +551,7 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part
void LLFloaterIMSessionTab::updateConversationViewParticipant(const LLUUID& participant_id)
{
LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id);
if (widget)
if (widget && widget->getViewModelItem())
{
widget->refresh();
}
@ -576,8 +576,11 @@ void LLFloaterIMSessionTab::refreshConversation()
{
participants_uuids.push_back(widget_it->first);
}
widget_it->second->refresh();
widget_it->second->setVisible(TRUE);
if (widget_it->second->getViewModelItem())
{
widget_it->second->refresh();
widget_it->second->setVisible(TRUE);
}
++widget_it;
}
if (is_ad_hoc || mIsP2PChat)
@ -1126,7 +1129,10 @@ void LLFloaterIMSessionTab::getSelectedUUIDs(uuid_vec_t& selected_uuids)
for (; it != it_end; ++it)
{
LLConversationItem* conversation_item = static_cast<LLConversationItem *>((*it)->getViewModelItem());
selected_uuids.push_back(conversation_item->getUUID());
if (conversation_item)
{
selected_uuids.push_back(conversation_item->getUUID());
}
}
}

View File

@ -741,7 +741,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
{
case LLModelPreview::MESH_OPTIMIZER_AUTO:
case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
case LLModelPreview::MESH_OPTIMIZER_COMBINE:
case LLModelPreview::MESH_OPTIMIZER_PRECISE:
mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode);
break;
default:
@ -1745,7 +1745,7 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
S32 index = lod_source_combo->getCurrentIndex();
if (index == LLModelPreview::MESH_OPTIMIZER_AUTO
|| index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
|| index == LLModelPreview::MESH_OPTIMIZER_COMBINE)
|| index == LLModelPreview::MESH_OPTIMIZER_PRECISE)
{ //rebuild LoD to update triangle counts
onLODParamCommit(lod, true);
}

View File

@ -480,30 +480,61 @@ void LLFloaterTools::refresh()
else
#endif
{
F32 link_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost();
S32 link_count = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount();
LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
F32 link_cost = selection->getSelectedLinksetCost();
S32 link_count = selection->getRootObjectCount();
S32 object_count = selection->getObjectCount();
LLCrossParcelFunctor func;
if (LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true))
{
// Selection crosses parcel bounds.
// We don't display remaining land capacity in this case.
const LLStringExplicit empty_str("");
childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", empty_str);
}
else
{
LLViewerObject* selected_object = mObjectSelection->getFirstObject();
if (selected_object)
{
// Select a parcel at the currently selected object's position.
LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal());
}
else
{
LL_WARNS() << "Failed to get selected object" << LL_ENDL;
}
}
LLCrossParcelFunctor func;
if (!LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true))
{
// Unless multiple parcels selected, higlight parcel object is at.
LLViewerObject* selected_object = mObjectSelection->getFirstObject();
if (selected_object)
{
// Select a parcel at the currently selected object's position.
LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal());
}
else
{
LL_WARNS() << "Failed to get selected object" << LL_ENDL;
}
}
if (object_count == 1)
{
// "selection_faces" shouldn't be visible if not LLToolFace::getInstance()
// But still need to be populated in case user switches
std::string faces_str = "";
for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end();)
{
LLObjectSelection::iterator nextiter = iter++; // not strictly needed, we have only one object
LLSelectNode* node = *nextiter;
LLViewerObject* object = (*nextiter)->getObject();
if (!object)
continue;
S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces());
for (S32 te = 0; te < num_tes; ++te)
{
if (node->isTESelected(te))
{
if (!faces_str.empty())
{
faces_str += ", ";
}
faces_str += llformat("%d", te);
}
}
}
childSetTextArg("selection_faces", "[FACES_STRING]", faces_str);
}
bool show_faces = (object_count == 1)
&& LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
getChildView("selection_faces")->setVisible(show_faces);
LLStringUtil::format_map_t selection_args;
selection_args["OBJ_COUNT"] = llformat("%.1d", link_count);
@ -824,7 +855,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty();
getChildView("selection_count")->setVisible(!land_visible && have_selection);
getChildView("remaining_capacity")->setVisible(!land_visible && have_selection);
getChildView("selection_faces")->setVisible(LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()
&& LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1);
getChildView("selection_empty")->setVisible(!land_visible && !have_selection);
mTab->setVisible(!land_visible);
@ -1095,7 +1127,7 @@ void LLFloaterTools::onClickGridOptions()
{
LLFloater* floaterp = LLFloaterReg::showInstance("build_options");
// position floater next to build tools, not over
floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp));
floaterp->setShape(gFloaterView->findNeighboringPosition(this, floaterp), true);
}
// static
@ -1181,26 +1213,6 @@ void LLFloaterTools::updateLandImpacts()
return;
}
S32 rezzed_prims = parcel->getSimWidePrimCount();
S32 total_capacity = parcel->getSimWideMaxPrimCapacity();
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
if (region)
{
S32 max_tasks_per_region = (S32)region->getMaxTasks();
total_capacity = llmin(total_capacity, max_tasks_per_region);
}
std::string remaining_capacity_str = "";
bool show_mesh_cost = gMeshRepo.meshRezEnabled();
if (show_mesh_cost)
{
LLStringUtil::format_map_t remaining_capacity_args;
remaining_capacity_args["LAND_CAPACITY"] = llformat("%d", total_capacity - rezzed_prims);
remaining_capacity_str = getString("status_remaining_capacity", remaining_capacity_args);
}
childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", remaining_capacity_str);
// Update land impacts info in the weights floater
LLFloaterObjectWeights* object_weights_floater = LLFloaterReg::findTypedInstance<LLFloaterObjectWeights>("object_weights");
if(object_weights_floater)

View File

@ -45,6 +45,7 @@
//#include "llfirstuse.h"
#include "llfloaterreg.h" // getTypedInstance()
#include "llfocusmgr.h"
#include "lliconctrl.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
@ -307,6 +308,8 @@ BOOL LLFloaterWorldMap::postBuild()
mCurZoomVal = log(LLWorldMapView::sMapScale/256.f)/log(2.f);
getChild<LLUICtrl>("zoom slider")->setValue(mCurZoomVal);
getChild<LLPanel>("expand_btn_panel")->setMouseDownCallback(boost::bind(&LLFloaterWorldMap::onExpandCollapseBtn, this));
setDefaultBtn(NULL);
@ -1315,6 +1318,22 @@ void LLFloaterWorldMap::onCopySLURL()
LLNotificationsUtil::add("CopySLURL", args);
}
void LLFloaterWorldMap::onExpandCollapseBtn()
{
LLLayoutStack* floater_stack = getChild<LLLayoutStack>("floater_map_stack");
LLLayoutPanel* controls_panel = getChild<LLLayoutPanel>("controls_lp");
bool toggle_collapse = !controls_panel->isCollapsed();
floater_stack->collapsePanel(controls_panel, toggle_collapse);
floater_stack->updateLayout();
std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon");
std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip");
getChild<LLIconCtrl>("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name));
getChild<LLIconCtrl>("expand_collapse_icon")->setToolTip(tooltip);
getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip);
}
// protected
void LLFloaterWorldMap::centerOnTarget(BOOL animate)
{

View File

@ -130,6 +130,8 @@ protected:
void onShowAgentBtn();
void onCopySLURL();
void onExpandCollapseBtn();
void centerOnTarget(BOOL animate);
void updateLocation();

View File

@ -348,7 +348,7 @@ void LLInspectAvatar::onClickMuteVolume()
LLMuteList* mute_list = LLMuteList::getInstance();
bool is_muted = mute_list->isMuted(mAvatarID, LLMute::flagVoiceChat);
LLMute mute(mAvatarID, mAvatarName.getDisplayName(), LLMute::AGENT);
LLMute mute(mAvatarID, mAvatarName.getUserName(), LLMute::AGENT);
if (!is_muted)
{
mute_list->add(mute, LLMute::flagVoiceChat);

View File

@ -795,6 +795,19 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
disabled_items.push_back(std::string("Copy"));
}
if (isAgentInventory())
{
items.push_back(std::string("New folder from selected"));
items.push_back(std::string("Subfolder Separator"));
std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs();
uuid_vec_t ids;
std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids));
if (!is_only_items_selected(ids) && !is_only_cats_selected(ids))
{
disabled_items.push_back(std::string("New folder from selected"));
}
}
if (obj->getIsLinkType())
{
items.push_back(std::string("Find Original"));
@ -4291,7 +4304,16 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t&
items.push_back(std::string("Conference Chat Folder"));
items.push_back(std::string("IM All Contacts In Folder"));
}
if (((flags & ITEM_IN_MULTI_SELECTION) == 0) && hasChildren())
{
items.push_back(std::string("Ungroup folder items"));
}
}
else
{
disabled_items.push_back(std::string("New folder from selected"));
}
#ifndef LL_RELEASE_FOR_DOWNLOAD
if (LLFolderType::lookupIsProtectedType(type) && is_agent_inventory)

View File

@ -1868,6 +1868,86 @@ void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id)
}
}
void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids)
{
for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
{
LLInventoryItem* inv_item = gInventory.getItem(*it);
if (inv_item)
{
change_item_parent(*it, new_cat_uuid);
}
else
{
LLInventoryCategory* inv_cat = gInventory.getCategory(*it);
if (inv_cat && !LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
{
gInventory.changeCategoryParent((LLViewerInventoryCategory*)inv_cat, new_cat_uuid, false);
}
}
}
LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
if (!floater_inventory)
{
LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL;
return;
}
LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
if (sidepanel_inventory)
{
if (sidepanel_inventory->getActivePanel())
{
sidepanel_inventory->getActivePanel()->setSelection(new_cat_uuid, TAKE_FOCUS_YES);
LLFolderViewItem* fv_folder = sidepanel_inventory->getActivePanel()->getItemByID(new_cat_uuid);
if (fv_folder)
{
fv_folder->setOpen(TRUE);
}
}
}
}
bool is_only_cats_selected(const uuid_vec_t& selected_uuids)
{
for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
{
LLInventoryCategory* inv_cat = gInventory.getCategory(*it);
if (!inv_cat)
{
return false;
}
}
return true;
}
bool is_only_items_selected(const uuid_vec_t& selected_uuids)
{
for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it)
{
LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
if (!inv_item)
{
return false;
}
}
return true;
}
void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::string& folder_name)
{
LLInventoryObject* first_item = gInventory.getObject(*selected_uuids.begin());
if (!first_item)
{
return;
}
inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids);
gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func);
}
///----------------------------------------------------------------------------
/// LLInventoryCollectFunctor implementations
///----------------------------------------------------------------------------
@ -2522,6 +2602,81 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
(new LLDirPickerThread(boost::bind(&LLInventoryAction::saveMultipleTextures, _1, selected_items, model), std::string()))->getFile();
}
else if ("new_folder_from_selected" == action)
{
LLInventoryObject* first_item = gInventory.getObject(*ids.begin());
if (!first_item)
{
return;
}
const LLUUID& parent_uuid = first_item->getParentUUID();
for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
{
LLInventoryObject *item = gInventory.getObject(*it);
if (!item || item->getParentUUID() != parent_uuid)
{
LLNotificationsUtil::add("SameFolderRequired");
return;
}
}
LLSD args;
args["DESC"] = LLTrans::getString("New Folder");
LLNotificationsUtil::add("CreateSubfolder", args, LLSD(),
[ids](const LLSD& notification, const LLSD& response)
{
S32 opt = LLNotificationsUtil::getSelectedOption(notification, response);
if (opt == 0)
{
std::string settings_name = response["message"].asString();
LLInventoryObject::correctInventoryName(settings_name);
if (settings_name.empty())
{
settings_name = LLTrans::getString("New Folder");
}
move_items_to_new_subfolder(ids, settings_name);
}
});
}
else if ("ungroup_folder_items" == action)
{
if (selected_uuid_set.size() == 1)
{
LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin());
if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
{
return;
}
const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
LLInventoryModel::cat_array_t cats = *cat_array;
LLInventoryModel::item_array_t items = *item_array;
for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
{
LLViewerInventoryCategory* cat = *cat_iter;
if (cat)
{
gInventory.changeCategoryParent(cat, new_cat_uuid, false);
}
}
for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
{
LLViewerInventoryItem* item = *item_iter;
if(item)
{
gInventory.changeItemParent(item, new_cat_uuid, false);
}
}
gInventory.removeCategory(inv_cat->getUUID());
gInventory.notifyObservers();
}
}
else
{
std::set<LLFolderViewItem*>::iterator set_iter;

View File

@ -93,6 +93,10 @@ LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth);
S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false);
void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id);
void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::string& folder_name);
void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids);
bool is_only_cats_selected(const uuid_vec_t& selected_uuids);
bool is_only_items_selected(const uuid_vec_t& selected_uuids);
/** Miscellaneous global functions
** **

View File

@ -298,31 +298,41 @@ LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem
applyXUILayout(icon_params, this);
mIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
if (mIconCtrl)
{
addChild(mIconCtrl);
}
else
if (!mIconCtrl)
{
LLIconCtrl::Params icon_params;
icon_params.name = "item_icon";
mIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
}
if (mIconCtrl)
{
addChild(mIconCtrl);
}
else
{
LL_ERRS() << "Failed to create mIconCtrl" << LL_ENDL;
}
LLTextBox::Params text_params(params.item_name);
applyXUILayout(text_params, this);
mTitleCtrl = LLUICtrlFactory::create<LLTextBox>(text_params);
if (mTitleCtrl)
if (!mTitleCtrl)
{
addChild(mTitleCtrl);
}
else
{
LLTextBox::Params text_aprams;
LLTextBox::Params text_params;
text_params.name = "item_title";
mTitleCtrl = LLUICtrlFactory::create<LLTextBox>(text_params);
}
if (mTitleCtrl)
{
addChild(mTitleCtrl);
}
else
{
LL_ERRS() << "Failed to create mTitleCtrl" << LL_ENDL;
}
}
class WidgetVisibilityChanger

View File

@ -122,7 +122,7 @@ public:
LLUUID getWorldID(LLUUID tracking_id);
bool isLocal(LLUUID world_id);
std::string getFilename(LLUUID tracking_id);
void feedScrollList(LLScrollListCtrl* ctrl);
void doUpdates();
void setNeedsRebake();

View File

@ -838,8 +838,10 @@ void LLModelPreview::clearIncompatible(S32 lod)
// at this point we don't care about sub-models,
// different amount of sub-models means face count mismatch, not incompatibility
U32 lod_size = countRootModels(mModel[lod]);
bool replaced_base_model = (lod == LLModel::LOD_HIGH);
for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)
{ //clear out any entries that aren't compatible with this model
{
// Clear out any entries that aren't compatible with this model
if (i != lod)
{
if (countRootModels(mModel[i]) != lod_size)
@ -853,10 +855,48 @@ void LLModelPreview::clearIncompatible(S32 lod)
mBaseModel = mModel[lod];
mBaseScene = mScene[lod];
mVertexBuffer[5].clear();
replaced_base_model = true;
}
}
}
}
if (replaced_base_model && !mGenLOD)
{
// In case base was replaced, we might need to restart generation
// Check if already started
bool subscribe_for_generation = mLodsQuery.empty();
// Remove previously scheduled work
mLodsQuery.clear();
LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
if (!fmp) return;
// Schedule new work
for (S32 i = LLModel::LOD_HIGH; i >= 0; --i)
{
if (mModel[i].empty())
{
// Base model was replaced, regenerate this lod if applicable
LLComboBox* lod_combo = mFMP->findChild<LLComboBox>("lod_source_" + lod_name[i]);
if (!lod_combo) return;
S32 lod_mode = lod_combo->getCurrentIndex();
if (lod_mode != LOD_FROM_FILE)
{
mLodsQuery.push_back(i);
}
}
}
// Subscribe if we have pending work and not subscribed yet
if (!mLodsQuery.empty() && subscribe_for_generation)
{
doOnIdleRepeating(lodQueryCallback);
}
}
}
void LLModelPreview::loadModelCallback(S32 loaded_lod)
@ -1243,8 +1283,9 @@ void LLModelPreview::restoreNormals()
// Runs per object, but likely it is a better way to run per model+submodels
// returns a ratio of base model indices to resulting indices
// returns -1 in case of failure
F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy)
F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, eSimplificationMode simplification_mode)
{
// I. Weld faces together
// Figure out buffer size
S32 size_indices = 0;
S32 size_vertices = 0;
@ -1279,20 +1320,21 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
{
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
// vertices
// Vertices
S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes);
// normals
// Normals
LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes);
// tex coords
// Tex coords
copy_bytes = face.mNumVertices * sizeof(LLVector2);
memcpy((void*)(combined_tex_coords + combined_positions_shift), (void*)face.mTexCoords, copy_bytes);
combined_positions_shift += face.mNumVertices;
// indices, sadly can't do dumb memcpy for indices, need to adjust each value
// Indices
// Sadly can't do dumb memcpy for indices, need to adjust each value
for (S32 i = 0; i < face.mNumIndices; ++i)
{
U16 idx = face.mIndices[i];
@ -1303,10 +1345,42 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
indices_idx_shift += face.mNumVertices;
}
// Now that we have buffers, optimize
// II. Generate a shadow buffer if nessesary.
// Welds together vertices if possible
U32* shadow_indices = NULL;
// if MESH_OPTIMIZER_FULL, just leave as is, since generateShadowIndexBufferU32
// won't do anything new, model was remaped on a per face basis.
// Similar for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
// since 'simplifySloppy' ignores all topology, including normals and uvs.
// Note: simplifySloppy can affect UVs significantly.
if (simplification_mode == MESH_OPTIMIZER_NO_NORMALS)
{
// strip normals, reflections should restore relatively correctly
shadow_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
LLMeshOptimizer::generateShadowIndexBufferU32(shadow_indices, combined_indices, size_indices, combined_positions, NULL, combined_tex_coords, size_vertices);
}
if (simplification_mode == MESH_OPTIMIZER_NO_UVS)
{
// strip uvs, can heavily affect textures
shadow_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
LLMeshOptimizer::generateShadowIndexBufferU32(shadow_indices, combined_indices, size_indices, combined_positions, NULL, NULL, size_vertices);
}
U32* source_indices = NULL;
if (shadow_indices)
{
source_indices = shadow_indices;
}
else
{
source_indices = combined_indices;
}
// III. Simplify
S32 target_indices = 0;
F32 result_error = 0; // how far from original the model is, 1 == 100%
S32 new_indices = 0;
S32 size_new_indices = 0;
if (indices_decimator > 0)
{
@ -1316,38 +1390,43 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
{
target_indices = 3;
}
new_indices = LLMeshOptimizer::simplifyU32(
size_new_indices = LLMeshOptimizer::simplifyU32(
output_indices,
combined_indices,
source_indices,
size_indices,
combined_positions,
size_vertices,
LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
target_indices,
error_threshold,
sloppy,
simplification_mode == MESH_OPTIMIZER_NO_TOPOLOGY,
&result_error);
if (result_error < 0)
{
LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
<< " new Indices: " << size_new_indices
<< " original count: " << size_indices << LL_ENDL;
}
if (new_indices < 3)
// free unused buffers
ll_aligned_free_32(combined_indices);
ll_aligned_free_32(shadow_indices);
combined_indices = NULL;
shadow_indices = NULL;
if (size_new_indices < 3)
{
// Model should have at least one visible triangle
ll_aligned_free<64>(combined_positions);
ll_aligned_free_32(output_indices);
ll_aligned_free_32(combined_indices);
return -1;
}
// repack back into individual faces
// IV. Repack back into individual faces
LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
LLVector4a* buffer_normals = buffer_positions + size_vertices;
@ -1378,7 +1457,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
}
// Copy relevant indices and vertices
for (S32 i = 0; i < new_indices; ++i)
for (S32 i = 0; i < size_new_indices; ++i)
{
U32 idx = output_indices[i];
@ -1401,19 +1480,19 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for"
<< " model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
<< " new Indices: " << size_new_indices
<< " original count: " << size_indices
<< " error treshold: " << error_threshold
<< LL_ENDL;
// U16 vertices overflow shouldn't happen, but just in case
new_indices = 0;
size_new_indices = 0;
valid_faces = 0;
for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
{
genMeshOptimizerPerFace(base_model, target_model, face_idx, indices_decimator, error_threshold, false);
genMeshOptimizerPerFace(base_model, target_model, face_idx, indices_decimator, error_threshold, simplification_mode);
const LLVolumeFace &face = target_model->getVolumeFace(face_idx);
new_indices += face.mNumIndices;
size_new_indices += face.mNumIndices;
if (face.mNumIndices >= 3)
{
valid_faces++;
@ -1421,7 +1500,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
}
if (valid_faces)
{
return (F32)size_indices / (F32)new_indices;
return (F32)size_indices / (F32)size_new_indices;
}
else
{
@ -1491,18 +1570,17 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
ll_aligned_free<64>(buffer_positions);
ll_aligned_free_32(output_indices);
ll_aligned_free_16(buffer_indices);
ll_aligned_free_32(combined_indices);
if (new_indices < 3 || valid_faces == 0)
if (size_new_indices < 3 || valid_faces == 0)
{
// Model should have at least one visible triangle
return -1;
}
return (F32)size_indices / (F32)new_indices;
return (F32)size_indices / (F32)size_new_indices;
}
F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, bool sloppy)
F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, eSimplificationMode simplification_mode)
{
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
S32 size_indices = face.mNumIndices;
@ -1510,14 +1588,40 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
{
return -1;
}
// todo: do not allocate per each face, add one large buffer somewhere
// faces have limited amount of indices
S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
U16* output = (U16*)ll_aligned_malloc_16(size);
U16* output_indices = (U16*)ll_aligned_malloc_16(size);
U16* shadow_indices = NULL;
// if MESH_OPTIMIZER_FULL, just leave as is, since generateShadowIndexBufferU32
// won't do anything new, model was remaped on a per face basis.
// Similar for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
// since 'simplifySloppy' ignores all topology, including normals and uvs.
if (simplification_mode == MESH_OPTIMIZER_NO_NORMALS)
{
U16* shadow_indices = (U16*)ll_aligned_malloc_16(size);
LLMeshOptimizer::generateShadowIndexBufferU16(shadow_indices, face.mIndices, size_indices, face.mPositions, NULL, face.mTexCoords, face.mNumVertices);
}
if (simplification_mode == MESH_OPTIMIZER_NO_UVS)
{
U16* shadow_indices = (U16*)ll_aligned_malloc_16(size);
LLMeshOptimizer::generateShadowIndexBufferU16(shadow_indices, face.mIndices, size_indices, face.mPositions, NULL, NULL, face.mNumVertices);
}
// Don't run ShadowIndexBuffer for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless
U16* source_indices = NULL;
if (shadow_indices)
{
source_indices = shadow_indices;
}
else
{
source_indices = face.mIndices;
}
S32 target_indices = 0;
F32 result_error = 0; // how far from original the model is, 1 == 100%
S32 new_indices = 0;
S32 size_new_indices = 0;
if (indices_decimator > 0)
{
@ -1527,25 +1631,25 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
{
target_indices = 3;
}
new_indices = LLMeshOptimizer::simplify(
output,
face.mIndices,
size_new_indices = LLMeshOptimizer::simplify(
output_indices,
source_indices,
size_indices,
face.mPositions,
face.mNumVertices,
LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
target_indices,
error_threshold,
sloppy,
simplification_mode == MESH_OPTIMIZER_NO_TOPOLOGY,
&result_error);
if (result_error < 0)
{
LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx
<< " of model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
<< " new Indices: " << size_new_indices
<< " original count: " << size_indices
<< " error treshold: " << error_threshold
<< LL_ENDL;
@ -1556,10 +1660,9 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
// Copy old values
new_face = face;
if (new_indices < 3)
if (size_new_indices < 3)
{
if (!sloppy)
if (simplification_mode != MESH_OPTIMIZER_NO_TOPOLOGY)
{
// meshopt_optimizeSloppy() can optimize triangles away even if target_indices is > 2,
// but optimize() isn't supposed to
@ -1583,23 +1686,24 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
else
{
// Assign new values
new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
new_face.resizeIndices(size_new_indices); // will wipe out mIndices, so new_face can't substitute output
S32 idx_size = (size_new_indices * sizeof(U16) + 0xF) & ~0xF;
LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output_indices, idx_size);
// clear unused values
// Clear unused values
new_face.optimize();
}
ll_aligned_free_16(output);
ll_aligned_free_16(output_indices);
ll_aligned_free_16(shadow_indices);
if (new_indices < 3)
if (size_new_indices < 3)
{
// At least one triangle is needed
return -1;
}
return (F32)size_indices / (F32)new_indices;
return (F32)size_indices / (F32)size_new_indices;
}
void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit)
@ -1733,16 +1837,19 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
// Ideally this should run not per model,
// but combine all submodels with origin model as well
if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE)
if (model_meshopt_mode == MESH_OPTIMIZER_PRECISE)
{
// Run meshoptimizer for each model/object, up to 8 faces in one model.
// Ideally this should run not per model,
// but combine all submodels with origin model as well
F32 res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
if (res < 0)
// Run meshoptimizer for each face
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
{
target_model->copyVolumeFaces(base);
F32 res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
if (res < 0)
{
// Mesh optimizer failed and returned an invalid model
const LLVolumeFace &face = base->getVolumeFace(face_idx);
LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
new_face = face;
}
}
}
@ -1751,19 +1858,29 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
// Run meshoptimizer for each face
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
{
if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true) < 0)
if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY) < 0)
{
// Sloppy failed and returned an invalid model
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
}
}
}
if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
{
// Switches between 'combine' method and 'sloppy' based on combine's result.
F32 allowed_ratio_drift = 2.f;
F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
// Remove progressively more data if we can't reach the target.
F32 allowed_ratio_drift = 1.8f;
F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
{
precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_NORMALS);
}
if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
{
precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_UVS);
}
if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
{
@ -1771,10 +1888,11 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
// Sloppy variant can fail entirely and has issues with precision,
// so code needs to do multiple attempts with different decimators.
// Todo: this is a bit of a mess, needs to be refined and improved
F32 last_working_decimator = 0.f;
F32 last_working_ratio = F32_MAX;
F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
if (sloppy_ratio > 0)
{
@ -1797,13 +1915,13 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
// side due to overal lack of precision, and we don't need an ideal result, which
// likely does not exist, just a better one, so a partial correction is enough.
F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2;
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
}
if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio)
{
// Compensation didn't work, return back to previous decimator
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
}
if (sloppy_ratio < 0)
@ -1836,7 +1954,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
&& sloppy_decimator > precise_ratio
&& sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case
{
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);
sloppy_decimator = sloppy_decimator / sloppy_decimation_step;
}
}
@ -1856,7 +1974,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
else
{
// Fallback to normal method
precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL);
}
LL_INFOS() << "Model " << target_model->getName()
@ -3767,7 +3885,7 @@ bool LLModelPreview::lodQueryCallback()
}
// return false to continue cycle
return false;
return preview->mLodsQuery.empty();
}
}
// nothing to process

View File

@ -125,7 +125,7 @@ public:
{
LOD_FROM_FILE = 0,
MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face
MESH_OPTIMIZER_COMBINE, // combines faces into a single model, simplifies, then splits back into faces
MESH_OPTIMIZER_PRECISE, // combines faces into a single model, simplifies, then splits back into faces
MESH_OPTIMIZER_SLOPPY, // uses sloppy method, works per face
USE_LOD_ABOVE,
} eLoDMode;
@ -225,13 +225,21 @@ private:
// Count amount of original models, excluding sub-models
static U32 countRootModels(LLModelLoader::model_list models);
typedef enum
{
MESH_OPTIMIZER_FULL,
MESH_OPTIMIZER_NO_NORMALS,
MESH_OPTIMIZER_NO_UVS,
MESH_OPTIMIZER_NO_TOPOLOGY,
} eSimplificationMode;
// Merges faces into single mesh, simplifies using mesh optimizer,
// then splits back into faces.
// Returns reached simplification ratio. -1 in case of a failure.
F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, bool sloppy);
F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode);
// Simplifies specified face using mesh optimizer.
// Returns reached simplification ratio. -1 in case of a failure.
F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, bool sloppy);
F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode);
protected:
friend class LLModelLoader;

View File

@ -232,7 +232,7 @@ void LLPanelBlockedList::onFilterEdit(const std::string& search_string)
void LLPanelBlockedList::callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
{
if (names.empty() || ids.empty()) return;
LLMute mute(ids[0], names[0].getAccountName(), LLMute::AGENT);
LLMute mute(ids[0], names[0].getUserName(), LLMute::AGENT);
LLMuteList::getInstance()->add(mute);
showPanelAndSelect(mute.mID);
}

View File

@ -1308,7 +1308,8 @@ void LLPanelEditWearable::changeCamera(U8 subpart)
gMorphView->setCameraOffset( subpart_entry->mCameraOffset );
if (gSavedSettings.getBOOL("AppearanceCameraMovement"))
{
gMorphView->updateCamera();
gAgentCamera.setFocusOnAvatar(FALSE, FALSE);
gMorphView->updateCamera();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,7 @@ class LLUICtrl;
class LLViewerObject;
class LLFloater;
class LLMaterialID;
class LLMenuButton;
// Represents an edit for use in replicating the op across one or more materials in the selection set.
//
@ -96,6 +97,8 @@ public:
LLPanelFace();
virtual ~LLPanelFace();
void draw();
void refresh();
void setMediaURL(const std::string& url);
void setMediaType(const std::string& mime_type);
@ -128,6 +131,8 @@ protected:
void sendMedia();
void alignTestureLayer();
void updateCopyTexButton();
// this function is to return TRUE if the drag should succeed.
static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item);
@ -210,6 +215,18 @@ protected:
static LLSD renderMaterialToLLSD(LLUUID uuid, void* userdata);
static void applyMaterialUUID(LLUUID uuid, void*);
public: // needs to be accessible to selection manager
void onCopyColor(); // records all selected faces
void onPasteColor(); // to specific face
void onPasteColor(LLViewerObject* objectp, S32 te); // to specific face
void onCopyTexture();
void onPasteTexture();
void onPasteTexture(LLViewerObject* objectp, S32 te);
protected:
void menuDoToSelected(const LLSD& userdata);
bool menuEnableItem(const LLSD& userdata);
static F32 valueGlow(LLViewerObject* object, S32 face);
@ -406,7 +423,10 @@ private:
* If agent selects texture which is not allowed to be applied for the currently selected object,
* all controls of the floater texture picker which allow to apply the texture will be disabled.
*/
void onTextureSelectionChanged(LLInventoryItem* itemp);
void onTextureSelectionChanged(LLInventoryItem* itemp);
LLMenuButton* mMenuClipboardColor;
LLMenuButton* mMenuClipboardTexture;
bool mIsAlpha;
@ -421,7 +441,9 @@ private:
* up-arrow on a spinner, and avoids running afoul of its throttle.
*/
bool mUpdateInFlight;
bool mUpdatePending;
bool mUpdatePending;
LLSD mClipboardParams;
public:
#if defined(DEF_GET_MAT_STATE)

View File

@ -46,6 +46,7 @@
#include "llcombobox.h"
#include "llfocusmgr.h"
#include "llmanipscale.h"
#include "llmenubutton.h"
#include "llpreviewscript.h"
#include "llresmgr.h"
#include "llselectmgr.h"
@ -117,8 +118,9 @@ BOOL LLPanelObject::postBuild()
// Phantom checkbox
mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl");
childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this);
// Position
mMenuClipboardPos = getChild<LLMenuButton>("clipboard_pos_btn");
mLabelPosition = getChild<LLTextBox>("label position");
mCtrlPosX = getChild<LLSpinCtrl>("Pos X");
childSetCommitCallback("Pos X",onCommitPosition,this);
@ -128,6 +130,7 @@ BOOL LLPanelObject::postBuild()
childSetCommitCallback("Pos Z",onCommitPosition,this);
// Scale
mMenuClipboardSize = getChild<LLMenuButton>("clipboard_size_btn");
mLabelSize = getChild<LLTextBox>("label size");
mCtrlScaleX = getChild<LLSpinCtrl>("Scale X");
childSetCommitCallback("Scale X",onCommitScale,this);
@ -141,6 +144,7 @@ BOOL LLPanelObject::postBuild()
childSetCommitCallback("Scale Z",onCommitScale,this);
// Rotation
mMenuClipboardRot = getChild<LLMenuButton>("clipboard_rot_btn");
mLabelRotation = getChild<LLTextBox>("label rotation");
mCtrlRotX = getChild<LLSpinCtrl>("Rot X");
childSetCommitCallback("Rot X",onCommitRotation,this);
@ -155,6 +159,8 @@ BOOL LLPanelObject::postBuild()
mComboBaseType = getChild<LLComboBox>("comboBaseType");
childSetCommitCallback("comboBaseType",onCommitParametric,this);
mMenuClipboardParams = getChild<LLMenuButton>("clipboard_obj_params_btn");
// Cut
mLabelCut = getChild<LLTextBox>("text cut");
mSpinCutBegin = getChild<LLSpinCtrl>("cut begin");
@ -285,8 +291,13 @@ LLPanelObject::LLPanelObject()
mSelectedType(MI_BOX),
mSculptTextureRevert(LLUUID::null),
mSculptTypeRevert(0),
mHasClipboardPos(false),
mHasClipboardSize(false),
mHasClipboardRot(false),
mSizeChanged(FALSE)
{
mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2));
mEnableCallbackRegistrar.add("PanelObject.menuEnable", boost::bind(&LLPanelObject::menuEnableItem, this, _2));
}
@ -373,7 +384,7 @@ void LLPanelObject::getState( )
calcp->clearVar(LLCalc::Z_POS);
}
mMenuClipboardPos->setEnabled(enable_move);
mLabelPosition->setEnabled( enable_move );
mCtrlPosX->setEnabled(enable_move);
mCtrlPosY->setEnabled(enable_move);
@ -399,6 +410,7 @@ void LLPanelObject::getState( )
calcp->setVar(LLCalc::Z_SCALE, 0.f);
}
mMenuClipboardSize->setEnabled(enable_scale);
mLabelSize->setEnabled( enable_scale );
mCtrlScaleX->setEnabled( enable_scale );
mCtrlScaleY->setEnabled( enable_scale );
@ -430,6 +442,7 @@ void LLPanelObject::getState( )
calcp->clearVar(LLCalc::Z_ROT);
}
mMenuClipboardRot->setEnabled(enable_rotate);
mLabelRotation->setEnabled( enable_rotate );
mCtrlRotX->setEnabled( enable_rotate );
mCtrlRotY->setEnabled( enable_rotate );
@ -607,7 +620,7 @@ void LLPanelObject::getState( )
}
else
{
LL_INFOS() << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL;
LL_INFOS("FloaterTools") << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL;
selected_item = MI_BOX;
}
@ -933,6 +946,7 @@ void LLPanelObject::getState( )
// Update field enablement
mComboBaseType ->setEnabled( enabled );
mMenuClipboardParams->setEnabled(enabled);
mLabelCut ->setEnabled( enabled );
mSpinCutBegin ->setEnabled( enabled );
@ -1093,7 +1107,8 @@ void LLPanelObject::getState( )
}
mComboBaseType->setEnabled(!isMesh);
mMenuClipboardParams->setEnabled(!isMesh);
if (mCtrlSculptType)
{
if (sculpt_stitching == LL_SCULPT_TYPE_NONE)
@ -1157,11 +1172,11 @@ void LLPanelObject::sendIsPhysical()
LLSelectMgr::getInstance()->selectionUpdatePhysics(value);
mIsPhysical = value;
LL_INFOS() << "update physics sent" << LL_ENDL;
LL_INFOS("FloaterTools") << "update physics sent" << LL_ENDL;
}
else
{
LL_INFOS() << "update physics not changed" << LL_ENDL;
LL_INFOS("FloaterTools") << "update physics not changed" << LL_ENDL;
}
}
@ -1173,11 +1188,11 @@ void LLPanelObject::sendIsTemporary()
LLSelectMgr::getInstance()->selectionUpdateTemporary(value);
mIsTemporary = value;
LL_INFOS() << "update temporary sent" << LL_ENDL;
LL_INFOS("FloaterTools") << "update temporary sent" << LL_ENDL;
}
else
{
LL_INFOS() << "update temporary not changed" << LL_ENDL;
LL_INFOS("FloaterTools") << "update temporary not changed" << LL_ENDL;
}
}
@ -1190,11 +1205,11 @@ void LLPanelObject::sendIsPhantom()
LLSelectMgr::getInstance()->selectionUpdatePhantom(value);
mIsPhantom = value;
LL_INFOS() << "update phantom sent" << LL_ENDL;
LL_INFOS("FloaterTools") << "update phantom sent" << LL_ENDL;
}
else
{
LL_INFOS() << "update phantom not changed" << LL_ENDL;
LL_INFOS("FloaterTools") << "update phantom not changed" << LL_ENDL;
}
}
@ -1304,7 +1319,7 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
break;
default:
LL_WARNS() << "Unknown base type " << selected_type
LL_WARNS("FloaterTools") << "Unknown base type " << selected_type
<< " in getVolumeParams()" << LL_ENDL;
// assume a box
selected_type = MI_BOX;
@ -1644,13 +1659,15 @@ void LLPanelObject::sendPosition(BOOL btn_down)
LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
LLViewerRegion* regionp = mObject->getRegion();
// Clamp the Z height
const F32 height = newpos.mV[VZ];
const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal());
const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight();
if (!regionp) return;
if (!mObject->isAttachment())
{
// Clamp the Z height
const F32 height = newpos.mV[VZ];
const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal());
const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight();
if ( height < min_height)
{
newpos.mV[VZ] = min_height;
@ -2011,3 +2028,283 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata)
self->sendSculpt();
}
void LLPanelObject::menuDoToSelected(const LLSD& userdata)
{
std::string command = userdata.asString();
// paste
if (command == "psr_paste")
{
onPastePos();
onPasteSize();
onPasteRot();
}
else if (command == "pos_paste")
{
onPastePos();
}
else if (command == "size_paste")
{
onPasteSize();
}
else if (command == "rot_paste")
{
onPasteRot();
}
else if (command == "params_paste")
{
onPasteParams();
}
// copy
else if (command == "psr_copy")
{
onCopyPos();
onCopySize();
onCopyRot();
}
else if (command == "pos_copy")
{
onCopyPos();
}
else if (command == "size_copy")
{
onCopySize();
}
else if (command == "rot_copy")
{
onCopyRot();
}
else if (command == "params_copy")
{
onCopyParams();
}
}
bool LLPanelObject::menuEnableItem(const LLSD& userdata)
{
std::string command = userdata.asString();
// paste options
if (command == "psr_paste")
{
S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME))
&& (selected_count == 1);
if (!single_volume)
{
return false;
}
bool enable_move;
bool enable_modify;
LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify);
return enable_move && enable_modify && mHasClipboardPos && mHasClipboardSize && mHasClipboardRot;
}
else if (command == "pos_paste")
{
// assumes that menu won't be active if there is no move permission
return mHasClipboardPos;
}
else if (command == "size_paste")
{
return mHasClipboardSize;
}
else if (command == "rot_paste")
{
return mHasClipboardRot;
}
else if (command == "params_paste")
{
return mClipboardParams.isMap() && !mClipboardParams.emptyMap();
}
// copy options
else if (command == "psr_copy")
{
S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME))
&& (selected_count == 1);
if (!single_volume)
{
return false;
}
bool enable_move;
bool enable_modify;
LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify);
// since we forbid seeing values we also should forbid copying them
return enable_move && enable_modify;
}
return false;
}
void LLPanelObject::onCopyPos()
{
mClipboardPos = LLVector3(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
std::string stringVec = llformat("<%g, %g, %g>", mClipboardPos.mV[VX], mClipboardPos.mV[VY], mClipboardPos.mV[VZ]);
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
mHasClipboardPos = true;
}
void LLPanelObject::onCopySize()
{
mClipboardSize = LLVector3(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get());
std::string stringVec = llformat("<%g, %g, %g>", mClipboardSize.mV[VX], mClipboardSize.mV[VY], mClipboardSize.mV[VZ]);
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
mHasClipboardSize = true;
}
void LLPanelObject::onCopyRot()
{
mClipboardRot = LLVector3(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get());
std::string stringVec = llformat("<%g, %g, %g>", mClipboardRot.mV[VX], mClipboardRot.mV[VY], mClipboardRot.mV[VZ]);
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
mHasClipboardRot = true;
}
void LLPanelObject::onPastePos()
{
if (!mHasClipboardPos) return;
if (mObject.isNull()) return;
LLViewerRegion* regionp = mObject->getRegion();
if (!regionp) return;
// Clamp pos on non-attachments, just keep the prims within the region
if (!mObject->isAttachment())
{
F32 max_width = regionp->getWidth(); // meters
mClipboardPos.mV[VX] = llclamp(mClipboardPos.mV[VX], 0.f, max_width);
mClipboardPos.mV[VY] = llclamp(mClipboardPos.mV[VY], 0.f, max_width);
//height will get properly clamped by sendPosition
}
mCtrlPosX->set( mClipboardPos.mV[VX] );
mCtrlPosY->set( mClipboardPos.mV[VY] );
mCtrlPosZ->set( mClipboardPos.mV[VZ] );
sendPosition(FALSE);
}
void LLPanelObject::onPasteSize()
{
if (!mHasClipboardSize) return;
mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
mClipboardSize.mV[VZ] = llclamp(mClipboardSize.mV[VZ], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
mCtrlScaleX->set(mClipboardSize.mV[VX]);
mCtrlScaleY->set(mClipboardSize.mV[VY]);
mCtrlScaleZ->set(mClipboardSize.mV[VZ]);
sendScale(FALSE);
}
void LLPanelObject::onPasteRot()
{
if (!mHasClipboardRot) return;
mCtrlRotX->set(mClipboardRot.mV[VX]);
mCtrlRotY->set(mClipboardRot.mV[VY]);
mCtrlRotZ->set(mClipboardRot.mV[VZ]);
sendRotation(FALSE);
}
void LLPanelObject::onCopyParams()
{
LLViewerObject* objectp = mObject;
if (!objectp || objectp->isMesh())
{
return;
}
mClipboardParams.clear();
// Parametrics
LLVolumeParams params;
getVolumeParams(params);
mClipboardParams["volume_params"] = params.asLLSD();
// Sculpted Prim
if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
{
LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
LLUUID texture_id = sculpt_params->getSculptTexture();
if (get_can_copy_texture(texture_id))
{
LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL;
mClipboardParams["sculpt"]["id"] = texture_id;
}
else
{
mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE);
}
mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType();
}
}
void LLPanelObject::onPasteParams()
{
LLViewerObject* objectp = mObject;
if (!objectp)
{
return;
}
// Sculpted Prim
if (mClipboardParams.has("sculpt"))
{
LLSculptParams sculpt_params;
LLUUID sculpt_id = mClipboardParams["sculpt"]["id"].asUUID();
U8 sculpt_type = (U8)mClipboardParams["sculpt"]["type"].asInteger();
sculpt_params.setSculptTexture(sculpt_id, sculpt_type);
objectp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
}
else
{
LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
if (sculpt_params)
{
objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE);
}
}
// volume params
// make sure updateVolume() won't affect flexible
if (mClipboardParams.has("volume_params"))
{
LLVolumeParams params;
params.fromLLSD(mClipboardParams["volume_params"]);
LLVOVolume *volobjp = (LLVOVolume *)objectp;
if (volobjp->isFlexible())
{
if (params.getPathParams().getCurveType() == LL_PCODE_PATH_LINE)
{
params.getPathParams().setCurveType(LL_PCODE_PATH_FLEXIBLE);
}
}
else if (params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
{
params.getPathParams().setCurveType(LL_PCODE_PATH_LINE);
}
objectp->updateVolume(params);
}
}

View File

@ -37,6 +37,7 @@ class LLCheckBoxCtrl;
class LLTextBox;
class LLUICtrl;
class LLButton;
class LLMenuButton;
class LLViewerObject;
class LLComboBox;
class LLColorSwatchCtrl;
@ -66,6 +67,14 @@ public:
static void onCommitPhantom( LLUICtrl* ctrl, void* userdata);
static void onCommitPhysics( LLUICtrl* ctrl, void* userdata);
void onCopyPos();
void onPastePos();
void onCopySize();
void onPasteSize();
void onCopyRot();
void onPasteRot();
void onCopyParams();
void onPasteParams();
static void onCommitParametric(LLUICtrl* ctrl, void* userdata);
@ -75,6 +84,9 @@ public:
BOOL onDropSculpt(LLInventoryItem* item);
static void onCommitSculptType( LLUICtrl *ctrl, void* userdata);
void menuDoToSelected(const LLSD& userdata);
bool menuEnableItem(const LLSD& userdata);
protected:
void getState();
@ -92,6 +104,7 @@ protected:
protected:
// Per-object options
LLComboBox* mComboBaseType;
LLMenuButton* mMenuClipboardParams;
LLTextBox* mLabelCut;
LLSpinCtrl* mSpinCutBegin;
@ -131,17 +144,20 @@ protected:
LLTextBox* mLabelRevolutions;
LLSpinCtrl* mSpinRevolutions;
LLMenuButton* mMenuClipboardPos;
LLTextBox* mLabelPosition;
LLSpinCtrl* mCtrlPosX;
LLSpinCtrl* mCtrlPosY;
LLSpinCtrl* mCtrlPosZ;
LLMenuButton* mMenuClipboardSize;
LLTextBox* mLabelSize;
LLSpinCtrl* mCtrlScaleX;
LLSpinCtrl* mCtrlScaleY;
LLSpinCtrl* mCtrlScaleZ;
BOOL mSizeChanged;
LLMenuButton* mMenuClipboardRot;
LLTextBox* mLabelRotation;
LLSpinCtrl* mCtrlRotX;
LLSpinCtrl* mCtrlRotY;
@ -157,7 +173,7 @@ protected:
LLComboBox *mCtrlSculptType;
LLCheckBoxCtrl *mCtrlSculptMirror;
LLCheckBoxCtrl *mCtrlSculptInvert;
LLVector3 mCurEulerDegrees; // to avoid sending rotation when not changed
BOOL mIsPhysical; // to avoid sending "physical" when not changed
BOOL mIsTemporary; // to avoid sending "temporary" when not changed
@ -167,6 +183,15 @@ protected:
LLUUID mSculptTextureRevert; // so we can revert the sculpt texture on cancel
U8 mSculptTypeRevert; // so we can revert the sculpt type on cancel
LLVector3 mClipboardPos;
LLVector3 mClipboardSize;
LLVector3 mClipboardRot;
LLSD mClipboardParams;
bool mHasClipboardPos;
bool mHasClipboardSize;
bool mHasClipboardRot;
LLPointer<LLViewerObject> mObject;
LLPointer<LLViewerObject> mRootObject;
};

View File

@ -618,7 +618,18 @@ const std::string& LLTaskCategoryBridge::getDisplayName() const
if (cat)
{
mDisplayName.assign(cat->getName());
std::string name = cat->getName();
if (mChildren.size() > 0)
{
// Add item count
// Normally we would be using getLabelSuffix for this
// but object's inventory just uses displaynames
LLStringUtil::format_map_t args;
args["[ITEMS_COUNT]"] = llformat("%d", mChildren.size());
name.append(" " + LLTrans::getString("InventoryItemsCount", args));
}
mDisplayName.assign(name);
}
return mDisplayName;
@ -1578,6 +1589,8 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root
{
createViewsForCategory(&contents, inventory_root, new_folder);
}
// Refresh for label to add item count
new_folder->refresh();
}
}

View File

@ -51,6 +51,7 @@
#include "llfocusmgr.h"
#include "llmanipscale.h"
#include "llinventorymodel.h"
#include "llmenubutton.h"
#include "llpreviewscript.h"
#include "llresmgr.h"
#include "llselectmgr.h"
@ -177,6 +178,9 @@ BOOL LLPanelVolume::postBuild()
mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution));
}
mMenuClipboardFeatures = getChild<LLMenuButton>("clipboard_features_params_btn");
mMenuClipboardLight = getChild<LLMenuButton>("clipboard_light_params_btn");
std::map<std::string, std::string> material_name_map;
material_name_map["Stone"]= LLTrans::getString("Stone");
material_name_map["Metal"]= LLTrans::getString("Metal");
@ -217,6 +221,8 @@ LLPanelVolume::LLPanelVolume()
{
setMouseOpaque(FALSE);
mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", boost::bind(&LLPanelVolume::menuDoToSelected, this, _2));
mEnableCallbackRegistrar.add("PanelVolume.menuEnable", boost::bind(&LLPanelVolume::menuEnableItem, this, _2));
}
@ -455,7 +461,6 @@ void LLPanelVolume::getState( )
gAgentAvatarp->updateMeshVisibility();
}
}
// Flexible properties
BOOL is_flexible = volobjp && volobjp->isFlexible();
@ -610,6 +615,9 @@ void LLPanelVolume::getState( )
mObject = objectp;
mRootObject = root_objectp;
mMenuClipboardFeatures->setEnabled(editable && single_volume && volobjp); // Note: physics doesn't need to be limited by single volume
mMenuClipboardLight->setEnabled(editable && single_volume && volobjp);
}
// static
@ -896,6 +904,290 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data)
}
}
void LLPanelVolume::onCopyFeatures()
{
LLViewerObject* objectp = mObject;
if (!objectp)
{
return;
}
LLSD clipboard;
LLVOVolume *volobjp = NULL;
if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
{
volobjp = (LLVOVolume *)objectp;
}
// Flexi Prim
if (volobjp && volobjp->isFlexible())
{
LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
if (attributes)
{
clipboard["flex"]["lod"] = attributes->getSimulateLOD();
clipboard["flex"]["gav"] = attributes->getGravity();
clipboard["flex"]["ten"] = attributes->getTension();
clipboard["flex"]["fri"] = attributes->getAirFriction();
clipboard["flex"]["sen"] = attributes->getWindSensitivity();
LLVector3 force = attributes->getUserForce();
clipboard["flex"]["forx"] = force.mV[0];
clipboard["flex"]["fory"] = force.mV[1];
clipboard["flex"]["forz"] = force.mV[2];
}
}
// Physics
{
clipboard["physics"]["shape"] = objectp->getPhysicsShapeType();
clipboard["physics"]["gravity"] = objectp->getPhysicsGravity();
clipboard["physics"]["friction"] = objectp->getPhysicsFriction();
clipboard["physics"]["density"] = objectp->getPhysicsDensity();
clipboard["physics"]["restitution"] = objectp->getPhysicsRestitution();
U8 material_code = 0;
struct f : public LLSelectedTEGetFunctor<U8>
{
U8 get(LLViewerObject* object, S32 te)
{
return object->getMaterial();
}
} func;
bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func, material_code);
// This should always be true since material should be per object.
if (material_same)
{
clipboard["physics"]["material"] = material_code;
}
}
mClipboardParams["features"] = clipboard;
}
void LLPanelVolume::onPasteFeatures()
{
LLViewerObject* objectp = mObject;
if (!objectp && mClipboardParams.has("features"))
{
return;
}
LLSD &clipboard = mClipboardParams["features"];
LLVOVolume *volobjp = NULL;
if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
{
volobjp = (LLVOVolume *)objectp;
}
// Physics
bool is_root = objectp->isRoot();
// Not sure if phantom should go under physics, but doesn't fit elsewhere
BOOL is_phantom = clipboard["is_phantom"].asBoolean() && is_root;
LLSelectMgr::getInstance()->selectionUpdatePhantom(is_phantom);
BOOL is_physical = clipboard["is_physical"].asBoolean() && is_root;
LLSelectMgr::getInstance()->selectionUpdatePhysics(is_physical);
if (clipboard.has("physics"))
{
objectp->setPhysicsShapeType((U8)clipboard["physics"]["shape"].asInteger());
U8 cur_material = objectp->getMaterial();
U8 material = (U8)clipboard["physics"]["material"].asInteger() | (cur_material & ~LL_MCODE_MASK);
objectp->setMaterial(material);
objectp->sendMaterialUpdate();
objectp->setPhysicsGravity(clipboard["physics"]["gravity"].asReal());
objectp->setPhysicsFriction(clipboard["physics"]["friction"].asReal());
objectp->setPhysicsDensity(clipboard["physics"]["density"].asReal());
objectp->setPhysicsRestitution(clipboard["physics"]["restitution"].asReal());
objectp->updateFlags(TRUE);
}
// Flexible
bool is_flexible = clipboard.has("flex");
if (is_flexible && volobjp->canBeFlexible())
{
LLVOVolume *volobjp = (LLVOVolume *)objectp;
BOOL update_shape = FALSE;
// do before setParameterEntry or it will think that it is already flexi
update_shape = volobjp->setIsFlexible(is_flexible);
if (objectp->getClickAction() == CLICK_ACTION_SIT)
{
objectp->setClickAction(CLICK_ACTION_NONE);
}
LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
if (attributes)
{
LLFlexibleObjectData new_attributes;
new_attributes = *attributes;
new_attributes.setSimulateLOD(clipboard["flex"]["lod"].asInteger());
new_attributes.setGravity(clipboard["flex"]["gav"].asReal());
new_attributes.setTension(clipboard["flex"]["ten"].asReal());
new_attributes.setAirFriction(clipboard["flex"]["fri"].asReal());
new_attributes.setWindSensitivity(clipboard["flex"]["sen"].asReal());
F32 fx = (F32)clipboard["flex"]["forx"].asReal();
F32 fy = (F32)clipboard["flex"]["fory"].asReal();
F32 fz = (F32)clipboard["flex"]["forz"].asReal();
LLVector3 force(fx, fy, fz);
new_attributes.setUserForce(force);
objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true);
}
if (update_shape)
{
mObject->sendShapeUpdate();
LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom());
}
}
else
{
LLVOVolume *volobjp = (LLVOVolume *)objectp;
if (volobjp->setIsFlexible(false))
{
mObject->sendShapeUpdate();
LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom());
}
}
}
void LLPanelVolume::onCopyLight()
{
LLViewerObject* objectp = mObject;
if (!objectp)
{
return;
}
LLSD clipboard;
LLVOVolume *volobjp = NULL;
if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
{
volobjp = (LLVOVolume *)objectp;
}
// Light Source
if (volobjp && volobjp->getIsLight())
{
clipboard["light"]["intensity"] = volobjp->getLightIntensity();
clipboard["light"]["radius"] = volobjp->getLightRadius();
clipboard["light"]["falloff"] = volobjp->getLightFalloff();
LLColor3 color = volobjp->getLightSRGBColor();
clipboard["light"]["r"] = color.mV[0];
clipboard["light"]["g"] = color.mV[1];
clipboard["light"]["b"] = color.mV[2];
// Spotlight
if (volobjp->isLightSpotlight())
{
LLUUID id = volobjp->getLightTextureID();
if (id.notNull() && get_can_copy_texture(id))
{
clipboard["spot"]["id"] = id;
LLVector3 spot_params = volobjp->getSpotLightParams();
clipboard["spot"]["fov"] = spot_params.mV[0];
clipboard["spot"]["focus"] = spot_params.mV[1];
clipboard["spot"]["ambiance"] = spot_params.mV[2];
}
}
}
mClipboardParams["light"] = clipboard;
}
void LLPanelVolume::onPasteLight()
{
LLViewerObject* objectp = mObject;
if (!objectp && mClipboardParams.has("light"))
{
return;
}
LLSD &clipboard = mClipboardParams["light"];
LLVOVolume *volobjp = NULL;
if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
{
volobjp = (LLVOVolume *)objectp;
}
// Light Source
if (volobjp)
{
if (clipboard.has("light"))
{
volobjp->setIsLight(TRUE);
volobjp->setLightIntensity((F32)clipboard["light"]["intensity"].asReal());
volobjp->setLightRadius((F32)clipboard["light"]["radius"].asReal());
volobjp->setLightFalloff((F32)clipboard["light"]["falloff"].asReal());
F32 r = (F32)clipboard["light"]["r"].asReal();
F32 g = (F32)clipboard["light"]["g"].asReal();
F32 b = (F32)clipboard["light"]["b"].asReal();
volobjp->setLightSRGBColor(LLColor3(r, g, b));
}
else
{
volobjp->setIsLight(FALSE);
}
if (clipboard.has("spot"))
{
volobjp->setLightTextureID(clipboard["spot"]["id"].asUUID());
LLVector3 spot_params;
spot_params.mV[0] = (F32)clipboard["spot"]["fov"].asReal();
spot_params.mV[1] = (F32)clipboard["spot"]["focus"].asReal();
spot_params.mV[2] = (F32)clipboard["spot"]["ambiance"].asReal();
volobjp->setSpotLightParams(spot_params);
}
}
}
void LLPanelVolume::menuDoToSelected(const LLSD& userdata)
{
std::string command = userdata.asString();
// paste
if (command == "features_paste")
{
onPasteFeatures();
}
else if (command == "light_paste")
{
onPasteLight();
}
// copy
else if (command == "features_copy")
{
onCopyFeatures();
}
else if (command == "light_copy")
{
onCopyLight();
}
}
bool LLPanelVolume::menuEnableItem(const LLSD& userdata)
{
std::string command = userdata.asString();
// paste options
if (command == "features_paste")
{
return mClipboardParams.has("features");
}
else if (command == "light_paste")
{
return mClipboardParams.has("light");
}
return false;
}
// static
void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata )
{

View File

@ -37,6 +37,7 @@ class LLCheckBoxCtrl;
class LLTextBox;
class LLUICtrl;
class LLButton;
class LLMenuButton;
class LLViewerObject;
class LLComboBox;
class LLColorSwatchCtrl;
@ -79,6 +80,13 @@ public:
static void setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp);
void onCopyFeatures();
void onPasteFeatures();
void onCopyLight();
void onPasteLight();
void menuDoToSelected(const LLSD& userdata);
bool menuEnableItem(const LLSD& userdata);
protected:
void getState();
@ -126,6 +134,11 @@ protected:
LLSpinCtrl* mSpinPhysicsFriction;
LLSpinCtrl* mSpinPhysicsDensity;
LLSpinCtrl* mSpinPhysicsRestitution;
LLMenuButton* mMenuClipboardFeatures;
LLMenuButton* mMenuClipboardLight;
LLSD mClipboardParams;
};
#endif

View File

@ -80,6 +80,67 @@ static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
//static const char WHITE_IMAGE_NAME[] = "Blank Texture";
//static const char NO_IMAGE_NAME[] = "None";
//static
bool get_is_predefined_texture(LLUUID asset_id)
{
if (asset_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture"))
|| asset_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID"))
|| asset_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID"))
|| asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE))
{
return true;
}
return false;
}
LLUUID get_copy_free_item_by_asset_id(LLUUID asset_id, bool no_trans_perm)
{
LLViewerInventoryCategory::cat_array_t cats;
LLViewerInventoryItem::item_array_t items;
LLAssetIDMatches asset_id_matches(asset_id);
gInventory.collectDescendentsIf(LLUUID::null,
cats,
items,
LLInventoryModel::INCLUDE_TRASH,
asset_id_matches);
LLUUID res;
if (items.size())
{
for (S32 i = 0; i < items.size(); i++)
{
LLViewerInventoryItem* itemp = items[i];
if (itemp)
{
LLPermissions item_permissions = itemp->getPermissions();
if (item_permissions.allowOperationBy(PERM_COPY,
gAgent.getID(),
gAgent.getGroupID()))
{
bool allow_trans = item_permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID(), gAgent.getGroupID());
if (allow_trans != no_trans_perm)
{
return itemp->getUUID();
}
res = itemp->getUUID();
}
}
}
}
return res;
}
bool get_can_copy_texture(LLUUID asset_id)
{
// User is allowed to copy a texture if:
// library asset or default texture,
// or copy perm asset exists in user's inventory
return get_is_predefined_texture(asset_id) || get_copy_free_item_by_asset_id(asset_id).notNull();
}
LLFloaterTexturePicker::LLFloaterTexturePicker(
LLView* owner,
LLUUID image_asset_id,

View File

@ -52,6 +52,16 @@ class LLViewerFetchedTexture;
typedef boost::function<BOOL (LLUICtrl*, LLInventoryItem*)> drag_n_drop_callback;
typedef boost::function<void (LLInventoryItem*)> texture_selected_callback;
// Helper functions for UI that work with picker
bool get_is_predefined_texture(LLUUID asset_id);
// texture picker works by asset ids since objects normaly do
// not retain inventory ids as result these functions are looking
// for textures in inventory by asset ids
// This search can be performance unfriendly and doesn't warranty
// that the texture is original source of asset
LLUUID get_copy_free_item_by_asset_id(LLUUID image_id, bool no_trans_perm = false);
bool get_can_copy_texture(LLUUID image_id);
//////////////////////////////////////////////////////////////////////////////////////////
// LLTextureCtrl

View File

@ -291,7 +291,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
mLineEditor->setText(edit_text_contents);
std::string notif_name = mNotification->getName();
if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name))
if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name) || ("CreateSubfolder" == notif_name))
{
mLineEditor->setPrevalidate(&LLTextValidate::validateASCII);
}

View File

@ -1160,7 +1160,8 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
S32 hit_face,
LLInventoryItem* item,
LLToolDragAndDrop::ESource source,
const LLUUID& src_id)
const LLUUID& src_id,
S32 tex_channel)
{
if (hit_face == -1) return;
if (!item)
@ -1184,7 +1185,8 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
if (gFloaterTools->getVisible() && panel_face)
{
switch (LLSelectMgr::getInstance()->getTextureChannel())
tex_channel = (tex_channel > -1) ? tex_channel : LLSelectMgr::getInstance()->getTextureChannel();
switch (tex_channel)
{
case 0:

View File

@ -246,7 +246,8 @@ public:
static void dropTextureOneFace(LLViewerObject* hit_obj, S32 hit_face,
LLInventoryItem* item,
ESource source,
const LLUUID& src_id);
const LLUUID& src_id,
S32 tex_channel = -1);
static void dropTextureAllFaces(LLViewerObject* hit_obj,
LLInventoryItem* item,
ESource source,

View File

@ -2724,6 +2724,32 @@ void handle_object_touch()
send_ObjectDeGrab_message(object, pick);
}
void handle_object_show_original()
{
LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
if (!object)
{
return;
}
LLViewerObject *parent = (LLViewerObject*)object->getParent();
while (parent)
{
if(parent->isAvatar())
{
break;
}
object = parent;
parent = (LLViewerObject*)parent->getParent();
}
if (!object || object->isAvatar())
{
return;
}
show_item_original(object->getAttachmentItemID());
}
static void init_default_item_label(const std::string& item_name)
@ -9530,6 +9556,7 @@ void initialize_menus()
// Object pie menu
view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
commit.add("Object.Touch", boost::bind(&handle_object_touch));
commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original));
commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
commit.add("Object.Delete", boost::bind(&handle_object_delete));
view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");

View File

@ -948,6 +948,7 @@ void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_M
break;
case STATE_MODE_DIFF:
if (mOctreeNode)
{
LLSpatialSetOcclusionStateDiff setter(state);
setter.traverse(mOctreeNode);
@ -955,6 +956,7 @@ void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_M
break;
case STATE_MODE_BRANCH:
if (mOctreeNode)
{
LLSpatialSetOcclusionState setter(state);
setter.traverse(mOctreeNode);
@ -1024,6 +1026,7 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE
break;
case STATE_MODE_DIFF:
if (mOctreeNode)
{
LLSpatialClearOcclusionStateDiff clearer(state);
clearer.traverse(mOctreeNode);
@ -1031,6 +1034,7 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE
break;
case STATE_MODE_BRANCH:
if (mOctreeNode)
{
LLSpatialClearOcclusionState clearer(state);
clearer.traverse(mOctreeNode);

View File

@ -103,7 +103,6 @@
#include "llfilepicker.h"
#include "llfirstuse.h"
#include "llfloater.h"
#include "llfloaterbuildoptions.h"
#include "llfloaterbuyland.h"
#include "llfloatercamera.h"
#include "llfloaterland.h"

View File

@ -4621,7 +4621,12 @@ bool LLVOAvatar::updateCharacter(LLAgent &agent)
}
else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
{
getOffObject();
// If we are starting up, motion might be loading
LLMotion *motionp = mMotionController.findMotion(ANIM_AGENT_SIT_GROUND_CONSTRAINED);
if (!motionp || !mMotionController.isMotionLoading(motionp))
{
getOffObject();
}
}
//--------------------------------------------------------------------

View File

@ -232,6 +232,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mMediaImplList.resize(getNumTEs());
mLastFetchedMediaVersion = -1;
mServerDrawableUpdateCount = 0;
memset(&mIndexInTex, 0, sizeof(S32) * LLRender::NUM_VOLUME_TEXTURE_CHANNELS);
mMDCImplCount = 0;
mLastRiggingInfoLOD = -1;
@ -327,6 +328,9 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
LLColor4U color;
const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA);
const bool previously_volume_changed = mVolumeChanged;
const bool previously_face_mapping_changed = mFaceMappingChanged;
const bool previously_color_changed = mColorChanged;
// Do base class updates...
U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
@ -550,9 +554,31 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
// ...and clean up any media impls
cleanUpMediaImpls();
if ((
(mVolumeChanged && !previously_volume_changed) ||
(mFaceMappingChanged && !previously_face_mapping_changed) ||
(mColorChanged && !previously_color_changed)
)
&& !mLODChanged) {
onDrawableUpdateFromServer();
}
return retval;
}
// Called when a volume, material, etc is updated by the server, possibly by a
// script. If this occurs too often for this object, mark it as active so that
// it doesn't disrupt the octree/render batches, thereby potentially causing a
// big performance penalty.
void LLVOVolume::onDrawableUpdateFromServer()
{
constexpr U32 UPDATES_UNTIL_ACTIVE = 8;
++mServerDrawableUpdateCount;
if (mDrawable && !mDrawable->isActive() && mServerDrawableUpdateCount > UPDATES_UNTIL_ACTIVE)
{
mDrawable->makeActive();
}
}
void LLVOVolume::animateTextures()
{
@ -1677,7 +1703,7 @@ void LLVOVolume::regenFaces()
}
}
BOOL LLVOVolume::genBBoxes(BOOL force_global)
BOOL LLVOVolume::genBBoxes(BOOL force_global, BOOL should_update_octree_bounds)
{
LL_PROFILE_ZONE_SCOPED;
BOOL res = TRUE;
@ -1753,20 +1779,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
}
}
bool rigged = false;
if (!isAnimatedObject())
{
rigged = isRiggedMesh() && isAttachment();
}
else
{
rigged = isRiggedMesh() && getControlAvatar() && getControlAvatar()->mPlaying;
}
if (any_valid_boxes)
{
if (rebuild)
if (rebuild && should_update_octree_bounds)
{
//get the Avatar associated with this object if it's rigged
LLVOAvatar* avatar = nullptr;
@ -1928,7 +1943,7 @@ void LLVOVolume::updateRelativeXform(bool force_identity)
}
}
bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled, BOOL &should_update_octree_bounds)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
bool regen_faces = false;
@ -1960,6 +1975,9 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
}
compiled = TRUE;
// new_lod > old_lod breaks a feedback loop between LOD updates and
// bounding box updates.
should_update_octree_bounds = should_update_octree_bounds || mSculptChanged || new_lod > old_lod;
sNumLODChanges += new_num_faces;
if ((S32)getNumTEs() != getVolume()->getNumFaces())
@ -2019,8 +2037,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
group->dirtyMesh();
}
BOOL compiled = FALSE;
updateRelativeXform();
if (mDrawable.isNull()) // Not sure why this is happening, but it is...
@ -2028,49 +2044,55 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
return TRUE; // No update to complete
}
BOOL compiled = FALSE;
// This should be true in most cases, unless we're sure no octree update is
// needed.
BOOL should_update_octree_bounds = bool(getRiggedVolume()) || mDrawable->isState(LLDrawable::REBUILD_POSITION) || !mDrawable->getSpatialExtents()->isFinite3();
if (mVolumeChanged || mFaceMappingChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
bool was_regen_faces = false;
should_update_octree_bounds = true;
if (mVolumeChanged)
{
was_regen_faces = lodOrSculptChanged(drawable, compiled);
was_regen_faces = lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
drawable->setState(LLDrawable::REBUILD_VOLUME);
}
else if (mSculptChanged || mLODChanged || mColorChanged)
{
compiled = TRUE;
was_regen_faces = lodOrSculptChanged(drawable, compiled);
was_regen_faces = lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
}
if (!was_regen_faces) {
regenFaces();
}
genBBoxes(FALSE);
}
else if (mLODChanged || mSculptChanged || mColorChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
compiled = TRUE;
lodOrSculptChanged(drawable, compiled);
lodOrSculptChanged(drawable, compiled, should_update_octree_bounds);
if(drawable->isState(LLDrawable::REBUILD_RIGGED | LLDrawable::RIGGED))
{
updateRiggedVolume(false);
}
genBBoxes(FALSE);
}
// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
else
{
compiled = TRUE;
// All it did was move or we changed the texture coordinate offset
genBBoxes(FALSE);
}
// Generate bounding boxes if needed, and update the object's size in the
// octree
genBBoxes(FALSE, should_update_octree_bounds);
// Update face flags
updateFaceFlags();

View File

@ -236,7 +236,7 @@ public:
void updateFaceFlags();
void regenFaces();
BOOL genBBoxes(BOOL force_global);
BOOL genBBoxes(BOOL force_global, BOOL should_update_octree_bounds = TRUE);
void preRebuild();
virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max) override;
virtual F32 getBinRadius() override;
@ -403,13 +403,14 @@ protected:
static S32 mRenderComplexity_last;
static S32 mRenderComplexity_current;
void onDrawableUpdateFromServer();
void requestMediaDataUpdate(bool isNew);
void cleanUpMediaImpls();
void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ;
void removeMediaImpl(S32 texture_index) ;
private:
bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled);
bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled, BOOL &shouldUpdateOctreeBounds);
public:
@ -441,6 +442,7 @@ private:
LLPointer<LLViewerFetchedTexture> mLightTexture;
media_list_t mMediaImplList;
S32 mLastFetchedMediaVersion; // as fetched from the server, starts as -1
U32 mServerDrawableUpdateCount;
S32 mIndexInTex[LLRender::NUM_VOLUME_TEXTURE_CHANNELS];
S32 mMDCImplCount;

View File

@ -3976,7 +3976,7 @@ void LLPipeline::postSort(LLCamera& camera)
}
LL_PUSH_CALLSTACKS();
// If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
if (LLFloaterTelehub::renderBeacons())
if (LLFloaterTelehub::renderBeacons() && !sShadowRender)
{
LLFloaterTelehub::addBeacons();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

View File

@ -448,6 +448,13 @@ with the same filename but different name
<texture name="OptionsMenu_Off" file_name="icons/OptionsMenu_Off.png" preload="false" />
<texture name="OptionsMenu_Press" file_name="icons/OptionsMenu_Press.png" preload="false" />
<texture name="ClipboardSmallMenu_Disabled" file_name="icons/ClipboardSmallMenu_Disabled.png" preload="false" />
<texture name="ClipboardSmallMenu_Off" file_name="icons/ClipboardSmallMenu_Off.png" preload="false" />
<texture name="ClipboardSmallMenu_Press" file_name="icons/ClipboardSmallMenu_Press.png" preload="false" />
<texture name="ClipboardMenu_Disabled" file_name="icons/ClipboardMenu_Disabled.png" preload="false" />
<texture name="ClipboardMenu_Off" file_name="icons/ClipboardMenu_Off.png" preload="false" />
<texture name="ClipboardMenu_Press" file_name="icons/ClipboardMenu_Press.png" preload="false" />
<texture name="OutboxStatus_Success" file_name="green_checkmark.png" preload="false" />
<texture name="OutboxStatus_Warning" file_name="icons/pop_up_caution.png" preload="false" />
<texture name="OutboxStatus_Error" file_name="red_x.png" preload="false" />
@ -804,6 +811,8 @@ with the same filename but different name
<texture name="map_infohub.tga" />
<texture name="map_telehub.tga" />
<texture name="map_track_16.tga" />
<texture name="map_ui_collapse_icon.png" />
<texture name="map_ui_expand_icon.png" />
<texture name="notify_caution_icon.tga" />

View File

@ -2,7 +2,7 @@
<floater
positioning="cascading"
legacy_header_height="18"
height="640"
height="609"
layout="topleft"
bg_opaque_image="Window_NoTitle_Foreground"
bg_alpha_image="Window_NoTitle_Background"
@ -68,7 +68,7 @@
</floater.string>
<floater.string
name="status_selectcount">
[OBJ_COUNT] objects selected, land impact [LAND_IMPACT]
[OBJ_COUNT] objects selected, land impact [LAND_IMPACT] [secondlife:///app/openfloater/object_weights More info]
</floater.string>
<floater.string
name="status_remaining_capacity">
@ -763,11 +763,12 @@
font="SansSerifSmall"
layout="topleft"
left="10"
name="selection_count"
name="selection_faces"
top_delta="0"
visible="false"
width="280">
</text>
Faces selected: [FACES_STRING]
</text>
<text
text_color="LtGray_50"
type="string"
@ -777,11 +778,10 @@
font="SansSerifSmall"
layout="topleft"
left="10"
name="remaining_capacity"
name="selection_count"
top_pad="0"
visible="false"
width="280">
[CAPACITY_STRING] [secondlife:///app/openfloater/object_weights More info]
</text>
<!-- <text -->
<!-- text_color="LtGray_50" -->
@ -820,7 +820,7 @@
width="282"/>
<tab_container
follows="left|top"
height="460"
height="426"
halign="center"
left="0"
name="Object Info Tabs"
@ -1430,16 +1430,40 @@ even though the user gets a free copy.
tool_tip="Causes object to not collide with other objects or avatars"
top_pad="0"
width="123" />
<text
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left_delta="0"
name="object_horizontal"
top_pad="10"
width="95" />
<menu_button
menu_filename="menu_copy_paste_pos.xml"
follows="top|left"
height="11"
image_disabled="ClipboardSmallMenu_Disabled"
image_selected="ClipboardSmallMenu_Press"
image_unselected="ClipboardSmallMenu_Off"
layout="topleft"
left_delta="0"
top_pad="13"
name="clipboard_pos_btn"
tool_tip="Paste options"
width="19"/>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
name="label position"
top_pad="10"
tool_tip="Position (meters)"
left_pad="8"
top_delta="0"
width="121">
Position (meters)
Position (m)
</text>
<spinner
follows="left|top"
@ -1449,12 +1473,12 @@ even though the user gets a free copy.
label="X"
label_width="10"
layout="topleft"
left_delta="0"
left_delta="-27"
max_val="512"
min_val="-256"
name="Pos X"
text_enabled_color="1 0 0.3 .7"
top_pad="5"
top_pad="8"
width="87" />
<spinner
follows="left|top"
@ -1481,21 +1505,36 @@ even though the user gets a free copy.
layout="topleft"
left_delta="0"
max_val="4096"
min_val="-32"
name="Pos Z"
text_enabled_color="0 0.8 1 .65"
top_pad="3"
width="87" />
<menu_button
menu_filename="menu_copy_paste_size.xml"
follows="top|left"
height="11"
image_disabled="ClipboardSmallMenu_Disabled"
image_selected="ClipboardSmallMenu_Press"
image_unselected="ClipboardSmallMenu_Off"
layout="topleft"
left_delta="0"
top_pad="13"
name="clipboard_size_btn"
tool_tip="Paste options"
width="19"/>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_delta="0"
left_pad="8"
top_delta="0"
name="label size"
top_pad="6"
tool_tip="Size (meters)"
width="121">
Size (meters)
Size (m)
</text>
<spinner
follows="left|top"
@ -1505,12 +1544,12 @@ even though the user gets a free copy.
label="X"
label_width="10"
layout="topleft"
left_delta="0"
left_delta="-27"
max_val="64"
min_val="0.01"
name="Scale X"
text_enabled_color="1 1 1 1"
top_pad="5"
top_pad="8"
width="87" />
<spinner
follows="left|top"
@ -1542,17 +1581,31 @@ even though the user gets a free copy.
text_enabled_color="1 1 1 1"
top_pad="3"
width="87" />
<menu_button
menu_filename="menu_copy_paste_rot.xml"
follows="top|left"
height="11"
image_disabled="ClipboardSmallMenu_Disabled"
image_selected="ClipboardSmallMenu_Press"
image_unselected="ClipboardSmallMenu_Off"
layout="topleft"
left_delta="0"
top_pad="13"
name="clipboard_rot_btn"
tool_tip="Paste options"
width="19"/>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_delta="0"
left_pad="8"
top_delta="0"
name="label rotation"
top_pad="10"
tool_tip="Rotation (degrees)"
width="121">
Rotation (degrees)
Rotation (°)
</text>
<spinner
decimal_digits="2"
@ -1563,12 +1616,12 @@ even though the user gets a free copy.
label="X"
label_width="10"
layout="topleft"
left_delta="0"
left_delta="-27"
max_val="9999"
min_val="-9999"
name="Rot X"
text_enabled_color="1 1 1 1"
top_pad="5"
top_pad="8"
width="87" />
<spinner
decimal_digits="2"
@ -1614,13 +1667,23 @@ even though the user gets a free copy.
width="150">
Prim Type
</text>-->
<view_border
bevel_style="none"
follows="top|left"
layout="topleft"
name="object_vertical"
left="117"
top="6"
height="500"
width="0"/>
<combo_box
height="19"
layout="topleft"
name="comboBaseType"
top="6"
left="125"
width="150">
width="125">
<combo_box.item
label="Box"
name="Box"
@ -1654,13 +1717,26 @@ even though the user gets a free copy.
name="Sculpted"
value="Sculpted" />
</combo_box>
<menu_button
menu_filename="menu_copy_paste_object.xml"
follows="top|left"
height="15"
image_disabled="ClipboardMenu_Disabled"
image_selected="ClipboardMenu_Press"
image_unselected="ClipboardMenu_Off"
layout="topleft"
left_pad="8"
top_delta="2"
name="clipboard_obj_params_btn"
tool_tip="Paste options"
width="22"/>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_delta="0"
left="125"
name="text cut"
top_pad="5"
width="150">
@ -1700,7 +1776,7 @@ even though the user gets a free copy.
layout="topleft"
left="125"
name="text hollow"
top_pad="6"
top_pad="7"
width="68">
Hollow
</text>
@ -1748,7 +1824,7 @@ even though the user gets a free copy.
layout="topleft"
left="125"
name="Hollow Shape"
top_pad="4"
top_pad="7"
width="150">
Hollow Shape
</text>
@ -1784,7 +1860,7 @@ even though the user gets a free copy.
layout="topleft"
left_delta="0"
name="text twist"
top_pad="5"
top_pad="7"
width="150">
Twist (begin/end)
</text>
@ -1826,12 +1902,12 @@ even though the user gets a free copy.
layout="topleft"
left="125"
name="scale_taper"
top_pad="3"
top_pad="7"
width="150">
Taper
</text>
<text
visible="false"
visible="false"
type="string"
length="1"
follows="left|top"
@ -1879,7 +1955,7 @@ even though the user gets a free copy.
layout="topleft"
left="125"
name="text topshear"
top_pad="3"
top_pad="5"
width="141">
Top Shear
</text>
@ -1922,12 +1998,12 @@ even though the user gets a free copy.
layout="topleft"
left="125"
name="advanced_cut"
top_pad="3"
top_pad="7"
width="150">
Profile Cut (begin/end)
</text>
<text
visible="false"
visible="false"
type="string"
length="1"
follows="left|top"
@ -1986,7 +2062,7 @@ even though the user gets a free copy.
layout="topleft"
left="125"
name="text taper2"
top_pad="3"
top_pad="7"
width="150">
Taper
</text>
@ -2029,7 +2105,7 @@ even though the user gets a free copy.
layout="topleft"
left="125"
name="text radius delta"
top_pad="2"
top_pad="7"
width="78">
Radius
</text>
@ -2157,6 +2233,19 @@ even though the user gets a free copy.
<panel.string name="None">None</panel.string>
<panel.string name="Prim">Prim</panel.string>
<panel.string name="Convex Hull">Convex Hull</panel.string>
<menu_button
menu_filename="menu_copy_paste_features.xml"
follows="top|left"
height="15"
image_disabled="ClipboardMenu_Disabled"
image_selected="ClipboardMenu_Press"
image_unselected="ClipboardMenu_Off"
layout="topleft"
left="258"
top="8"
name="clipboard_features_params_btn"
tool_tip="Paste options"
width="22"/>
<text
type="string"
length="1"
@ -2309,6 +2398,15 @@ even though the user gets a free copy.
name="FlexForceZ"
top_pad="4"
width="128" />
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
name="object_horizontal"
top_pad="10"
width="278" />
<check_box
height="16"
@ -2317,7 +2415,7 @@ even though the user gets a free copy.
left="10"
name="Light Checkbox Ctrl"
tool_tip="Causes object to emit light"
top_pad="10"
top_pad="8"
width="60" />
<color_swatch
can_apply_immediately="true"
@ -2344,6 +2442,19 @@ even though the user gets a free copy.
name="light texture control"
tool_tip="Click to choose a projection image (only has effect with deferred rendering enabled)"
width="32" />
<menu_button
menu_filename="menu_copy_paste_light.xml"
follows="top|left"
height="15"
image_disabled="ClipboardMenu_Disabled"
image_selected="ClipboardMenu_Press"
image_unselected="ClipboardMenu_Off"
layout="topleft"
left="258"
top_delta="0"
name="clipboard_light_params_btn"
tool_tip="Paste options"
width="22"/>
<spinner
follows="left|top"
height="19"
@ -2353,7 +2464,7 @@ even though the user gets a free copy.
layout="topleft"
left="10"
name="Light Intensity"
top_delta="32"
top_pad="26"
width="128" />
<spinner bottom_delta="0"
decimal_digits="3"
@ -2638,7 +2749,7 @@ even though the user gets a free copy.
border_visible="true"
bevel_style="in"
follows="left|top|right"
height="325"
height="335"
layout="topleft"
left="10"
name="contents_inventory"

View File

@ -14,6 +14,31 @@
single_instance="true"
title="WORLD MAP"
width="650">
<string
name="collapse_icon"
value="map_ui_collapse_icon.png"/>
<string
name="expand_icon"
value="map_ui_expand_icon.png"/>
<string
name="collapse_tooltip"
value="Hide map controls"/>
<string
name="expand_tooltip"
value="Show map controls"/>
<layout_stack
animate="false"
follows="all"
name="floater_map_stack"
tab_group="1"
top="16"
left="0"
right="-1"
bottom="-1">
<layout_panel
name="map_lp"
width="385"
height="575">
<panel
filename="panel_world_map.xml"
follows="all"
@ -21,17 +46,48 @@
layout="topleft"
left="10"
name="objects_mapview"
top="25"
top="6"
width="375" />
<panel
follows="top|right"
height="30"
layout="topleft"
left_pad="-29"
name="expand_btn_panel"
background_visible="true"
bg_opaque_color="FloaterFocusBackgroundColor"
bg_alpha_color="FloaterDefaultBackgroundColor"
background_opaque="true"
tool_tip="Hide map controls"
top="350"
width="30">
<icon
follows="top|right"
height="16"
width="16"
top="7"
left="7"
scale_image="false"
image_name="map_ui_collapse_icon.png"
layout="topleft"
mouse_opaque="true"
name="expand_collapse_icon"
tool_tip="Hide map controls" />
</panel>
</layout_panel>
<layout_panel
height="575"
width="265"
expanded_min_dim="265"
name="controls_lp">
<panel
name="layout_panel_1"
height="22"
width="238"
follows="right|top"
top="25"
left_pad="5"
background_visible="true"
bg_alpha_color="DkGray2">
name="layout_panel_1"
height="22"
width="238"
follows="right|top"
top="6"
background_visible="true"
bg_alpha_color="DkGray2">
<text
text_color="White"
font="SansSerifLarge"
@ -43,17 +99,17 @@
layout="topleft"
left="15"
name="events_label"
top="3"
width="215">
Legend
</text>
</panel>
<panel
follows="right|top"
height="126"
top_pad="0"
width="238"
name="layout_panel_2">
<panel
follows="right|top"
height="126"
top_pad="4"
width="238"
left="1"
name="layout_panel_2">
<button
follows="right|top"
height="22"
@ -690,4 +746,6 @@
show_text="false"
width="200" />
</panel>
</layout_panel>
</layout_stack>
</floater>

View File

@ -33,6 +33,13 @@
function="Object.EnableTouch"
name="EnableTouch"/>
</menu_item_call>
<menu_item_call
label="Show in inventory"
layout="topleft"
name="Show original">
<menu_item_call.on_click
function="Object.ShowOriginal" />
</menu_item_call>
<menu_item_separator
layout="topleft" />

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
layout="topleft"
name="Copy Paste Color Menu">
<menu_item_call
label="Copy"
layout="topleft"
name="params_copy"
visible="true">
<on_click function="PanelFace.menuDoToSelected" parameter="color_copy" />
</menu_item_call>
<menu_item_call
label="Paste"
layout="topleft"
name="params_paste"
visible="true">
<on_click function="PanelFace.menuDoToSelected" parameter="color_paste" />
<on_enable function="PanelFace.menuEnable" parameter="color_paste" />
</menu_item_call>
</toggleable_menu>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
layout="topleft"
name="Copy Paste Features Menu">
<menu_item_call
label="Copy"
layout="topleft"
name="params_copy"
visible="true">
<on_click function="PanelVolume.menuDoToSelected" parameter="features_copy" />
</menu_item_call>
<menu_item_call
label="Paste"
layout="topleft"
name="params_paste"
visible="true">
<on_click function="PanelVolume.menuDoToSelected" parameter="features_paste" />
<on_enable function="PanelVolume.menuEnable" parameter="features_paste" />
</menu_item_call>
</toggleable_menu>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
layout="topleft"
name="Copy Paste Light Menu">
<menu_item_call
label="Copy"
layout="topleft"
name="params_copy"
visible="true">
<on_click function="PanelVolume.menuDoToSelected" parameter="light_copy" />
</menu_item_call>
<menu_item_call
label="Paste"
layout="topleft"
name="params_paste"
visible="true">
<on_click function="PanelVolume.menuDoToSelected" parameter="light_paste" />
<on_enable function="PanelVolume.menuEnable" parameter="light_paste" />
</menu_item_call>
</toggleable_menu>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
layout="topleft"
name="Copy Paste Object Menu">
<menu_item_call
label="Copy"
layout="topleft"
name="params_copy"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="params_copy" />
</menu_item_call>
<menu_item_call
label="Paste"
layout="topleft"
name="params_paste"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="params_paste" />
<on_enable function="PanelObject.menuEnable" parameter="params_paste" />
</menu_item_call>
</toggleable_menu>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
layout="topleft"
name="Copy Paste Position Menu">
<menu_item_call
label="Copy all"
layout="topleft"
name="psr_copy"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
<on_enable function="PanelObject.menuEnable" parameter="psr_copy" />
</menu_item_call>
<menu_item_call
label="Copy position"
layout="topleft"
name="pos_copy"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="pos_copy" />
</menu_item_call>
<menu_item_call
label="Paste all"
layout="topleft"
name="psr_paste"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
<on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
</menu_item_call>
<menu_item_call
label="Paste position"
layout="topleft"
name="pos_paste"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="pos_paste" />
<on_enable function="PanelObject.menuEnable" parameter="pos_paste" />
</menu_item_call>
</toggleable_menu>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
layout="topleft"
name="Copy Paste Rotation Menu">
<menu_item_call
label="Copy all"
layout="topleft"
name="psr_copy"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
<on_enable function="PanelObject.menuEnable" parameter="rot_paste" />
</menu_item_call>
<menu_item_call
label="Copy rotation"
layout="topleft"
name="rot_copy"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="rot_copy" />
</menu_item_call>
<menu_item_call
label="Paste all"
layout="topleft"
name="psr_paste"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
<on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
</menu_item_call>
<menu_item_call
label="Paste rotation"
layout="topleft"
name="rot_paste"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="rot_paste" />
<on_enable function="PanelObject.menuEnable" parameter="rot_paste" />
</menu_item_call>
</toggleable_menu>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
layout="topleft"
name="Copy Paste Size Menu">
<menu_item_call
label="Copy all"
layout="topleft"
name="psr_copy"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" />
<on_enable function="PanelObject.menuEnable" parameter="psr_copy" />
</menu_item_call>
<menu_item_call
label="Copy size"
layout="topleft"
name="size_copy"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="size_copy" />
</menu_item_call>
<menu_item_call
label="Paste all"
layout="topleft"
name="psr_paste"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" />
<on_enable function="PanelObject.menuEnable" parameter="psr_paste" />
</menu_item_call>
<menu_item_call
label="Paste size"
layout="topleft"
name="size_paste"
visible="true">
<on_click function="PanelObject.menuDoToSelected" parameter="size_paste" />
<on_enable function="PanelObject.menuEnable" parameter="size_paste" />
</menu_item_call>
</toggleable_menu>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
layout="topleft"
name="Copy Paste Texture Menu">
<menu_item_call
label="Copy"
layout="topleft"
name="params_copy"
visible="true">
<on_click function="PanelFace.menuDoToSelected" parameter="texture_copy" />
</menu_item_call>
<menu_item_call
label="Paste"
layout="topleft"
name="params_paste"
visible="true">
<on_click function="PanelFace.menuDoToSelected" parameter="texture_paste" />
<on_enable function="PanelFace.menuEnable" parameter="texture_paste" />
</menu_item_call>
</toggleable_menu>

View File

@ -923,6 +923,25 @@
function="Inventory.DoToSelected"
parameter="apply_settings_parcel" />
</menu_item_call>
<menu_item_separator
layout="topleft"
name="Subfolder Separator" />
<menu_item_call
label="Create folder from selected"
layout="topleft"
name="New folder from selected">
<menu_item_call.on_click
function="Inventory.DoToSelected"
parameter="new_folder_from_selected" />
</menu_item_call>
<menu_item_call
label="Ungroup folder items"
layout="topleft"
name="Ungroup folder items">
<menu_item_call.on_click
function="Inventory.DoToSelected"
parameter="ungroup_folder_items" />
</menu_item_call>
<menu_item_separator
layout="topleft"
name="Marketplace Separator" />

View File

@ -9120,6 +9120,29 @@ We cannot display a preview of this texture because it is no-copy and/or no-tran
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="FacePasteFailed"
type="alertmodal">
Paste failed. [REASON]
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="FacePasteTexturePermissions"
type="alertmodal">
You applied a texture with limited permissions, object will inherit permissions from texture.
<usetemplate
ignoretext="Paste: You applied a texture with limited permissions"
name="notifyignore"/>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="ConfirmLeaveCall"
@ -11722,7 +11745,7 @@ This Region does not support environmental settings.
<notification
icon="alertmodal.tga"
label="Save Outfit"
label="Save Environmental Settings"
name="SaveSettingAs"
type="alertmodal">
<unique/>
@ -11901,6 +11924,40 @@ Unpacking: [UNPACK_TIME]s [USIZE]KB
</form>
</notification>
<notification
icon="alertmodal.tga"
label="Create subfolder"
name="CreateSubfolder"
type="alertmodal">
<unique/>
Name the new folder:
<tag>confirm</tag>
<form name="form">
<input name="message" type="text">
[DESC]
</input>
<button
default="true"
index="0"
name="OK"
text="OK"/>
<button
index="1"
name="Cancel"
text="Cancel"/>
</form>
</notification>
<notification
icon="alertmodal.tga"
name="SameFolderRequired"
type="alert">
Selected items must be in the same folder.
<tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="notifytip.tga"
name="MaterialCreated"

View File

@ -11,6 +11,36 @@
name="Texture"
top="0"
width="295">
<panel.string
name="paste_error_face_selection_mismatch">
When multiple faces are copied, the target object must have the same number of faces selected.
</panel.string>
<panel.string
name="paste_error_object_face_count_mismatch">
When all faces of an object are copied, the target object must have the same number of faces.
</panel.string>
<panel.string
name="paste_error_inventory_not_found">
One or more texture not found in inventory.
</panel.string>
<panel.string
name="paste_options">
Paste options
</panel.string>
<menu_button
menu_filename="menu_copy_paste_color.xml"
follows="top|left"
height="15"
image_disabled="ClipboardMenu_Disabled"
image_selected="ClipboardMenu_Press"
image_unselected="ClipboardMenu_Off"
layout="topleft"
left="258"
top="8"
name="clipboard_color_params_btn"
tool_tip="Paste options"
width="22"/>
<text
type="string"
length="1"
@ -36,7 +66,7 @@
name="colorswatch"
tool_tip="Click to open color picker"
top="20"
width="64" />
width="54" />
<text
type="string"
length="1"
@ -84,7 +114,7 @@
left_delta="0"
name="glow"
top_pad="4"
width="80" />
width="77" />
<check_box
height="19"
label="Full Bright"
@ -93,13 +123,22 @@
name="checkbox fullbright"
top_pad="4"
width="81" />
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
name="object_horizontal"
top_pad="4"
width="278" />
<combo_box
height="23"
layout="topleft"
left="10"
name="combobox matmedia"
top_pad="5"
width="100">
top_pad="17"
width="90">
<combo_box.item
label="Materials"
name="Materials"
@ -113,7 +152,7 @@
control_name="ComboMaterialType"
height="50"
layout="topleft"
left_pad="20"
left_pad="5"
top_delta="-10"
width="150"
visible = "false"
@ -139,7 +178,20 @@
layout="topleft"
top_pad="1"
value="2"/>
</radio_group>
</radio_group>
<menu_button
menu_filename="menu_copy_paste_texture.xml"
follows="top|left"
height="15"
image_disabled="ClipboardMenu_Disabled"
image_selected="ClipboardMenu_Press"
image_unselected="ClipboardMenu_Off"
layout="topleft"
left="258"
top_delta="0"
name="clipboard_texture_params_btn"
tool_tip="Paste options"
width="22"/>
<check_box
control_name="SyncMaterialSettings"
follows="top|left"
@ -150,7 +202,7 @@
left="8"
name="checkbox_sync_settings"
tool_tip="Adjust all maps repeats simultaneously"
top_pad="-16"
top_pad="19"
width="160" />
<texture_picker
can_apply_immediately="true"
@ -771,14 +823,14 @@
top_delta="16"
width="260" />
<button
left="10"
top="257"
follows="left|top"
layout="topleft"
left="9"
top="204"
height="20"
label="Align"
label_selected="Align current texture layers"
layout="topleft"
name="button align textures"
top_delta="0"
tool_tip="Align current texture layers"
width="66" />
<web_browser

View File

@ -459,7 +459,7 @@
label="Price: L$"
label_width="73"
width="150"
min_val="1"
min_val="0"
height="20"
max_val="999999999"
tool_tip="Object cost." />