Merge remote-tracking branch 'origin/master' into DRTVWR-559
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -2563,7 +2563,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo
|
|||
|
||||
if (!mNoOptimize)
|
||||
{
|
||||
ret->optimizeVolumeFaces();
|
||||
ret->remapVolumeFaces();
|
||||
}
|
||||
|
||||
volume_faces = remainder.size();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
6.6.2
|
||||
6.6.3
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@ protected:
|
|||
void onShowAgentBtn();
|
||||
void onCopySLURL();
|
||||
|
||||
void onExpandCollapseBtn();
|
||||
|
||||
void centerOnTarget(BOOL animate);
|
||||
void updateLocation();
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
** **
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 231 B |
|
After Width: | Height: | Size: 231 B |
|
After Width: | Height: | Size: 224 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 215 B |
|
After Width: | Height: | Size: 300 B |
|
After Width: | Height: | Size: 284 B |
|
|
@ -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" />
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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." />
|
||||
|
|
|
|||