diff options
Diffstat (limited to 'indra')
223 files changed, 10789 insertions, 9230 deletions
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index bb108d7dd9..34c39d36a8 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -70,6 +70,7 @@ if(WINDOWS) if (MSVC80) FIND_PATH(debug_msvc8_redist_path msvcr80d.dll PATHS + ${MSVC_DEBUG_REDIST_PATH} [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC80.DebugCRT NO_DEFAULT_PATH NO_DEFAULT_PATH @@ -94,6 +95,7 @@ if (MSVC80) FIND_PATH(release_msvc8_redist_path msvcr80.dll PATHS + ${MSVC_REDIST_PATH} [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC80.CRT NO_DEFAULT_PATH NO_DEFAULT_PATH diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp index b1ec9e9875..ad1845d387 100644 --- a/indra/llcommon/llavatarname.cpp +++ b/indra/llcommon/llavatarname.cpp @@ -48,7 +48,7 @@ LLAvatarName::LLAvatarName() mLegacyFirstName(), mLegacyLastName(), mIsDisplayNameDefault(false), - mIsDummy(false), + mIsTemporaryName(false), mExpires(F64_MAX), mNextUpdate(0.0) { } diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h index 145aeccd35..ba258d6d52 100644 --- a/indra/llcommon/llavatarname.h +++ b/indra/llcommon/llavatarname.h @@ -79,7 +79,7 @@ public: // Under error conditions, we may insert "dummy" records with // names like "???" into caches as placeholders. These can be // shown in UI, but are not serialized. - bool mIsDummy; + bool mIsTemporaryName; // Names can change, so need to keep track of when name was // last checked. diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 06ad7736d3..21d1c84d69 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -26,6 +26,12 @@ #include "linden_common.h" +#include "llmemory.h" + +#if MEM_TRACK_MEM +#include "llthread.h" +#endif + #if defined(LL_WINDOWS) # include <windows.h> # include <psapi.h> @@ -37,8 +43,6 @@ # include <unistd.h> #endif -#include "llmemory.h" - //---------------------------------------------------------------------------- //static @@ -86,6 +90,20 @@ U64 LLMemory::getCurrentRSS() return counters.WorkingSetSize; } +//static +U32 LLMemory::getWorkingSetSize() +{ + PROCESS_MEMORY_COUNTERS pmc ; + U32 ret = 0 ; + + if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) ) + { + ret = pmc.WorkingSetSize ; + } + + return ret ; +} + #elif defined(LL_DARWIN) /* @@ -132,6 +150,11 @@ U64 LLMemory::getCurrentRSS() return residentSize; } +U32 LLMemory::getWorkingSetSize() +{ + return 0 ; +} + #elif defined(LL_LINUX) U64 LLMemory::getCurrentRSS() @@ -166,6 +189,11 @@ bail: return rss; } +U32 LLMemory::getWorkingSetSize() +{ + return 0 ; +} + #elif LL_SOLARIS #include <sys/types.h> #include <sys/stat.h> @@ -194,6 +222,12 @@ U64 LLMemory::getCurrentRSS() return((U64)proc_psinfo.pr_rssize * 1024); } + +U32 LLMemory::getWorkingSetSize() +{ + return 0 ; +} + #else U64 LLMemory::getCurrentRSS() @@ -201,4 +235,144 @@ U64 LLMemory::getCurrentRSS() return 0; } +U32 LLMemory::getWorkingSetSize() +{ + return 0 ; +} + #endif + +//-------------------------------------------------------------------------------------------------- +#if MEM_TRACK_MEM +#include "llframetimer.h" + +//static +LLMemTracker* LLMemTracker::sInstance = NULL ; + +LLMemTracker::LLMemTracker() +{ + mLastAllocatedMem = LLMemory::getWorkingSetSize() ; + mCapacity = 128 ; + mCurIndex = 0 ; + mCounter = 0 ; + mDrawnIndex = 0 ; + mPaused = FALSE ; + + mMutexp = new LLMutex(NULL) ; + mStringBuffer = new char*[128] ; + mStringBuffer[0] = new char[mCapacity * 128] ; + for(S32 i = 1 ; i < mCapacity ; i++) + { + mStringBuffer[i] = mStringBuffer[i-1] + 128 ; + } +} + +LLMemTracker::~LLMemTracker() +{ + delete[] mStringBuffer[0] ; + delete[] mStringBuffer; + delete mMutexp ; +} + +//static +LLMemTracker* LLMemTracker::getInstance() +{ + if(!sInstance) + { + sInstance = new LLMemTracker() ; + } + return sInstance ; +} + +//static +void LLMemTracker::release() +{ + if(sInstance) + { + delete sInstance ; + sInstance = NULL ; + } +} + +//static +void LLMemTracker::track(const char* function, const int line) +{ + static const S32 MIN_ALLOCATION = 0 ; //1KB + + if(mPaused) + { + return ; + } + + U32 allocated_mem = LLMemory::getWorkingSetSize() ; + + LLMutexLock lock(mMutexp) ; + + S32 delta_mem = allocated_mem - mLastAllocatedMem ; + mLastAllocatedMem = allocated_mem ; + + if(delta_mem <= 0) + { + return ; //occupied memory does not grow + } + + if(delta_mem < MIN_ALLOCATION) + { + return ; + } + + char* buffer = mStringBuffer[mCurIndex++] ; + F32 time = (F32)LLFrameTimer::getElapsedSeconds() ; + S32 hours = (S32)(time / (60*60)); + S32 mins = (S32)((time - hours*(60*60)) / 60); + S32 secs = (S32)((time - hours*(60*60) - mins*60)); + strcpy(buffer, function) ; + sprintf(buffer + strlen(function), " line: %d DeltaMem: %d (bytes) Time: %d:%02d:%02d", line, delta_mem, hours,mins,secs) ; + + if(mCounter < mCapacity) + { + mCounter++ ; + } + if(mCurIndex >= mCapacity) + { + mCurIndex = 0 ; + } +} + + +//static +void LLMemTracker::preDraw(BOOL pause) +{ + mMutexp->lock() ; + + mPaused = pause ; + mDrawnIndex = mCurIndex - 1; + mNumOfDrawn = 0 ; +} + +//static +void LLMemTracker::postDraw() +{ + mMutexp->unlock() ; +} + +//static +const char* LLMemTracker::getNextLine() +{ + if(mNumOfDrawn >= mCounter) + { + return NULL ; + } + mNumOfDrawn++; + + if(mDrawnIndex < 0) + { + mDrawnIndex = mCapacity - 1 ; + } + + return mStringBuffer[mDrawnIndex--] ; +} + +#endif //MEM_TRACK_MEM +//-------------------------------------------------------------------------------------------------- + diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 8d114f744b..0adb78236e 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -26,9 +26,8 @@ #ifndef LLMEMORY_H #define LLMEMORY_H -#include <stdlib.h> +#include "llmemtype.h" -// A not necessarily efficient, but general, aligned malloc http://stackoverflow.com/questions/196329/osx-lacks-memalign #if 0 //DON'T use ll_aligned_foo now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals) inline void* ll_aligned_malloc( size_t size, int align ) { @@ -107,10 +106,55 @@ public: // Return the resident set size of the current process, in bytes. // Return value is zero if not known. static U64 getCurrentRSS(); + static U32 getWorkingSetSize(); private: static char* reserveMem; }; +//---------------------------------------------------------------------------- +#if MEM_TRACK_MEM +class LLMutex ; +class LL_COMMON_API LLMemTracker +{ +private: + LLMemTracker() ; + ~LLMemTracker() ; + +public: + static void release() ; + static LLMemTracker* getInstance() ; + + void track(const char* function, const int line) ; + void preDraw(BOOL pause) ; + void postDraw() ; + const char* getNextLine() ; + +private: + static LLMemTracker* sInstance ; + + char** mStringBuffer ; + S32 mCapacity ; + U32 mLastAllocatedMem ; + S32 mCurIndex ; + S32 mCounter; + S32 mDrawnIndex; + S32 mNumOfDrawn; + BOOL mPaused; + LLMutex* mMutexp ; +}; + +#define MEM_TRACK_RELEASE LLMemTracker::release() ; +#define MEM_TRACK LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ; + +#else // MEM_TRACK_MEM + +#define MEM_TRACK_RELEASE +#define MEM_TRACK + +#endif // MEM_TRACK_MEM + +//---------------------------------------------------------------------------- + // LLRefCount moved to llrefcount.h // LLPointer moved to llpointer.h diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp index fe83f87d4b..6290a7158f 100644 --- a/indra/llcommon/llmemtype.cpp +++ b/indra/llcommon/llmemtype.cpp @@ -229,3 +229,4 @@ char const * LLMemType::getNameFromID(S32 id) return DeclareMemType::mNameList[id]; } +//-------------------------------------------------------------------------------------------------- diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index b46a99e030..39211bf7fa 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -274,11 +274,11 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components) ++sRawImageCount; } -LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only) - : LLImageBase() -{ - createFromFile(filename, j2c_lowest_mip_only); -} +//LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only) +// : LLImageBase() +//{ +// createFromFile(filename, j2c_lowest_mip_only); +//} LLImageRaw::~LLImageRaw() { @@ -1178,7 +1178,7 @@ file_extensions[] = { "png", IMG_CODEC_PNG } }; #define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions) - +#if 0 static std::string find_file(std::string &name, S8 *codec) { std::string tname; @@ -1196,7 +1196,7 @@ static std::string find_file(std::string &name, S8 *codec) } return std::string(""); } - +#endif EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten) { for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++) @@ -1206,7 +1206,7 @@ EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten) } return IMG_CODEC_INVALID; } - +#if 0 bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only) { std::string name = filename; @@ -1313,7 +1313,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip return true; } - +#endif //--------------------------------------------------------------------------- // LLImageFormatted //--------------------------------------------------------------------------- diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index bca7e915fa..825b9aab1a 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -164,7 +164,7 @@ public: LLImageRaw(U16 width, U16 height, S8 components); LLImageRaw(U8 *data, U16 width, U16 height, S8 components); // Construct using createFromFile (used by tools) - LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false); + //LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false); /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); @@ -226,7 +226,7 @@ public: protected: // Create an image from a local file (generally used in tools) - bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false); + //bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false); void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ); void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ); diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index fe737e2072..2cc7d3c460 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -50,8 +50,6 @@ LLPngWrapper::LLPngWrapper() mCompressionType( 0 ), mFilterMethod( 0 ), mFinalSize( 0 ), - mHasBKGD(false), - mBackgroundColor(), mGamma(0.f) { } @@ -111,9 +109,9 @@ void LLPngWrapper::writeFlush(png_structp png_ptr) } // Read the PNG file using the libpng. The low-level interface is used here -// because we want to do various transformations (including setting the -// matte background if any, and applying gama) which can't be done with -// the high-level interface. The scanline also begins at the bottom of +// because we want to do various transformations (including applying gama) +// which can't be done with the high-level interface. +// The scanline also begins at the bottom of // the image (per SecondLife conventions) instead of at the top, so we // must assign row-pointers in "reverse" order. BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop) @@ -201,8 +199,7 @@ void LLPngWrapper::normalizeImage() // 2. Convert grayscales to RGB // 3. Create alpha layer from transparency // 4. Ensure 8-bpp for all images - // 5. Apply background matte if any - // 6. Set (or guess) gamma + // 5. Set (or guess) gamma if (mColorType == PNG_COLOR_TYPE_PALETTE) { @@ -229,12 +226,6 @@ void LLPngWrapper::normalizeImage() { png_set_strip_16(mReadPngPtr); } - mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); - if (mHasBKGD) - { - png_set_background(mReadPngPtr, mBackgroundColor, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - } #if LL_DARWIN const F64 SCREEN_GAMMA = 1.8; @@ -261,7 +252,6 @@ void LLPngWrapper::updateMetaData() mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr); mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr); mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr); - mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); } // Method to write raw image into PNG at dest. The raw scanline begins diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h index 47a4207d66..739f435996 100644 --- a/indra/llimage/llpngwrapper.h +++ b/indra/llimage/llpngwrapper.h @@ -88,9 +88,6 @@ private: U32 mFinalSize; - bool mHasBKGD; - png_color_16p mBackgroundColor; - F64 mGamma; std::string mErrorMessage; diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 276f7b0f06..fdfc24f8b7 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -294,10 +294,8 @@ public: //is it here? if (isInside(data->getPositionGroup())) { - if (getElementCount() < LL_OCTREE_MAX_CAPACITY && - (contains(data->getBinRadius()) || - (data->getBinRadius() > getSize()[0] && - parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) + if ((getElementCount() < LL_OCTREE_MAX_CAPACITY && contains(data->getBinRadius()) || + (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) { //it belongs here #if LL_OCTREE_PARANOIA_CHECK //if this is a redundant insertion, error out (should never happen) @@ -359,7 +357,7 @@ public: //make sure no existing node matches this position for (U32 i = 0; i < getChildCount(); i++) { - if (mChild[i]->getCenter().equal3(center)) + if (mChild[i]->getCenter().equals3(center)) { OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl; return false; @@ -488,18 +486,18 @@ public: { #if LL_OCTREE_PARANOIA_CHECK - if (child->getSize().equal3(getSize())) + if (child->getSize().equals3(getSize())) { OCT_ERRS << "Child size is same as parent size!" << llendl; } for (U32 i = 0; i < getChildCount(); i++) { - if(!mChild[i]->getSize().equal3(child->getSize())) + if(!mChild[i]->getSize().equals3(child->getSize())) { OCT_ERRS <<"Invalid octree child size." << llendl; } - if (mChild[i]->getCenter().equal3(child->getCenter())) + if (mChild[i]->getCenter().equals3(child->getCenter())) { OCT_ERRS <<"Duplicate octree child position." << llendl; } diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 244c4574e1..617a8b4ca3 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,7269 +1,7269 @@ -/** - - * @file llvolume.cpp - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llmemory.h" -#include "llmath.h" - -#include <set> -#if !LL_WINDOWS -#include <stdint.h> -#endif - -#include "llerror.h" -#include "llmemtype.h" - -#include "llvolumemgr.h" -#include "v2math.h" -#include "v3math.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llmatrix3a.h" -#include "lloctree.h" -#include "lldarray.h" -#include "llvolume.h" -#include "llvolumeoctree.h" -#include "llstl.h" -#include "llsdserialize.h" -#include "llvector4a.h" -#include "llmatrix4a.h" - -#define DEBUG_SILHOUETTE_BINORMALS 0 -#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette -#define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette - -const F32 CUT_MIN = 0.f; -const F32 CUT_MAX = 1.f; -const F32 MIN_CUT_DELTA = 0.02f; - -const F32 HOLLOW_MIN = 0.f; -const F32 HOLLOW_MAX = 0.95f; -const F32 HOLLOW_MAX_SQUARE = 0.7f; - -const F32 TWIST_MIN = -1.f; -const F32 TWIST_MAX = 1.f; - -const F32 RATIO_MIN = 0.f; -const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper - -const F32 HOLE_X_MIN= 0.05f; -const F32 HOLE_X_MAX= 1.0f; - -const F32 HOLE_Y_MIN= 0.05f; -const F32 HOLE_Y_MAX= 0.5f; - -const F32 SHEAR_MIN = -0.5f; -const F32 SHEAR_MAX = 0.5f; - -const F32 REV_MIN = 1.f; -const F32 REV_MAX = 4.f; - -const F32 TAPER_MIN = -1.f; -const F32 TAPER_MAX = 1.f; - -const F32 SKEW_MIN = -0.95f; -const F32 SKEW_MAX = 0.95f; - -const F32 SCULPT_MIN_AREA = 0.002f; -const S32 SCULPT_MIN_AREA_DETAIL = 1; - -extern BOOL gDebugGL; - -void assert_aligned(void* ptr, uintptr_t alignment) -{ -#if 0 - uintptr_t t = (uintptr_t) ptr; - if (t%alignment != 0) - { - llerrs << "WTF?" << llendl; - } -#endif -} - -BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) -{ - LLVector3 test = (pt2-pt1)%(pt3-pt2); - - //answer - if(test * norm < 0) - { - return FALSE; - } - else - { - return TRUE; - } -} - -BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) -{ - return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV); -} - -BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size) -{ - F32 fAWdU[3]; - F32 dir[3]; - F32 diff[3]; - - for (U32 i = 0; i < 3; i++) - { - dir[i] = 0.5f * (end[i] - start[i]); - diff[i] = (0.5f * (end[i] + start[i])) - center[i]; - fAWdU[i] = fabsf(dir[i]); - if(fabsf(diff[i])>size[i] + fAWdU[i]) return false; - } - - float f; - f = dir[1] * diff[2] - dir[2] * diff[1]; if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1]) return false; - f = dir[2] * diff[0] - dir[0] * diff[2]; if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0]) return false; - f = dir[0] * diff[1] - dir[1] * diff[0]; if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0]) return false; - - return true; -} - - - -// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir. -// returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b, -// and returns the intersection point along dir in intersection_t. - -// Moller-Trumbore algorithm -BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t) -{ - - /* find vectors for two edges sharing vert0 */ - LLVector4a edge1; - edge1.setSub(vert1, vert0); - - LLVector4a edge2; - edge2.setSub(vert2, vert0); - - /* begin calculating determinant - also used to calculate U parameter */ - LLVector4a pvec; - pvec.setCross3(dir, edge2); - - /* if determinant is near zero, ray lies in plane of triangle */ - LLVector4a det; - det.setAllDot3(edge1, pvec); - - if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7) - { - /* calculate distance from vert0 to ray origin */ - LLVector4a tvec; - tvec.setSub(orig, vert0); - - /* calculate U parameter and test bounds */ - LLVector4a u; - u.setAllDot3(tvec,pvec); - - if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) && - (u.lessEqual(det).getGatheredBits() & 0x7)) - { - /* prepare to test V parameter */ - LLVector4a qvec; - qvec.setCross3(tvec, edge1); - - /* calculate V parameter and test bounds */ - LLVector4a v; - v.setAllDot3(dir, qvec); - - - //if (!(v < 0.f || u + v > det)) - - LLVector4a sum_uv; - sum_uv.setAdd(u, v); - - S32 v_gequal = v.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7; - S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 0x7; - - if (v_gequal && sum_lequal) - { - /* calculate t, scale parameters, ray intersects triangle */ - LLVector4a t; - t.setAllDot3(edge2,qvec); - - t.div(det); - u.div(det); - v.div(det); - - intersection_a = u[0]; - intersection_b = v[0]; - intersection_t = t[0]; - return TRUE; - } - } - } - - return FALSE; -} - -BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t) -{ - F32 u, v, t; - - /* find vectors for two edges sharing vert0 */ - LLVector4a edge1; - edge1.setSub(vert1, vert0); - - - LLVector4a edge2; - edge2.setSub(vert2, vert0); - - /* begin calculating determinant - also used to calculate U parameter */ - LLVector4a pvec; - pvec.setCross3(dir, edge2); - - /* if determinant is near zero, ray lies in plane of triangle */ - F32 det = edge1.dot3(pvec).getF32(); - - - if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) - { - return FALSE; - } - - F32 inv_det = 1.f / det; - - /* calculate distance from vert0 to ray origin */ - LLVector4a tvec; - tvec.setSub(orig, vert0); - - /* calculate U parameter and test bounds */ - u = (tvec.dot3(pvec).getF32()) * inv_det; - if (u < 0.f || u > 1.f) - { - return FALSE; - } - - /* prepare to test V parameter */ - tvec.sub(edge1); - - /* calculate V parameter and test bounds */ - v = (dir.dot3(tvec).getF32()) * inv_det; - - if (v < 0.f || u + v > 1.f) - { - return FALSE; - } - - /* calculate t, ray intersects triangle */ - t = (edge2.dot3(tvec).getF32()) * inv_det; - - intersection_a = u; - intersection_b = v; - intersection_t = t; - - - return TRUE; -} - -//helper for non-aligned vectors -BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided) -{ - LLVector4a vert0a, vert1a, vert2a, origa, dira; - vert0a.load3(vert0.mV); - vert1a.load3(vert1.mV); - vert2a.load3(vert2.mV); - origa.load3(orig.mV); - dira.load3(dir.mV); - - if (two_sided) - { - return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira, - intersection_a, intersection_b, intersection_t); - } - else - { - return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira, - intersection_a, intersection_b, intersection_t); - } -} - -class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle> -{ -public: - const LLVolumeFace* mFace; - - LLVolumeOctreeRebound(const LLVolumeFace* face) - { - mFace = face; - } - - virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch) - { //this is a depth first traversal, so it's safe to assum all children have complete - //bounding data - - LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); - - LLVector4a& min = node->mExtents[0]; - LLVector4a& max = node->mExtents[1]; - - if (!branch->getData().empty()) - { //node has data, find AABB that binds data set - const LLVolumeTriangle* tri = *(branch->getData().begin()); - - //initialize min/max to first available vertex - min = *(tri->mV[0]); - max = *(tri->mV[0]); - - for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = - branch->getData().begin(); iter != branch->getData().end(); ++iter) - { //for each triangle in node - - //stretch by triangles in node - tri = *iter; - - min.setMin(min, *tri->mV[0]); - min.setMin(min, *tri->mV[1]); - min.setMin(min, *tri->mV[2]); - - max.setMax(max, *tri->mV[0]); - max.setMax(max, *tri->mV[1]); - max.setMax(max, *tri->mV[2]); - } - } - else if (!branch->getChildren().empty()) - { //no data, but child nodes exist - LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0); - - //initialize min/max to extents of first child - min = child->mExtents[0]; - max = child->mExtents[1]; - } - else - { - llerrs << "WTF? Empty leaf" << llendl; - } - - for (S32 i = 0; i < branch->getChildCount(); ++i) - { //stretch by child extents - LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); - min.setMin(min, child->mExtents[0]); - max.setMax(max, child->mExtents[1]); - } - - node->mBounds[0].setAdd(min, max); - node->mBounds[0].mul(0.5f); - - node->mBounds[1].setSub(max,min); - node->mBounds[1].mul(0.5f); - } -}; - -//------------------------------------------------------------------- -// statics -//------------------------------------------------------------------- - - -//---------------------------------------------------- - -LLProfile::Face* LLProfile::addCap(S16 faceID) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - Face *face = vector_append(mFaces, 1); - - face->mIndex = 0; - face->mCount = mTotal; - face->mScaleU= 1.0f; - face->mCap = TRUE; - face->mFaceID = faceID; - return face; -} - -LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - Face *face = vector_append(mFaces, 1); - - face->mIndex = i; - face->mCount = count; - face->mScaleU= scaleU; - - face->mFlat = flat; - face->mCap = FALSE; - face->mFaceID = faceID; - return face; -} - -// What is the bevel parameter used for? - DJS 04/05/02 -// Bevel parameter is currently unused but presumedly would support -// filleted and chamfered corners -void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - // Generate an n-sided "circular" path. - // 0 is (1,0), and we go counter-clockwise along a circular path from there. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; - F32 scale = 0.5f; - F32 t, t_step, t_first, t_fraction, ang, ang_step; - LLVector3 pt1,pt2; - - F32 begin = params.getBegin(); - F32 end = params.getEnd(); - - t_step = 1.0f / sides; - ang_step = 2.0f*F_PI*t_step*ang_scale; - - // Scale to have size "match" scale. Compensates to get object to generally fill bounding box. - - S32 total_sides = llround(sides / ang_scale); // Total number of sides all around - - if (total_sides < 8) - { - scale = tableScale[total_sides]; - } - - t_first = floor(begin * sides) / (F32)sides; - - // pt1 is the first point on the fractional face. - // Starting t and ang values for the first face - t = t_first; - ang = 2.0f*F_PI*(t*ang_scale + offset); - pt1.setVec(cos(ang)*scale,sin(ang)*scale, t); - - // Increment to the next point. - // pt2 is the end point on the fractional face - t += t_step; - ang += ang_step; - pt2.setVec(cos(ang)*scale,sin(ang)*scale,t); - - t_fraction = (begin - t_first)*sides; - - // Only use if it's not almost exactly on an edge. - if (t_fraction < 0.9999f) - { - LLVector3 new_pt = lerp(pt1, pt2, t_fraction); - mProfile.push_back(new_pt); - } - - // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02 - while (t < end) - { - // Iterate through all the integer steps of t. - pt1.setVec(cos(ang)*scale,sin(ang)*scale,t); - - if (mProfile.size() > 0) { - LLVector3 p = mProfile[mProfile.size()-1]; - for (S32 i = 0; i < split && mProfile.size() > 0; i++) { - mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1)); - } - } - mProfile.push_back(pt1); - - t += t_step; - ang += ang_step; - } - - t_fraction = (end - (t - t_step))*sides; - - // pt1 is the first point on the fractional face - // pt2 is the end point on the fractional face - pt2.setVec(cos(ang)*scale,sin(ang)*scale,t); - - // Find the fraction that we need to add to the end point. - t_fraction = (end - (t - t_step))*sides; - if (t_fraction > 0.0001f) - { - LLVector3 new_pt = lerp(pt1, pt2, t_fraction); - - if (mProfile.size() > 0) { - LLVector3 p = mProfile[mProfile.size()-1]; - for (S32 i = 0; i < split && mProfile.size() > 0; i++) { - mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1)); - } - } - mProfile.push_back(new_pt); - } - - // If we're sliced, the profile is open. - if ((end - begin)*ang_scale < 0.99f) - { - if ((end - begin)*ang_scale > 0.5f) - { - mConcave = TRUE; - } - else - { - mConcave = FALSE; - } - mOpen = TRUE; - if (params.getHollow() <= 0) - { - // put center point if not hollow. - mProfile.push_back(LLVector3(0,0,0)); - } - } - else - { - // The profile isn't open. - mOpen = FALSE; - mConcave = FALSE; - } - - mTotal = mProfile.size(); -} - -void LLProfile::genNormals(const LLProfileParams& params) -{ - S32 count = mProfile.size(); - - S32 outer_count; - if (mTotalOut) - { - outer_count = mTotalOut; - } - else - { - outer_count = mTotal / 2; - } - - mEdgeNormals.resize(count * 2); - mEdgeCenters.resize(count * 2); - mNormals.resize(count); - - LLVector2 pt0,pt1; - - BOOL hollow = (params.getHollow() > 0); - - S32 i0, i1, i2, i3, i4; - - // Parametrically generate normal - for (i2 = 0; i2 < count; i2++) - { - mNormals[i2].mV[0] = mProfile[i2].mV[0]; - mNormals[i2].mV[1] = mProfile[i2].mV[1]; - if (hollow && (i2 >= outer_count)) - { - mNormals[i2] *= -1.f; - } - if (mNormals[i2].magVec() < 0.001) - { - // Special case for point at center, get adjacent points. - i1 = (i2 - 1) >= 0 ? i2 - 1 : count - 1; - i0 = (i1 - 1) >= 0 ? i1 - 1 : count - 1; - i3 = (i2 + 1) < count ? i2 + 1 : 0; - i4 = (i3 + 1) < count ? i3 + 1 : 0; - - pt0.setVec(mProfile[i1].mV[VX] + mProfile[i1].mV[VX] - mProfile[i0].mV[VX], - mProfile[i1].mV[VY] + mProfile[i1].mV[VY] - mProfile[i0].mV[VY]); - pt1.setVec(mProfile[i3].mV[VX] + mProfile[i3].mV[VX] - mProfile[i4].mV[VX], - mProfile[i3].mV[VY] + mProfile[i3].mV[VY] - mProfile[i4].mV[VY]); - - mNormals[i2] = pt0 + pt1; - mNormals[i2] *= 0.5f; - } - mNormals[i2].normVec(); - } - - S32 num_normal_sets = isConcave() ? 2 : 1; - for (S32 normal_set = 0; normal_set < num_normal_sets; normal_set++) - { - S32 point_num; - for (point_num = 0; point_num < mTotal; point_num++) - { - LLVector3 point_1 = mProfile[point_num]; - point_1.mV[VZ] = 0.f; - - LLVector3 point_2; - - if (isConcave() && normal_set == 0 && point_num == (mTotal - 1) / 2) - { - point_2 = mProfile[mTotal - 1]; - } - else if (isConcave() && normal_set == 1 && point_num == mTotal - 1) - { - point_2 = mProfile[(mTotal - 1) / 2]; - } - else - { - LLVector3 delta_pos; - S32 neighbor_point = (point_num + 1) % mTotal; - while(delta_pos.magVecSquared() < 0.01f * 0.01f) - { - point_2 = mProfile[neighbor_point]; - delta_pos = point_2 - point_1; - neighbor_point = (neighbor_point + 1) % mTotal; - if (neighbor_point == point_num) - { - break; - } - } - } - - point_2.mV[VZ] = 0.f; - LLVector3 face_normal = (point_2 - point_1) % LLVector3::z_axis; - face_normal.normVec(); - mEdgeNormals[normal_set * count + point_num] = face_normal; - mEdgeCenters[normal_set * count + point_num] = lerp(point_1, point_2, 0.5f); - } - } -} - - -// Hollow is percent of the original bounding box, not of this particular -// profile's geometry. Thus, a swept triangle needs lower hollow values than -// a swept square. -LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) -{ - // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them. - - // Total add has number of vertices on outside. - mTotalOut = mTotal; - - // Why is the "bevel" parameter -1? DJS 04/05/02 - genNGon(params, llfloor(sides),offset,-1, ang_scale, split); - - Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat); - - std::vector<LLVector3> pt; - pt.resize(mTotal) ; - - for (S32 i=mTotalOut;i<mTotal;i++) - { - pt[i] = mProfile[i] * box_hollow; - } - - S32 j=mTotal-1; - for (S32 i=mTotalOut;i<mTotal;i++) - { - mProfile[i] = pt[j--]; - } - - for (S32 i=0;i<(S32)mFaces.size();i++) - { - if (mFaces[i].mCap) - { - mFaces[i].mCount *= 2; - } - } - - return face; -} - - - -BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if ((!mDirty) && (!is_sculpted)) - { - return FALSE; - } - mDirty = FALSE; - - if (detail < MIN_LOD) - { - llinfos << "Generating profile with LOD < MIN_LOD. CLAMPING" << llendl; - detail = MIN_LOD; - } - - mProfile.clear(); - mFaces.clear(); - - // Generate the face data - S32 i; - F32 begin = params.getBegin(); - F32 end = params.getEnd(); - F32 hollow = params.getHollow(); - - // Quick validation to eliminate some server crashes. - if (begin > end - 0.01f) - { - llwarns << "LLProfile::generate() assertion failed (begin >= end)" << llendl; - return FALSE; - } - - S32 face_num = 0; - - switch (params.getCurveType() & LL_PCODE_PROFILE_MASK) - { - case LL_PCODE_PROFILE_SQUARE: - { - genNGon(params, 4,-0.375, 0, 1, split); - if (path_open) - { - addCap (LL_FACE_PATH_BEGIN); - } - - for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++) - { - addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); - } - - for (i = 0; i <(S32) mProfile.size(); i++) - { - // Scale by 4 to generate proper tex coords. - mProfile[i].mV[2] *= 4.f; - } - - if (hollow) - { - switch (params.getCurveType() & LL_PCODE_HOLE_MASK) - { - case LL_PCODE_HOLE_TRIANGLE: - // This offset is not correct, but we can't change it now... DK 11/17/04 - addHole(params, TRUE, 3, -0.375f, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - // TODO: Compute actual detail levels for cubes - addHole(params, FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); - break; - case LL_PCODE_HOLE_SAME: - case LL_PCODE_HOLE_SQUARE: - default: - addHole(params, TRUE, 4, -0.375f, hollow, 1.f, split); - break; - } - } - - if (path_open) { - mFaces[0].mCount = mTotal; - } - } - break; - case LL_PCODE_PROFILE_ISOTRI: - case LL_PCODE_PROFILE_RIGHTTRI: - case LL_PCODE_PROFILE_EQUALTRI: - { - genNGon(params, 3,0, 0, 1, split); - for (i = 0; i <(S32) mProfile.size(); i++) - { - // Scale by 3 to generate proper tex coords. - mProfile[i].mV[2] *= 3.f; - } - - if (path_open) - { - addCap(LL_FACE_PATH_BEGIN); - } - - for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++) - { - addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); - } - if (hollow) - { - // Swept triangles need smaller hollowness values, - // because the triangle doesn't fill the bounding box. - F32 triangle_hollow = hollow / 2.f; - - switch (params.getCurveType() & LL_PCODE_HOLE_MASK) - { - case LL_PCODE_HOLE_CIRCLE: - // TODO: Actually generate level of detail for triangles - addHole(params, FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); - break; - case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 4, 0, triangle_hollow, 1.f, split); - break; - case LL_PCODE_HOLE_SAME: - case LL_PCODE_HOLE_TRIANGLE: - default: - addHole(params, TRUE, 3, 0, triangle_hollow, 1.f, split); - break; - } - } - } - break; - case LL_PCODE_PROFILE_CIRCLE: - { - // If this has a square hollow, we should adjust the - // number of faces a bit so that the geometry lines up. - U8 hole_type=0; - F32 circle_detail = MIN_DETAIL_FACES * detail; - if (hollow) - { - hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; - if (hole_type == LL_PCODE_HOLE_SQUARE) - { - // Snap to the next multiple of four sides, - // so that corners line up. - circle_detail = llceil(circle_detail / 4.0f) * 4.0f; - } - } - - S32 sides = (S32)circle_detail; - - if (is_sculpted) - sides = sculpt_size; - - genNGon(params, sides); - - if (path_open) - { - addCap (LL_FACE_PATH_BEGIN); - } - - if (mOpen && !hollow) - { - addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); - } - else - { - addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE); - } - - if (hollow) - { - switch (hole_type) - { - case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 4, 0, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_TRIANGLE: - addHole(params, TRUE, 3, 0, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - case LL_PCODE_HOLE_SAME: - default: - addHole(params, FALSE, circle_detail, 0, hollow, 1.f); - break; - } - } - } - break; - case LL_PCODE_PROFILE_CIRCLE_HALF: - { - // If this has a square hollow, we should adjust the - // number of faces a bit so that the geometry lines up. - U8 hole_type=0; - // Number of faces is cut in half because it's only a half-circle. - F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f; - if (hollow) - { - hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; - if (hole_type == LL_PCODE_HOLE_SQUARE) - { - // Snap to the next multiple of four sides (div 2), - // so that corners line up. - circle_detail = llceil(circle_detail / 2.0f) * 2.0f; - } - } - genNGon(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f); - if (path_open) - { - addCap(LL_FACE_PATH_BEGIN); - } - if (mOpen && !params.getHollow()) - { - addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); - } - else - { - addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE); - } - - if (hollow) - { - switch (hole_type) - { - case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 2, 0.5f, hollow, 0.5f, split); - break; - case LL_PCODE_HOLE_TRIANGLE: - addHole(params, TRUE, 3, 0.5f, hollow, 0.5f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - case LL_PCODE_HOLE_SAME: - default: - addHole(params, FALSE, circle_detail, 0.5f, hollow, 0.5f); - break; - } - } - - // Special case for openness of sphere - if ((params.getEnd() - params.getBegin()) < 1.f) - { - mOpen = TRUE; - } - else if (!hollow) - { - mOpen = FALSE; - mProfile.push_back(mProfile[0]); - mTotal++; - } - } - break; - default: - llerrs << "Unknown profile: getCurveType()=" << params.getCurveType() << llendl; - break; - }; - - if (path_open) - { - addCap(LL_FACE_PATH_END); // bottom - } - - if ( mOpen) // interior edge caps - { - addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, TRUE); - - if (hollow) - { - addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, TRUE); - } - else - { - addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE); - } - } - - //genNormals(params); - - return TRUE; -} - - - -BOOL LLProfileParams::importFile(LLFILE *fp) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - F32 tempF32; - U32 tempU32; - - while (!feof(fp)) - { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("hollow",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setHollow(tempF32); - } - else - { - llwarns << "unknown keyword " << keyword << " in profile import" << llendl; - } - } - - return TRUE; -} - - -BOOL LLProfileParams::exportFile(LLFILE *fp) const -{ - fprintf(fp,"\t\tprofile 0\n"); - fprintf(fp,"\t\t{\n"); - fprintf(fp,"\t\t\tcurve\t%d\n", getCurveType()); - fprintf(fp,"\t\t\tbegin\t%g\n", getBegin()); - fprintf(fp,"\t\t\tend\t%g\n", getEnd()); - fprintf(fp,"\t\t\thollow\t%g\n", getHollow()); - fprintf(fp, "\t\t}\n"); - return TRUE; -} - - -BOOL LLProfileParams::importLegacyStream(std::istream& input_stream) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - F32 tempF32; - U32 tempU32; - - while (input_stream.good()) - { - input_stream.getline(buffer, BUFSIZE); - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, - valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("hollow",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setHollow(tempF32); - } - else - { - llwarns << "unknown keyword " << keyword << " in profile import" << llendl; - } - } - - return TRUE; -} - - -BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const -{ - output_stream <<"\t\tprofile 0\n"; - output_stream <<"\t\t{\n"; - output_stream <<"\t\t\tcurve\t" << (S32) getCurveType() << "\n"; - output_stream <<"\t\t\tbegin\t" << getBegin() << "\n"; - output_stream <<"\t\t\tend\t" << getEnd() << "\n"; - output_stream <<"\t\t\thollow\t" << getHollow() << "\n"; - output_stream << "\t\t}\n"; - return TRUE; -} - -LLSD LLProfileParams::asLLSD() const -{ - LLSD sd; - - sd["curve"] = getCurveType(); - sd["begin"] = getBegin(); - sd["end"] = getEnd(); - sd["hollow"] = getHollow(); - return sd; -} - -bool LLProfileParams::fromLLSD(LLSD& sd) -{ - setCurveType(sd["curve"].asInteger()); - setBegin((F32)sd["begin"].asReal()); - setEnd((F32)sd["end"].asReal()); - setHollow((F32)sd["hollow"].asReal()); - return true; -} - -void LLProfileParams::copyParams(const LLProfileParams ¶ms) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - setCurveType(params.getCurveType()); - setBegin(params.getBegin()); - setEnd(params.getEnd()); - setHollow(params.getHollow()); -} - - -LLPath::~LLPath() -{ -} - -void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) -{ - // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; - - F32 revolutions = params.getRevolutions(); - F32 skew = params.getSkew(); - F32 skew_mag = fabs(skew); - F32 hole_x = params.getScaleX() * (1.0f - skew_mag); - F32 hole_y = params.getScaleY(); - - // Calculate taper begin/end for x,y (Negative means taper the beginning) - F32 taper_x_begin = 1.0f; - F32 taper_x_end = 1.0f - params.getTaperX(); - F32 taper_y_begin = 1.0f; - F32 taper_y_end = 1.0f - params.getTaperY(); - - if ( taper_x_end > 1.0f ) - { - // Flip tapering. - taper_x_begin = 2.0f - taper_x_end; - taper_x_end = 1.0f; - } - if ( taper_y_end > 1.0f ) - { - // Flip tapering. - taper_y_begin = 2.0f - taper_y_end; - taper_y_end = 1.0f; - } - - // For spheres, the radius is usually zero. - F32 radius_start = 0.5f; - if (sides < 8) - { - radius_start = tableScale[sides]; - } - - // Scale the radius to take the hole size into account. - radius_start *= 1.0f - hole_y; - - // Now check the radius offset to calculate the start,end radius. (Negative means - // decrease the start radius instead). - F32 radius_end = radius_start; - F32 radius_offset = params.getRadiusOffset(); - if (radius_offset < 0.f) - { - radius_start *= 1.f + radius_offset; - } - else - { - radius_end *= 1.f - radius_offset; - } - - // Is the path NOT a closed loop? - mOpen = ( (params.getEnd()*end_scale - params.getBegin() < 1.0f) || - (skew_mag > 0.001f) || - (fabs(taper_x_end - taper_x_begin) > 0.001f) || - (fabs(taper_y_end - taper_y_begin) > 0.001f) || - (fabs(radius_end - radius_start) > 0.001f) ); - - F32 ang, c, s; - LLQuaternion twist, qang; - PathPt *pt; - LLVector3 path_axis (1.f, 0.f, 0.f); - //LLVector3 twist_axis(0.f, 0.f, 1.f); - F32 twist_begin = params.getTwistBegin() * twist_scale; - F32 twist_end = params.getTwist() * twist_scale; - - // We run through this once before the main loop, to make sure - // the path begins at the correct cut. - F32 step= 1.0f / sides; - F32 t = params.getBegin(); - pt = vector_append(mPath, 1); - ang = 2.0f*F_PI*revolutions * t; - s = sin(ang)*lerp(radius_start, radius_end, t); - c = cos(ang)*lerp(radius_start, radius_end, t); - - - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; - - t+=step; - - // Snap to a quantized parameter, so that cut does not - // affect most sample points. - t = ((S32)(t * sides)) / (F32)sides; - - // Run through the non-cut dependent points. - while (t < params.getEnd()) - { - pt = vector_append(mPath, 1); - - ang = 2.0f*F_PI*revolutions * t; - c = cos(ang)*lerp(radius_start, radius_end, t); - s = sin(ang)*lerp(radius_start, radius_end, t); - - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; - - t+=step; - } - - // Make one final pass for the end cut. - t = params.getEnd(); - pt = vector_append(mPath, 1); - ang = 2.0f*F_PI*revolutions * t; - c = cos(ang)*lerp(radius_start, radius_end, t); - s = sin(ang)*lerp(radius_start, radius_end, t); - - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; - - mTotal = mPath.size(); -} - -const LLVector2 LLPathParams::getBeginScale() const -{ - LLVector2 begin_scale(1.f, 1.f); - if (getScaleX() > 1) - { - begin_scale.mV[0] = 2-getScaleX(); - } - if (getScaleY() > 1) - { - begin_scale.mV[1] = 2-getScaleY(); - } - return begin_scale; -} - -const LLVector2 LLPathParams::getEndScale() const -{ - LLVector2 end_scale(1.f, 1.f); - if (getScaleX() < 1) - { - end_scale.mV[0] = getScaleX(); - } - if (getScaleY() < 1) - { - end_scale.mV[1] = getScaleY(); - } - return end_scale; -} - -BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if ((!mDirty) && (!is_sculpted)) - { - return FALSE; - } - - if (detail < MIN_LOD) - { - llinfos << "Generating path with LOD < MIN! Clamping to 1" << llendl; - detail = MIN_LOD; - } - - mDirty = FALSE; - S32 np = 2; // hardcode for line - - mPath.clear(); - mOpen = TRUE; - - // Is this 0xf0 mask really necessary? DK 03/02/05 - switch (params.getCurveType() & 0xf0) - { - default: - case LL_PCODE_PATH_LINE: - { - // Take the begin/end twist into account for detail. - np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2; - if (np < split+2) - { - np = split+2; - } - - mStep = 1.0f / (np-1); - - mPath.resize(np); - - LLVector2 start_scale = params.getBeginScale(); - LLVector2 end_scale = params.getEndScale(); - - for (S32 i=0;i<np;i++) - { - F32 t = lerp(params.getBegin(),params.getEnd(),(F32)i * mStep); - mPath[i].mPos.setVec(lerp(0,params.getShear().mV[0],t), - lerp(0,params.getShear().mV[1],t), - t - 0.5f); - mPath[i].mRot.setQuat(lerp(F_PI * params.getTwistBegin(),F_PI * params.getTwist(),t),0,0,1); - mPath[i].mScale.mV[0] = lerp(start_scale.mV[0],end_scale.mV[0],t); - mPath[i].mScale.mV[1] = lerp(start_scale.mV[1],end_scale.mV[1],t); - mPath[i].mTexT = t; - } - } - break; - - case LL_PCODE_PATH_CIRCLE: - { - // Increase the detail as the revolutions and twist increase. - F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist()); - - S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions()); - - if (is_sculpted) - sides = sculpt_size; - - genNGon(params, sides); - } - break; - - case LL_PCODE_PATH_CIRCLE2: - { - if (params.getEnd() - params.getBegin() >= 0.99f && - params.getScaleX() >= .99f) - { - mOpen = FALSE; - } - - //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); - genNGon(params, llfloor(MIN_DETAIL_FACES * detail)); - - F32 t = 0.f; - F32 tStep = 1.0f / mPath.size(); - - F32 toggle = 0.5f; - for (S32 i=0;i<(S32)mPath.size();i++) - { - mPath[i].mPos.mV[0] = toggle; - if (toggle == 0.5f) - toggle = -0.5f; - else - toggle = 0.5f; - t += tStep; - } - } - - break; - - case LL_PCODE_PATH_TEST: - - np = 5; - mStep = 1.0f / (np-1); - - mPath.resize(np); - - for (S32 i=0;i<np;i++) - { - F32 t = (F32)i * mStep; - mPath[i].mPos.setVec(0, - lerp(0, -sin(F_PI*params.getTwist()*t)*0.5f,t), - lerp(-0.5, cos(F_PI*params.getTwist()*t)*0.5f,t)); - mPath[i].mScale.mV[0] = lerp(1,params.getScale().mV[0],t); - mPath[i].mScale.mV[1] = lerp(1,params.getScale().mV[1],t); - mPath[i].mTexT = t; - mPath[i].mRot.setQuat(F_PI * params.getTwist() * t,1,0,0); - } - - break; - }; - - if (params.getTwist() != params.getTwistBegin()) mOpen = TRUE; - - //if ((int(fabsf(params.getTwist() - params.getTwistBegin())*100))%100 != 0) { - // mOpen = TRUE; - //} - - return TRUE; -} - -BOOL LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - mOpen = TRUE; // Draw end caps - if (getPathLength() == 0) - { - // Path hasn't been generated yet. - // Some algorithms later assume at least TWO path points. - resizePath(2); - for (U32 i = 0; i < 2; i++) - { - mPath[i].mPos.setVec(0, 0, 0); - mPath[i].mRot.setQuat(0, 0, 0); - mPath[i].mScale.setVec(1, 1); - mPath[i].mTexT = 0; - } - } - - return TRUE; -} - - -BOOL LLPathParams::importFile(LLFILE *fp) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - - F32 tempF32; - F32 x, y; - U32 tempU32; - - while (!feof(fp)) - { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("scale",keyword)) - { - // Legacy for one dimensional scale per path - sscanf(valuestr,"%g",&tempF32); - setScale(tempF32, tempF32); - } - else if (!strcmp("scale_x", keyword)) - { - sscanf(valuestr, "%g", &x); - setScaleX(x); - } - else if (!strcmp("scale_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setScaleY(y); - } - else if (!strcmp("shear_x", keyword)) - { - sscanf(valuestr, "%g", &x); - setShearX(x); - } - else if (!strcmp("shear_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setShearY(y); - } - else if (!strcmp("twist",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setTwist(tempF32); - } - else if (!strcmp("twist_begin", keyword)) - { - sscanf(valuestr, "%g", &y); - setTwistBegin(y); - } - else if (!strcmp("radius_offset", keyword)) - { - sscanf(valuestr, "%g", &y); - setRadiusOffset(y); - } - else if (!strcmp("taper_x", keyword)) - { - sscanf(valuestr, "%g", &y); - setTaperX(y); - } - else if (!strcmp("taper_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setTaperY(y); - } - else if (!strcmp("revolutions", keyword)) - { - sscanf(valuestr, "%g", &y); - setRevolutions(y); - } - else if (!strcmp("skew", keyword)) - { - sscanf(valuestr, "%g", &y); - setSkew(y); - } - else - { - llwarns << "unknown keyword " << " in path import" << llendl; - } - } - return TRUE; -} - - -BOOL LLPathParams::exportFile(LLFILE *fp) const -{ - fprintf(fp, "\t\tpath 0\n"); - fprintf(fp, "\t\t{\n"); - fprintf(fp, "\t\t\tcurve\t%d\n", getCurveType()); - fprintf(fp, "\t\t\tbegin\t%g\n", getBegin()); - fprintf(fp, "\t\t\tend\t%g\n", getEnd()); - fprintf(fp, "\t\t\tscale_x\t%g\n", getScaleX() ); - fprintf(fp, "\t\t\tscale_y\t%g\n", getScaleY() ); - fprintf(fp, "\t\t\tshear_x\t%g\n", getShearX() ); - fprintf(fp, "\t\t\tshear_y\t%g\n", getShearY() ); - fprintf(fp,"\t\t\ttwist\t%g\n", getTwist()); - - fprintf(fp,"\t\t\ttwist_begin\t%g\n", getTwistBegin()); - fprintf(fp,"\t\t\tradius_offset\t%g\n", getRadiusOffset()); - fprintf(fp,"\t\t\ttaper_x\t%g\n", getTaperX()); - fprintf(fp,"\t\t\ttaper_y\t%g\n", getTaperY()); - fprintf(fp,"\t\t\trevolutions\t%g\n", getRevolutions()); - fprintf(fp,"\t\t\tskew\t%g\n", getSkew()); - - fprintf(fp, "\t\t}\n"); - return TRUE; -} - - -BOOL LLPathParams::importLegacyStream(std::istream& input_stream) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - - F32 tempF32; - F32 x, y; - U32 tempU32; - - while (input_stream.good()) - { - input_stream.getline(buffer, BUFSIZE); - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("scale",keyword)) - { - // Legacy for one dimensional scale per path - sscanf(valuestr,"%g",&tempF32); - setScale(tempF32, tempF32); - } - else if (!strcmp("scale_x", keyword)) - { - sscanf(valuestr, "%g", &x); - setScaleX(x); - } - else if (!strcmp("scale_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setScaleY(y); - } - else if (!strcmp("shear_x", keyword)) - { - sscanf(valuestr, "%g", &x); - setShearX(x); - } - else if (!strcmp("shear_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setShearY(y); - } - else if (!strcmp("twist",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setTwist(tempF32); - } - else if (!strcmp("twist_begin", keyword)) - { - sscanf(valuestr, "%g", &y); - setTwistBegin(y); - } - else if (!strcmp("radius_offset", keyword)) - { - sscanf(valuestr, "%g", &y); - setRadiusOffset(y); - } - else if (!strcmp("taper_x", keyword)) - { - sscanf(valuestr, "%g", &y); - setTaperX(y); - } - else if (!strcmp("taper_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setTaperY(y); - } - else if (!strcmp("revolutions", keyword)) - { - sscanf(valuestr, "%g", &y); - setRevolutions(y); - } - else if (!strcmp("skew", keyword)) - { - sscanf(valuestr, "%g", &y); - setSkew(y); - } - else - { - llwarns << "unknown keyword " << " in path import" << llendl; - } - } - return TRUE; -} - - -BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const -{ - output_stream << "\t\tpath 0\n"; - output_stream << "\t\t{\n"; - output_stream << "\t\t\tcurve\t" << (S32) getCurveType() << "\n"; - output_stream << "\t\t\tbegin\t" << getBegin() << "\n"; - output_stream << "\t\t\tend\t" << getEnd() << "\n"; - output_stream << "\t\t\tscale_x\t" << getScaleX() << "\n"; - output_stream << "\t\t\tscale_y\t" << getScaleY() << "\n"; - output_stream << "\t\t\tshear_x\t" << getShearX() << "\n"; - output_stream << "\t\t\tshear_y\t" << getShearY() << "\n"; - output_stream <<"\t\t\ttwist\t" << getTwist() << "\n"; - - output_stream <<"\t\t\ttwist_begin\t" << getTwistBegin() << "\n"; - output_stream <<"\t\t\tradius_offset\t" << getRadiusOffset() << "\n"; - output_stream <<"\t\t\ttaper_x\t" << getTaperX() << "\n"; - output_stream <<"\t\t\ttaper_y\t" << getTaperY() << "\n"; - output_stream <<"\t\t\trevolutions\t" << getRevolutions() << "\n"; - output_stream <<"\t\t\tskew\t" << getSkew() << "\n"; - - output_stream << "\t\t}\n"; - return TRUE; -} - -LLSD LLPathParams::asLLSD() const -{ - LLSD sd = LLSD(); - sd["curve"] = getCurveType(); - sd["begin"] = getBegin(); - sd["end"] = getEnd(); - sd["scale_x"] = getScaleX(); - sd["scale_y"] = getScaleY(); - sd["shear_x"] = getShearX(); - sd["shear_y"] = getShearY(); - sd["twist"] = getTwist(); - sd["twist_begin"] = getTwistBegin(); - sd["radius_offset"] = getRadiusOffset(); - sd["taper_x"] = getTaperX(); - sd["taper_y"] = getTaperY(); - sd["revolutions"] = getRevolutions(); - sd["skew"] = getSkew(); - - return sd; -} - -bool LLPathParams::fromLLSD(LLSD& sd) -{ - setCurveType(sd["curve"].asInteger()); - setBegin((F32)sd["begin"].asReal()); - setEnd((F32)sd["end"].asReal()); - setScaleX((F32)sd["scale_x"].asReal()); - setScaleY((F32)sd["scale_y"].asReal()); - setShearX((F32)sd["shear_x"].asReal()); - setShearY((F32)sd["shear_y"].asReal()); - setTwist((F32)sd["twist"].asReal()); - setTwistBegin((F32)sd["twist_begin"].asReal()); - setRadiusOffset((F32)sd["radius_offset"].asReal()); - setTaperX((F32)sd["taper_x"].asReal()); - setTaperY((F32)sd["taper_y"].asReal()); - setRevolutions((F32)sd["revolutions"].asReal()); - setSkew((F32)sd["skew"].asReal()); - return true; -} - -void LLPathParams::copyParams(const LLPathParams ¶ms) -{ - setCurveType(params.getCurveType()); - setBegin(params.getBegin()); - setEnd(params.getEnd()); - setScale(params.getScaleX(), params.getScaleY() ); - setShear(params.getShearX(), params.getShearY() ); - setTwist(params.getTwist()); - setTwistBegin(params.getTwistBegin()); - setRadiusOffset(params.getRadiusOffset()); - setTaper( params.getTaperX(), params.getTaperY() ); - setRevolutions(params.getRevolutions()); - setSkew(params.getSkew()); -} - -S32 profile_delete_lock = 1 ; -LLProfile::~LLProfile() -{ - if(profile_delete_lock) - { - llerrs << "LLProfile should not be deleted here!" << llendl ; - } -} - - -S32 LLVolume::sNumMeshPoints = 0; - -LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) - : mParams(params) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - mUnique = is_unique; - mFaceMask = 0x0; - mDetail = detail; - mSculptLevel = -2; - mIsTetrahedron = FALSE; - mLODScaleBias.setVec(1,1,1); - mHullPoints = NULL; - mHullIndices = NULL; - mNumHullPoints = 0; - mNumHullIndices = 0; - - // set defaults - if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) - { - mPathp = new LLDynamicPath(); - } - else - { - mPathp = new LLPath(); - } - mProfilep = new LLProfile(); - - mGenerateSingleFace = generate_single_face; - - generate(); - - if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE) - { - createVolumeFaces(); - } -} - -void LLVolume::resizePath(S32 length) -{ - mPathp->resizePath(length); - mVolumeFaces.clear(); -} - -void LLVolume::regen() -{ - generate(); - createVolumeFaces(); -} - -void LLVolume::genBinormals(S32 face) -{ - mVolumeFaces[face].createBinormals(); -} - -LLVolume::~LLVolume() -{ - sNumMeshPoints -= mMesh.size(); - delete mPathp; - - profile_delete_lock = 0 ; - delete mProfilep; - profile_delete_lock = 1 ; - - mPathp = NULL; - mProfilep = NULL; - mVolumeFaces.clear(); - - free(mHullPoints); - mHullPoints = NULL; - free(mHullIndices); - mHullIndices = NULL; -} - -BOOL LLVolume::generate() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - llassert_always(mProfilep); - - //Added 10.03.05 Dave Parks - // Split is a parameter to LLProfile::generate that tesselates edges on the profile - // to prevent lighting and texture interpolation errors on triangles that are - // stretched due to twisting or scaling on the path. - S32 split = (S32) ((mDetail)*0.66f); - - if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE && - (mParams.getPathParams().getScale().mV[0] != 1.0f || - mParams.getPathParams().getScale().mV[1] != 1.0f) && - (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI)) - { - split = 0; - } - - mLODScaleBias.setVec(0.5f, 0.5f, 0.5f); - - F32 profile_detail = mDetail; - F32 path_detail = mDetail; - - U8 path_type = mParams.getPathParams().getCurveType(); - U8 profile_type = mParams.getProfileParams().getCurveType(); - - if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) - { //cylinders don't care about Z-Axis - mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); - } - else if (path_type == LL_PCODE_PATH_CIRCLE) - { - mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); - } - - //******************************************************************** - //debug info, to be removed - if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20)) - { - llinfos << "sizeS: " << mPathp->mPath.size() << " sizeT: " << mProfilep->mProfile.size() << llendl ; - llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; - llinfos << mParams << llendl ; - llinfos << "more info to check if mProfilep is deleted or not." << llendl ; - llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; - - llerrs << "LLVolume corrupted!" << llendl ; - } - //******************************************************************** - - BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); - BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); - - if (regenPath || regenProf ) - { - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - //******************************************************************** - //debug info, to be removed - if((U32)(sizeS * sizeT) > (1u << 20)) - { - llinfos << "regenPath: " << (S32)regenPath << " regenProf: " << (S32)regenProf << llendl ; - llinfos << "sizeS: " << sizeS << " sizeT: " << sizeT << llendl ; - llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; - llinfos << mParams << llendl ; - llinfos << "more info to check if mProfilep is deleted or not." << llendl ; - llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; - - llerrs << "LLVolume corrupted!" << llendl ; - } - //******************************************************************** - - sNumMeshPoints -= mMesh.size(); - mMesh.resize(sizeT * sizeS); - sNumMeshPoints += mMesh.size(); - - //generate vertex positions - - // Run along the path. - for (S32 s = 0; s < sizeS; ++s) - { - LLVector2 scale = mPathp->mPath[s].mScale; - LLQuaternion rot = mPathp->mPath[s].mRot; - - // Run along the profile. - for (S32 t = 0; t < sizeT; ++t) - { - S32 m = s*sizeT + t; - Point& pt = mMesh[m]; - - pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0]; - pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1]; - pt.mPos.mV[2] = 0.0f; - pt.mPos = pt.mPos * rot; - pt.mPos += mPathp->mPath[s].mPos; - } - } - - for (std::vector<LLProfile::Face>::iterator iter = mProfilep->mFaces.begin(); - iter != mProfilep->mFaces.end(); ++iter) - { - LLFaceID id = iter->mFaceID; - mFaceMask |= id; - } - - return TRUE; - } - return FALSE; -} - -void LLVolumeFace::VertexData::init() -{ - if (!mData) - { - mData = (LLVector4a*) malloc(sizeof(LLVector4a)*2); - } -} - -LLVolumeFace::VertexData::VertexData() -{ - mData = NULL; - init(); -} - -LLVolumeFace::VertexData::VertexData(const VertexData& rhs) -{ - mData = NULL; - *this = rhs; -} - -const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs) -{ - if (this != &rhs) - { - init(); - LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 2*sizeof(LLVector4a)); - mTexCoord = rhs.mTexCoord; - } - return *this; -} - -LLVolumeFace::VertexData::~VertexData() -{ - free(mData); - mData = NULL; -} - -LLVector4a& LLVolumeFace::VertexData::getPosition() -{ - return mData[POSITION]; -} - -LLVector4a& LLVolumeFace::VertexData::getNormal() -{ - return mData[NORMAL]; -} - -const LLVector4a& LLVolumeFace::VertexData::getPosition() const -{ - return mData[POSITION]; -} - -const LLVector4a& LLVolumeFace::VertexData::getNormal() const -{ - return mData[NORMAL]; -} - - -void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos) -{ - mData[POSITION] = pos; -} - -void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm) -{ - mData[NORMAL] = norm; -} - -bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const -{ - const F32* lp = this->getPosition().getF32ptr(); - const F32* rp = rhs.getPosition().getF32ptr(); - - if (lp[0] != rp[0]) - { - return lp[0] < rp[0]; - } - - if (rp[1] != lp[1]) - { - return lp[1] < rp[1]; - } - - if (rp[2] != lp[2]) - { - return lp[2] < rp[2]; - } - - lp = getNormal().getF32ptr(); - rp = rhs.getNormal().getF32ptr(); - - if (lp[0] != rp[0]) - { - return lp[0] < rp[0]; - } - - if (rp[1] != lp[1]) - { - return lp[1] < rp[1]; - } - - if (rp[2] != lp[2]) - { - return lp[2] < rp[2]; - } - - if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0]) - { - return mTexCoord.mV[0] < rhs.mTexCoord.mV[0]; - } - - return mTexCoord.mV[1] < rhs.mTexCoord.mV[1]; -} - -bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const -{ - return mData[POSITION].equals3(rhs.getPosition()) && - mData[NORMAL].equals3(rhs.getNormal()) && - mTexCoord == rhs.mTexCoord; -} - -bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const -{ - bool retval = false; - if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord) - { - if (angle_cutoff > 1.f) - { - retval = (mData[NORMAL].equals3(rhs.mData[NORMAL])); - } - else - { - F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32(); - retval = cur_angle > angle_cutoff; - } - } - - return retval; -} - -BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name) -{ - std::ifstream is; - - is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary); - - BOOL success = createVolumeFacesFromStream(is); - - is.close(); - - return success; -} - -BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) -{ - mSculptLevel = -1; // default is an error occured - - LLSD header; - { - if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024)) - { - llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; - return FALSE; - } - } - - std::string nm[] = - { - "lowest_lod", - "low_lod", - "medium_lod", - "high_lod" - }; - - S32 lod = llclamp((S32) mDetail, 0, 3); - - while (lod < 4 && - (header[nm[lod]]["offset"].asInteger() == -1 || - header[nm[lod]]["size"].asInteger() == 0 )) - { - ++lod; - } - - if (lod >= 4) - { - lod = llclamp((S32) mDetail, 0, 3); - - while (lod >= 0 && - (header[nm[lod]]["offset"].asInteger() == -1 || - header[nm[lod]]["size"].asInteger() == 0) ) - { - --lod; - } - - if (lod < 0) - { - llwarns << "Mesh header missing LOD offsets. Not a valid mesh asset!" << llendl; - return FALSE; - } - } - - is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); - - return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()); -} - -bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) -{ - //input stream is now pointing at a zlib compressed block of LLSD - //decompress block - LLSD mdl; - if (!unzip_llsd(mdl, is, size)) - { - llwarns << "not a valid mesh asset!" << llendl; - return false; - } - - { - U32 face_count = mdl.size(); - - if (face_count == 0) - { - llerrs << "WTF?" << llendl; - } - - mVolumeFaces.resize(face_count); - - for (U32 i = 0; i < face_count; ++i) - { - LLSD::Binary pos = mdl[i]["Position"]; - LLSD::Binary norm = mdl[i]["Normal"]; - LLSD::Binary tc = mdl[i]["TexCoord0"]; - LLSD::Binary idx = mdl[i]["TriangleList"]; - - LLVolumeFace& face = mVolumeFaces[i]; - - //copy out indices - face.resizeIndices(idx.size()/2); - - if (idx.empty() || face.mNumIndices < 3) - { //why is there an empty index list? - llerrs <<"WTF?" << llendl; - continue; - } - - U16* indices = (U16*) &(idx[0]); - for (U32 j = 0; j < idx.size()/2; ++j) - { - face.mIndices[j] = indices[j]; - } - - //copy out vertices - U32 num_verts = pos.size()/(3*2); - face.resizeVertices(num_verts); - - if (mdl[i].has("Weights")) - { - face.allocateWeights(num_verts); - - LLSD::Binary weights = mdl[i]["Weights"]; - - U32 idx = 0; - - U32 cur_vertex = 0; - while (idx < weights.size() && cur_vertex < num_verts) - { - const U8 END_INFLUENCES = 0xFF; - U8 joint = weights[idx++]; - - U32 cur_influence = 0; - LLVector4 wght(0,0,0,0); - - while (joint != END_INFLUENCES && idx < weights.size()) - { - U16 influence = weights[idx++]; - influence |= ((U16) weights[idx++] << 8); - - F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f); - wght.mV[cur_influence++] = (F32) joint + w; - - if (cur_influence >= 4) - { - joint = END_INFLUENCES; - } - else - { - joint = weights[idx++]; - } - } - - face.mWeights[cur_vertex].loadua(wght.mV); - - cur_vertex++; - } - - if (cur_vertex != num_verts || idx != weights.size()) - { - llwarns << "Vertex weight count does not match vertex count!" << llendl; - } - - } - - LLVector3 minp; - LLVector3 maxp; - LLVector2 min_tc; - LLVector2 max_tc; - - minp.setValue(mdl[i]["PositionDomain"]["Min"]); - maxp.setValue(mdl[i]["PositionDomain"]["Max"]); - LLVector4a min_pos, max_pos; - min_pos.load3(minp.mV); - max_pos.load3(maxp.mV); - - min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]); - max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]); - - LLVector4a pos_range; - pos_range.setSub(max_pos, min_pos); - LLVector2 tc_range = max_tc - min_tc; - - LLVector4a* pos_out = face.mPositions; - LLVector4a* norm_out = face.mNormals; - LLVector2* tc_out = face.mTexCoords; - - for (U32 j = 0; j < num_verts; ++j) - { - U16* v = (U16*) &(pos[j*3*2]); - - pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]); - pos_out->div(65535.f); - pos_out->mul(pos_range); - pos_out->add(min_pos); - - pos_out++; - - U16* n = (U16*) &(norm[j*3*2]); - - norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]); - norm_out->div(65535.f); - norm_out->mul(2.f); - norm_out->sub(1.f); - norm_out++; - - U16* t = (U16*) &(tc[j*2*2]); - - tc_out->mV[0] = (F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0]; - tc_out->mV[1] = (F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1]; - - tc_out++; - } - - - // modifier flags? - bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR); - bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT); - - - // translate to actions: - bool do_reflect_x = false; - bool do_reverse_triangles = false; - bool do_invert_normals = false; - - if (do_mirror) - { - do_reflect_x = true; - do_reverse_triangles = !do_reverse_triangles; - } - - if (do_invert) - { - do_invert_normals = true; - do_reverse_triangles = !do_reverse_triangles; - } - - // now do the work - - if (do_reflect_x) - { - LLVector4a* p = (LLVector4a*) face.mPositions; - LLVector4a* n = (LLVector4a*) face.mNormals; - - for (S32 i = 0; i < face.mNumVertices; i++) - { - p[i].mul(-1.0f); - n[i].mul(-1.0f); - } - } - - if (do_invert_normals) - { - LLVector4a* n = (LLVector4a*) face.mNormals; - - for (S32 i = 0; i < face.mNumVertices; i++) - { - n[i].mul(-1.0f); - } - } - - if (do_reverse_triangles) - { - for (U32 j = 0; j < face.mNumIndices; j += 3) - { - // swap the 2nd and 3rd index - S32 swap = face.mIndices[j+1]; - face.mIndices[j+1] = face.mIndices[j+2]; - face.mIndices[j+2] = swap; - } - } - - //calculate bounding box - LLVector4a& min = face.mExtents[0]; - LLVector4a& max = face.mExtents[1]; - - min.clear(); - max.clear(); - min = max = face.mPositions[0]; - - for (S32 i = 1; i < face.mNumVertices; ++i) - { - min.setMin(min, face.mPositions[i]); - max.setMax(max, face.mPositions[i]); - } - } - } - - mSculptLevel = 0; // success! - - cacheOptimize(); - - return true; -} - -void tetrahedron_set_normal(LLVolumeFace::VertexData* cv) -{ - LLVector4a v0; - v0.setSub(cv[1].getPosition(), cv[0].getNormal()); - LLVector4a v1; - v1.setSub(cv[2].getNormal(), cv[0].getPosition()); - - cv[0].getNormal().setCross3(v0,v1); - cv[0].getNormal().normalize3fast(); - cv[1].setNormal(cv[0].getNormal()); - cv[2].setNormal(cv[1].getNormal()); -} - -BOOL LLVolume::isTetrahedron() -{ - return mIsTetrahedron; -} - -void LLVolume::makeTetrahedron() -{ - mVolumeFaces.clear(); - - LLVolumeFace face; - - F32 x = 0.25f; - LLVector4a p[] = - { //unit tetrahedron corners - LLVector4a(x,x,x), - LLVector4a(-x,-x,x), - LLVector4a(-x,x,-x), - LLVector4a(x,-x,-x) - }; - - face.mExtents[0].splat(-x); - face.mExtents[1].splat(x); - - LLVolumeFace::VertexData cv[3]; - - //set texture coordinates - cv[0].mTexCoord = LLVector2(0,0); - cv[1].mTexCoord = LLVector2(1,0); - cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3); - - - //side 1 - cv[0].setPosition(p[1]); - cv[1].setPosition(p[0]); - cv[2].setPosition(p[2]); - - tetrahedron_set_normal(cv); - - face.resizeVertices(12); - face.resizeIndices(12); - - LLVector4a* v = (LLVector4a*) face.mPositions; - LLVector4a* n = (LLVector4a*) face.mNormals; - LLVector2* tc = (LLVector2*) face.mTexCoords; - - v[0] = cv[0].getPosition(); - v[1] = cv[1].getPosition(); - v[2] = cv[2].getPosition(); - v += 3; - - n[0] = cv[0].getNormal(); - n[1] = cv[1].getNormal(); - n[2] = cv[2].getNormal(); - n += 3; - - tc[0] = cv[0].mTexCoord; - tc[1] = cv[1].mTexCoord; - tc[2] = cv[2].mTexCoord; - tc += 3; - - - //side 2 - cv[0].setPosition(p[3]); - cv[1].setPosition(p[0]); - cv[2].setPosition(p[1]); - - tetrahedron_set_normal(cv); - - v[0] = cv[0].getPosition(); - v[1] = cv[1].getPosition(); - v[2] = cv[2].getPosition(); - v += 3; - - n[0] = cv[0].getNormal(); - n[1] = cv[1].getNormal(); - n[2] = cv[2].getNormal(); - n += 3; - - tc[0] = cv[0].mTexCoord; - tc[1] = cv[1].mTexCoord; - tc[2] = cv[2].mTexCoord; - tc += 3; - - //side 3 - cv[0].setPosition(p[3]); - cv[1].setPosition(p[1]); - cv[2].setPosition(p[2]); - - tetrahedron_set_normal(cv); - - v[0] = cv[0].getPosition(); - v[1] = cv[1].getPosition(); - v[2] = cv[2].getPosition(); - v += 3; - - n[0] = cv[0].getNormal(); - n[1] = cv[1].getNormal(); - n[2] = cv[2].getNormal(); - n += 3; - - tc[0] = cv[0].mTexCoord; - tc[1] = cv[1].mTexCoord; - tc[2] = cv[2].mTexCoord; - tc += 3; - - //side 4 - cv[0].setPosition(p[2]); - cv[1].setPosition(p[0]); - cv[2].setPosition(p[3]); - - tetrahedron_set_normal(cv); - - v[0] = cv[0].getPosition(); - v[1] = cv[1].getPosition(); - v[2] = cv[2].getPosition(); - v += 3; - - n[0] = cv[0].getNormal(); - n[1] = cv[1].getNormal(); - n[2] = cv[2].getNormal(); - n += 3; - - tc[0] = cv[0].mTexCoord; - tc[1] = cv[1].mTexCoord; - tc[2] = cv[2].mTexCoord; - tc += 3; - - //set index buffer - for (U16 i = 0; i < 12; i++) - { - face.mIndices[i] = i; - } - - mVolumeFaces.push_back(face); - mSculptLevel = 0; - mIsTetrahedron = TRUE; -} - -void LLVolume::copyVolumeFaces(const LLVolume* volume) -{ - mVolumeFaces = volume->mVolumeFaces; - mSculptLevel = 0; - mIsTetrahedron = FALSE; -} - -void LLVolume::cacheOptimize() -{ - for (S32 i = 0; i < mVolumeFaces.size(); ++i) - { - mVolumeFaces[i].cacheOptimize(); - } -} - - -S32 LLVolume::getNumFaces() const -{ - U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK); - - if (sculpt_type == LL_SCULPT_TYPE_MESH) - { - return LL_SCULPT_MESH_MAX_FACES; - } - - return (S32)mProfilep->mFaces.size(); -} - - -void LLVolume::createVolumeFaces() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if (mGenerateSingleFace) - { - // do nothing - } - else - { - S32 num_faces = getNumFaces(); - BOOL partial_build = TRUE; - if (num_faces != mVolumeFaces.size()) - { - partial_build = FALSE; - mVolumeFaces.resize(num_faces); - } - // Initialize volume faces with parameter data - for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++) - { - LLVolumeFace& vf = mVolumeFaces[i]; - LLProfile::Face& face = mProfilep->mFaces[i]; - vf.mBeginS = face.mIndex; - vf.mNumS = face.mCount; - if (vf.mNumS < 0) - { - llerrs << "Volume face corruption detected." << llendl; - } - - vf.mBeginT = 0; - vf.mNumT= getPath().mPath.size(); - vf.mID = i; - - // Set the type mask bits correctly - if (mParams.getProfileParams().getHollow() > 0) - { - vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK; - } - if (mProfilep->isOpen()) - { - vf.mTypeMask |= LLVolumeFace::OPEN_MASK; - } - if (face.mCap) - { - vf.mTypeMask |= LLVolumeFace::CAP_MASK; - if (face.mFaceID == LL_FACE_PATH_BEGIN) - { - vf.mTypeMask |= LLVolumeFace::TOP_MASK; - } - else - { - llassert(face.mFaceID == LL_FACE_PATH_END); - vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK; - } - } - else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) - { - vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK; - } - else - { - vf.mTypeMask |= LLVolumeFace::SIDE_MASK; - if (face.mFlat) - { - vf.mTypeMask |= LLVolumeFace::FLAT_MASK; - } - if (face.mFaceID & LL_FACE_INNER_SIDE) - { - vf.mTypeMask |= LLVolumeFace::INNER_MASK; - if (face.mFlat && vf.mNumS > 2) - { //flat inner faces have to copy vert normals - vf.mNumS = vf.mNumS*2; - if (vf.mNumS < 0) - { - llerrs << "Volume face corruption detected." << llendl; - } - } - } - else - { - vf.mTypeMask |= LLVolumeFace::OUTER_MASK; - } - } - } - - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) - { - (*iter).create(this, partial_build); - } - } -} - - -inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b) -{ - // maps RGB values to vector values [0..255] -> [-0.5..0.5] - LLVector3 value; - value.mV[VX] = r / 255.f - 0.5f; - value.mV[VY] = g / 255.f - 0.5f; - value.mV[VZ] = b / 255.f - 0.5f; - - return value; -} - -inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) -{ - U32 index = (x + y * sculpt_width) * sculpt_components; - return index; -} - - -inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) -{ - U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width); - U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height); - - return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); -} - - -inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data) -{ - LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]); - - return v; -} - -inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) -{ - U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components); - - return sculpt_index_to_vector(index, sculpt_data); -} - -inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) -{ - U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); - - return sculpt_index_to_vector(index, sculpt_data); -} - - -F32 LLVolume::sculptGetSurfaceArea() -{ - // test to see if image has enough variation to create non-degenerate geometry - - F32 area = 0; - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - for (S32 s = 0; s < sizeS-1; s++) - { - for (S32 t = 0; t < sizeT-1; t++) - { - // get four corners of quad - LLVector3 p1 = mMesh[(s )*sizeT + (t )].mPos; - LLVector3 p2 = mMesh[(s+1)*sizeT + (t )].mPos; - LLVector3 p3 = mMesh[(s )*sizeT + (t+1)].mPos; - LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos; - - // compute the area of the quad by taking the length of the cross product of the two triangles - LLVector3 cross1 = (p1 - p2) % (p1 - p3); - LLVector3 cross2 = (p4 - p2) % (p4 - p3); - area += (cross1.magVec() + cross2.magVec()) / 2.0; - } - } - - return area; -} - -// create placeholder shape -void LLVolume::sculptGeneratePlaceholder() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - S32 line = 0; - - // for now, this is a sphere. - for (S32 s = 0; s < sizeS; s++) - { - for (S32 t = 0; t < sizeT; t++) - { - S32 i = t + line; - Point& pt = mMesh[i]; - - - F32 u = (F32)s/(sizeS-1); - F32 v = (F32)t/(sizeT-1); - - const F32 RADIUS = (F32) 0.3; - - pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS); - pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS); - pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS); - - } - line += sizeT; - } -} - -// create the vertices from the map -void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type) -{ - U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR - - - LLMemType m1(LLMemType::MTYPE_VOLUME); - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - S32 line = 0; - for (S32 s = 0; s < sizeS; s++) - { - // Run along the profile. - for (S32 t = 0; t < sizeT; t++) - { - S32 i = t + line; - Point& pt = mMesh[i]; - - S32 reversed_t = t; - - if (reverse_horizontal) - { - reversed_t = sizeT - t - 1; - } - - U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width); - U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height); - - - if (y == 0) // top row stitching - { - // pinch? - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - { - x = sculpt_width / 2; - } - } - - if (y == sculpt_height) // bottom row stitching - { - // wrap? - if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) - { - y = 0; - } - else - { - y = sculpt_height - 1; - } - - // pinch? - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - { - x = sculpt_width / 2; - } - } - - if (x == sculpt_width) // side stitching - { - // wrap? - if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || - (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || - (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) - { - x = 0; - } - - else - { - x = sculpt_width - 1; - } - } - - pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); - - if (sculpt_mirror) - { - pt.mPos.mV[VX] *= -1.f; - } - } - - line += sizeT; - } -} - - -const S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square -const S32 SCULPT_REZ_2 = 8; -const S32 SCULPT_REZ_3 = 16; -const S32 SCULPT_REZ_4 = 32; - -S32 sculpt_sides(F32 detail) -{ - - // detail is usually one of: 1, 1.5, 2.5, 4.0. - - if (detail <= 1.0) - { - return SCULPT_REZ_1; - } - if (detail <= 2.0) - { - return SCULPT_REZ_2; - } - if (detail <= 3.0) - { - return SCULPT_REZ_3; - } - else - { - return SCULPT_REZ_4; - } -} - - - -// determine the number of vertices in both s and t direction for this sculpt -void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) -{ - // this code has the following properties: - // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map - // while still using all available verts - // 2) the mesh cannot have more verts than is allowed by LOD - // 3) the mesh cannot have more verts than is allowed by the map - - S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0); - S32 max_vertices_map = width * height / 4; - - S32 vertices; - if (max_vertices_map > 0) - vertices = llmin(max_vertices_lod, max_vertices_map); - else - vertices = max_vertices_lod; - - - F32 ratio; - if ((width == 0) || (height == 0)) - ratio = 1.f; - else - ratio = (F32) width / (F32) height; - - - s = (S32)(F32) sqrt(((F32)vertices / ratio)); - - s = llmax(s, 4); // no degenerate sizes, please - t = vertices / s; - - t = llmax(t, 4); // no degenerate sizes, please - s = vertices / t; -} - -// sculpt replaces generate() for sculpted surfaces -void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - U8 sculpt_type = mParams.getSculptType(); - - BOOL data_is_empty = FALSE; - - if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) - { - sculpt_level = -1; - data_is_empty = TRUE; - } - - S32 requested_sizeS = 0; - S32 requested_sizeT = 0; - - sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT); - - mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS); - mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT); - - S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got - S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got - - // weird crash bug - DEV-11158 - trying to collect more data: - if ((sizeS == 0) || (sizeT == 0)) - { - llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl; - } - - sNumMeshPoints -= mMesh.size(); - mMesh.resize(sizeS * sizeT); - sNumMeshPoints += mMesh.size(); - - //generate vertex positions - if (!data_is_empty) - { - sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type); - - // don't test lowest LOD to support legacy content DEV-33670 - if (mDetail > SCULPT_MIN_AREA_DETAIL) - { - if (sculptGetSurfaceArea() < SCULPT_MIN_AREA) - { - data_is_empty = TRUE; - } - } - } - - if (data_is_empty) - { - sculptGeneratePlaceholder(); - } - - - - for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) - { - mFaceMask |= mProfilep->mFaces[i].mFaceID; - } - - mSculptLevel = sculpt_level; - - // Delete any existing faces so that they get regenerated - mVolumeFaces.clear(); - - createVolumeFaces(); -} - - - - -BOOL LLVolume::isCap(S32 face) -{ - return mProfilep->mFaces[face].mCap; -} - -BOOL LLVolume::isFlat(S32 face) -{ - return mProfilep->mFaces[face].mFlat; -} - - -bool LLVolumeParams::isSculpt() const -{ - return mSculptID.notNull(); -} - -bool LLVolumeParams::isMeshSculpt() const -{ - return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH); -} - -bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const -{ - return ( (getPathParams() == params.getPathParams()) && - (getProfileParams() == params.getProfileParams()) && - (mSculptID == params.mSculptID) && - (mSculptType == params.mSculptType) ); -} - -bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const -{ - return ( (getPathParams() != params.getPathParams()) || - (getProfileParams() != params.getProfileParams()) || - (mSculptID != params.mSculptID) || - (mSculptType != params.mSculptType) ); -} - -bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const -{ - if( getPathParams() != params.getPathParams() ) - { - return getPathParams() < params.getPathParams(); - } - - if (getProfileParams() != params.getProfileParams()) - { - return getProfileParams() < params.getProfileParams(); - } - - if (mSculptID != params.mSculptID) - { - return mSculptID < params.mSculptID; - } - - return mSculptType < params.mSculptType; - - -} - -void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - mProfileParams.copyParams(params.mProfileParams); - mPathParams.copyParams(params.mPathParams); - mSculptID = params.getSculptID(); - mSculptType = params.getSculptType(); -} - -// Less restricitve approx 0 for volumes -const F32 APPROXIMATELY_ZERO = 0.001f; -bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO) -{ - return (f >= -tolerance) && (f <= tolerance); -} - -// return true if in range (or nearly so) -static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO) -{ - F32 min_delta = v - min; - if (min_delta < 0.f) - { - v = min; - if (!approx_zero(min_delta, tolerance)) - return false; - } - F32 max_delta = max - v; - if (max_delta < 0.f) - { - v = max; - if (!approx_zero(max_delta, tolerance)) - return false; - } - return true; -} - -bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e) -{ - bool valid = true; - - // First, clamp to valid ranges. - F32 begin = b; - valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); - - F32 end = e; - if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error - valid &= limit_range(end, MIN_CUT_DELTA, 1.f); - - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); - - // Now set them. - mProfileParams.setBegin(begin); - mProfileParams.setEnd(end); - - return valid; -} - -bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e) -{ - bool valid = true; - - // First, clamp to valid ranges. - F32 begin = b; - valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); - - F32 end = e; - valid &= limit_range(end, MIN_CUT_DELTA, 1.f); - - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); - - // Now set them. - mPathParams.setBegin(begin); - mPathParams.setEnd(end); - - return valid; -} - -bool LLVolumeParams::setHollow(const F32 h) -{ - // Validate the hollow based on path and profile. - U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK; - - F32 max_hollow = HOLLOW_MAX; - - // Only square holes have trouble. - if (LL_PCODE_HOLE_SQUARE == hole_type) - { - switch(profile) - { - case LL_PCODE_PROFILE_CIRCLE: - case LL_PCODE_PROFILE_CIRCLE_HALF: - case LL_PCODE_PROFILE_EQUALTRI: - max_hollow = HOLLOW_MAX_SQUARE; - } - } - - F32 hollow = h; - bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow); - mProfileParams.setHollow(hollow); - - return valid; -} - -bool LLVolumeParams::setTwistBegin(const F32 b) -{ - F32 twist_begin = b; - bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX); - mPathParams.setTwistBegin(twist_begin); - return valid; -} - -bool LLVolumeParams::setTwistEnd(const F32 e) -{ - F32 twist_end = e; - bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX); - mPathParams.setTwistEnd(twist_end); - return valid; -} - -bool LLVolumeParams::setRatio(const F32 x, const F32 y) -{ - F32 min_x = RATIO_MIN; - F32 max_x = RATIO_MAX; - F32 min_y = RATIO_MIN; - F32 max_y = RATIO_MAX; - // If this is a circular path (and not a sphere) then 'ratio' is actually hole size. - U8 path_type = mPathParams.getCurveType(); - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PATH_CIRCLE == path_type && - LL_PCODE_PROFILE_CIRCLE_HALF != profile_type) - { - // Holes are more restricted... - min_x = HOLE_X_MIN; - max_x = HOLE_X_MAX; - min_y = HOLE_Y_MIN; - max_y = HOLE_Y_MAX; - } - - F32 ratio_x = x; - bool valid = limit_range(ratio_x, min_x, max_x); - F32 ratio_y = y; - valid &= limit_range(ratio_y, min_y, max_y); - - mPathParams.setScale(ratio_x, ratio_y); - - return valid; -} - -bool LLVolumeParams::setShear(const F32 x, const F32 y) -{ - F32 shear_x = x; - bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX); - F32 shear_y = y; - valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX); - mPathParams.setShear(shear_x, shear_y); - return valid; -} - -bool LLVolumeParams::setTaperX(const F32 v) -{ - F32 taper = v; - bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); - mPathParams.setTaperX(taper); - return valid; -} - -bool LLVolumeParams::setTaperY(const F32 v) -{ - F32 taper = v; - bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); - mPathParams.setTaperY(taper); - return valid; -} - -bool LLVolumeParams::setRevolutions(const F32 r) -{ - F32 revolutions = r; - bool valid = limit_range(revolutions, REV_MIN, REV_MAX); - mPathParams.setRevolutions(revolutions); - return valid; -} - -bool LLVolumeParams::setRadiusOffset(const F32 offset) -{ - bool valid = true; - - // If this is a sphere, just set it to 0 and get out. - U8 path_type = mPathParams.getCurveType(); - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type || - LL_PCODE_PATH_CIRCLE != path_type ) - { - mPathParams.setRadiusOffset(0.f); - return true; - } - - // Limit radius offset, based on taper and hole size y. - F32 radius_offset = offset; - F32 taper_y = getTaperY(); - F32 radius_mag = fabs(radius_offset); - F32 hole_y_mag = fabs(getRatioY()); - F32 taper_y_mag = fabs(taper_y); - // Check to see if the taper effects us. - if ( (radius_offset > 0.f && taper_y < 0.f) || - (radius_offset < 0.f && taper_y > 0.f) ) - { - // The taper does not help increase the radius offset range. - taper_y_mag = 0.f; - } - F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); - - // Enforce the maximum magnitude. - F32 delta = max_radius_mag - radius_mag; - if (delta < 0.f) - { - // Check radius offset sign. - if (radius_offset < 0.f) - { - radius_offset = -max_radius_mag; - } - else - { - radius_offset = max_radius_mag; - } - valid = approx_zero(delta, .1f); - } - - mPathParams.setRadiusOffset(radius_offset); - return valid; -} - -bool LLVolumeParams::setSkew(const F32 skew_value) -{ - bool valid = true; - - // Check the skew value against the revolutions. - F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX); - F32 skew_mag = fabs(skew); - F32 revolutions = getRevolutions(); - F32 scale_x = getRatioX(); - F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); - // Discontinuity; A revolution of 1 allows skews below 0.5. - if ( fabs(revolutions - 1.0f) < 0.001) - min_skew_mag = 0.0f; - - // Clip skew. - F32 delta = skew_mag - min_skew_mag; - if (delta < 0.f) - { - // Check skew sign. - if (skew < 0.0f) - { - skew = -min_skew_mag; - } - else - { - skew = min_skew_mag; - } - valid = approx_zero(delta, .01f); - } - - mPathParams.setSkew(skew); - return valid; -} - -bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type) -{ - mSculptID = sculpt_id; - mSculptType = sculpt_type; - return true; -} - -bool LLVolumeParams::setType(U8 profile, U8 path) -{ - bool result = true; - // First, check profile and path for validity. - U8 profile_type = profile & LL_PCODE_PROFILE_MASK; - U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4; - U8 path_type = path >> 4; - - if (profile_type > LL_PCODE_PROFILE_MAX) - { - // Bad profile. Make it square. - profile = LL_PCODE_PROFILE_SQUARE; - result = false; - llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type - << ") to be LL_PCODE_PROFILE_SQUARE" << llendl; - } - else if (hole_type > LL_PCODE_HOLE_MAX) - { - // Bad hole. Make it the same. - profile = profile_type; - result = false; - llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type - << ") to be LL_PCODE_HOLE_SAME" << llendl; - } - - if (path_type < LL_PCODE_PATH_MIN || - path_type > LL_PCODE_PATH_MAX) - { - // Bad path. Make it linear. - result = false; - llwarns << "LLVolumeParams::setType changing bad path (" << path - << ") to be LL_PCODE_PATH_LINE" << llendl; - path = LL_PCODE_PATH_LINE; - } - - mProfileParams.setCurveType(profile); - mPathParams.setCurveType(path); - return result; -} - -// static -bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, - U8 path_curve, F32 path_begin, F32 path_end, - F32 scx, F32 scy, F32 shx, F32 shy, - F32 twistend, F32 twistbegin, F32 radiusoffset, - F32 tx, F32 ty, F32 revolutions, F32 skew) -{ - LLVolumeParams test_params; - if (!test_params.setType (prof_curve, path_curve)) - { - return false; - } - if (!test_params.setBeginAndEndS (prof_begin, prof_end)) - { - return false; - } - if (!test_params.setBeginAndEndT (path_begin, path_end)) - { - return false; - } - if (!test_params.setHollow (hollow)) - { - return false; - } - if (!test_params.setTwistBegin (twistbegin)) - { - return false; - } - if (!test_params.setTwistEnd (twistend)) - { - return false; - } - if (!test_params.setRatio (scx, scy)) - { - return false; - } - if (!test_params.setShear (shx, shy)) - { - return false; - } - if (!test_params.setTaper (tx, ty)) - { - return false; - } - if (!test_params.setRevolutions (revolutions)) - { - return false; - } - if (!test_params.setRadiusOffset (radiusoffset)) - { - return false; - } - if (!test_params.setSkew (skew)) - { - return false; - } - return true; -} - -S32 *LLVolume::getTriangleIndices(U32 &num_indices) const -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - S32 expected_num_triangle_indices = getNumTriangleIndices(); - if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES) - { - // we don't allow LLVolumes with this many vertices - llwarns << "Couldn't allocate triangle indices" << llendl; - num_indices = 0; - return NULL; - } - - S32* index = new S32[expected_num_triangle_indices]; - S32 count = 0; - - // Let's do this totally diffently, as we don't care about faces... - // Counter-clockwise triangles are forward facing... - - BOOL open = getProfile().isOpen(); - BOOL hollow = (mParams.getProfileParams().getHollow() > 0); - BOOL path_open = getPath().isOpen(); - S32 size_s, size_s_out, size_t; - S32 s, t, i; - size_s = getProfile().getTotal(); - size_s_out = getProfile().getTotalOut(); - size_t = getPath().mPath.size(); - - // NOTE -- if the construction of the triangles below ever changes - // then getNumTriangleIndices() method may also have to be updated. - - if (open) /* Flawfinder: ignore */ - { - if (hollow) - { - // Open hollow -- much like the closed solid, except we - // we need to stitch up the gap between s=0 and s=size_s-1 - - for (t = 0; t < size_t - 1; t++) - { - // The outer face, first cut, and inner face - for (s = 0; s < size_s - 1; s++) - { - i = s + t*size_s; - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - - // The other cut face - index[count++] = s + t*size_s; // x,y - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = s + (t+1)*size_s; // x,y+1 - - index[count++] = s + (t+1)*size_s; // x,y+1 - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = 0 + (t+1)*size_s; // x+1,y+1 - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - // Top cap - S32 pt1 = 0; - S32 pt2 = size_s-1; - S32 i = (size_t - 1)*size_s; - - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1 + i; - index[count++] = pt1 + 1 + i; - index[count++] = pt2 + i; - pt1++; - } - else - { - index[count++] = pt1 + i; - index[count++] = pt2 - 1 + i; - index[count++] = pt2 + i; - pt2--; - } - } - - // Bottom cap - pt1 = 0; - pt2 = size_s-1; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt1 + 1; - pt1++; - } - else - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt2 - 1; - pt2--; - } - } - } - } - else - { - // Open solid - - for (t = 0; t < size_t - 1; t++) - { - // Outer face + 1 cut face - for (s = 0; s < size_s - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - - // The other cut face - index[count++] = (size_s - 1) + (t*size_s); // x,y - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 - - index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 - index[count++] = 0 + (t*size_s); // x+1,y - index[count++] = 0 + (t+1)*size_s; // x+1,y+1 - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - for (s = 0; s < size_s - 2; s++) - { - index[count++] = s+1; - index[count++] = s; - index[count++] = size_s - 1; - } - - // We've got a top cap - S32 offset = (size_t - 1)*size_s; - for (s = 0; s < size_s - 2; s++) - { - // Inverted ordering from bottom cap. - index[count++] = offset + size_s - 1; - index[count++] = offset + s; - index[count++] = offset + s + 1; - } - } - } - } - else if (hollow) - { - // Closed hollow - // Outer face - - for (t = 0; t < size_t - 1; t++) - { - for (s = 0; s < size_s_out - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + 1 + size_s; // x+1,y+1 - } - } - - // Inner face - // Invert facing from outer face - for (t = 0; t < size_t - 1; t++) - { - for (s = size_s_out; s < size_s - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + 1 + size_s; // x+1,y+1 - } - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - // Top cap - S32 pt1 = 0; - S32 pt2 = size_s-1; - S32 i = (size_t - 1)*size_s; - - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1 + i; - index[count++] = pt1 + 1 + i; - index[count++] = pt2 + i; - pt1++; - } - else - { - index[count++] = pt1 + i; - index[count++] = pt2 - 1 + i; - index[count++] = pt2 + i; - pt2--; - } - } - - // Bottom cap - pt1 = 0; - pt2 = size_s-1; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt1 + 1; - pt1++; - } - else - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt2 - 1; - pt2--; - } - } - } - } - else - { - // Closed solid. Easy case. - for (t = 0; t < size_t - 1; t++) - { - for (s = 0; s < size_s - 1; s++) - { - // Should wrap properly, but for now... - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - // bottom cap - for (s = 1; s < size_s - 2; s++) - { - index[count++] = s+1; - index[count++] = s; - index[count++] = 0; - } - - // top cap - S32 offset = (size_t - 1)*size_s; - for (s = 1; s < size_s - 2; s++) - { - // Inverted ordering from bottom cap. - index[count++] = offset; - index[count++] = offset + s; - index[count++] = offset + s + 1; - } - } - } - -#ifdef LL_DEBUG - // assert that we computed the correct number of indices - if (count != expected_num_triangle_indices ) - { - llerrs << "bad index count prediciton:" - << " expected=" << expected_num_triangle_indices - << " actual=" << count << llendl; - } -#endif - -#if 0 - // verify that each index does not point beyond the size of the mesh - S32 num_vertices = mMesh.size(); - for (i = 0; i < count; i+=3) - { - llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl; - llassert(index[i] < num_vertices); - llassert(index[i+1] < num_vertices); - llassert(index[i+2] < num_vertices); - } -#endif - - num_indices = count; - return index; -} - -S32 LLVolume::getNumTriangleIndices() const -{ - BOOL profile_open = getProfile().isOpen(); - BOOL hollow = (mParams.getProfileParams().getHollow() > 0); - BOOL path_open = getPath().isOpen(); - - S32 size_s, size_s_out, size_t; - size_s = getProfile().getTotal(); - size_s_out = getProfile().getTotalOut(); - size_t = getPath().mPath.size(); - - S32 count = 0; - if (profile_open) /* Flawfinder: ignore */ - { - if (hollow) - { - // Open hollow -- much like the closed solid, except we - // we need to stitch up the gap between s=0 and s=size_s-1 - count = (size_t - 1) * (((size_s -1) * 6) + 6); - } - else - { - count = (size_t - 1) * (((size_s -1) * 6) + 6); - } - } - else if (hollow) - { - // Closed hollow - // Outer face - count = (size_t - 1) * (size_s_out - 1) * 6; - - // Inner face - count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6; - } - else - { - // Closed solid. Easy case. - count = (size_t - 1) * (size_s - 1) * 6; - } - - if (path_open) - { - S32 cap_triangle_count = size_s - 3; - if ( profile_open - || hollow ) - { - cap_triangle_count = size_s - 2; - } - if ( cap_triangle_count > 0 ) - { - // top and bottom caps - count += cap_triangle_count * 2 * 3; - } - } - return count; -} - - -S32 LLVolume::getNumTriangles() const -{ - U32 triangle_count = 0; - - for (S32 i = 0; i < getNumVolumeFaces(); ++i) - { - triangle_count += getVolumeFace(i).mNumIndices/3; - } - - return triangle_count; -} - - -//----------------------------------------------------------------------------- -// generateSilhouetteVertices() -//----------------------------------------------------------------------------- -void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, - std::vector<LLVector3> &normals, - std::vector<S32> &segments, - const LLVector3& obj_cam_vec_in, - const LLMatrix4& mat_in, - const LLMatrix3& norm_mat_in, - S32 face_mask) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - LLMatrix4a mat; - mat.loadu(mat_in); - - LLMatrix4a norm_mat; - norm_mat.loadu(norm_mat_in); - - LLVector4a obj_cam_vec; - obj_cam_vec.load3(obj_cam_vec_in.mV); - - vertices.clear(); - normals.clear(); - segments.clear(); - - if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - { - return; - } - - S32 cur_index = 0; - //for each face - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) - { - LLVolumeFace& face = *iter; - - if (!(face_mask & (0x1 << cur_index++)) || - face.mNumIndices == 0 || face.mEdge.empty()) - { - continue; - } - - if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { - - } - else { - - //============================================== - //DEBUG draw edge map instead of silhouette edge - //============================================== - -#if DEBUG_SILHOUETTE_EDGE_MAP - - //for each triangle - U32 count = face.mNumIndices; - for (U32 j = 0; j < count/3; j++) { - //get vertices - S32 v1 = face.mIndices[j*3+0]; - S32 v2 = face.mIndices[j*3+1]; - S32 v3 = face.mIndices[j*3+2]; - - //get current face center - LLVector3 cCenter = (face.mVertices[v1].getPosition() + - face.mVertices[v2].getPosition() + - face.mVertices[v3].getPosition()) / 3.0f; - - //for each edge - for (S32 k = 0; k < 3; k++) { - S32 nIndex = face.mEdge[j*3+k]; - if (nIndex <= -1) { - continue; - } - - if (nIndex >= (S32) count/3) { - continue; - } - //get neighbor vertices - v1 = face.mIndices[nIndex*3+0]; - v2 = face.mIndices[nIndex*3+1]; - v3 = face.mIndices[nIndex*3+2]; - - //get neighbor face center - LLVector3 nCenter = (face.mVertices[v1].getPosition() + - face.mVertices[v2].getPosition() + - face.mVertices[v3].getPosition()) / 3.0f; - - //draw line - vertices.push_back(cCenter); - vertices.push_back(nCenter); - normals.push_back(LLVector3(1,1,1)); - normals.push_back(LLVector3(1,1,1)); - segments.push_back(vertices.size()); - } - } - - continue; - - //============================================== - //DEBUG - //============================================== - - //============================================== - //DEBUG draw normals instead of silhouette edge - //============================================== -#elif DEBUG_SILHOUETTE_NORMALS - - //for each vertex - for (U32 j = 0; j < face.mNumVertices; j++) { - vertices.push_back(face.mVertices[j].getPosition()); - vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f); - normals.push_back(LLVector3(0,0,1)); - normals.push_back(LLVector3(0,0,1)); - segments.push_back(vertices.size()); -#if DEBUG_SILHOUETTE_BINORMALS - vertices.push_back(face.mVertices[j].getPosition()); - vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f); - normals.push_back(LLVector3(0,0,1)); - normals.push_back(LLVector3(0,0,1)); - segments.push_back(vertices.size()); -#endif - } - - continue; -#else - //============================================== - //DEBUG - //============================================== - - static const U8 AWAY = 0x01, - TOWARDS = 0x02; - - //for each triangle - std::vector<U8> fFacing; - vector_append(fFacing, face.mNumIndices/3); - - LLVector4a* v = (LLVector4a*) face.mPositions; - LLVector4a* n = (LLVector4a*) face.mNormals; - - for (U32 j = 0; j < face.mNumIndices/3; j++) - { - //approximate normal - S32 v1 = face.mIndices[j*3+0]; - S32 v2 = face.mIndices[j*3+1]; - S32 v3 = face.mIndices[j*3+2]; - - LLVector4a c1,c2; - c1.setSub(v[v1], v[v2]); - c2.setSub(v[v2], v[v3]); - - LLVector4a norm; - - norm.setCross3(c1, c2); - - if (norm.dot3(norm) < 0.00000001f) - { - fFacing[j] = AWAY | TOWARDS; - } - else - { - //get view vector - LLVector4a view; - view.setSub(obj_cam_vec, v[v1]); - bool away = view.dot3(norm) > 0.0f; - if (away) - { - fFacing[j] = AWAY; - } - else - { - fFacing[j] = TOWARDS; - } - } - } - - //for each triangle - for (U32 j = 0; j < face.mNumIndices/3; j++) - { - if (fFacing[j] == (AWAY | TOWARDS)) - { //this is a degenerate triangle - //take neighbor facing (degenerate faces get facing of one of their neighbors) - // *FIX IF NEEDED: this does not deal with neighboring degenerate faces - for (S32 k = 0; k < 3; k++) - { - S32 index = face.mEdge[j*3+k]; - if (index != -1) - { - fFacing[j] = fFacing[index]; - break; - } - } - continue; //skip degenerate face - } - - //for each edge - for (S32 k = 0; k < 3; k++) { - S32 index = face.mEdge[j*3+k]; - if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) { - //our neighbor is degenerate, make him face our direction - fFacing[face.mEdge[j*3+k]] = fFacing[j]; - continue; - } - - if (index == -1 || //edge has no neighbor, MUST be a silhouette edge - (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge - - S32 v1 = face.mIndices[j*3+k]; - S32 v2 = face.mIndices[j*3+((k+1)%3)]; - - LLVector4a t; - mat.affineTransform(v[v1], t); - vertices.push_back(LLVector3(t[0], t[1], t[2])); - - norm_mat.rotate(n[v1], t); - - t.normalize3fast(); - normals.push_back(LLVector3(t[0], t[1], t[2])); - - mat.affineTransform(v[v2], t); - vertices.push_back(LLVector3(t[0], t[1], t[2])); - - norm_mat.rotate(n[v2], t); - t.normalize3fast(); - normals.push_back(LLVector3(t[0], t[1], t[2])); - - segments.push_back(vertices.size()); - } - } - } -#endif - } - } -} - -S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) -{ - LLVector4a starta, enda; - starta.load3(start.mV); - enda.load3(end.mV); - - return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal); - -} - - -S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - S32 face, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) -{ - S32 hit_face = -1; - - S32 start_face; - S32 end_face; - - if (face == -1) // ALL_SIDES - { - start_face = 0; - end_face = getNumVolumeFaces() - 1; - } - else - { - start_face = face; - end_face = face; - } - - LLVector4a dir; - dir.setSub(end, start); - - F32 closest_t = 2.f; // must be larger than 1 - - end_face = llmin(end_face, getNumVolumeFaces()-1); - - for (S32 i = start_face; i <= end_face; i++) - { - LLVolumeFace &face = mVolumeFaces[i]; - - LLVector4a box_center; - box_center.setAdd(face.mExtents[0], face.mExtents[1]); - box_center.mul(0.5f); - - LLVector4a box_size; - box_size.setSub(face.mExtents[1], face.mExtents[0]); - - if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) - { - if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them - { - genBinormals(i); - } - - if (!face.mOctree) - { - face.createOctree(); - } - - //LLVector4a* p = (LLVector4a*) face.mPositions; - - LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal); - intersect.traverse(face.mOctree); - if (intersect.mHitFace) - { - hit_face = i; - } - } - } - - - return hit_face; -} - -class LLVertexIndexPair -{ -public: - LLVertexIndexPair(const LLVector3 &vertex, const S32 index); - - LLVector3 mVertex; - S32 mIndex; -}; - -LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) -{ - mVertex = vertex; - mIndex = index; -} - -const F32 VERTEX_SLOP = 0.00001f; -const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP; - -struct lessVertex -{ - bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b) - { - const F32 slop = VERTEX_SLOP; - - if (a->mVertex.mV[0] + slop < b->mVertex.mV[0]) - { - return TRUE; - } - else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0]) - { - return FALSE; - } - - if (a->mVertex.mV[1] + slop < b->mVertex.mV[1]) - { - return TRUE; - } - else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1]) - { - return FALSE; - } - - if (a->mVertex.mV[2] + slop < b->mVertex.mV[2]) - { - return TRUE; - } - else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2]) - { - return FALSE; - } - - return FALSE; - } -}; - -struct lessTriangle -{ - bool operator()(const S32 *a, const S32 *b) - { - if (*a < *b) - { - return TRUE; - } - else if (*a > *b) - { - return FALSE; - } - - if (*(a+1) < *(b+1)) - { - return TRUE; - } - else if (*(a+1) > *(b+1)) - { - return FALSE; - } - - if (*(a+2) < *(b+2)) - { - return TRUE; - } - else if (*(a+2) > *(b+2)) - { - return FALSE; - } - - return FALSE; - } -}; - -BOOL equalTriangle(const S32 *a, const S32 *b) -{ - if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2))) - { - return TRUE; - } - return FALSE; -} - -BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, - const std::vector<Point>& input_vertices, - const S32 num_input_triangles, - S32 *input_triangles, - S32 &num_output_vertices, - LLVector3 **output_vertices, - S32 &num_output_triangles, - S32 **output_triangles) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - /* Testing: avoid any cleanup - static BOOL skip_cleanup = TRUE; - if ( skip_cleanup ) - { - num_output_vertices = num_input_vertices; - num_output_triangles = num_input_triangles; - - *output_vertices = new LLVector3[num_input_vertices]; - for (S32 index = 0; index < num_input_vertices; index++) - { - (*output_vertices)[index] = input_vertices[index].mPos; - } - - *output_triangles = new S32[num_input_triangles*3]; - memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32)); // Flawfinder: ignore - return TRUE; - } - */ - - // Here's how we do this: - // Create a structure which contains the original vertex index and the - // LLVector3 data. - // "Sort" the data by the vectors - // Create an array the size of the old vertex list, with a mapping of - // old indices to new indices. - // Go through triangles, shift so the lowest index is first - // Sort triangles by first index - // Remove duplicate triangles - // Allocate and pack new triangle data. - - //LLTimer cleanupTimer; - //llinfos << "In vertices: " << num_input_vertices << llendl; - //llinfos << "In triangles: " << num_input_triangles << llendl; - - S32 i; - typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t; - vertex_set_t vertex_list; - - LLVertexIndexPair *pairp = NULL; - for (i = 0; i < num_input_vertices; i++) - { - LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i); - vertex_list.insert(new_pairp); - } - - // Generate the vertex mapping and the list of vertices without - // duplicates. This will crash if there are no vertices. - llassert(num_input_vertices > 0); // check for no vertices! - S32 *vertex_mapping = new S32[num_input_vertices]; - LLVector3 *new_vertices = new LLVector3[num_input_vertices]; - LLVertexIndexPair *prev_pairp = NULL; - - S32 new_num_vertices; - - new_num_vertices = 0; - for (vertex_set_t::iterator iter = vertex_list.begin(), - end = vertex_list.end(); - iter != end; iter++) - { - pairp = *iter; - if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD)) - { - new_vertices[new_num_vertices] = pairp->mVertex; - //llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl; - new_num_vertices++; - // Update the previous - prev_pairp = pairp; - } - else - { - //llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl; - } - vertex_mapping[pairp->mIndex] = new_num_vertices - 1; - } - - // Iterate through triangles and remove degenerates, re-ordering vertices - // along the way. - S32 *new_triangles = new S32[num_input_triangles * 3]; - S32 new_num_triangles = 0; - - for (i = 0; i < num_input_triangles; i++) - { - S32 v1 = i*3; - S32 v2 = v1 + 1; - S32 v3 = v1 + 2; - - //llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; - input_triangles[v1] = vertex_mapping[input_triangles[v1]]; - input_triangles[v2] = vertex_mapping[input_triangles[v2]]; - input_triangles[v3] = vertex_mapping[input_triangles[v3]]; - - if ((input_triangles[v1] == input_triangles[v2]) - || (input_triangles[v1] == input_triangles[v3]) - || (input_triangles[v2] == input_triangles[v3])) - { - //llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; - // Degenerate triangle, skip - continue; - } - - if (input_triangles[v1] < input_triangles[v2]) - { - if (input_triangles[v1] < input_triangles[v3]) - { - // (0 < 1) && (0 < 2) - new_triangles[new_num_triangles*3] = input_triangles[v1]; - new_triangles[new_num_triangles*3+1] = input_triangles[v2]; - new_triangles[new_num_triangles*3+2] = input_triangles[v3]; - } - else - { - // (0 < 1) && (2 < 0) - new_triangles[new_num_triangles*3] = input_triangles[v3]; - new_triangles[new_num_triangles*3+1] = input_triangles[v1]; - new_triangles[new_num_triangles*3+2] = input_triangles[v2]; - } - } - else if (input_triangles[v2] < input_triangles[v3]) - { - // (1 < 0) && (1 < 2) - new_triangles[new_num_triangles*3] = input_triangles[v2]; - new_triangles[new_num_triangles*3+1] = input_triangles[v3]; - new_triangles[new_num_triangles*3+2] = input_triangles[v1]; - } - else - { - // (1 < 0) && (2 < 1) - new_triangles[new_num_triangles*3] = input_triangles[v3]; - new_triangles[new_num_triangles*3+1] = input_triangles[v1]; - new_triangles[new_num_triangles*3+2] = input_triangles[v2]; - } - new_num_triangles++; - } - - if (new_num_triangles == 0) - { - llwarns << "Created volume object with 0 faces." << llendl; - delete[] new_triangles; - delete[] vertex_mapping; - delete[] new_vertices; - return FALSE; - } - - typedef std::set<S32*, lessTriangle> triangle_set_t; - triangle_set_t triangle_list; - - for (i = 0; i < new_num_triangles; i++) - { - triangle_list.insert(&new_triangles[i*3]); - } - - // Sort through the triangle list, and delete duplicates - - S32 *prevp = NULL; - S32 *curp = NULL; - - S32 *sorted_tris = new S32[new_num_triangles*3]; - S32 cur_tri = 0; - for (triangle_set_t::iterator iter = triangle_list.begin(), - end = triangle_list.end(); - iter != end; iter++) - { - curp = *iter; - if (!prevp || !equalTriangle(prevp, curp)) - { - //llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; - sorted_tris[cur_tri*3] = *curp; - sorted_tris[cur_tri*3+1] = *(curp+1); - sorted_tris[cur_tri*3+2] = *(curp+2); - cur_tri++; - prevp = curp; - } - else - { - //llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; - } - } - - *output_vertices = new LLVector3[new_num_vertices]; - num_output_vertices = new_num_vertices; - for (i = 0; i < new_num_vertices; i++) - { - (*output_vertices)[i] = new_vertices[i]; - } - - *output_triangles = new S32[cur_tri*3]; - num_output_triangles = cur_tri; - memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32)); /* Flawfinder: ignore */ - - /* - llinfos << "Out vertices: " << num_output_vertices << llendl; - llinfos << "Out triangles: " << num_output_triangles << llendl; - for (i = 0; i < num_output_vertices; i++) - { - llinfos << i << ":" << (*output_vertices)[i] << llendl; - } - for (i = 0; i < num_output_triangles; i++) - { - llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl; - } - */ - - //llinfos << "Out vertices: " << num_output_vertices << llendl; - //llinfos << "Out triangles: " << num_output_triangles << llendl; - delete[] vertex_mapping; - vertex_mapping = NULL; - delete[] new_vertices; - new_vertices = NULL; - delete[] new_triangles; - new_triangles = NULL; - delete[] sorted_tris; - sorted_tris = NULL; - triangle_list.clear(); - std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer()); - vertex_list.clear(); - - return TRUE; -} - - -BOOL LLVolumeParams::importFile(LLFILE *fp) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - //llinfos << "importing volume" << llendl; - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of this buffer will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - - while (!feof(fp)) - { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf(buffer, " %255s", keyword); /* Flawfinder: ignore */ - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("profile", keyword)) - { - mProfileParams.importFile(fp); - } - else if (!strcmp("path",keyword)) - { - mPathParams.importFile(fp); - } - else - { - llwarns << "unknown keyword " << keyword << " in volume import" << llendl; - } - } - - return TRUE; -} - -BOOL LLVolumeParams::exportFile(LLFILE *fp) const -{ - fprintf(fp,"\tshape 0\n"); - fprintf(fp,"\t{\n"); - mPathParams.exportFile(fp); - mProfileParams.exportFile(fp); - fprintf(fp, "\t}\n"); - return TRUE; -} - - -BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - //llinfos << "importing volume" << llendl; - const S32 BUFSIZE = 16384; - // *NOTE: changing the size or type of this buffer will require - // changing the sscanf below. - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - char keyword[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - - while (input_stream.good()) - { - input_stream.getline(buffer, BUFSIZE); - sscanf(buffer, " %255s", keyword); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("profile", keyword)) - { - mProfileParams.importLegacyStream(input_stream); - } - else if (!strcmp("path",keyword)) - { - mPathParams.importLegacyStream(input_stream); - } - else - { - llwarns << "unknown keyword " << keyword << " in volume import" << llendl; - } - } - - return TRUE; -} - -BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - output_stream <<"\tshape 0\n"; - output_stream <<"\t{\n"; - mPathParams.exportLegacyStream(output_stream); - mProfileParams.exportLegacyStream(output_stream); - output_stream << "\t}\n"; - return TRUE; -} - -LLSD LLVolumeParams::sculptAsLLSD() const -{ - LLSD sd = LLSD(); - sd["id"] = getSculptID(); - sd["type"] = getSculptType(); - - return sd; -} - -bool LLVolumeParams::sculptFromLLSD(LLSD& sd) -{ - setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger()); - return true; -} - -LLSD LLVolumeParams::asLLSD() const -{ - LLSD sd = LLSD(); - sd["path"] = mPathParams; - sd["profile"] = mProfileParams; - sd["sculpt"] = sculptAsLLSD(); - - return sd; -} - -bool LLVolumeParams::fromLLSD(LLSD& sd) -{ - mPathParams.fromLLSD(sd["path"]); - mProfileParams.fromLLSD(sd["profile"]); - sculptFromLLSD(sd["sculpt"]); - - return true; -} - -void LLVolumeParams::reduceS(F32 begin, F32 end) -{ - begin = llclampf(begin); - end = llclampf(end); - if (begin > end) - { - F32 temp = begin; - begin = end; - end = temp; - } - F32 a = mProfileParams.getBegin(); - F32 b = mProfileParams.getEnd(); - mProfileParams.setBegin(a + begin * (b - a)); - mProfileParams.setEnd(a + end * (b - a)); -} - -void LLVolumeParams::reduceT(F32 begin, F32 end) -{ - begin = llclampf(begin); - end = llclampf(end); - if (begin > end) - { - F32 temp = begin; - begin = end; - end = temp; - } - F32 a = mPathParams.getBegin(); - F32 b = mPathParams.getEnd(); - mPathParams.setBegin(a + begin * (b - a)); - mPathParams.setEnd(a + end * (b - a)); -} - -const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity -const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity - -// returns TRUE if the shape can be approximated with a convex shape -// for collison purposes -BOOL LLVolumeParams::isConvex() const -{ - if (!getSculptID().isNull()) - { - // can't determine, be safe and say no: - return FALSE; - } - - F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); - F32 hollow = mProfileParams.getHollow(); - - U8 path_type = mPathParams.getCurveType(); - if ( path_length > MIN_CONCAVE_PATH_WEDGE - && ( mPathParams.getTwist() != mPathParams.getTwistBegin() - || (hollow > 0.f - && LL_PCODE_PATH_LINE != path_type) ) ) - { - // twist along a "not too short" path is concave - return FALSE; - } - - F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); - BOOL same_hole = hollow == 0.f - || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; - - F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) - { - // it is a sphere and spheres get twice the minimum profile wedge - min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; - } - - BOOL convex_profile = ( ( profile_length == 1.f - || profile_length <= 0.5f ) - && hollow == 0.f ) // trivially convex - || ( profile_length <= min_profile_wedge - && same_hole ); // effectvely convex (even when hollow) - - if (!convex_profile) - { - // profile is concave - return FALSE; - } - - if ( LL_PCODE_PATH_LINE == path_type ) - { - // straight paths with convex profile - return TRUE; - } - - BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f); - if (concave_path) - { - return FALSE; - } - - // we're left with spheres, toroids and tubes - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) - { - // at this stage all spheres must be convex - return TRUE; - } - - // it's a toroid or tube - if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) - { - // effectively convex - return TRUE; - } - - return FALSE; -} - -// debug -void LLVolumeParams::setCube() -{ - mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE); - mProfileParams.setBegin(0.f); - mProfileParams.setEnd(1.f); - mProfileParams.setHollow(0.f); - - mPathParams.setBegin(0.f); - mPathParams.setEnd(1.f); - mPathParams.setScale(1.f, 1.f); - mPathParams.setShear(0.f, 0.f); - mPathParams.setCurveType(LL_PCODE_PATH_LINE); - mPathParams.setTwistBegin(0.f); - mPathParams.setTwistEnd(0.f); - mPathParams.setRadiusOffset(0.f); - mPathParams.setTaper(0.f, 0.f); - mPathParams.setRevolutions(0.f); - mPathParams.setSkew(0.f); -} - -LLFaceID LLVolume::generateFaceMask() -{ - LLFaceID new_mask = 0x0000; - - switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK) - { - case LL_PCODE_PROFILE_CIRCLE: - case LL_PCODE_PROFILE_CIRCLE_HALF: - new_mask |= LL_FACE_OUTER_SIDE_0; - break; - case LL_PCODE_PROFILE_SQUARE: - { - for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++) - { - new_mask |= LL_FACE_OUTER_SIDE_0 << side; - } - } - break; - case LL_PCODE_PROFILE_ISOTRI: - case LL_PCODE_PROFILE_EQUALTRI: - case LL_PCODE_PROFILE_RIGHTTRI: - { - for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++) - { - new_mask |= LL_FACE_OUTER_SIDE_0 << side; - } - } - break; - default: - llerrs << "Unknown profile!" << llendl; - break; - } - - // handle hollow objects - if (mParams.getProfileParams().getHollow() > 0) - { - new_mask |= LL_FACE_INNER_SIDE; - } - - // handle open profile curves - if (mProfilep->isOpen()) - { - new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END; - } - - // handle open path curves - if (mPathp->isOpen()) - { - new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END; - } - - return new_mask; -} - -BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask) -{ - LLFaceID test_mask = 0; - for(S32 i = 0; i < getNumFaces(); i++) - { - test_mask |= mProfilep->mFaces[i].mFaceID; - } - - return test_mask == face_mask; -} - -BOOL LLVolume::isConvex() const -{ - // mParams.isConvex() may return FALSE even though the final - // geometry is actually convex due to LOD approximations. - // TODO -- provide LLPath and LLProfile with isConvex() methods - // that correctly determine convexity. -- Leviathan - return mParams.isConvex(); -} - - -std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params) -{ - s << "{type=" << (U32) profile_params.mCurveType; - s << ", begin=" << profile_params.mBegin; - s << ", end=" << profile_params.mEnd; - s << ", hollow=" << profile_params.mHollow; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params) -{ - s << "{type=" << (U32) path_params.mCurveType; - s << ", begin=" << path_params.mBegin; - s << ", end=" << path_params.mEnd; - s << ", twist=" << path_params.mTwistEnd; - s << ", scale=" << path_params.mScale; - s << ", shear=" << path_params.mShear; - s << ", twist_begin=" << path_params.mTwistBegin; - s << ", radius_offset=" << path_params.mRadiusOffset; - s << ", taper=" << path_params.mTaper; - s << ", revolutions=" << path_params.mRevolutions; - s << ", skew=" << path_params.mSkew; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params) -{ - s << "{profileparams = " << volume_params.mProfileParams; - s << ", pathparams = " << volume_params.mPathParams; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLProfile &profile) -{ - s << " {open=" << (U32) profile.mOpen; - s << ", dirty=" << profile.mDirty; - s << ", totalout=" << profile.mTotalOut; - s << ", total=" << profile.mTotal; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLPath &path) -{ - s << "{open=" << (U32) path.mOpen; - s << ", dirty=" << path.mDirty; - s << ", step=" << path.mStep; - s << ", total=" << path.mTotal; - s << "}"; - return s; -} - -std::ostream& operator<<(std::ostream &s, const LLVolume &volume) -{ - s << "{params = " << volume.getParams(); - s << ", path = " << *volume.mPathp; - s << ", profile = " << *volume.mProfilep; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) -{ - s << "{params = " << volumep->getParams(); - s << ", path = " << *(volumep->mPathp); - s << ", profile = " << *(volumep->mProfilep); - s << "}"; - return s; -} - -LLVolumeFace::LLVolumeFace() : - mID(0), - mTypeMask(0), - mBeginS(0), - mBeginT(0), - mNumS(0), - mNumT(0), - mNumVertices(0), - mNumIndices(0), - mPositions(NULL), - mNormals(NULL), - mBinormals(NULL), - mTexCoords(NULL), - mIndices(NULL), - mWeights(NULL), - mOctree(NULL) -{ - mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3); - mCenter = mExtents+2; -} - -LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) -: mID(0), - mTypeMask(0), - mBeginS(0), - mBeginT(0), - mNumS(0), - mNumT(0), - mNumVertices(0), - mNumIndices(0), - mPositions(NULL), - mNormals(NULL), - mBinormals(NULL), - mTexCoords(NULL), - mIndices(NULL), - mWeights(NULL), - mOctree(NULL) -{ - mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3); - mCenter = mExtents+2; - *this = src; -} - -LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) -{ - if (&src == this) - { //self assignment, do nothing - return *this; - } - - mID = src.mID; - mTypeMask = src.mTypeMask; - mBeginS = src.mBeginS; - mBeginT = src.mBeginT; - mNumS = src.mNumS; - mNumT = src.mNumT; - - mExtents[0] = src.mExtents[0]; - mExtents[1] = src.mExtents[1]; - *mCenter = *src.mCenter; - - mNumVertices = 0; - mNumIndices = 0; - - freeData(); - - LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a)); - - resizeVertices(src.mNumVertices); - resizeIndices(src.mNumIndices); - - if (mNumVertices) - { - S32 vert_size = mNumVertices*sizeof(LLVector4a); - S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF; - - LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size); - LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size); - LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size); - - - if (src.mBinormals) - { - allocateBinormals(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size); - } - else - { - free(mBinormals); - mBinormals = NULL; - } - - if (src.mWeights) - { - allocateWeights(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); - } - else - { - free(mWeights); - mWeights = NULL; - } - } - - if (mNumIndices) - { - S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF; - - LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); - } - - //delete - return *this; -} - -LLVolumeFace::~LLVolumeFace() -{ - free(mExtents); - mExtents = NULL; - - freeData(); -} - -void LLVolumeFace::freeData() -{ - free(mPositions); - mPositions = NULL; - free( mNormals); - mNormals = NULL; - free(mTexCoords); - mTexCoords = NULL; - free(mIndices); - mIndices = NULL; - free(mBinormals); - mBinormals = NULL; - free(mWeights); - mWeights = NULL; - - delete mOctree; - mOctree = NULL; -} - -BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) -{ - //tree for this face is no longer valid - delete mOctree; - mOctree = NULL; - - if (mTypeMask & CAP_MASK) - { - return createCap(volume, partial_build); - } - else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) - { - return createSide(volume, partial_build); - } - else - { - llerrs << "Unknown/uninitialized face type!" << llendl; - return FALSE; - } -} - -void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv) -{ - cv.setPosition(mPositions[index]); - cv.setNormal(mNormals[index]); - cv.mTexCoord = mTexCoords[index]; -} - -bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const -{ - return getPosition().equals3(rhs.getPosition()) && - mTexCoord == rhs.mTexCoord && - getNormal().equals3(rhs.getNormal()); -} - -bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a, const LLVector3& b) const -{ - if (a.mV[0] != b.mV[0]) - { - return a.mV[0] < b.mV[0]; - } - - if (a.mV[1] != b.mV[1]) - { - return a.mV[1] < b.mV[1]; - } - - return a.mV[2] < b.mV[2]; -} - -void LLVolumeFace::optimize(F32 angle_cutoff) -{ - LLVolumeFace new_face; - - //map of points to vector of vertices at that point - VertexMapData::PointMap point_map; - - //remove redundant vertices - for (U32 i = 0; i < mNumIndices; ++i) - { - U16 index = mIndices[i]; - - LLVolumeFace::VertexData cv; - getVertexData(index, cv); - - BOOL found = FALSE; - VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr())); - if (point_iter != point_map.end()) - { //duplicate point might exist - for (U32 j = 0; j < point_iter->second.size(); ++j) - { - LLVolumeFace::VertexData& tv = (point_iter->second)[j]; - if (tv.compareNormal(cv, angle_cutoff)) - { - found = TRUE; - new_face.pushIndex((point_iter->second)[j].mIndex); - break; - } - } - } - - if (!found) - { - new_face.pushVertex(cv); - U16 index = (U16) new_face.mNumVertices-1; - new_face.pushIndex(index); - - VertexMapData d; - d.setPosition(cv.getPosition()); - d.mTexCoord = cv.mTexCoord; - d.setNormal(cv.getNormal()); - d.mIndex = index; - if (point_iter != point_map.end()) - { - point_iter->second.push_back(d); - } - else - { - point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d); - } - } - } - - swapData(new_face); -} - -class LLVCacheTriangleData; - -class LLVCacheVertexData -{ -public: - S32 mIdx; - S32 mCacheTag; - F32 mScore; - U32 mActiveTriangles; - std::vector<LLVCacheTriangleData*> mTriangles; - - LLVCacheVertexData() - { - mCacheTag = -1; - mScore = 0.f; - mActiveTriangles = 0; - mIdx = -1; - } -}; - -class LLVCacheTriangleData -{ -public: - bool mActive; - F32 mScore; - LLVCacheVertexData* mVertex[3]; - - LLVCacheTriangleData() - { - mActive = true; - mScore = 0.f; - mVertex[0] = mVertex[1] = mVertex[2] = NULL; - } - - void complete() - { - mActive = false; - for (S32 i = 0; i < 3; ++i) - { - if (mVertex[i]) - { - llassert_always(mVertex[i]->mActiveTriangles > 0); - mVertex[i]->mActiveTriangles--; - } - } - } - - bool operator<(const LLVCacheTriangleData& rhs) const - { //highest score first - return rhs.mScore < mScore; - } -}; - -const F32 FindVertexScore_CacheDecayPower = 1.5f; -const F32 FindVertexScore_LastTriScore = 0.75f; -const F32 FindVertexScore_ValenceBoostScale = 2.0f; -const F32 FindVertexScore_ValenceBoostPower = 0.5f; -const U32 MaxSizeVertexCache = 32; - -F32 find_vertex_score(LLVCacheVertexData& data) -{ - if (data.mActiveTriangles == 0) - { //no triangle references this vertex - return -1.f; - } - - F32 score = 0.f; - - S32 cache_idx = data.mCacheTag; - - if (cache_idx < 0) - { - //not in cache - } - else - { - if (cache_idx < 3) - { //vertex was in the last triangle - score = FindVertexScore_LastTriScore; - } - else - { //more points for being higher in the cache - F32 scaler = 1.f/(MaxSizeVertexCache-3); - score = 1.f-((cache_idx-3)*scaler); - score = powf(score, FindVertexScore_CacheDecayPower); - } - } - - //bonus points for having low valence - F32 valence_boost = powf(data.mActiveTriangles, -FindVertexScore_ValenceBoostPower); - score += FindVertexScore_ValenceBoostScale * valence_boost; - - return score; -} - -class LLVCacheFIFO -{ -public: - LLVCacheVertexData* mCache[MaxSizeVertexCache]; - U32 mMisses; - - LLVCacheFIFO() - { - mMisses = 0; - for (U32 i = 0; i < MaxSizeVertexCache; ++i) - { - mCache[i] = NULL; - } - } - - void addVertex(LLVCacheVertexData* data) - { - if (data->mCacheTag == -1) - { - mMisses++; - - S32 end = MaxSizeVertexCache-1; - - if (mCache[end]) - { - mCache[end]->mCacheTag = -1; - } - - for (S32 i = end; i > 0; --i) - { - mCache[i] = mCache[i-1]; - if (mCache[i]) - { - mCache[i]->mCacheTag = i; - } - } - - mCache[0] = data; - data->mCacheTag = 0; - } - } -}; - -class LLVCacheLRU -{ -public: - LLVCacheVertexData* mCache[MaxSizeVertexCache+3]; - - LLVCacheTriangleData* mBestTriangle; - - U32 mMisses; - - LLVCacheLRU() - { - for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) - { - mCache[i] = NULL; - } - - mBestTriangle = NULL; - mMisses = 0; - } - - void addVertex(LLVCacheVertexData* data) - { - S32 end = MaxSizeVertexCache+2; - if (data->mCacheTag != -1) - { //just moving a vertex to the front of the cache - end = data->mCacheTag; - } - else - { - mMisses++; - if (mCache[end]) - { //adding a new vertex, vertex at end of cache falls off - mCache[end]->mCacheTag = -1; - } - } - - for (S32 i = end; i > 0; --i) - { //adjust cache pointers and tags - mCache[i] = mCache[i-1]; - - if (mCache[i]) - { - mCache[i]->mCacheTag = i; - } - } - - mCache[0] = data; - mCache[0]->mCacheTag = 0; - } - - void addTriangle(LLVCacheTriangleData* data) - { - addVertex(data->mVertex[0]); - addVertex(data->mVertex[1]); - addVertex(data->mVertex[2]); - } - - void updateScores() - { - for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) - { //trailing 3 vertices aren't actually in the cache for scoring purposes - if (mCache[i]) - { - mCache[i]->mCacheTag = -1; - } - } - - for (U32 i = 0; i < MaxSizeVertexCache; ++i) - { //update scores of vertices in cache - if (mCache[i]) - { - mCache[i]->mScore = find_vertex_score(*(mCache[i])); - llassert_always(mCache[i]->mCacheTag == i); - } - } - - mBestTriangle = NULL; - //update triangle scores - for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) - { - if (mCache[i]) - { - for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j) - { - LLVCacheTriangleData* tri = mCache[i]->mTriangles[j]; - if (tri->mActive) - { - tri->mScore = tri->mVertex[0]->mScore; - tri->mScore += tri->mVertex[1]->mScore; - tri->mScore += tri->mVertex[2]->mScore; - - if (!mBestTriangle || mBestTriangle->mScore < tri->mScore) - { - mBestTriangle = tri; - } - } - } - } - } - - //knock trailing 3 vertices off the cache - for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) - { - if (mCache[i]) - { - llassert_always(mCache[i]->mCacheTag == -1); - mCache[i] = NULL; - } - } - } -}; - - -void LLVolumeFace::cacheOptimize() -{ //optimize for vertex cache according to Forsyth method: - // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html - - LLVCacheLRU cache; - - //mapping of vertices to triangles and indices - std::vector<LLVCacheVertexData> vertex_data; - - //mapping of triangles do vertices - std::vector<LLVCacheTriangleData> triangle_data; - - triangle_data.resize(mNumIndices/3); - vertex_data.resize(mNumVertices); - - for (U32 i = 0; i < mNumIndices; i++) - { //populate vertex data and triangle data arrays - U16 idx = mIndices[i]; - U32 tri_idx = i/3; - - vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx])); - vertex_data[idx].mIdx = idx; - triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]); - } - - /*F32 pre_acmr = 1.f; - //measure cache misses from before rebuild - { - LLVCacheFIFO test_cache; - for (U32 i = 0; i < mNumIndices; ++i) - { - test_cache.addVertex(&vertex_data[mIndices[i]]); - } - - for (U32 i = 0; i < mNumVertices; i++) - { - vertex_data[i].mCacheTag = -1; - } - - pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3); - }*/ - - for (U32 i = 0; i < mNumVertices; i++) - { //initialize score values (no cache -- might try a fifo cache here) - vertex_data[i].mScore = find_vertex_score(vertex_data[i]); - vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size(); - - for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j) - { - vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore; - } - } - - //sort triangle data by score - std::sort(triangle_data.begin(), triangle_data.end()); - - std::vector<U16> new_indices; - - LLVCacheTriangleData* tri; - - //prime pump by adding first triangle to cache; - tri = &(triangle_data[0]); - cache.addTriangle(tri); - new_indices.push_back(tri->mVertex[0]->mIdx); - new_indices.push_back(tri->mVertex[1]->mIdx); - new_indices.push_back(tri->mVertex[2]->mIdx); - tri->complete(); - - U32 breaks = 0; - for (U32 i = 1; i < mNumIndices/3; ++i) - { - cache.updateScores(); - tri = cache.mBestTriangle; - if (!tri) - { - breaks++; - for (U32 j = 0; j < triangle_data.size(); ++j) - { - if (triangle_data[j].mActive) - { - tri = &(triangle_data[j]); - break; - } - } - } - - cache.addTriangle(tri); - new_indices.push_back(tri->mVertex[0]->mIdx); - new_indices.push_back(tri->mVertex[1]->mIdx); - new_indices.push_back(tri->mVertex[2]->mIdx); - tri->complete(); - } - - for (U32 i = 0; i < mNumIndices; ++i) - { - mIndices[i] = new_indices[i]; - } - - /*F32 post_acmr = 1.f; - //measure cache misses from after rebuild - { - LLVCacheFIFO test_cache; - for (U32 i = 0; i < mNumVertices; i++) - { - vertex_data[i].mCacheTag = -1; - } - - for (U32 i = 0; i < mNumIndices; ++i) - { - test_cache.addVertex(&vertex_data[mIndices[i]]); - } - - post_acmr = (F32) test_cache.mMisses/(mNumIndices/3); - }*/ - - //optimize for pre-TnL cache - - //allocate space for new buffer - S32 num_verts = mNumVertices; - LLVector4a* pos = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - LLVector4a* norm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; - LLVector2* tc = (LLVector2*) malloc(size); - - LLVector4a* wght = NULL; - if (mWeights) - { - wght = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - } - - LLVector4a* binorm = NULL; - if (mBinormals) - { - binorm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - } - - //allocate mapping of old indices to new indices - std::vector<S32> new_idx; - new_idx.resize(mNumVertices, -1); - - S32 cur_idx = 0; - for (U32 i = 0; i < mNumIndices; ++i) - { - U16 idx = mIndices[i]; - if (new_idx[idx] == -1) - { //this vertex hasn't been added yet - new_idx[idx] = cur_idx; - - //copy vertex data - pos[cur_idx] = mPositions[idx]; - norm[cur_idx] = mNormals[idx]; - tc[cur_idx] = mTexCoords[idx]; - if (mWeights) - { - wght[cur_idx] = mWeights[idx]; - } - if (mBinormals) - { - binorm[cur_idx] = mBinormals[idx]; - } - - cur_idx++; - } - } - - for (U32 i = 0; i < mNumIndices; ++i) - { - mIndices[i] = new_idx[mIndices[i]]; - } - - free(mPositions); - free(mNormals); - free(mTexCoords); - free(mWeights); - free(mBinormals); - - mPositions = pos; - mNormals = norm; - mTexCoords = tc; - mWeights = wght; - mBinormals = binorm; - - //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks); - //llinfos << result << llendl; - -} - -void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size) -{ - if (mOctree) - { - return; - } - - mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL); - new LLVolumeOctreeListener(mOctree); - - for (U32 i = 0; i < mNumIndices; i+= 3) - { //for each triangle - LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle(); - - const LLVector4a& v0 = mPositions[mIndices[i]]; - const LLVector4a& v1 = mPositions[mIndices[i+1]]; - const LLVector4a& v2 = mPositions[mIndices[i+2]]; - - //store pointers to vertex data - tri->mV[0] = &v0; - tri->mV[1] = &v1; - tri->mV[2] = &v2; - - //store indices - tri->mIndex[0] = mIndices[i]; - tri->mIndex[1] = mIndices[i+1]; - tri->mIndex[2] = mIndices[i+2]; - - //get minimum point - LLVector4a min = v0; - min.setMin(min, v1); - min.setMin(min, v2); - - //get maximum point - LLVector4a max = v0; - max.setMax(max, v1); - max.setMax(max, v2); - - //compute center - LLVector4a center; - center.setAdd(min, max); - center.mul(0.5f); - - tri->mPositionGroup = center; - - //compute "radius" - LLVector4a size; - size.setSub(max,min); - - tri->mRadius = size.getLength3().getF32() * scaler; - - //insert - mOctree->insert(tri); - } - - //remove unneeded octree layers - while (!mOctree->balance()) { } - - //calculate AABB for each node - LLVolumeOctreeRebound rebound(this); - rebound.traverse(mOctree); - - if (gDebugGL) - { - LLVolumeOctreeValidate validate; - validate.traverse(mOctree); - } -} - - -void LLVolumeFace::swapData(LLVolumeFace& rhs) -{ - llswap(rhs.mPositions, mPositions); - llswap(rhs.mNormals, mNormals); - llswap(rhs.mBinormals, mBinormals); - llswap(rhs.mTexCoords, mTexCoords); - llswap(rhs.mIndices,mIndices); - llswap(rhs.mNumVertices, mNumVertices); - llswap(rhs.mNumIndices, mNumIndices); -} - -void LerpPlanarVertex(LLVolumeFace::VertexData& v0, - LLVolumeFace::VertexData& v1, - LLVolumeFace::VertexData& v2, - LLVolumeFace::VertexData& vout, - F32 coef01, - F32 coef02) -{ - - LLVector4a lhs; - lhs.setSub(v1.getPosition(), v0.getPosition()); - lhs.mul(coef01); - LLVector4a rhs; - rhs.setSub(v2.getPosition(), v0.getPosition()); - rhs.mul(coef02); - - rhs.add(lhs); - rhs.add(v0.getPosition()); - - vout.setPosition(rhs); - - vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02); - vout.setNormal(v0.getNormal()); -} - -BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const std::vector<LLVolume::Point>& mesh = volume->getMesh(); - const std::vector<LLVector3>& profile = volume->getProfile().mProfile; - S32 max_s = volume->getProfile().getTotal(); - S32 max_t = volume->getPath().mPath.size(); - - // S32 i; - S32 num_vertices = 0, num_indices = 0; - S32 grid_size = (profile.size()-1)/4; - S32 quad_count = (grid_size * grid_size); - - num_vertices = (grid_size+1)*(grid_size+1); - num_indices = quad_count * 4; - - LLVector4a& min = mExtents[0]; - LLVector4a& max = mExtents[1]; - - S32 offset = 0; - if (mTypeMask & TOP_MASK) - { - offset = (max_t-1) * max_s; - } - else - { - offset = mBeginS; - } - - { - VertexData corners[4]; - VertexData baseVert; - for(S32 t = 0; t < 4; t++) - { - corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV); - corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f; - corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1]; - } - - { - LLVector4a lhs; - lhs.setSub(corners[1].getPosition(), corners[0].getPosition()); - LLVector4a rhs; - rhs.setSub(corners[2].getPosition(), corners[1].getPosition()); - baseVert.getNormal().setCross3(lhs, rhs); - baseVert.getNormal().normalize3fast(); - } - - if(!(mTypeMask & TOP_MASK)) - { - baseVert.getNormal().mul(-1.0f); - } - else - { - //Swap the UVs on the U(X) axis for top face - LLVector2 swap; - swap = corners[0].mTexCoord; - corners[0].mTexCoord=corners[3].mTexCoord; - corners[3].mTexCoord=swap; - swap = corners[1].mTexCoord; - corners[1].mTexCoord=corners[2].mTexCoord; - corners[2].mTexCoord=swap; - } - - LLVector4a binormal; - - calc_binormal_from_triangle( binormal, - corners[0].getPosition(), corners[0].mTexCoord, - corners[1].getPosition(), corners[1].mTexCoord, - corners[2].getPosition(), corners[2].mTexCoord); - - binormal.normalize3fast(); - - S32 size = (grid_size+1)*(grid_size+1); - resizeVertices(size); - allocateBinormals(size); - - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; - LLVector4a* binorm = (LLVector4a*) mBinormals; - LLVector2* tc = (LLVector2*) mTexCoords; - - for(int gx = 0;gx<grid_size+1;gx++) - { - for(int gy = 0;gy<grid_size+1;gy++) - { - VertexData newVert; - LerpPlanarVertex( - corners[0], - corners[1], - corners[3], - newVert, - (F32)gx/(F32)grid_size, - (F32)gy/(F32)grid_size); - - *pos++ = newVert.getPosition(); - *norm++ = baseVert.getNormal(); - *tc++ = newVert.mTexCoord; - *binorm++ = binormal; - - if (gx == 0 && gy == 0) - { - min = newVert.getPosition(); - max = min; - } - else - { - min.setMin(min, newVert.getPosition()); - max.setMax(max, newVert.getPosition()); - } - } - } - - mCenter->setAdd(min, max); - mCenter->mul(0.5f); - } - - if (!partial_build) - { - resizeIndices(grid_size*grid_size*6); - - U16* out = mIndices; - - S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; - for(S32 gx = 0;gx<grid_size;gx++) - { - - for(S32 gy = 0;gy<grid_size;gy++) - { - if (mTypeMask & TOP_MASK) - { - for(S32 i=5;i>=0;i--) - { - *out++ = ((gy*(grid_size+1))+gx+idxs[i]); - } - } - else - { - for(S32 i=0;i<6;i++) - { - *out++ = ((gy*(grid_size+1))+gx+idxs[i]); - } - } - } - } - } - - return TRUE; -} - - -BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if (!(mTypeMask & HOLLOW_MASK) && - !(mTypeMask & OPEN_MASK) && - ((volume->getParams().getPathParams().getBegin()==0.0f)&& - (volume->getParams().getPathParams().getEnd()==1.0f))&& - (volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE && - volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE) - ){ - return createUnCutCubeCap(volume, partial_build); - } - - S32 num_vertices = 0, num_indices = 0; - - const std::vector<LLVolume::Point>& mesh = volume->getMesh(); - const std::vector<LLVector3>& profile = volume->getProfile().mProfile; - - // All types of caps have the same number of vertices and indices - num_vertices = profile.size(); - num_indices = (profile.size() - 2)*3; - - if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) - { - resizeVertices(num_vertices+1); - allocateBinormals(num_vertices+1); - - if (!partial_build) - { - resizeIndices(num_indices+3); - } - } - else - { - resizeVertices(num_vertices); - allocateBinormals(num_vertices); - - if (!partial_build) - { - resizeIndices(num_indices); - } - } - - S32 max_s = volume->getProfile().getTotal(); - S32 max_t = volume->getPath().mPath.size(); - - mCenter->clear(); - - S32 offset = 0; - if (mTypeMask & TOP_MASK) - { - offset = (max_t-1) * max_s; - } - else - { - offset = mBeginS; - } - - // Figure out the normal, assume all caps are flat faces. - // Cross product to get normals. - - LLVector2 cuv; - LLVector2 min_uv, max_uv; - - LLVector4a& min = mExtents[0]; - LLVector4a& max = mExtents[1]; - - LLVector2* tc = (LLVector2*) mTexCoords; - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; - LLVector4a* binorm = (LLVector4a*) mBinormals; - - // Copy the vertices into the array - for (S32 i = 0; i < num_vertices; i++) - { - if (mTypeMask & TOP_MASK) - { - tc[i].mV[0] = profile[i].mV[0]+0.5f; - tc[i].mV[1] = profile[i].mV[1]+0.5f; - } - else - { - // Mirror for underside. - tc[i].mV[0] = profile[i].mV[0]+0.5f; - tc[i].mV[1] = 0.5f - profile[i].mV[1]; - } - - pos[i].load3(mesh[i + offset].mPos.mV); - - if (i == 0) - { - max = pos[i]; - min = max; - min_uv = max_uv = tc[i]; - } - else - { - update_min_max(min,max,pos[i]); - update_min_max(min_uv, max_uv, tc[i]); - } - } - - mCenter->setAdd(min, max); - mCenter->mul(0.5f); - - cuv = (min_uv + max_uv)*0.5f; - - LLVector4a binormal; - calc_binormal_from_triangle(binormal, - *mCenter, cuv, - pos[0], tc[0], - pos[1], tc[1]); - binormal.normalize3fast(); - - LLVector4a normal; - LLVector4a d0, d1; - - - d0.setSub(*mCenter, pos[0]); - d1.setSub(*mCenter, pos[1]); - - if (mTypeMask & TOP_MASK) - { - normal.setCross3(d0, d1); - } - else - { - normal.setCross3(d1, d0); - } - - normal.normalize3fast(); - - VertexData vd; - vd.setPosition(*mCenter); - vd.mTexCoord = cuv; - - if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) - { - pos[num_vertices] = *mCenter; - tc[num_vertices] = cuv; - num_vertices++; - } - - for (S32 i = 0; i < num_vertices; i++) - { - binorm[i].load4a(binormal.getF32ptr()); - norm[i].load4a(normal.getF32ptr()); - } - - if (partial_build) - { - return TRUE; - } - - if (mTypeMask & HOLLOW_MASK) - { - if (mTypeMask & TOP_MASK) - { - // HOLLOW TOP - // Does it matter if it's open or closed? - djs - - S32 pt1 = 0, pt2 = num_vertices - 1; - S32 i = 0; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = profile[pt1]; - LLVector3 p2 = profile[pt2]; - LLVector3 pa = profile[pt1+1]; - LLVector3 pb = profile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - mIndices[i++] = pt1; - mIndices[i++] = pt1 + 1; - mIndices[i++] = pt2; - pt1++; - } - else - { - mIndices[i++] = pt1; - mIndices[i++] = pt2 - 1; - mIndices[i++] = pt2; - pt2--; - } - } - } - else - { - // HOLLOW BOTTOM - // Does it matter if it's open or closed? - djs - - llassert(mTypeMask & BOTTOM_MASK); - S32 pt1 = 0, pt2 = num_vertices - 1; - - S32 i = 0; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = profile[pt1]; - LLVector3 p2 = profile[pt2]; - LLVector3 pa = profile[pt1+1]; - LLVector3 pb = profile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - // Flipped backfacing from top - if (use_tri1a2) - { - mIndices[i++] = pt1; - mIndices[i++] = pt2; - mIndices[i++] = pt1 + 1; - pt1++; - } - else - { - mIndices[i++] = pt1; - mIndices[i++] = pt2; - mIndices[i++] = pt2 - 1; - pt2--; - } - } - } - } - else - { - // Not hollow, generate the triangle fan. - U16 v1 = 2; - U16 v2 = 1; - - if (mTypeMask & TOP_MASK) - { - v1 = 1; - v2 = 2; - } - - for (S32 i = 0; i < (num_vertices - 2); i++) - { - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+v1] = i; - mIndices[3*i+v2] = i + 1; - } - - - } - - return TRUE; -} - -void LLVolumeFace::createBinormals() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if (!mBinormals) - { - allocateBinormals(mNumVertices); - - //generate binormals - LLVector4a* pos = mPositions; - LLVector2* tc = (LLVector2*) mTexCoords; - LLVector4a* binorm = (LLVector4a*) mBinormals; - - LLVector4a* end = mBinormals+mNumVertices; - while (binorm < end) - { - (*binorm++).clear(); - } - - binorm = mBinormals; - - for (U32 i = 0; i < mNumIndices/3; i++) - { //for each triangle - const U16& i0 = mIndices[i*3+0]; - const U16& i1 = mIndices[i*3+1]; - const U16& i2 = mIndices[i*3+2]; - - //calculate binormal - LLVector4a binormal; - calc_binormal_from_triangle(binormal, - pos[i0], tc[i0], - pos[i1], tc[i1], - pos[i2], tc[i2]); - - - //add triangle normal to vertices - binorm[i0].add(binormal); - binorm[i1].add(binormal); - binorm[i2].add(binormal); - - //even out quad contributions - if (i % 2 == 0) - { - binorm[i2].add(binormal); - } - else - { - binorm[i1].add(binormal); - } - } - - //normalize binormals - for (U32 i = 0; i < mNumVertices; i++) - { - binorm[i].normalize3fast(); - //bump map/planar projection code requires normals to be normalized - mNormals[i].normalize3fast(); - } - } -} - -void LLVolumeFace::resizeVertices(S32 num_verts) -{ - free(mPositions); - free(mNormals); - free(mBinormals); - free(mTexCoords); - - mBinormals = NULL; - - if (num_verts) - { - mPositions = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - assert_aligned(mPositions, 16); - mNormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - assert_aligned(mNormals, 16); - - //pad texture coordinate block end to allow for QWORD reads - S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; - mTexCoords = (LLVector2*) malloc(size); - assert_aligned(mTexCoords, 16); - } - else - { - mPositions = NULL; - mNormals = NULL; - mTexCoords = NULL; - } - - mNumVertices = num_verts; -} - -void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv) -{ - pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord); -} - -void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc) -{ - S32 new_verts = mNumVertices+1; - S32 new_size = new_verts*16; -// S32 old_size = mNumVertices*16; - - //positions - mPositions = (LLVector4a*) realloc(mPositions, new_size); - - //normals - mNormals = (LLVector4a*) realloc(mNormals, new_size); - - //tex coords - new_size = ((new_verts*8)+0xF) & ~0xF; - mTexCoords = (LLVector2*) realloc(mTexCoords, new_size); - - - //just clear binormals - free(mBinormals); - mBinormals = NULL; - - mPositions[mNumVertices] = pos; - mNormals[mNumVertices] = norm; - mTexCoords[mNumVertices] = tc; - - mNumVertices++; -} - -void LLVolumeFace::allocateBinormals(S32 num_verts) -{ - free(mBinormals); - mBinormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); -} - -void LLVolumeFace::allocateWeights(S32 num_verts) -{ - free(mWeights); - mWeights = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); -} - -void LLVolumeFace::resizeIndices(S32 num_indices) -{ - free(mIndices); - - if (num_indices) - { - //pad index block end to allow for QWORD reads - S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF; - - mIndices = (U16*) malloc(size); - } - else - { - mIndices = NULL; - } - - mNumIndices = num_indices; -} - -void LLVolumeFace::pushIndex(const U16& idx) -{ - S32 new_count = mNumIndices + 1; - S32 new_size = ((new_count*2)+0xF) & ~0xF; - - S32 old_size = ((mNumIndices*2)+0xF) & ~0xF; - if (new_size != old_size) - { - mIndices = (U16*) realloc(mIndices, new_size); - } - - mIndices[mNumIndices++] = idx; -} - -void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx) -{ - resizeVertices(v.size()); - resizeIndices(idx.size()); - - for (U32 i = 0; i < v.size(); ++i) - { - mPositions[i] = v[i].getPosition(); - mNormals[i] = v[i].getNormal(); - mTexCoords[i] = v[i].mTexCoord; - } - - for (U32 i = 0; i < idx.size(); ++i) - { - mIndices[i] = idx[i]; - } -} - -void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in) -{ - U16 offset = mNumVertices; - - S32 new_count = face.mNumVertices + mNumVertices; - - if (new_count > 65536) - { - llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl; - } - - if (face.mNumVertices == 0) - { - llerrs << "Cannot append empty face." << llendl; - } - - //allocate new buffer space - mPositions = (LLVector4a*) realloc(mPositions, new_count*sizeof(LLVector4a)); - assert_aligned(mPositions, 16); - mNormals = (LLVector4a*) realloc(mNormals, new_count*sizeof(LLVector4a)); - assert_aligned(mNormals, 16); - mTexCoords = (LLVector2*) realloc(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF); - assert_aligned(mTexCoords, 16); - - mNumVertices = new_count; - - //get destination address of appended face - LLVector4a* dst_pos = mPositions+offset; - LLVector2* dst_tc = mTexCoords+offset; - LLVector4a* dst_norm = mNormals+offset; - - //get source addresses of appended face - const LLVector4a* src_pos = face.mPositions; - const LLVector2* src_tc = face.mTexCoords; - const LLVector4a* src_norm = face.mNormals; - - //load aligned matrices - LLMatrix4a mat, norm_mat; - mat.loadu(mat_in); - norm_mat.loadu(norm_mat_in); - - for (U32 i = 0; i < face.mNumVertices; ++i) - { - //transform appended face position and store - mat.affineTransform(src_pos[i], dst_pos[i]); - - //transform appended face normal and store - norm_mat.rotate(src_norm[i], dst_norm[i]); - dst_norm[i].normalize3fast(); - - //copy appended face texture coordinate - dst_tc[i] = src_tc[i]; - - if (offset == 0 && i == 0) - { //initialize bounding box - mExtents[0] = mExtents[1] = dst_pos[i]; - } - else - { - //stretch bounding box - update_min_max(mExtents[0], mExtents[1], dst_pos[i]); - } - } - - - new_count = mNumIndices + face.mNumIndices; - - //allocate new index buffer - mIndices = (U16*) realloc(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF); - - //get destination address into new index buffer - U16* dst_idx = mIndices+mNumIndices; - mNumIndices = new_count; - - for (U32 i = 0; i < face.mNumIndices; ++i) - { //copy indices, offsetting by old vertex count - dst_idx[i] = face.mIndices[i]+offset; - } -} - -BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - BOOL flat = mTypeMask & FLAT_MASK; - - U8 sculpt_type = volume->getParams().getSculptType(); - U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - BOOL sculpt_reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR - - S32 num_vertices, num_indices; - - const std::vector<LLVolume::Point>& mesh = volume->getMesh(); - const std::vector<LLVector3>& profile = volume->getProfile().mProfile; - const std::vector<LLPath::PathPt>& path_data = volume->getPath().mPath; - - S32 max_s = volume->getProfile().getTotal(); - - S32 s, t, i; - F32 ss, tt; - - num_vertices = mNumS*mNumT; - num_indices = (mNumS-1)*(mNumT-1)*6; - - if (!partial_build) - { - resizeVertices(num_vertices); - resizeIndices(num_indices); - - if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) - { - mEdge.resize(num_indices); - } - } - - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; - LLVector2* tc = (LLVector2*) mTexCoords; - S32 begin_stex = llfloor( profile[mBeginS].mV[2] ); - S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; - - S32 cur_vertex = 0; - // Copy the vertices into the array - for (t = mBeginT; t < mBeginT + mNumT; t++) - { - tt = path_data[t].mTexT; - for (s = 0; s < num_s; s++) - { - if (mTypeMask & END_MASK) - { - if (s) - { - ss = 1.f; - } - else - { - ss = 0.f; - } - } - else - { - // Get s value for tex-coord. - if (!flat) - { - ss = profile[mBeginS + s].mV[2]; - } - else - { - ss = profile[mBeginS + s].mV[2] - begin_stex; - } - } - - if (sculpt_reverse_horizontal) - { - ss = 1.f - ss; - } - - // Check to see if this triangle wraps around the array. - if (mBeginS + s >= max_s) - { - // We're wrapping - i = mBeginS + s + max_s*(t-1); - } - else - { - i = mBeginS + s + max_s*t; - } - - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); - - norm[cur_vertex].clear(); - cur_vertex++; - - if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0) - { - - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); - - norm[cur_vertex].clear(); - - cur_vertex++; - } - } - - if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) - { - if (mTypeMask & OPEN_MASK) - { - s = num_s-1; - } - else - { - s = 0; - } - - i = mBeginS + s + max_s*t; - ss = profile[mBeginS + s].mV[2] - begin_stex; - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); - norm[cur_vertex].clear(); - - cur_vertex++; - } - } - - - //get bounding box for this side - LLVector4a& face_min = mExtents[0]; - LLVector4a& face_max = mExtents[1]; - mCenter->clear(); - - face_min = face_max = pos[0]; - - for (U32 i = 1; i < mNumVertices; ++i) - { - update_min_max(face_min, face_max, pos[i]); - } - - mCenter->setAdd(face_min, face_max); - mCenter->mul(0.5f); - - S32 cur_index = 0; - S32 cur_edge = 0; - BOOL flat_face = mTypeMask & FLAT_MASK; - - if (!partial_build) - { - // Now we generate the indices. - for (t = 0; t < (mNumT-1); t++) - { - for (s = 0; s < (mNumS-1); s++) - { - mIndices[cur_index++] = s + mNumS*t; //bottom left - mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right - mIndices[cur_index++] = s + mNumS*(t+1); //top left - mIndices[cur_index++] = s + mNumS*t; //bottom left - mIndices[cur_index++] = s+1 + mNumS*t; //bottom right - mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right - - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face - if (t < mNumT-2) { //top right/top left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; - } - else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor - mEdge[cur_edge++] = -1; - } - else { //wrap on T - mEdge[cur_edge++] = s*2+1; - } - if (s > 0) { //top left/bottom left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; - } - else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor - mEdge[cur_edge++] = -1; - } - else { //wrap on S - mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1; - } - - if (t > 0) { //bottom left/bottom right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; - } - else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor - mEdge[cur_edge++] = -1; - } - else { //wrap on T - mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2; - } - if (s < mNumS-2) { //bottom right/top right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; - } - else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor - mEdge[cur_edge++] = -1; - } - else { //wrap on S - mEdge[cur_edge++] = (mNumS-1)*2*t; - } - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face - } - } - } - - //clear normals - for (U32 i = 0; i < mNumVertices; i++) - { - mNormals[i].clear(); - } - - //generate normals - for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle - { - const U16* idx = &(mIndices[i*3]); - - - LLVector4a* v[] = - { pos+idx[0], pos+idx[1], pos+idx[2] }; - - LLVector4a* n[] = - { norm+idx[0], norm+idx[1], norm+idx[2] }; - - //calculate triangle normal - LLVector4a a, b, c; - - a.setSub(*v[0], *v[1]); - b.setSub(*v[0], *v[2]); - c.setCross3(a,b); - - n[0]->add(c); - n[1]->add(c); - n[2]->add(c); - - //even out quad contributions - n[i%2+1]->add(c); - } - - // adjust normals based on wrapping and stitching - - LLVector4a top; - top.setSub(pos[0], pos[mNumS*(mNumT-2)]); - BOOL s_bottom_converges = (top.dot3(top) < 0.000001f); - - top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]); - BOOL s_top_converges = (top.dot3(top) < 0.000001f); - - if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes - { - if (volume->getPath().isOpen() == FALSE) - { //wrap normals on T - for (S32 i = 0; i < mNumS; i++) - { - LLVector4a n; - n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); - norm[i] = n; - norm[mNumS*(mNumT-1)+i] = n; - } - } - - if ((volume->getProfile().isOpen() == FALSE) && !(s_bottom_converges)) - { //wrap normals on S - for (S32 i = 0; i < mNumT; i++) - { - LLVector4a n; - n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); - norm[mNumS * i] = n; - norm[mNumS * i+mNumS-1] = n; - } - } - - if (volume->getPathType() == LL_PCODE_PATH_CIRCLE && - ((volume->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) - { - if (s_bottom_converges) - { //all lower S have same normal - for (S32 i = 0; i < mNumT; i++) - { - norm[mNumS*i].set(1,0,0); - } - } - - if (s_top_converges) - { //all upper S have same normal - for (S32 i = 0; i < mNumT; i++) - { - norm[mNumS*i+mNumS-1].set(-1,0,0); - } - } - } - } - else // logic for sculpt volumes - { - BOOL average_poles = FALSE; - BOOL wrap_s = FALSE; - BOOL wrap_t = FALSE; - - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - average_poles = TRUE; - - if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || - (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || - (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) - wrap_s = TRUE; - - if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) - wrap_t = TRUE; - - - if (average_poles) - { - // average normals for north pole - - LLVector4a average; - average.clear(); - - for (S32 i = 0; i < mNumS; i++) - { - average.add(norm[i]); - } - - // set average - for (S32 i = 0; i < mNumS; i++) - { - norm[i] = average; - } - - // average normals for south pole - - average.clear(); - - for (S32 i = 0; i < mNumS; i++) - { - average.add(norm[i + mNumS * (mNumT - 1)]); - } - - // set average - for (S32 i = 0; i < mNumS; i++) - { - norm[i + mNumS * (mNumT - 1)] = average; - } - - } - - - if (wrap_s) - { - for (S32 i = 0; i < mNumT; i++) - { - LLVector4a n; - n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); - norm[mNumS * i] = n; - norm[mNumS * i+mNumS-1] = n; - } - } - - if (wrap_t) - { - for (S32 i = 0; i < mNumS; i++) - { - LLVector4a n; - n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); - norm[i] = n; - norm[mNumS*(mNumT-1)+i] = n; - } - } - - } - - return TRUE; -} - -// Finds binormal based on three vertices with texture coordinates. -// Fills in dummy values if the triangle has degenerate texture coordinates. -void calc_binormal_from_triangle(LLVector4a& binormal, - - const LLVector4a& pos0, - const LLVector2& tex0, - const LLVector4a& pos1, - const LLVector2& tex1, - const LLVector4a& pos2, - const LLVector2& tex2) -{ - LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a lhs, rhs; - - LLVector4a r0; - lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2); - r0.setCross3(lhs, rhs); - - LLVector4a r1; - lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2); - r1.setCross3(lhs, rhs); - - LLVector4a r2; - lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2); - r2.setCross3(lhs, rhs); - - if( r0[VX] && r1[VX] && r2[VX] ) - { - binormal.set( - -r0[VZ] / r0[VX], - -r1[VZ] / r1[VX], - -r2[VZ] / r2[VX]); - // binormal.normVec(); - } - else - { - binormal.set( 0, 1 , 0 ); - } -} +/**
+
+ * @file llvolume.cpp
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llmemory.h"
+#include "llmath.h"
+
+#include <set>
+#if !LL_WINDOWS
+#include <stdint.h>
+#endif
+
+#include "llerror.h"
+#include "llmemtype.h"
+
+#include "llvolumemgr.h"
+#include "v2math.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "m4math.h"
+#include "m3math.h"
+#include "llmatrix3a.h"
+#include "lloctree.h"
+#include "lldarray.h"
+#include "llvolume.h"
+#include "llvolumeoctree.h"
+#include "llstl.h"
+#include "llsdserialize.h"
+#include "llvector4a.h"
+#include "llmatrix4a.h"
+
+#define DEBUG_SILHOUETTE_BINORMALS 0
+#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
+#define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette
+
+const F32 CUT_MIN = 0.f;
+const F32 CUT_MAX = 1.f;
+const F32 MIN_CUT_DELTA = 0.02f;
+
+const F32 HOLLOW_MIN = 0.f;
+const F32 HOLLOW_MAX = 0.95f;
+const F32 HOLLOW_MAX_SQUARE = 0.7f;
+
+const F32 TWIST_MIN = -1.f;
+const F32 TWIST_MAX = 1.f;
+
+const F32 RATIO_MIN = 0.f;
+const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper
+
+const F32 HOLE_X_MIN= 0.05f;
+const F32 HOLE_X_MAX= 1.0f;
+
+const F32 HOLE_Y_MIN= 0.05f;
+const F32 HOLE_Y_MAX= 0.5f;
+
+const F32 SHEAR_MIN = -0.5f;
+const F32 SHEAR_MAX = 0.5f;
+
+const F32 REV_MIN = 1.f;
+const F32 REV_MAX = 4.f;
+
+const F32 TAPER_MIN = -1.f;
+const F32 TAPER_MAX = 1.f;
+
+const F32 SKEW_MIN = -0.95f;
+const F32 SKEW_MAX = 0.95f;
+
+const F32 SCULPT_MIN_AREA = 0.002f;
+const S32 SCULPT_MIN_AREA_DETAIL = 1;
+
+extern BOOL gDebugGL;
+
+void assert_aligned(void* ptr, uintptr_t alignment)
+{
+#if 0
+ uintptr_t t = (uintptr_t) ptr;
+ if (t%alignment != 0)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+#endif
+}
+
+BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
+{
+ LLVector3 test = (pt2-pt1)%(pt3-pt2);
+
+ //answer
+ if(test * norm < 0)
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
+{
+ return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV);
+}
+
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size)
+{
+ F32 fAWdU[3];
+ F32 dir[3];
+ F32 diff[3];
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ dir[i] = 0.5f * (end[i] - start[i]);
+ diff[i] = (0.5f * (end[i] + start[i])) - center[i];
+ fAWdU[i] = fabsf(dir[i]);
+ if(fabsf(diff[i])>size[i] + fAWdU[i]) return false;
+ }
+
+ float f;
+ f = dir[1] * diff[2] - dir[2] * diff[1]; if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1]) return false;
+ f = dir[2] * diff[0] - dir[0] * diff[2]; if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0]) return false;
+ f = dir[0] * diff[1] - dir[1] * diff[0]; if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0]) return false;
+
+ return true;
+}
+
+
+
+// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
+// returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b,
+// and returns the intersection point along dir in intersection_t.
+
+// Moller-Trumbore algorithm
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t)
+{
+
+ /* find vectors for two edges sharing vert0 */
+ LLVector4a edge1;
+ edge1.setSub(vert1, vert0);
+
+ LLVector4a edge2;
+ edge2.setSub(vert2, vert0);
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ LLVector4a pvec;
+ pvec.setCross3(dir, edge2);
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ LLVector4a det;
+ det.setAllDot3(edge1, pvec);
+
+ if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7)
+ {
+ /* calculate distance from vert0 to ray origin */
+ LLVector4a tvec;
+ tvec.setSub(orig, vert0);
+
+ /* calculate U parameter and test bounds */
+ LLVector4a u;
+ u.setAllDot3(tvec,pvec);
+
+ if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) &&
+ (u.lessEqual(det).getGatheredBits() & 0x7))
+ {
+ /* prepare to test V parameter */
+ LLVector4a qvec;
+ qvec.setCross3(tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ LLVector4a v;
+ v.setAllDot3(dir, qvec);
+
+
+ //if (!(v < 0.f || u + v > det))
+
+ LLVector4a sum_uv;
+ sum_uv.setAdd(u, v);
+
+ S32 v_gequal = v.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7;
+ S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 0x7;
+
+ if (v_gequal && sum_lequal)
+ {
+ /* calculate t, scale parameters, ray intersects triangle */
+ LLVector4a t;
+ t.setAllDot3(edge2,qvec);
+
+ t.div(det);
+ u.div(det);
+ v.div(det);
+
+ intersection_a = u[0];
+ intersection_b = v[0];
+ intersection_t = t[0];
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t)
+{
+ F32 u, v, t;
+
+ /* find vectors for two edges sharing vert0 */
+ LLVector4a edge1;
+ edge1.setSub(vert1, vert0);
+
+
+ LLVector4a edge2;
+ edge2.setSub(vert2, vert0);
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ LLVector4a pvec;
+ pvec.setCross3(dir, edge2);
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ F32 det = edge1.dot3(pvec).getF32();
+
+
+ if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
+ {
+ return FALSE;
+ }
+
+ F32 inv_det = 1.f / det;
+
+ /* calculate distance from vert0 to ray origin */
+ LLVector4a tvec;
+ tvec.setSub(orig, vert0);
+
+ /* calculate U parameter and test bounds */
+ u = (tvec.dot3(pvec).getF32()) * inv_det;
+ if (u < 0.f || u > 1.f)
+ {
+ return FALSE;
+ }
+
+ /* prepare to test V parameter */
+ tvec.sub(edge1);
+
+ /* calculate V parameter and test bounds */
+ v = (dir.dot3(tvec).getF32()) * inv_det;
+
+ if (v < 0.f || u + v > 1.f)
+ {
+ return FALSE;
+ }
+
+ /* calculate t, ray intersects triangle */
+ t = (edge2.dot3(tvec).getF32()) * inv_det;
+
+ intersection_a = u;
+ intersection_b = v;
+ intersection_t = t;
+
+
+ return TRUE;
+}
+
+//helper for non-aligned vectors
+BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided)
+{
+ LLVector4a vert0a, vert1a, vert2a, origa, dira;
+ vert0a.load3(vert0.mV);
+ vert1a.load3(vert1.mV);
+ vert2a.load3(vert2.mV);
+ origa.load3(orig.mV);
+ dira.load3(dir.mV);
+
+ if (two_sided)
+ {
+ return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira,
+ intersection_a, intersection_b, intersection_t);
+ }
+ else
+ {
+ return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira,
+ intersection_a, intersection_b, intersection_t);
+ }
+}
+
+class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
+{
+public:
+ const LLVolumeFace* mFace;
+
+ LLVolumeOctreeRebound(const LLVolumeFace* face)
+ {
+ mFace = face;
+ }
+
+ virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+ { //this is a depth first traversal, so it's safe to assum all children have complete
+ //bounding data
+
+ LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ LLVector4a& min = node->mExtents[0];
+ LLVector4a& max = node->mExtents[1];
+
+ if (!branch->getData().empty())
+ { //node has data, find AABB that binds data set
+ const LLVolumeTriangle* tri = *(branch->getData().begin());
+
+ //initialize min/max to first available vertex
+ min = *(tri->mV[0]);
+ max = *(tri->mV[0]);
+
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
+ branch->getData().begin(); iter != branch->getData().end(); ++iter)
+ { //for each triangle in node
+
+ //stretch by triangles in node
+ tri = *iter;
+
+ min.setMin(min, *tri->mV[0]);
+ min.setMin(min, *tri->mV[1]);
+ min.setMin(min, *tri->mV[2]);
+
+ max.setMax(max, *tri->mV[0]);
+ max.setMax(max, *tri->mV[1]);
+ max.setMax(max, *tri->mV[2]);
+ }
+ }
+ else if (!branch->getChildren().empty())
+ { //no data, but child nodes exist
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
+
+ //initialize min/max to extents of first child
+ min = child->mExtents[0];
+ max = child->mExtents[1];
+ }
+ else
+ {
+ llerrs << "WTF? Empty leaf" << llendl;
+ }
+
+ for (S32 i = 0; i < branch->getChildCount(); ++i)
+ { //stretch by child extents
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+ min.setMin(min, child->mExtents[0]);
+ max.setMax(max, child->mExtents[1]);
+ }
+
+ node->mBounds[0].setAdd(min, max);
+ node->mBounds[0].mul(0.5f);
+
+ node->mBounds[1].setSub(max,min);
+ node->mBounds[1].mul(0.5f);
+ }
+};
+
+//-------------------------------------------------------------------
+// statics
+//-------------------------------------------------------------------
+
+
+//----------------------------------------------------
+
+LLProfile::Face* LLProfile::addCap(S16 faceID)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ Face *face = vector_append(mFaces, 1);
+
+ face->mIndex = 0;
+ face->mCount = mTotal;
+ face->mScaleU= 1.0f;
+ face->mCap = TRUE;
+ face->mFaceID = faceID;
+ return face;
+}
+
+LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ Face *face = vector_append(mFaces, 1);
+
+ face->mIndex = i;
+ face->mCount = count;
+ face->mScaleU= scaleU;
+
+ face->mFlat = flat;
+ face->mCap = FALSE;
+ face->mFaceID = faceID;
+ return face;
+}
+
+// What is the bevel parameter used for? - DJS 04/05/02
+// Bevel parameter is currently unused but presumedly would support
+// filleted and chamfered corners
+void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ // Generate an n-sided "circular" path.
+ // 0 is (1,0), and we go counter-clockwise along a circular path from there.
+ const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
+ F32 scale = 0.5f;
+ F32 t, t_step, t_first, t_fraction, ang, ang_step;
+ LLVector3 pt1,pt2;
+
+ F32 begin = params.getBegin();
+ F32 end = params.getEnd();
+
+ t_step = 1.0f / sides;
+ ang_step = 2.0f*F_PI*t_step*ang_scale;
+
+ // Scale to have size "match" scale. Compensates to get object to generally fill bounding box.
+
+ S32 total_sides = llround(sides / ang_scale); // Total number of sides all around
+
+ if (total_sides < 8)
+ {
+ scale = tableScale[total_sides];
+ }
+
+ t_first = floor(begin * sides) / (F32)sides;
+
+ // pt1 is the first point on the fractional face.
+ // Starting t and ang values for the first face
+ t = t_first;
+ ang = 2.0f*F_PI*(t*ang_scale + offset);
+ pt1.setVec(cos(ang)*scale,sin(ang)*scale, t);
+
+ // Increment to the next point.
+ // pt2 is the end point on the fractional face
+ t += t_step;
+ ang += ang_step;
+ pt2.setVec(cos(ang)*scale,sin(ang)*scale,t);
+
+ t_fraction = (begin - t_first)*sides;
+
+ // Only use if it's not almost exactly on an edge.
+ if (t_fraction < 0.9999f)
+ {
+ LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
+ mProfile.push_back(new_pt);
+ }
+
+ // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02
+ while (t < end)
+ {
+ // Iterate through all the integer steps of t.
+ pt1.setVec(cos(ang)*scale,sin(ang)*scale,t);
+
+ if (mProfile.size() > 0) {
+ LLVector3 p = mProfile[mProfile.size()-1];
+ for (S32 i = 0; i < split && mProfile.size() > 0; i++) {
+ mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1));
+ }
+ }
+ mProfile.push_back(pt1);
+
+ t += t_step;
+ ang += ang_step;
+ }
+
+ t_fraction = (end - (t - t_step))*sides;
+
+ // pt1 is the first point on the fractional face
+ // pt2 is the end point on the fractional face
+ pt2.setVec(cos(ang)*scale,sin(ang)*scale,t);
+
+ // Find the fraction that we need to add to the end point.
+ t_fraction = (end - (t - t_step))*sides;
+ if (t_fraction > 0.0001f)
+ {
+ LLVector3 new_pt = lerp(pt1, pt2, t_fraction);
+
+ if (mProfile.size() > 0) {
+ LLVector3 p = mProfile[mProfile.size()-1];
+ for (S32 i = 0; i < split && mProfile.size() > 0; i++) {
+ mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1));
+ }
+ }
+ mProfile.push_back(new_pt);
+ }
+
+ // If we're sliced, the profile is open.
+ if ((end - begin)*ang_scale < 0.99f)
+ {
+ if ((end - begin)*ang_scale > 0.5f)
+ {
+ mConcave = TRUE;
+ }
+ else
+ {
+ mConcave = FALSE;
+ }
+ mOpen = TRUE;
+ if (params.getHollow() <= 0)
+ {
+ // put center point if not hollow.
+ mProfile.push_back(LLVector3(0,0,0));
+ }
+ }
+ else
+ {
+ // The profile isn't open.
+ mOpen = FALSE;
+ mConcave = FALSE;
+ }
+
+ mTotal = mProfile.size();
+}
+
+void LLProfile::genNormals(const LLProfileParams& params)
+{
+ S32 count = mProfile.size();
+
+ S32 outer_count;
+ if (mTotalOut)
+ {
+ outer_count = mTotalOut;
+ }
+ else
+ {
+ outer_count = mTotal / 2;
+ }
+
+ mEdgeNormals.resize(count * 2);
+ mEdgeCenters.resize(count * 2);
+ mNormals.resize(count);
+
+ LLVector2 pt0,pt1;
+
+ BOOL hollow = (params.getHollow() > 0);
+
+ S32 i0, i1, i2, i3, i4;
+
+ // Parametrically generate normal
+ for (i2 = 0; i2 < count; i2++)
+ {
+ mNormals[i2].mV[0] = mProfile[i2].mV[0];
+ mNormals[i2].mV[1] = mProfile[i2].mV[1];
+ if (hollow && (i2 >= outer_count))
+ {
+ mNormals[i2] *= -1.f;
+ }
+ if (mNormals[i2].magVec() < 0.001)
+ {
+ // Special case for point at center, get adjacent points.
+ i1 = (i2 - 1) >= 0 ? i2 - 1 : count - 1;
+ i0 = (i1 - 1) >= 0 ? i1 - 1 : count - 1;
+ i3 = (i2 + 1) < count ? i2 + 1 : 0;
+ i4 = (i3 + 1) < count ? i3 + 1 : 0;
+
+ pt0.setVec(mProfile[i1].mV[VX] + mProfile[i1].mV[VX] - mProfile[i0].mV[VX],
+ mProfile[i1].mV[VY] + mProfile[i1].mV[VY] - mProfile[i0].mV[VY]);
+ pt1.setVec(mProfile[i3].mV[VX] + mProfile[i3].mV[VX] - mProfile[i4].mV[VX],
+ mProfile[i3].mV[VY] + mProfile[i3].mV[VY] - mProfile[i4].mV[VY]);
+
+ mNormals[i2] = pt0 + pt1;
+ mNormals[i2] *= 0.5f;
+ }
+ mNormals[i2].normVec();
+ }
+
+ S32 num_normal_sets = isConcave() ? 2 : 1;
+ for (S32 normal_set = 0; normal_set < num_normal_sets; normal_set++)
+ {
+ S32 point_num;
+ for (point_num = 0; point_num < mTotal; point_num++)
+ {
+ LLVector3 point_1 = mProfile[point_num];
+ point_1.mV[VZ] = 0.f;
+
+ LLVector3 point_2;
+
+ if (isConcave() && normal_set == 0 && point_num == (mTotal - 1) / 2)
+ {
+ point_2 = mProfile[mTotal - 1];
+ }
+ else if (isConcave() && normal_set == 1 && point_num == mTotal - 1)
+ {
+ point_2 = mProfile[(mTotal - 1) / 2];
+ }
+ else
+ {
+ LLVector3 delta_pos;
+ S32 neighbor_point = (point_num + 1) % mTotal;
+ while(delta_pos.magVecSquared() < 0.01f * 0.01f)
+ {
+ point_2 = mProfile[neighbor_point];
+ delta_pos = point_2 - point_1;
+ neighbor_point = (neighbor_point + 1) % mTotal;
+ if (neighbor_point == point_num)
+ {
+ break;
+ }
+ }
+ }
+
+ point_2.mV[VZ] = 0.f;
+ LLVector3 face_normal = (point_2 - point_1) % LLVector3::z_axis;
+ face_normal.normVec();
+ mEdgeNormals[normal_set * count + point_num] = face_normal;
+ mEdgeCenters[normal_set * count + point_num] = lerp(point_1, point_2, 0.5f);
+ }
+ }
+}
+
+
+// Hollow is percent of the original bounding box, not of this particular
+// profile's geometry. Thus, a swept triangle needs lower hollow values than
+// a swept square.
+LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split)
+{
+ // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them.
+
+ // Total add has number of vertices on outside.
+ mTotalOut = mTotal;
+
+ // Why is the "bevel" parameter -1? DJS 04/05/02
+ genNGon(params, llfloor(sides),offset,-1, ang_scale, split);
+
+ Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat);
+
+ std::vector<LLVector3> pt;
+ pt.resize(mTotal) ;
+
+ for (S32 i=mTotalOut;i<mTotal;i++)
+ {
+ pt[i] = mProfile[i] * box_hollow;
+ }
+
+ S32 j=mTotal-1;
+ for (S32 i=mTotalOut;i<mTotal;i++)
+ {
+ mProfile[i] = pt[j--];
+ }
+
+ for (S32 i=0;i<(S32)mFaces.size();i++)
+ {
+ if (mFaces[i].mCap)
+ {
+ mFaces[i].mCount *= 2;
+ }
+ }
+
+ return face;
+}
+
+
+
+BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split,
+ BOOL is_sculpted, S32 sculpt_size)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ if ((!mDirty) && (!is_sculpted))
+ {
+ return FALSE;
+ }
+ mDirty = FALSE;
+
+ if (detail < MIN_LOD)
+ {
+ llinfos << "Generating profile with LOD < MIN_LOD. CLAMPING" << llendl;
+ detail = MIN_LOD;
+ }
+
+ mProfile.clear();
+ mFaces.clear();
+
+ // Generate the face data
+ S32 i;
+ F32 begin = params.getBegin();
+ F32 end = params.getEnd();
+ F32 hollow = params.getHollow();
+
+ // Quick validation to eliminate some server crashes.
+ if (begin > end - 0.01f)
+ {
+ llwarns << "LLProfile::generate() assertion failed (begin >= end)" << llendl;
+ return FALSE;
+ }
+
+ S32 face_num = 0;
+
+ switch (params.getCurveType() & LL_PCODE_PROFILE_MASK)
+ {
+ case LL_PCODE_PROFILE_SQUARE:
+ {
+ genNGon(params, 4,-0.375, 0, 1, split);
+ if (path_open)
+ {
+ addCap (LL_FACE_PATH_BEGIN);
+ }
+
+ for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++)
+ {
+ addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE);
+ }
+
+ for (i = 0; i <(S32) mProfile.size(); i++)
+ {
+ // Scale by 4 to generate proper tex coords.
+ mProfile[i].mV[2] *= 4.f;
+ }
+
+ if (hollow)
+ {
+ switch (params.getCurveType() & LL_PCODE_HOLE_MASK)
+ {
+ case LL_PCODE_HOLE_TRIANGLE:
+ // This offset is not correct, but we can't change it now... DK 11/17/04
+ addHole(params, TRUE, 3, -0.375f, hollow, 1.f, split);
+ break;
+ case LL_PCODE_HOLE_CIRCLE:
+ // TODO: Compute actual detail levels for cubes
+ addHole(params, FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f);
+ break;
+ case LL_PCODE_HOLE_SAME:
+ case LL_PCODE_HOLE_SQUARE:
+ default:
+ addHole(params, TRUE, 4, -0.375f, hollow, 1.f, split);
+ break;
+ }
+ }
+
+ if (path_open) {
+ mFaces[0].mCount = mTotal;
+ }
+ }
+ break;
+ case LL_PCODE_PROFILE_ISOTRI:
+ case LL_PCODE_PROFILE_RIGHTTRI:
+ case LL_PCODE_PROFILE_EQUALTRI:
+ {
+ genNGon(params, 3,0, 0, 1, split);
+ for (i = 0; i <(S32) mProfile.size(); i++)
+ {
+ // Scale by 3 to generate proper tex coords.
+ mProfile[i].mV[2] *= 3.f;
+ }
+
+ if (path_open)
+ {
+ addCap(LL_FACE_PATH_BEGIN);
+ }
+
+ for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++)
+ {
+ addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE);
+ }
+ if (hollow)
+ {
+ // Swept triangles need smaller hollowness values,
+ // because the triangle doesn't fill the bounding box.
+ F32 triangle_hollow = hollow / 2.f;
+
+ switch (params.getCurveType() & LL_PCODE_HOLE_MASK)
+ {
+ case LL_PCODE_HOLE_CIRCLE:
+ // TODO: Actually generate level of detail for triangles
+ addHole(params, FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f);
+ break;
+ case LL_PCODE_HOLE_SQUARE:
+ addHole(params, TRUE, 4, 0, triangle_hollow, 1.f, split);
+ break;
+ case LL_PCODE_HOLE_SAME:
+ case LL_PCODE_HOLE_TRIANGLE:
+ default:
+ addHole(params, TRUE, 3, 0, triangle_hollow, 1.f, split);
+ break;
+ }
+ }
+ }
+ break;
+ case LL_PCODE_PROFILE_CIRCLE:
+ {
+ // If this has a square hollow, we should adjust the
+ // number of faces a bit so that the geometry lines up.
+ U8 hole_type=0;
+ F32 circle_detail = MIN_DETAIL_FACES * detail;
+ if (hollow)
+ {
+ hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK;
+ if (hole_type == LL_PCODE_HOLE_SQUARE)
+ {
+ // Snap to the next multiple of four sides,
+ // so that corners line up.
+ circle_detail = llceil(circle_detail / 4.0f) * 4.0f;
+ }
+ }
+
+ S32 sides = (S32)circle_detail;
+
+ if (is_sculpted)
+ sides = sculpt_size;
+
+ genNGon(params, sides);
+
+ if (path_open)
+ {
+ addCap (LL_FACE_PATH_BEGIN);
+ }
+
+ if (mOpen && !hollow)
+ {
+ addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE);
+ }
+ else
+ {
+ addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE);
+ }
+
+ if (hollow)
+ {
+ switch (hole_type)
+ {
+ case LL_PCODE_HOLE_SQUARE:
+ addHole(params, TRUE, 4, 0, hollow, 1.f, split);
+ break;
+ case LL_PCODE_HOLE_TRIANGLE:
+ addHole(params, TRUE, 3, 0, hollow, 1.f, split);
+ break;
+ case LL_PCODE_HOLE_CIRCLE:
+ case LL_PCODE_HOLE_SAME:
+ default:
+ addHole(params, FALSE, circle_detail, 0, hollow, 1.f);
+ break;
+ }
+ }
+ }
+ break;
+ case LL_PCODE_PROFILE_CIRCLE_HALF:
+ {
+ // If this has a square hollow, we should adjust the
+ // number of faces a bit so that the geometry lines up.
+ U8 hole_type=0;
+ // Number of faces is cut in half because it's only a half-circle.
+ F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f;
+ if (hollow)
+ {
+ hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK;
+ if (hole_type == LL_PCODE_HOLE_SQUARE)
+ {
+ // Snap to the next multiple of four sides (div 2),
+ // so that corners line up.
+ circle_detail = llceil(circle_detail / 2.0f) * 2.0f;
+ }
+ }
+ genNGon(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f);
+ if (path_open)
+ {
+ addCap(LL_FACE_PATH_BEGIN);
+ }
+ if (mOpen && !params.getHollow())
+ {
+ addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE);
+ }
+ else
+ {
+ addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE);
+ }
+
+ if (hollow)
+ {
+ switch (hole_type)
+ {
+ case LL_PCODE_HOLE_SQUARE:
+ addHole(params, TRUE, 2, 0.5f, hollow, 0.5f, split);
+ break;
+ case LL_PCODE_HOLE_TRIANGLE:
+ addHole(params, TRUE, 3, 0.5f, hollow, 0.5f, split);
+ break;
+ case LL_PCODE_HOLE_CIRCLE:
+ case LL_PCODE_HOLE_SAME:
+ default:
+ addHole(params, FALSE, circle_detail, 0.5f, hollow, 0.5f);
+ break;
+ }
+ }
+
+ // Special case for openness of sphere
+ if ((params.getEnd() - params.getBegin()) < 1.f)
+ {
+ mOpen = TRUE;
+ }
+ else if (!hollow)
+ {
+ mOpen = FALSE;
+ mProfile.push_back(mProfile[0]);
+ mTotal++;
+ }
+ }
+ break;
+ default:
+ llerrs << "Unknown profile: getCurveType()=" << params.getCurveType() << llendl;
+ break;
+ };
+
+ if (path_open)
+ {
+ addCap(LL_FACE_PATH_END); // bottom
+ }
+
+ if ( mOpen) // interior edge caps
+ {
+ addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, TRUE);
+
+ if (hollow)
+ {
+ addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, TRUE);
+ }
+ else
+ {
+ addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE);
+ }
+ }
+
+ //genNormals(params);
+
+ return TRUE;
+}
+
+
+
+BOOL LLProfileParams::importFile(LLFILE *fp)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ const S32 BUFSIZE = 16384;
+ char buffer[BUFSIZE]; /* Flawfinder: ignore */
+ // *NOTE: changing the size or type of these buffers will require
+ // changing the sscanf below.
+ char keyword[256]; /* Flawfinder: ignore */
+ char valuestr[256]; /* Flawfinder: ignore */
+ keyword[0] = 0;
+ valuestr[0] = 0;
+ F32 tempF32;
+ U32 tempU32;
+
+ while (!feof(fp))
+ {
+ if (fgets(buffer, BUFSIZE, fp) == NULL)
+ {
+ buffer[0] = '\0';
+ }
+
+ sscanf( /* Flawfinder: ignore */
+ buffer,
+ " %255s %255s",
+ keyword, valuestr);
+ if (!strcmp("{", keyword))
+ {
+ continue;
+ }
+ if (!strcmp("}",keyword))
+ {
+ break;
+ }
+ else if (!strcmp("curve", keyword))
+ {
+ sscanf(valuestr,"%d",&tempU32);
+ setCurveType((U8) tempU32);
+ }
+ else if (!strcmp("begin",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setBegin(tempF32);
+ }
+ else if (!strcmp("end",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setEnd(tempF32);
+ }
+ else if (!strcmp("hollow",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setHollow(tempF32);
+ }
+ else
+ {
+ llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOL LLProfileParams::exportFile(LLFILE *fp) const
+{
+ fprintf(fp,"\t\tprofile 0\n");
+ fprintf(fp,"\t\t{\n");
+ fprintf(fp,"\t\t\tcurve\t%d\n", getCurveType());
+ fprintf(fp,"\t\t\tbegin\t%g\n", getBegin());
+ fprintf(fp,"\t\t\tend\t%g\n", getEnd());
+ fprintf(fp,"\t\t\thollow\t%g\n", getHollow());
+ fprintf(fp, "\t\t}\n");
+ return TRUE;
+}
+
+
+BOOL LLProfileParams::importLegacyStream(std::istream& input_stream)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ const S32 BUFSIZE = 16384;
+ char buffer[BUFSIZE]; /* Flawfinder: ignore */
+ // *NOTE: changing the size or type of these buffers will require
+ // changing the sscanf below.
+ char keyword[256]; /* Flawfinder: ignore */
+ char valuestr[256]; /* Flawfinder: ignore */
+ keyword[0] = 0;
+ valuestr[0] = 0;
+ F32 tempF32;
+ U32 tempU32;
+
+ while (input_stream.good())
+ {
+ input_stream.getline(buffer, BUFSIZE);
+ sscanf( /* Flawfinder: ignore */
+ buffer,
+ " %255s %255s",
+ keyword,
+ valuestr);
+ if (!strcmp("{", keyword))
+ {
+ continue;
+ }
+ if (!strcmp("}",keyword))
+ {
+ break;
+ }
+ else if (!strcmp("curve", keyword))
+ {
+ sscanf(valuestr,"%d",&tempU32);
+ setCurveType((U8) tempU32);
+ }
+ else if (!strcmp("begin",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setBegin(tempF32);
+ }
+ else if (!strcmp("end",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setEnd(tempF32);
+ }
+ else if (!strcmp("hollow",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setHollow(tempF32);
+ }
+ else
+ {
+ llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const
+{
+ output_stream <<"\t\tprofile 0\n";
+ output_stream <<"\t\t{\n";
+ output_stream <<"\t\t\tcurve\t" << (S32) getCurveType() << "\n";
+ output_stream <<"\t\t\tbegin\t" << getBegin() << "\n";
+ output_stream <<"\t\t\tend\t" << getEnd() << "\n";
+ output_stream <<"\t\t\thollow\t" << getHollow() << "\n";
+ output_stream << "\t\t}\n";
+ return TRUE;
+}
+
+LLSD LLProfileParams::asLLSD() const
+{
+ LLSD sd;
+
+ sd["curve"] = getCurveType();
+ sd["begin"] = getBegin();
+ sd["end"] = getEnd();
+ sd["hollow"] = getHollow();
+ return sd;
+}
+
+bool LLProfileParams::fromLLSD(LLSD& sd)
+{
+ setCurveType(sd["curve"].asInteger());
+ setBegin((F32)sd["begin"].asReal());
+ setEnd((F32)sd["end"].asReal());
+ setHollow((F32)sd["hollow"].asReal());
+ return true;
+}
+
+void LLProfileParams::copyParams(const LLProfileParams ¶ms)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+ setCurveType(params.getCurveType());
+ setBegin(params.getBegin());
+ setEnd(params.getEnd());
+ setHollow(params.getHollow());
+}
+
+
+LLPath::~LLPath()
+{
+}
+
+void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale)
+{
+ // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane.
+ const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f };
+
+ F32 revolutions = params.getRevolutions();
+ F32 skew = params.getSkew();
+ F32 skew_mag = fabs(skew);
+ F32 hole_x = params.getScaleX() * (1.0f - skew_mag);
+ F32 hole_y = params.getScaleY();
+
+ // Calculate taper begin/end for x,y (Negative means taper the beginning)
+ F32 taper_x_begin = 1.0f;
+ F32 taper_x_end = 1.0f - params.getTaperX();
+ F32 taper_y_begin = 1.0f;
+ F32 taper_y_end = 1.0f - params.getTaperY();
+
+ if ( taper_x_end > 1.0f )
+ {
+ // Flip tapering.
+ taper_x_begin = 2.0f - taper_x_end;
+ taper_x_end = 1.0f;
+ }
+ if ( taper_y_end > 1.0f )
+ {
+ // Flip tapering.
+ taper_y_begin = 2.0f - taper_y_end;
+ taper_y_end = 1.0f;
+ }
+
+ // For spheres, the radius is usually zero.
+ F32 radius_start = 0.5f;
+ if (sides < 8)
+ {
+ radius_start = tableScale[sides];
+ }
+
+ // Scale the radius to take the hole size into account.
+ radius_start *= 1.0f - hole_y;
+
+ // Now check the radius offset to calculate the start,end radius. (Negative means
+ // decrease the start radius instead).
+ F32 radius_end = radius_start;
+ F32 radius_offset = params.getRadiusOffset();
+ if (radius_offset < 0.f)
+ {
+ radius_start *= 1.f + radius_offset;
+ }
+ else
+ {
+ radius_end *= 1.f - radius_offset;
+ }
+
+ // Is the path NOT a closed loop?
+ mOpen = ( (params.getEnd()*end_scale - params.getBegin() < 1.0f) ||
+ (skew_mag > 0.001f) ||
+ (fabs(taper_x_end - taper_x_begin) > 0.001f) ||
+ (fabs(taper_y_end - taper_y_begin) > 0.001f) ||
+ (fabs(radius_end - radius_start) > 0.001f) );
+
+ F32 ang, c, s;
+ LLQuaternion twist, qang;
+ PathPt *pt;
+ LLVector3 path_axis (1.f, 0.f, 0.f);
+ //LLVector3 twist_axis(0.f, 0.f, 1.f);
+ F32 twist_begin = params.getTwistBegin() * twist_scale;
+ F32 twist_end = params.getTwist() * twist_scale;
+
+ // We run through this once before the main loop, to make sure
+ // the path begins at the correct cut.
+ F32 step= 1.0f / sides;
+ F32 t = params.getBegin();
+ pt = vector_append(mPath, 1);
+ ang = 2.0f*F_PI*revolutions * t;
+ s = sin(ang)*lerp(radius_start, radius_end, t);
+ c = cos(ang)*lerp(radius_start, radius_end, t);
+
+
+ pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
+ + lerp(-skew ,skew, t) * 0.5f,
+ c + lerp(0,params.getShear().mV[1],s),
+ s);
+ pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
+ pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
+ pt->mTexT = t;
+
+ // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
+ twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
+ // Rotate the point around the circle's center.
+ qang.setQuat (ang,path_axis);
+ pt->mRot = twist * qang;
+
+ t+=step;
+
+ // Snap to a quantized parameter, so that cut does not
+ // affect most sample points.
+ t = ((S32)(t * sides)) / (F32)sides;
+
+ // Run through the non-cut dependent points.
+ while (t < params.getEnd())
+ {
+ pt = vector_append(mPath, 1);
+
+ ang = 2.0f*F_PI*revolutions * t;
+ c = cos(ang)*lerp(radius_start, radius_end, t);
+ s = sin(ang)*lerp(radius_start, radius_end, t);
+
+ pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
+ + lerp(-skew ,skew, t) * 0.5f,
+ c + lerp(0,params.getShear().mV[1],s),
+ s);
+
+ pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
+ pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
+ pt->mTexT = t;
+
+ // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
+ twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
+ // Rotate the point around the circle's center.
+ qang.setQuat (ang,path_axis);
+ pt->mRot = twist * qang;
+
+ t+=step;
+ }
+
+ // Make one final pass for the end cut.
+ t = params.getEnd();
+ pt = vector_append(mPath, 1);
+ ang = 2.0f*F_PI*revolutions * t;
+ c = cos(ang)*lerp(radius_start, radius_end, t);
+ s = sin(ang)*lerp(radius_start, radius_end, t);
+
+ pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s)
+ + lerp(-skew ,skew, t) * 0.5f,
+ c + lerp(0,params.getShear().mV[1],s),
+ s);
+ pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
+ pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
+ pt->mTexT = t;
+
+ // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
+ twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
+ // Rotate the point around the circle's center.
+ qang.setQuat (ang,path_axis);
+ pt->mRot = twist * qang;
+
+ mTotal = mPath.size();
+}
+
+const LLVector2 LLPathParams::getBeginScale() const
+{
+ LLVector2 begin_scale(1.f, 1.f);
+ if (getScaleX() > 1)
+ {
+ begin_scale.mV[0] = 2-getScaleX();
+ }
+ if (getScaleY() > 1)
+ {
+ begin_scale.mV[1] = 2-getScaleY();
+ }
+ return begin_scale;
+}
+
+const LLVector2 LLPathParams::getEndScale() const
+{
+ LLVector2 end_scale(1.f, 1.f);
+ if (getScaleX() < 1)
+ {
+ end_scale.mV[0] = getScaleX();
+ }
+ if (getScaleY() < 1)
+ {
+ end_scale.mV[1] = getScaleY();
+ }
+ return end_scale;
+}
+
+BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
+ BOOL is_sculpted, S32 sculpt_size)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ if ((!mDirty) && (!is_sculpted))
+ {
+ return FALSE;
+ }
+
+ if (detail < MIN_LOD)
+ {
+ llinfos << "Generating path with LOD < MIN! Clamping to 1" << llendl;
+ detail = MIN_LOD;
+ }
+
+ mDirty = FALSE;
+ S32 np = 2; // hardcode for line
+
+ mPath.clear();
+ mOpen = TRUE;
+
+ // Is this 0xf0 mask really necessary? DK 03/02/05
+ switch (params.getCurveType() & 0xf0)
+ {
+ default:
+ case LL_PCODE_PATH_LINE:
+ {
+ // Take the begin/end twist into account for detail.
+ np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2;
+ if (np < split+2)
+ {
+ np = split+2;
+ }
+
+ mStep = 1.0f / (np-1);
+
+ mPath.resize(np);
+
+ LLVector2 start_scale = params.getBeginScale();
+ LLVector2 end_scale = params.getEndScale();
+
+ for (S32 i=0;i<np;i++)
+ {
+ F32 t = lerp(params.getBegin(),params.getEnd(),(F32)i * mStep);
+ mPath[i].mPos.setVec(lerp(0,params.getShear().mV[0],t),
+ lerp(0,params.getShear().mV[1],t),
+ t - 0.5f);
+ mPath[i].mRot.setQuat(lerp(F_PI * params.getTwistBegin(),F_PI * params.getTwist(),t),0,0,1);
+ mPath[i].mScale.mV[0] = lerp(start_scale.mV[0],end_scale.mV[0],t);
+ mPath[i].mScale.mV[1] = lerp(start_scale.mV[1],end_scale.mV[1],t);
+ mPath[i].mTexT = t;
+ }
+ }
+ break;
+
+ case LL_PCODE_PATH_CIRCLE:
+ {
+ // Increase the detail as the revolutions and twist increase.
+ F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist());
+
+ S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions());
+
+ if (is_sculpted)
+ sides = sculpt_size;
+
+ genNGon(params, sides);
+ }
+ break;
+
+ case LL_PCODE_PATH_CIRCLE2:
+ {
+ if (params.getEnd() - params.getBegin() >= 0.99f &&
+ params.getScaleX() >= .99f)
+ {
+ mOpen = FALSE;
+ }
+
+ //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f);
+ genNGon(params, llfloor(MIN_DETAIL_FACES * detail));
+
+ F32 t = 0.f;
+ F32 tStep = 1.0f / mPath.size();
+
+ F32 toggle = 0.5f;
+ for (S32 i=0;i<(S32)mPath.size();i++)
+ {
+ mPath[i].mPos.mV[0] = toggle;
+ if (toggle == 0.5f)
+ toggle = -0.5f;
+ else
+ toggle = 0.5f;
+ t += tStep;
+ }
+ }
+
+ break;
+
+ case LL_PCODE_PATH_TEST:
+
+ np = 5;
+ mStep = 1.0f / (np-1);
+
+ mPath.resize(np);
+
+ for (S32 i=0;i<np;i++)
+ {
+ F32 t = (F32)i * mStep;
+ mPath[i].mPos.setVec(0,
+ lerp(0, -sin(F_PI*params.getTwist()*t)*0.5f,t),
+ lerp(-0.5, cos(F_PI*params.getTwist()*t)*0.5f,t));
+ mPath[i].mScale.mV[0] = lerp(1,params.getScale().mV[0],t);
+ mPath[i].mScale.mV[1] = lerp(1,params.getScale().mV[1],t);
+ mPath[i].mTexT = t;
+ mPath[i].mRot.setQuat(F_PI * params.getTwist() * t,1,0,0);
+ }
+
+ break;
+ };
+
+ if (params.getTwist() != params.getTwistBegin()) mOpen = TRUE;
+
+ //if ((int(fabsf(params.getTwist() - params.getTwistBegin())*100))%100 != 0) {
+ // mOpen = TRUE;
+ //}
+
+ return TRUE;
+}
+
+BOOL LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split,
+ BOOL is_sculpted, S32 sculpt_size)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ mOpen = TRUE; // Draw end caps
+ if (getPathLength() == 0)
+ {
+ // Path hasn't been generated yet.
+ // Some algorithms later assume at least TWO path points.
+ resizePath(2);
+ for (U32 i = 0; i < 2; i++)
+ {
+ mPath[i].mPos.setVec(0, 0, 0);
+ mPath[i].mRot.setQuat(0, 0, 0);
+ mPath[i].mScale.setVec(1, 1);
+ mPath[i].mTexT = 0;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOL LLPathParams::importFile(LLFILE *fp)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ const S32 BUFSIZE = 16384;
+ char buffer[BUFSIZE]; /* Flawfinder: ignore */
+ // *NOTE: changing the size or type of these buffers will require
+ // changing the sscanf below.
+ char keyword[256]; /* Flawfinder: ignore */
+ char valuestr[256]; /* Flawfinder: ignore */
+ keyword[0] = 0;
+ valuestr[0] = 0;
+
+ F32 tempF32;
+ F32 x, y;
+ U32 tempU32;
+
+ while (!feof(fp))
+ {
+ if (fgets(buffer, BUFSIZE, fp) == NULL)
+ {
+ buffer[0] = '\0';
+ }
+
+ sscanf( /* Flawfinder: ignore */
+ buffer,
+ " %255s %255s",
+ keyword, valuestr);
+ if (!strcmp("{", keyword))
+ {
+ continue;
+ }
+ if (!strcmp("}",keyword))
+ {
+ break;
+ }
+ else if (!strcmp("curve", keyword))
+ {
+ sscanf(valuestr,"%d",&tempU32);
+ setCurveType((U8) tempU32);
+ }
+ else if (!strcmp("begin",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setBegin(tempF32);
+ }
+ else if (!strcmp("end",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setEnd(tempF32);
+ }
+ else if (!strcmp("scale",keyword))
+ {
+ // Legacy for one dimensional scale per path
+ sscanf(valuestr,"%g",&tempF32);
+ setScale(tempF32, tempF32);
+ }
+ else if (!strcmp("scale_x", keyword))
+ {
+ sscanf(valuestr, "%g", &x);
+ setScaleX(x);
+ }
+ else if (!strcmp("scale_y", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setScaleY(y);
+ }
+ else if (!strcmp("shear_x", keyword))
+ {
+ sscanf(valuestr, "%g", &x);
+ setShearX(x);
+ }
+ else if (!strcmp("shear_y", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setShearY(y);
+ }
+ else if (!strcmp("twist",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setTwist(tempF32);
+ }
+ else if (!strcmp("twist_begin", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setTwistBegin(y);
+ }
+ else if (!strcmp("radius_offset", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setRadiusOffset(y);
+ }
+ else if (!strcmp("taper_x", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setTaperX(y);
+ }
+ else if (!strcmp("taper_y", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setTaperY(y);
+ }
+ else if (!strcmp("revolutions", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setRevolutions(y);
+ }
+ else if (!strcmp("skew", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setSkew(y);
+ }
+ else
+ {
+ llwarns << "unknown keyword " << " in path import" << llendl;
+ }
+ }
+ return TRUE;
+}
+
+
+BOOL LLPathParams::exportFile(LLFILE *fp) const
+{
+ fprintf(fp, "\t\tpath 0\n");
+ fprintf(fp, "\t\t{\n");
+ fprintf(fp, "\t\t\tcurve\t%d\n", getCurveType());
+ fprintf(fp, "\t\t\tbegin\t%g\n", getBegin());
+ fprintf(fp, "\t\t\tend\t%g\n", getEnd());
+ fprintf(fp, "\t\t\tscale_x\t%g\n", getScaleX() );
+ fprintf(fp, "\t\t\tscale_y\t%g\n", getScaleY() );
+ fprintf(fp, "\t\t\tshear_x\t%g\n", getShearX() );
+ fprintf(fp, "\t\t\tshear_y\t%g\n", getShearY() );
+ fprintf(fp,"\t\t\ttwist\t%g\n", getTwist());
+
+ fprintf(fp,"\t\t\ttwist_begin\t%g\n", getTwistBegin());
+ fprintf(fp,"\t\t\tradius_offset\t%g\n", getRadiusOffset());
+ fprintf(fp,"\t\t\ttaper_x\t%g\n", getTaperX());
+ fprintf(fp,"\t\t\ttaper_y\t%g\n", getTaperY());
+ fprintf(fp,"\t\t\trevolutions\t%g\n", getRevolutions());
+ fprintf(fp,"\t\t\tskew\t%g\n", getSkew());
+
+ fprintf(fp, "\t\t}\n");
+ return TRUE;
+}
+
+
+BOOL LLPathParams::importLegacyStream(std::istream& input_stream)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ const S32 BUFSIZE = 16384;
+ char buffer[BUFSIZE]; /* Flawfinder: ignore */
+ // *NOTE: changing the size or type of these buffers will require
+ // changing the sscanf below.
+ char keyword[256]; /* Flawfinder: ignore */
+ char valuestr[256]; /* Flawfinder: ignore */
+ keyword[0] = 0;
+ valuestr[0] = 0;
+
+ F32 tempF32;
+ F32 x, y;
+ U32 tempU32;
+
+ while (input_stream.good())
+ {
+ input_stream.getline(buffer, BUFSIZE);
+ sscanf( /* Flawfinder: ignore */
+ buffer,
+ " %255s %255s",
+ keyword, valuestr);
+ if (!strcmp("{", keyword))
+ {
+ continue;
+ }
+ if (!strcmp("}",keyword))
+ {
+ break;
+ }
+ else if (!strcmp("curve", keyword))
+ {
+ sscanf(valuestr,"%d",&tempU32);
+ setCurveType((U8) tempU32);
+ }
+ else if (!strcmp("begin",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setBegin(tempF32);
+ }
+ else if (!strcmp("end",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setEnd(tempF32);
+ }
+ else if (!strcmp("scale",keyword))
+ {
+ // Legacy for one dimensional scale per path
+ sscanf(valuestr,"%g",&tempF32);
+ setScale(tempF32, tempF32);
+ }
+ else if (!strcmp("scale_x", keyword))
+ {
+ sscanf(valuestr, "%g", &x);
+ setScaleX(x);
+ }
+ else if (!strcmp("scale_y", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setScaleY(y);
+ }
+ else if (!strcmp("shear_x", keyword))
+ {
+ sscanf(valuestr, "%g", &x);
+ setShearX(x);
+ }
+ else if (!strcmp("shear_y", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setShearY(y);
+ }
+ else if (!strcmp("twist",keyword))
+ {
+ sscanf(valuestr,"%g",&tempF32);
+ setTwist(tempF32);
+ }
+ else if (!strcmp("twist_begin", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setTwistBegin(y);
+ }
+ else if (!strcmp("radius_offset", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setRadiusOffset(y);
+ }
+ else if (!strcmp("taper_x", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setTaperX(y);
+ }
+ else if (!strcmp("taper_y", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setTaperY(y);
+ }
+ else if (!strcmp("revolutions", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setRevolutions(y);
+ }
+ else if (!strcmp("skew", keyword))
+ {
+ sscanf(valuestr, "%g", &y);
+ setSkew(y);
+ }
+ else
+ {
+ llwarns << "unknown keyword " << " in path import" << llendl;
+ }
+ }
+ return TRUE;
+}
+
+
+BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const
+{
+ output_stream << "\t\tpath 0\n";
+ output_stream << "\t\t{\n";
+ output_stream << "\t\t\tcurve\t" << (S32) getCurveType() << "\n";
+ output_stream << "\t\t\tbegin\t" << getBegin() << "\n";
+ output_stream << "\t\t\tend\t" << getEnd() << "\n";
+ output_stream << "\t\t\tscale_x\t" << getScaleX() << "\n";
+ output_stream << "\t\t\tscale_y\t" << getScaleY() << "\n";
+ output_stream << "\t\t\tshear_x\t" << getShearX() << "\n";
+ output_stream << "\t\t\tshear_y\t" << getShearY() << "\n";
+ output_stream <<"\t\t\ttwist\t" << getTwist() << "\n";
+
+ output_stream <<"\t\t\ttwist_begin\t" << getTwistBegin() << "\n";
+ output_stream <<"\t\t\tradius_offset\t" << getRadiusOffset() << "\n";
+ output_stream <<"\t\t\ttaper_x\t" << getTaperX() << "\n";
+ output_stream <<"\t\t\ttaper_y\t" << getTaperY() << "\n";
+ output_stream <<"\t\t\trevolutions\t" << getRevolutions() << "\n";
+ output_stream <<"\t\t\tskew\t" << getSkew() << "\n";
+
+ output_stream << "\t\t}\n";
+ return TRUE;
+}
+
+LLSD LLPathParams::asLLSD() const
+{
+ LLSD sd = LLSD();
+ sd["curve"] = getCurveType();
+ sd["begin"] = getBegin();
+ sd["end"] = getEnd();
+ sd["scale_x"] = getScaleX();
+ sd["scale_y"] = getScaleY();
+ sd["shear_x"] = getShearX();
+ sd["shear_y"] = getShearY();
+ sd["twist"] = getTwist();
+ sd["twist_begin"] = getTwistBegin();
+ sd["radius_offset"] = getRadiusOffset();
+ sd["taper_x"] = getTaperX();
+ sd["taper_y"] = getTaperY();
+ sd["revolutions"] = getRevolutions();
+ sd["skew"] = getSkew();
+
+ return sd;
+}
+
+bool LLPathParams::fromLLSD(LLSD& sd)
+{
+ setCurveType(sd["curve"].asInteger());
+ setBegin((F32)sd["begin"].asReal());
+ setEnd((F32)sd["end"].asReal());
+ setScaleX((F32)sd["scale_x"].asReal());
+ setScaleY((F32)sd["scale_y"].asReal());
+ setShearX((F32)sd["shear_x"].asReal());
+ setShearY((F32)sd["shear_y"].asReal());
+ setTwist((F32)sd["twist"].asReal());
+ setTwistBegin((F32)sd["twist_begin"].asReal());
+ setRadiusOffset((F32)sd["radius_offset"].asReal());
+ setTaperX((F32)sd["taper_x"].asReal());
+ setTaperY((F32)sd["taper_y"].asReal());
+ setRevolutions((F32)sd["revolutions"].asReal());
+ setSkew((F32)sd["skew"].asReal());
+ return true;
+}
+
+void LLPathParams::copyParams(const LLPathParams ¶ms)
+{
+ setCurveType(params.getCurveType());
+ setBegin(params.getBegin());
+ setEnd(params.getEnd());
+ setScale(params.getScaleX(), params.getScaleY() );
+ setShear(params.getShearX(), params.getShearY() );
+ setTwist(params.getTwist());
+ setTwistBegin(params.getTwistBegin());
+ setRadiusOffset(params.getRadiusOffset());
+ setTaper( params.getTaperX(), params.getTaperY() );
+ setRevolutions(params.getRevolutions());
+ setSkew(params.getSkew());
+}
+
+S32 profile_delete_lock = 1 ;
+LLProfile::~LLProfile()
+{
+ if(profile_delete_lock)
+ {
+ llerrs << "LLProfile should not be deleted here!" << llendl ;
+ }
+}
+
+
+S32 LLVolume::sNumMeshPoints = 0;
+
+LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face, const BOOL is_unique)
+ : mParams(params)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ mUnique = is_unique;
+ mFaceMask = 0x0;
+ mDetail = detail;
+ mSculptLevel = -2;
+ mIsTetrahedron = FALSE;
+ mLODScaleBias.setVec(1,1,1);
+ mHullPoints = NULL;
+ mHullIndices = NULL;
+ mNumHullPoints = 0;
+ mNumHullIndices = 0;
+
+ // set defaults
+ if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
+ {
+ mPathp = new LLDynamicPath();
+ }
+ else
+ {
+ mPathp = new LLPath();
+ }
+ mProfilep = new LLProfile();
+
+ mGenerateSingleFace = generate_single_face;
+
+ generate();
+
+ if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE)
+ {
+ createVolumeFaces();
+ }
+}
+
+void LLVolume::resizePath(S32 length)
+{
+ mPathp->resizePath(length);
+ mVolumeFaces.clear();
+}
+
+void LLVolume::regen()
+{
+ generate();
+ createVolumeFaces();
+}
+
+void LLVolume::genBinormals(S32 face)
+{
+ mVolumeFaces[face].createBinormals();
+}
+
+LLVolume::~LLVolume()
+{
+ sNumMeshPoints -= mMesh.size();
+ delete mPathp;
+
+ profile_delete_lock = 0 ;
+ delete mProfilep;
+ profile_delete_lock = 1 ;
+
+ mPathp = NULL;
+ mProfilep = NULL;
+ mVolumeFaces.clear();
+
+ free(mHullPoints);
+ mHullPoints = NULL;
+ free(mHullIndices);
+ mHullIndices = NULL;
+}
+
+BOOL LLVolume::generate()
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+ llassert_always(mProfilep);
+
+ //Added 10.03.05 Dave Parks
+ // Split is a parameter to LLProfile::generate that tesselates edges on the profile
+ // to prevent lighting and texture interpolation errors on triangles that are
+ // stretched due to twisting or scaling on the path.
+ S32 split = (S32) ((mDetail)*0.66f);
+
+ if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE &&
+ (mParams.getPathParams().getScale().mV[0] != 1.0f ||
+ mParams.getPathParams().getScale().mV[1] != 1.0f) &&
+ (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE ||
+ mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI ||
+ mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI ||
+ mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI))
+ {
+ split = 0;
+ }
+
+ mLODScaleBias.setVec(0.5f, 0.5f, 0.5f);
+
+ F32 profile_detail = mDetail;
+ F32 path_detail = mDetail;
+
+ U8 path_type = mParams.getPathParams().getCurveType();
+ U8 profile_type = mParams.getProfileParams().getCurveType();
+
+ if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE)
+ { //cylinders don't care about Z-Axis
+ mLODScaleBias.setVec(0.6f, 0.6f, 0.0f);
+ }
+ else if (path_type == LL_PCODE_PATH_CIRCLE)
+ {
+ mLODScaleBias.setVec(0.6f, 0.6f, 0.6f);
+ }
+
+ //********************************************************************
+ //debug info, to be removed
+ if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20))
+ {
+ llinfos << "sizeS: " << mPathp->mPath.size() << " sizeT: " << mProfilep->mProfile.size() << llendl ;
+ llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ;
+ llinfos << mParams << llendl ;
+ llinfos << "more info to check if mProfilep is deleted or not." << llendl ;
+ llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ;
+
+ llerrs << "LLVolume corrupted!" << llendl ;
+ }
+ //********************************************************************
+
+ BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split);
+ BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split);
+
+ if (regenPath || regenProf )
+ {
+ S32 sizeS = mPathp->mPath.size();
+ S32 sizeT = mProfilep->mProfile.size();
+
+ //********************************************************************
+ //debug info, to be removed
+ if((U32)(sizeS * sizeT) > (1u << 20))
+ {
+ llinfos << "regenPath: " << (S32)regenPath << " regenProf: " << (S32)regenProf << llendl ;
+ llinfos << "sizeS: " << sizeS << " sizeT: " << sizeT << llendl ;
+ llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ;
+ llinfos << mParams << llendl ;
+ llinfos << "more info to check if mProfilep is deleted or not." << llendl ;
+ llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ;
+
+ llerrs << "LLVolume corrupted!" << llendl ;
+ }
+ //********************************************************************
+
+ sNumMeshPoints -= mMesh.size();
+ mMesh.resize(sizeT * sizeS);
+ sNumMeshPoints += mMesh.size();
+
+ //generate vertex positions
+
+ // Run along the path.
+ for (S32 s = 0; s < sizeS; ++s)
+ {
+ LLVector2 scale = mPathp->mPath[s].mScale;
+ LLQuaternion rot = mPathp->mPath[s].mRot;
+
+ // Run along the profile.
+ for (S32 t = 0; t < sizeT; ++t)
+ {
+ S32 m = s*sizeT + t;
+ Point& pt = mMesh[m];
+
+ pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0];
+ pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1];
+ pt.mPos.mV[2] = 0.0f;
+ pt.mPos = pt.mPos * rot;
+ pt.mPos += mPathp->mPath[s].mPos;
+ }
+ }
+
+ for (std::vector<LLProfile::Face>::iterator iter = mProfilep->mFaces.begin();
+ iter != mProfilep->mFaces.end(); ++iter)
+ {
+ LLFaceID id = iter->mFaceID;
+ mFaceMask |= id;
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void LLVolumeFace::VertexData::init()
+{
+ if (!mData)
+ {
+ mData = (LLVector4a*) malloc(sizeof(LLVector4a)*2);
+ }
+}
+
+LLVolumeFace::VertexData::VertexData()
+{
+ mData = NULL;
+ init();
+}
+
+LLVolumeFace::VertexData::VertexData(const VertexData& rhs)
+{
+ mData = NULL;
+ *this = rhs;
+}
+
+const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs)
+{
+ if (this != &rhs)
+ {
+ init();
+ LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 2*sizeof(LLVector4a));
+ mTexCoord = rhs.mTexCoord;
+ }
+ return *this;
+}
+
+LLVolumeFace::VertexData::~VertexData()
+{
+ free(mData);
+ mData = NULL;
+}
+
+LLVector4a& LLVolumeFace::VertexData::getPosition()
+{
+ return mData[POSITION];
+}
+
+LLVector4a& LLVolumeFace::VertexData::getNormal()
+{
+ return mData[NORMAL];
+}
+
+const LLVector4a& LLVolumeFace::VertexData::getPosition() const
+{
+ return mData[POSITION];
+}
+
+const LLVector4a& LLVolumeFace::VertexData::getNormal() const
+{
+ return mData[NORMAL];
+}
+
+
+void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos)
+{
+ mData[POSITION] = pos;
+}
+
+void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm)
+{
+ mData[NORMAL] = norm;
+}
+
+bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const
+{
+ const F32* lp = this->getPosition().getF32ptr();
+ const F32* rp = rhs.getPosition().getF32ptr();
+
+ if (lp[0] != rp[0])
+ {
+ return lp[0] < rp[0];
+ }
+
+ if (rp[1] != lp[1])
+ {
+ return lp[1] < rp[1];
+ }
+
+ if (rp[2] != lp[2])
+ {
+ return lp[2] < rp[2];
+ }
+
+ lp = getNormal().getF32ptr();
+ rp = rhs.getNormal().getF32ptr();
+
+ if (lp[0] != rp[0])
+ {
+ return lp[0] < rp[0];
+ }
+
+ if (rp[1] != lp[1])
+ {
+ return lp[1] < rp[1];
+ }
+
+ if (rp[2] != lp[2])
+ {
+ return lp[2] < rp[2];
+ }
+
+ if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0])
+ {
+ return mTexCoord.mV[0] < rhs.mTexCoord.mV[0];
+ }
+
+ return mTexCoord.mV[1] < rhs.mTexCoord.mV[1];
+}
+
+bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const
+{
+ return mData[POSITION].equals3(rhs.getPosition()) &&
+ mData[NORMAL].equals3(rhs.getNormal()) &&
+ mTexCoord == rhs.mTexCoord;
+}
+
+bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const
+{
+ bool retval = false;
+ if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord)
+ {
+ if (angle_cutoff > 1.f)
+ {
+ retval = (mData[NORMAL].equals3(rhs.mData[NORMAL]));
+ }
+ else
+ {
+ F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32();
+ retval = cur_angle > angle_cutoff;
+ }
+ }
+
+ return retval;
+}
+
+BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
+{
+ std::ifstream is;
+
+ is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
+
+ BOOL success = createVolumeFacesFromStream(is);
+
+ is.close();
+
+ return success;
+}
+
+BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
+{
+ mSculptLevel = -1; // default is an error occured
+
+ LLSD header;
+ {
+ if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024))
+ {
+ llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl;
+ return FALSE;
+ }
+ }
+
+ std::string nm[] =
+ {
+ "lowest_lod",
+ "low_lod",
+ "medium_lod",
+ "high_lod"
+ };
+
+ S32 lod = llclamp((S32) mDetail, 0, 3);
+
+ while (lod < 4 &&
+ (header[nm[lod]]["offset"].asInteger() == -1 ||
+ header[nm[lod]]["size"].asInteger() == 0 ))
+ {
+ ++lod;
+ }
+
+ if (lod >= 4)
+ {
+ lod = llclamp((S32) mDetail, 0, 3);
+
+ while (lod >= 0 &&
+ (header[nm[lod]]["offset"].asInteger() == -1 ||
+ header[nm[lod]]["size"].asInteger() == 0) )
+ {
+ --lod;
+ }
+
+ if (lod < 0)
+ {
+ llwarns << "Mesh header missing LOD offsets. Not a valid mesh asset!" << llendl;
+ return FALSE;
+ }
+ }
+
+ is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+
+ return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger());
+}
+
+bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
+{
+ //input stream is now pointing at a zlib compressed block of LLSD
+ //decompress block
+ LLSD mdl;
+ if (!unzip_llsd(mdl, is, size))
+ {
+ llwarns << "not a valid mesh asset!" << llendl;
+ return false;
+ }
+
+ {
+ U32 face_count = mdl.size();
+
+ if (face_count == 0)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ mVolumeFaces.resize(face_count);
+
+ for (U32 i = 0; i < face_count; ++i)
+ {
+ LLSD::Binary pos = mdl[i]["Position"];
+ LLSD::Binary norm = mdl[i]["Normal"];
+ LLSD::Binary tc = mdl[i]["TexCoord0"];
+ LLSD::Binary idx = mdl[i]["TriangleList"];
+
+ LLVolumeFace& face = mVolumeFaces[i];
+
+ //copy out indices
+ face.resizeIndices(idx.size()/2);
+
+ if (idx.empty() || face.mNumIndices < 3)
+ { //why is there an empty index list?
+ llerrs <<"WTF?" << llendl;
+ continue;
+ }
+
+ U16* indices = (U16*) &(idx[0]);
+ for (U32 j = 0; j < idx.size()/2; ++j)
+ {
+ face.mIndices[j] = indices[j];
+ }
+
+ //copy out vertices
+ U32 num_verts = pos.size()/(3*2);
+ face.resizeVertices(num_verts);
+
+ if (mdl[i].has("Weights"))
+ {
+ face.allocateWeights(num_verts);
+
+ LLSD::Binary weights = mdl[i]["Weights"];
+
+ U32 idx = 0;
+
+ U32 cur_vertex = 0;
+ while (idx < weights.size() && cur_vertex < num_verts)
+ {
+ const U8 END_INFLUENCES = 0xFF;
+ U8 joint = weights[idx++];
+
+ U32 cur_influence = 0;
+ LLVector4 wght(0,0,0,0);
+
+ while (joint != END_INFLUENCES && idx < weights.size())
+ {
+ U16 influence = weights[idx++];
+ influence |= ((U16) weights[idx++] << 8);
+
+ F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
+ wght.mV[cur_influence++] = (F32) joint + w;
+
+ if (cur_influence >= 4)
+ {
+ joint = END_INFLUENCES;
+ }
+ else
+ {
+ joint = weights[idx++];
+ }
+ }
+
+ face.mWeights[cur_vertex].loadua(wght.mV);
+
+ cur_vertex++;
+ }
+
+ if (cur_vertex != num_verts || idx != weights.size())
+ {
+ llwarns << "Vertex weight count does not match vertex count!" << llendl;
+ }
+
+ }
+
+ LLVector3 minp;
+ LLVector3 maxp;
+ LLVector2 min_tc;
+ LLVector2 max_tc;
+
+ minp.setValue(mdl[i]["PositionDomain"]["Min"]);
+ maxp.setValue(mdl[i]["PositionDomain"]["Max"]);
+ LLVector4a min_pos, max_pos;
+ min_pos.load3(minp.mV);
+ max_pos.load3(maxp.mV);
+
+ min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
+ max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
+
+ LLVector4a pos_range;
+ pos_range.setSub(max_pos, min_pos);
+ LLVector2 tc_range = max_tc - min_tc;
+
+ LLVector4a* pos_out = face.mPositions;
+ LLVector4a* norm_out = face.mNormals;
+ LLVector2* tc_out = face.mTexCoords;
+
+ for (U32 j = 0; j < num_verts; ++j)
+ {
+ U16* v = (U16*) &(pos[j*3*2]);
+
+ pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]);
+ pos_out->div(65535.f);
+ pos_out->mul(pos_range);
+ pos_out->add(min_pos);
+
+ pos_out++;
+
+ U16* n = (U16*) &(norm[j*3*2]);
+
+ norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]);
+ norm_out->div(65535.f);
+ norm_out->mul(2.f);
+ norm_out->sub(1.f);
+ norm_out++;
+
+ U16* t = (U16*) &(tc[j*2*2]);
+
+ tc_out->mV[0] = (F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0];
+ tc_out->mV[1] = (F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1];
+
+ tc_out++;
+ }
+
+
+ // modifier flags?
+ bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR);
+ bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT);
+
+
+ // translate to actions:
+ bool do_reflect_x = false;
+ bool do_reverse_triangles = false;
+ bool do_invert_normals = false;
+
+ if (do_mirror)
+ {
+ do_reflect_x = true;
+ do_reverse_triangles = !do_reverse_triangles;
+ }
+
+ if (do_invert)
+ {
+ do_invert_normals = true;
+ do_reverse_triangles = !do_reverse_triangles;
+ }
+
+ // now do the work
+
+ if (do_reflect_x)
+ {
+ LLVector4a* p = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (S32 i = 0; i < face.mNumVertices; i++)
+ {
+ p[i].mul(-1.0f);
+ n[i].mul(-1.0f);
+ }
+ }
+
+ if (do_invert_normals)
+ {
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (S32 i = 0; i < face.mNumVertices; i++)
+ {
+ n[i].mul(-1.0f);
+ }
+ }
+
+ if (do_reverse_triangles)
+ {
+ for (U32 j = 0; j < face.mNumIndices; j += 3)
+ {
+ // swap the 2nd and 3rd index
+ S32 swap = face.mIndices[j+1];
+ face.mIndices[j+1] = face.mIndices[j+2];
+ face.mIndices[j+2] = swap;
+ }
+ }
+
+ //calculate bounding box
+ LLVector4a& min = face.mExtents[0];
+ LLVector4a& max = face.mExtents[1];
+
+ min.clear();
+ max.clear();
+ min = max = face.mPositions[0];
+
+ for (S32 i = 1; i < face.mNumVertices; ++i)
+ {
+ min.setMin(min, face.mPositions[i]);
+ max.setMax(max, face.mPositions[i]);
+ }
+ }
+ }
+
+ mSculptLevel = 0; // success!
+
+ cacheOptimize();
+
+ return true;
+}
+
+void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
+{
+ LLVector4a v0;
+ v0.setSub(cv[1].getPosition(), cv[0].getNormal());
+ LLVector4a v1;
+ v1.setSub(cv[2].getNormal(), cv[0].getPosition());
+
+ cv[0].getNormal().setCross3(v0,v1);
+ cv[0].getNormal().normalize3fast();
+ cv[1].setNormal(cv[0].getNormal());
+ cv[2].setNormal(cv[1].getNormal());
+}
+
+BOOL LLVolume::isTetrahedron()
+{
+ return mIsTetrahedron;
+}
+
+void LLVolume::makeTetrahedron()
+{
+ mVolumeFaces.clear();
+
+ LLVolumeFace face;
+
+ F32 x = 0.25f;
+ LLVector4a p[] =
+ { //unit tetrahedron corners
+ LLVector4a(x,x,x),
+ LLVector4a(-x,-x,x),
+ LLVector4a(-x,x,-x),
+ LLVector4a(x,-x,-x)
+ };
+
+ face.mExtents[0].splat(-x);
+ face.mExtents[1].splat(x);
+
+ LLVolumeFace::VertexData cv[3];
+
+ //set texture coordinates
+ cv[0].mTexCoord = LLVector2(0,0);
+ cv[1].mTexCoord = LLVector2(1,0);
+ cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3);
+
+
+ //side 1
+ cv[0].setPosition(p[1]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[2]);
+
+ tetrahedron_set_normal(cv);
+
+ face.resizeVertices(12);
+ face.resizeIndices(12);
+
+ LLVector4a* v = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+ LLVector2* tc = (LLVector2*) face.mTexCoords;
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+
+ //side 2
+ cv[0].setPosition(p[3]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[1]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //side 3
+ cv[0].setPosition(p[3]);
+ cv[1].setPosition(p[1]);
+ cv[2].setPosition(p[2]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //side 4
+ cv[0].setPosition(p[2]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[3]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //set index buffer
+ for (U16 i = 0; i < 12; i++)
+ {
+ face.mIndices[i] = i;
+ }
+
+ mVolumeFaces.push_back(face);
+ mSculptLevel = 0;
+ mIsTetrahedron = TRUE;
+}
+
+void LLVolume::copyVolumeFaces(const LLVolume* volume)
+{
+ mVolumeFaces = volume->mVolumeFaces;
+ mSculptLevel = 0;
+ mIsTetrahedron = FALSE;
+}
+
+void LLVolume::cacheOptimize()
+{
+ for (S32 i = 0; i < mVolumeFaces.size(); ++i)
+ {
+ mVolumeFaces[i].cacheOptimize();
+ }
+}
+
+
+S32 LLVolume::getNumFaces() const
+{
+ U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
+
+ if (sculpt_type == LL_SCULPT_TYPE_MESH)
+ {
+ return LL_SCULPT_MESH_MAX_FACES;
+ }
+
+ return (S32)mProfilep->mFaces.size();
+}
+
+
+void LLVolume::createVolumeFaces()
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ if (mGenerateSingleFace)
+ {
+ // do nothing
+ }
+ else
+ {
+ S32 num_faces = getNumFaces();
+ BOOL partial_build = TRUE;
+ if (num_faces != mVolumeFaces.size())
+ {
+ partial_build = FALSE;
+ mVolumeFaces.resize(num_faces);
+ }
+ // Initialize volume faces with parameter data
+ for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++)
+ {
+ LLVolumeFace& vf = mVolumeFaces[i];
+ LLProfile::Face& face = mProfilep->mFaces[i];
+ vf.mBeginS = face.mIndex;
+ vf.mNumS = face.mCount;
+ if (vf.mNumS < 0)
+ {
+ llerrs << "Volume face corruption detected." << llendl;
+ }
+
+ vf.mBeginT = 0;
+ vf.mNumT= getPath().mPath.size();
+ vf.mID = i;
+
+ // Set the type mask bits correctly
+ if (mParams.getProfileParams().getHollow() > 0)
+ {
+ vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK;
+ }
+ if (mProfilep->isOpen())
+ {
+ vf.mTypeMask |= LLVolumeFace::OPEN_MASK;
+ }
+ if (face.mCap)
+ {
+ vf.mTypeMask |= LLVolumeFace::CAP_MASK;
+ if (face.mFaceID == LL_FACE_PATH_BEGIN)
+ {
+ vf.mTypeMask |= LLVolumeFace::TOP_MASK;
+ }
+ else
+ {
+ llassert(face.mFaceID == LL_FACE_PATH_END);
+ vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK;
+ }
+ }
+ else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
+ {
+ vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK;
+ }
+ else
+ {
+ vf.mTypeMask |= LLVolumeFace::SIDE_MASK;
+ if (face.mFlat)
+ {
+ vf.mTypeMask |= LLVolumeFace::FLAT_MASK;
+ }
+ if (face.mFaceID & LL_FACE_INNER_SIDE)
+ {
+ vf.mTypeMask |= LLVolumeFace::INNER_MASK;
+ if (face.mFlat && vf.mNumS > 2)
+ { //flat inner faces have to copy vert normals
+ vf.mNumS = vf.mNumS*2;
+ if (vf.mNumS < 0)
+ {
+ llerrs << "Volume face corruption detected." << llendl;
+ }
+ }
+ }
+ else
+ {
+ vf.mTypeMask |= LLVolumeFace::OUTER_MASK;
+ }
+ }
+ }
+
+ for (face_list_t::iterator iter = mVolumeFaces.begin();
+ iter != mVolumeFaces.end(); ++iter)
+ {
+ (*iter).create(this, partial_build);
+ }
+ }
+}
+
+
+inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
+{
+ // maps RGB values to vector values [0..255] -> [-0.5..0.5]
+ LLVector3 value;
+ value.mV[VX] = r / 255.f - 0.5f;
+ value.mV[VY] = g / 255.f - 0.5f;
+ value.mV[VZ] = b / 255.f - 0.5f;
+
+ return value;
+}
+
+inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+{
+ U32 index = (x + y * sculpt_width) * sculpt_components;
+ return index;
+}
+
+
+inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+{
+ U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width);
+ U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height);
+
+ return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+}
+
+
+inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data)
+{
+ LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]);
+
+ return v;
+}
+
+inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
+{
+ U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components);
+
+ return sculpt_index_to_vector(index, sculpt_data);
+}
+
+inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
+{
+ U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+
+ return sculpt_index_to_vector(index, sculpt_data);
+}
+
+
+F32 LLVolume::sculptGetSurfaceArea()
+{
+ // test to see if image has enough variation to create non-degenerate geometry
+
+ F32 area = 0;
+
+ S32 sizeS = mPathp->mPath.size();
+ S32 sizeT = mProfilep->mProfile.size();
+
+ for (S32 s = 0; s < sizeS-1; s++)
+ {
+ for (S32 t = 0; t < sizeT-1; t++)
+ {
+ // get four corners of quad
+ LLVector3 p1 = mMesh[(s )*sizeT + (t )].mPos;
+ LLVector3 p2 = mMesh[(s+1)*sizeT + (t )].mPos;
+ LLVector3 p3 = mMesh[(s )*sizeT + (t+1)].mPos;
+ LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos;
+
+ // compute the area of the quad by taking the length of the cross product of the two triangles
+ LLVector3 cross1 = (p1 - p2) % (p1 - p3);
+ LLVector3 cross2 = (p4 - p2) % (p4 - p3);
+ area += (cross1.magVec() + cross2.magVec()) / 2.0;
+ }
+ }
+
+ return area;
+}
+
+// create placeholder shape
+void LLVolume::sculptGeneratePlaceholder()
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ S32 sizeS = mPathp->mPath.size();
+ S32 sizeT = mProfilep->mProfile.size();
+
+ S32 line = 0;
+
+ // for now, this is a sphere.
+ for (S32 s = 0; s < sizeS; s++)
+ {
+ for (S32 t = 0; t < sizeT; t++)
+ {
+ S32 i = t + line;
+ Point& pt = mMesh[i];
+
+
+ F32 u = (F32)s/(sizeS-1);
+ F32 v = (F32)t/(sizeT-1);
+
+ const F32 RADIUS = (F32) 0.3;
+
+ pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS);
+ pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS);
+ pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS);
+
+ }
+ line += sizeT;
+ }
+}
+
+// create the vertices from the map
+void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type)
+{
+ U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
+ BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
+ BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
+ BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR
+
+
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ S32 sizeS = mPathp->mPath.size();
+ S32 sizeT = mProfilep->mProfile.size();
+
+ S32 line = 0;
+ for (S32 s = 0; s < sizeS; s++)
+ {
+ // Run along the profile.
+ for (S32 t = 0; t < sizeT; t++)
+ {
+ S32 i = t + line;
+ Point& pt = mMesh[i];
+
+ S32 reversed_t = t;
+
+ if (reverse_horizontal)
+ {
+ reversed_t = sizeT - t - 1;
+ }
+
+ U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width);
+ U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height);
+
+
+ if (y == 0) // top row stitching
+ {
+ // pinch?
+ if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
+ {
+ x = sculpt_width / 2;
+ }
+ }
+
+ if (y == sculpt_height) // bottom row stitching
+ {
+ // wrap?
+ if (sculpt_stitching == LL_SCULPT_TYPE_TORUS)
+ {
+ y = 0;
+ }
+ else
+ {
+ y = sculpt_height - 1;
+ }
+
+ // pinch?
+ if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
+ {
+ x = sculpt_width / 2;
+ }
+ }
+
+ if (x == sculpt_width) // side stitching
+ {
+ // wrap?
+ if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) ||
+ (sculpt_stitching == LL_SCULPT_TYPE_TORUS) ||
+ (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER))
+ {
+ x = 0;
+ }
+
+ else
+ {
+ x = sculpt_width - 1;
+ }
+ }
+
+ pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data);
+
+ if (sculpt_mirror)
+ {
+ pt.mPos.mV[VX] *= -1.f;
+ }
+ }
+
+ line += sizeT;
+ }
+}
+
+
+const S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square
+const S32 SCULPT_REZ_2 = 8;
+const S32 SCULPT_REZ_3 = 16;
+const S32 SCULPT_REZ_4 = 32;
+
+S32 sculpt_sides(F32 detail)
+{
+
+ // detail is usually one of: 1, 1.5, 2.5, 4.0.
+
+ if (detail <= 1.0)
+ {
+ return SCULPT_REZ_1;
+ }
+ if (detail <= 2.0)
+ {
+ return SCULPT_REZ_2;
+ }
+ if (detail <= 3.0)
+ {
+ return SCULPT_REZ_3;
+ }
+ else
+ {
+ return SCULPT_REZ_4;
+ }
+}
+
+
+
+// determine the number of vertices in both s and t direction for this sculpt
+void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t)
+{
+ // this code has the following properties:
+ // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map
+ // while still using all available verts
+ // 2) the mesh cannot have more verts than is allowed by LOD
+ // 3) the mesh cannot have more verts than is allowed by the map
+
+ S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0);
+ S32 max_vertices_map = width * height / 4;
+
+ S32 vertices;
+ if (max_vertices_map > 0)
+ vertices = llmin(max_vertices_lod, max_vertices_map);
+ else
+ vertices = max_vertices_lod;
+
+
+ F32 ratio;
+ if ((width == 0) || (height == 0))
+ ratio = 1.f;
+ else
+ ratio = (F32) width / (F32) height;
+
+
+ s = (S32)(F32) sqrt(((F32)vertices / ratio));
+
+ s = llmax(s, 4); // no degenerate sizes, please
+ t = vertices / s;
+
+ t = llmax(t, 4); // no degenerate sizes, please
+ s = vertices / t;
+}
+
+// sculpt replaces generate() for sculpted surfaces
+void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+ U8 sculpt_type = mParams.getSculptType();
+
+ BOOL data_is_empty = FALSE;
+
+ if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL)
+ {
+ sculpt_level = -1;
+ data_is_empty = TRUE;
+ }
+
+ S32 requested_sizeS = 0;
+ S32 requested_sizeT = 0;
+
+ sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT);
+
+ mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS);
+ mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT);
+
+ S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got
+ S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got
+
+ // weird crash bug - DEV-11158 - trying to collect more data:
+ if ((sizeS == 0) || (sizeT == 0))
+ {
+ llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl;
+ }
+
+ sNumMeshPoints -= mMesh.size();
+ mMesh.resize(sizeS * sizeT);
+ sNumMeshPoints += mMesh.size();
+
+ //generate vertex positions
+ if (!data_is_empty)
+ {
+ sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type);
+
+ // don't test lowest LOD to support legacy content DEV-33670
+ if (mDetail > SCULPT_MIN_AREA_DETAIL)
+ {
+ if (sculptGetSurfaceArea() < SCULPT_MIN_AREA)
+ {
+ data_is_empty = TRUE;
+ }
+ }
+ }
+
+ if (data_is_empty)
+ {
+ sculptGeneratePlaceholder();
+ }
+
+
+
+ for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++)
+ {
+ mFaceMask |= mProfilep->mFaces[i].mFaceID;
+ }
+
+ mSculptLevel = sculpt_level;
+
+ // Delete any existing faces so that they get regenerated
+ mVolumeFaces.clear();
+
+ createVolumeFaces();
+}
+
+
+
+
+BOOL LLVolume::isCap(S32 face)
+{
+ return mProfilep->mFaces[face].mCap;
+}
+
+BOOL LLVolume::isFlat(S32 face)
+{
+ return mProfilep->mFaces[face].mFlat;
+}
+
+
+bool LLVolumeParams::isSculpt() const
+{
+ return mSculptID.notNull();
+}
+
+bool LLVolumeParams::isMeshSculpt() const
+{
+ return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
+}
+
+bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const
+{
+ return ( (getPathParams() == params.getPathParams()) &&
+ (getProfileParams() == params.getProfileParams()) &&
+ (mSculptID == params.mSculptID) &&
+ (mSculptType == params.mSculptType) );
+}
+
+bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const
+{
+ return ( (getPathParams() != params.getPathParams()) ||
+ (getProfileParams() != params.getProfileParams()) ||
+ (mSculptID != params.mSculptID) ||
+ (mSculptType != params.mSculptType) );
+}
+
+bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const
+{
+ if( getPathParams() != params.getPathParams() )
+ {
+ return getPathParams() < params.getPathParams();
+ }
+
+ if (getProfileParams() != params.getProfileParams())
+ {
+ return getProfileParams() < params.getProfileParams();
+ }
+
+ if (mSculptID != params.mSculptID)
+ {
+ return mSculptID < params.mSculptID;
+ }
+
+ return mSculptType < params.mSculptType;
+
+
+}
+
+void LLVolumeParams::copyParams(const LLVolumeParams ¶ms)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+ mProfileParams.copyParams(params.mProfileParams);
+ mPathParams.copyParams(params.mPathParams);
+ mSculptID = params.getSculptID();
+ mSculptType = params.getSculptType();
+}
+
+// Less restricitve approx 0 for volumes
+const F32 APPROXIMATELY_ZERO = 0.001f;
+bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO)
+{
+ return (f >= -tolerance) && (f <= tolerance);
+}
+
+// return true if in range (or nearly so)
+static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO)
+{
+ F32 min_delta = v - min;
+ if (min_delta < 0.f)
+ {
+ v = min;
+ if (!approx_zero(min_delta, tolerance))
+ return false;
+ }
+ F32 max_delta = max - v;
+ if (max_delta < 0.f)
+ {
+ v = max;
+ if (!approx_zero(max_delta, tolerance))
+ return false;
+ }
+ return true;
+}
+
+bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e)
+{
+ bool valid = true;
+
+ // First, clamp to valid ranges.
+ F32 begin = b;
+ valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
+
+ F32 end = e;
+ if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error
+ valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
+
+ valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
+
+ // Now set them.
+ mProfileParams.setBegin(begin);
+ mProfileParams.setEnd(end);
+
+ return valid;
+}
+
+bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e)
+{
+ bool valid = true;
+
+ // First, clamp to valid ranges.
+ F32 begin = b;
+ valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
+
+ F32 end = e;
+ valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
+
+ valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
+
+ // Now set them.
+ mPathParams.setBegin(begin);
+ mPathParams.setEnd(end);
+
+ return valid;
+}
+
+bool LLVolumeParams::setHollow(const F32 h)
+{
+ // Validate the hollow based on path and profile.
+ U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+ U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK;
+
+ F32 max_hollow = HOLLOW_MAX;
+
+ // Only square holes have trouble.
+ if (LL_PCODE_HOLE_SQUARE == hole_type)
+ {
+ switch(profile)
+ {
+ case LL_PCODE_PROFILE_CIRCLE:
+ case LL_PCODE_PROFILE_CIRCLE_HALF:
+ case LL_PCODE_PROFILE_EQUALTRI:
+ max_hollow = HOLLOW_MAX_SQUARE;
+ }
+ }
+
+ F32 hollow = h;
+ bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow);
+ mProfileParams.setHollow(hollow);
+
+ return valid;
+}
+
+bool LLVolumeParams::setTwistBegin(const F32 b)
+{
+ F32 twist_begin = b;
+ bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX);
+ mPathParams.setTwistBegin(twist_begin);
+ return valid;
+}
+
+bool LLVolumeParams::setTwistEnd(const F32 e)
+{
+ F32 twist_end = e;
+ bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX);
+ mPathParams.setTwistEnd(twist_end);
+ return valid;
+}
+
+bool LLVolumeParams::setRatio(const F32 x, const F32 y)
+{
+ F32 min_x = RATIO_MIN;
+ F32 max_x = RATIO_MAX;
+ F32 min_y = RATIO_MIN;
+ F32 max_y = RATIO_MAX;
+ // If this is a circular path (and not a sphere) then 'ratio' is actually hole size.
+ U8 path_type = mPathParams.getCurveType();
+ U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+ if ( LL_PCODE_PATH_CIRCLE == path_type &&
+ LL_PCODE_PROFILE_CIRCLE_HALF != profile_type)
+ {
+ // Holes are more restricted...
+ min_x = HOLE_X_MIN;
+ max_x = HOLE_X_MAX;
+ min_y = HOLE_Y_MIN;
+ max_y = HOLE_Y_MAX;
+ }
+
+ F32 ratio_x = x;
+ bool valid = limit_range(ratio_x, min_x, max_x);
+ F32 ratio_y = y;
+ valid &= limit_range(ratio_y, min_y, max_y);
+
+ mPathParams.setScale(ratio_x, ratio_y);
+
+ return valid;
+}
+
+bool LLVolumeParams::setShear(const F32 x, const F32 y)
+{
+ F32 shear_x = x;
+ bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX);
+ F32 shear_y = y;
+ valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX);
+ mPathParams.setShear(shear_x, shear_y);
+ return valid;
+}
+
+bool LLVolumeParams::setTaperX(const F32 v)
+{
+ F32 taper = v;
+ bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
+ mPathParams.setTaperX(taper);
+ return valid;
+}
+
+bool LLVolumeParams::setTaperY(const F32 v)
+{
+ F32 taper = v;
+ bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
+ mPathParams.setTaperY(taper);
+ return valid;
+}
+
+bool LLVolumeParams::setRevolutions(const F32 r)
+{
+ F32 revolutions = r;
+ bool valid = limit_range(revolutions, REV_MIN, REV_MAX);
+ mPathParams.setRevolutions(revolutions);
+ return valid;
+}
+
+bool LLVolumeParams::setRadiusOffset(const F32 offset)
+{
+ bool valid = true;
+
+ // If this is a sphere, just set it to 0 and get out.
+ U8 path_type = mPathParams.getCurveType();
+ U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+ if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ||
+ LL_PCODE_PATH_CIRCLE != path_type )
+ {
+ mPathParams.setRadiusOffset(0.f);
+ return true;
+ }
+
+ // Limit radius offset, based on taper and hole size y.
+ F32 radius_offset = offset;
+ F32 taper_y = getTaperY();
+ F32 radius_mag = fabs(radius_offset);
+ F32 hole_y_mag = fabs(getRatioY());
+ F32 taper_y_mag = fabs(taper_y);
+ // Check to see if the taper effects us.
+ if ( (radius_offset > 0.f && taper_y < 0.f) ||
+ (radius_offset < 0.f && taper_y > 0.f) )
+ {
+ // The taper does not help increase the radius offset range.
+ taper_y_mag = 0.f;
+ }
+ F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
+
+ // Enforce the maximum magnitude.
+ F32 delta = max_radius_mag - radius_mag;
+ if (delta < 0.f)
+ {
+ // Check radius offset sign.
+ if (radius_offset < 0.f)
+ {
+ radius_offset = -max_radius_mag;
+ }
+ else
+ {
+ radius_offset = max_radius_mag;
+ }
+ valid = approx_zero(delta, .1f);
+ }
+
+ mPathParams.setRadiusOffset(radius_offset);
+ return valid;
+}
+
+bool LLVolumeParams::setSkew(const F32 skew_value)
+{
+ bool valid = true;
+
+ // Check the skew value against the revolutions.
+ F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX);
+ F32 skew_mag = fabs(skew);
+ F32 revolutions = getRevolutions();
+ F32 scale_x = getRatioX();
+ F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
+ // Discontinuity; A revolution of 1 allows skews below 0.5.
+ if ( fabs(revolutions - 1.0f) < 0.001)
+ min_skew_mag = 0.0f;
+
+ // Clip skew.
+ F32 delta = skew_mag - min_skew_mag;
+ if (delta < 0.f)
+ {
+ // Check skew sign.
+ if (skew < 0.0f)
+ {
+ skew = -min_skew_mag;
+ }
+ else
+ {
+ skew = min_skew_mag;
+ }
+ valid = approx_zero(delta, .01f);
+ }
+
+ mPathParams.setSkew(skew);
+ return valid;
+}
+
+bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type)
+{
+ mSculptID = sculpt_id;
+ mSculptType = sculpt_type;
+ return true;
+}
+
+bool LLVolumeParams::setType(U8 profile, U8 path)
+{
+ bool result = true;
+ // First, check profile and path for validity.
+ U8 profile_type = profile & LL_PCODE_PROFILE_MASK;
+ U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4;
+ U8 path_type = path >> 4;
+
+ if (profile_type > LL_PCODE_PROFILE_MAX)
+ {
+ // Bad profile. Make it square.
+ profile = LL_PCODE_PROFILE_SQUARE;
+ result = false;
+ llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type
+ << ") to be LL_PCODE_PROFILE_SQUARE" << llendl;
+ }
+ else if (hole_type > LL_PCODE_HOLE_MAX)
+ {
+ // Bad hole. Make it the same.
+ profile = profile_type;
+ result = false;
+ llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type
+ << ") to be LL_PCODE_HOLE_SAME" << llendl;
+ }
+
+ if (path_type < LL_PCODE_PATH_MIN ||
+ path_type > LL_PCODE_PATH_MAX)
+ {
+ // Bad path. Make it linear.
+ result = false;
+ llwarns << "LLVolumeParams::setType changing bad path (" << path
+ << ") to be LL_PCODE_PATH_LINE" << llendl;
+ path = LL_PCODE_PATH_LINE;
+ }
+
+ mProfileParams.setCurveType(profile);
+ mPathParams.setCurveType(path);
+ return result;
+}
+
+// static
+bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
+ U8 path_curve, F32 path_begin, F32 path_end,
+ F32 scx, F32 scy, F32 shx, F32 shy,
+ F32 twistend, F32 twistbegin, F32 radiusoffset,
+ F32 tx, F32 ty, F32 revolutions, F32 skew)
+{
+ LLVolumeParams test_params;
+ if (!test_params.setType (prof_curve, path_curve))
+ {
+ return false;
+ }
+ if (!test_params.setBeginAndEndS (prof_begin, prof_end))
+ {
+ return false;
+ }
+ if (!test_params.setBeginAndEndT (path_begin, path_end))
+ {
+ return false;
+ }
+ if (!test_params.setHollow (hollow))
+ {
+ return false;
+ }
+ if (!test_params.setTwistBegin (twistbegin))
+ {
+ return false;
+ }
+ if (!test_params.setTwistEnd (twistend))
+ {
+ return false;
+ }
+ if (!test_params.setRatio (scx, scy))
+ {
+ return false;
+ }
+ if (!test_params.setShear (shx, shy))
+ {
+ return false;
+ }
+ if (!test_params.setTaper (tx, ty))
+ {
+ return false;
+ }
+ if (!test_params.setRevolutions (revolutions))
+ {
+ return false;
+ }
+ if (!test_params.setRadiusOffset (radiusoffset))
+ {
+ return false;
+ }
+ if (!test_params.setSkew (skew))
+ {
+ return false;
+ }
+ return true;
+}
+
+S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ S32 expected_num_triangle_indices = getNumTriangleIndices();
+ if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES)
+ {
+ // we don't allow LLVolumes with this many vertices
+ llwarns << "Couldn't allocate triangle indices" << llendl;
+ num_indices = 0;
+ return NULL;
+ }
+
+ S32* index = new S32[expected_num_triangle_indices];
+ S32 count = 0;
+
+ // Let's do this totally diffently, as we don't care about faces...
+ // Counter-clockwise triangles are forward facing...
+
+ BOOL open = getProfile().isOpen();
+ BOOL hollow = (mParams.getProfileParams().getHollow() > 0);
+ BOOL path_open = getPath().isOpen();
+ S32 size_s, size_s_out, size_t;
+ S32 s, t, i;
+ size_s = getProfile().getTotal();
+ size_s_out = getProfile().getTotalOut();
+ size_t = getPath().mPath.size();
+
+ // NOTE -- if the construction of the triangles below ever changes
+ // then getNumTriangleIndices() method may also have to be updated.
+
+ if (open) /* Flawfinder: ignore */
+ {
+ if (hollow)
+ {
+ // Open hollow -- much like the closed solid, except we
+ // we need to stitch up the gap between s=0 and s=size_s-1
+
+ for (t = 0; t < size_t - 1; t++)
+ {
+ // The outer face, first cut, and inner face
+ for (s = 0; s < size_s - 1; s++)
+ {
+ i = s + t*size_s;
+ index[count++] = i; // x,y
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + size_s; // x,y+1
+
+ index[count++] = i + size_s; // x,y+1
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + size_s + 1; // x+1,y+1
+ }
+
+ // The other cut face
+ index[count++] = s + t*size_s; // x,y
+ index[count++] = 0 + t*size_s; // x+1,y
+ index[count++] = s + (t+1)*size_s; // x,y+1
+
+ index[count++] = s + (t+1)*size_s; // x,y+1
+ index[count++] = 0 + t*size_s; // x+1,y
+ index[count++] = 0 + (t+1)*size_s; // x+1,y+1
+ }
+
+ // Do the top and bottom caps, if necessary
+ if (path_open)
+ {
+ // Top cap
+ S32 pt1 = 0;
+ S32 pt2 = size_s-1;
+ S32 i = (size_t - 1)*size_s;
+
+ while (pt2 - pt1 > 1)
+ {
+ // Use the profile points instead of the mesh, since you want
+ // the un-transformed profile distances.
+ LLVector3 p1 = getProfile().mProfile[pt1];
+ LLVector3 p2 = getProfile().mProfile[pt2];
+ LLVector3 pa = getProfile().mProfile[pt1+1];
+ LLVector3 pb = getProfile().mProfile[pt2-1];
+
+ p1.mV[VZ] = 0.f;
+ p2.mV[VZ] = 0.f;
+ pa.mV[VZ] = 0.f;
+ pb.mV[VZ] = 0.f;
+
+ // Use area of triangle to determine backfacing
+ F32 area_1a2, area_1ba, area_21b, area_2ab;
+ area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+ (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+ (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+
+ area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+ (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+
+ area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+ (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+ (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ BOOL use_tri1a2 = TRUE;
+ BOOL tri_1a2 = TRUE;
+ BOOL tri_21b = TRUE;
+
+ if (area_1a2 < 0)
+ {
+ tri_1a2 = FALSE;
+ }
+ if (area_2ab < 0)
+ {
+ // Can't use, because it contains point b
+ tri_1a2 = FALSE;
+ }
+ if (area_21b < 0)
+ {
+ tri_21b = FALSE;
+ }
+ if (area_1ba < 0)
+ {
+ // Can't use, because it contains point b
+ tri_21b = FALSE;
+ }
+
+ if (!tri_1a2)
+ {
+ use_tri1a2 = FALSE;
+ }
+ else if (!tri_21b)
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ LLVector3 d1 = p1 - pa;
+ LLVector3 d2 = p2 - pb;
+
+ if (d1.magVecSquared() < d2.magVecSquared())
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ use_tri1a2 = FALSE;
+ }
+ }
+
+ if (use_tri1a2)
+ {
+ index[count++] = pt1 + i;
+ index[count++] = pt1 + 1 + i;
+ index[count++] = pt2 + i;
+ pt1++;
+ }
+ else
+ {
+ index[count++] = pt1 + i;
+ index[count++] = pt2 - 1 + i;
+ index[count++] = pt2 + i;
+ pt2--;
+ }
+ }
+
+ // Bottom cap
+ pt1 = 0;
+ pt2 = size_s-1;
+ while (pt2 - pt1 > 1)
+ {
+ // Use the profile points instead of the mesh, since you want
+ // the un-transformed profile distances.
+ LLVector3 p1 = getProfile().mProfile[pt1];
+ LLVector3 p2 = getProfile().mProfile[pt2];
+ LLVector3 pa = getProfile().mProfile[pt1+1];
+ LLVector3 pb = getProfile().mProfile[pt2-1];
+
+ p1.mV[VZ] = 0.f;
+ p2.mV[VZ] = 0.f;
+ pa.mV[VZ] = 0.f;
+ pb.mV[VZ] = 0.f;
+
+ // Use area of triangle to determine backfacing
+ F32 area_1a2, area_1ba, area_21b, area_2ab;
+ area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+ (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+ (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+
+ area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+ (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+
+ area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+ (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+ (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ BOOL use_tri1a2 = TRUE;
+ BOOL tri_1a2 = TRUE;
+ BOOL tri_21b = TRUE;
+
+ if (area_1a2 < 0)
+ {
+ tri_1a2 = FALSE;
+ }
+ if (area_2ab < 0)
+ {
+ // Can't use, because it contains point b
+ tri_1a2 = FALSE;
+ }
+ if (area_21b < 0)
+ {
+ tri_21b = FALSE;
+ }
+ if (area_1ba < 0)
+ {
+ // Can't use, because it contains point b
+ tri_21b = FALSE;
+ }
+
+ if (!tri_1a2)
+ {
+ use_tri1a2 = FALSE;
+ }
+ else if (!tri_21b)
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ LLVector3 d1 = p1 - pa;
+ LLVector3 d2 = p2 - pb;
+
+ if (d1.magVecSquared() < d2.magVecSquared())
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ use_tri1a2 = FALSE;
+ }
+ }
+
+ if (use_tri1a2)
+ {
+ index[count++] = pt1;
+ index[count++] = pt2;
+ index[count++] = pt1 + 1;
+ pt1++;
+ }
+ else
+ {
+ index[count++] = pt1;
+ index[count++] = pt2;
+ index[count++] = pt2 - 1;
+ pt2--;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Open solid
+
+ for (t = 0; t < size_t - 1; t++)
+ {
+ // Outer face + 1 cut face
+ for (s = 0; s < size_s - 1; s++)
+ {
+ i = s + t*size_s;
+
+ index[count++] = i; // x,y
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + size_s; // x,y+1
+
+ index[count++] = i + size_s; // x,y+1
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + size_s + 1; // x+1,y+1
+ }
+
+ // The other cut face
+ index[count++] = (size_s - 1) + (t*size_s); // x,y
+ index[count++] = 0 + t*size_s; // x+1,y
+ index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1
+
+ index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1
+ index[count++] = 0 + (t*size_s); // x+1,y
+ index[count++] = 0 + (t+1)*size_s; // x+1,y+1
+ }
+
+ // Do the top and bottom caps, if necessary
+ if (path_open)
+ {
+ for (s = 0; s < size_s - 2; s++)
+ {
+ index[count++] = s+1;
+ index[count++] = s;
+ index[count++] = size_s - 1;
+ }
+
+ // We've got a top cap
+ S32 offset = (size_t - 1)*size_s;
+ for (s = 0; s < size_s - 2; s++)
+ {
+ // Inverted ordering from bottom cap.
+ index[count++] = offset + size_s - 1;
+ index[count++] = offset + s;
+ index[count++] = offset + s + 1;
+ }
+ }
+ }
+ }
+ else if (hollow)
+ {
+ // Closed hollow
+ // Outer face
+
+ for (t = 0; t < size_t - 1; t++)
+ {
+ for (s = 0; s < size_s_out - 1; s++)
+ {
+ i = s + t*size_s;
+
+ index[count++] = i; // x,y
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + size_s; // x,y+1
+
+ index[count++] = i + size_s; // x,y+1
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + 1 + size_s; // x+1,y+1
+ }
+ }
+
+ // Inner face
+ // Invert facing from outer face
+ for (t = 0; t < size_t - 1; t++)
+ {
+ for (s = size_s_out; s < size_s - 1; s++)
+ {
+ i = s + t*size_s;
+
+ index[count++] = i; // x,y
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + size_s; // x,y+1
+
+ index[count++] = i + size_s; // x,y+1
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + 1 + size_s; // x+1,y+1
+ }
+ }
+
+ // Do the top and bottom caps, if necessary
+ if (path_open)
+ {
+ // Top cap
+ S32 pt1 = 0;
+ S32 pt2 = size_s-1;
+ S32 i = (size_t - 1)*size_s;
+
+ while (pt2 - pt1 > 1)
+ {
+ // Use the profile points instead of the mesh, since you want
+ // the un-transformed profile distances.
+ LLVector3 p1 = getProfile().mProfile[pt1];
+ LLVector3 p2 = getProfile().mProfile[pt2];
+ LLVector3 pa = getProfile().mProfile[pt1+1];
+ LLVector3 pb = getProfile().mProfile[pt2-1];
+
+ p1.mV[VZ] = 0.f;
+ p2.mV[VZ] = 0.f;
+ pa.mV[VZ] = 0.f;
+ pb.mV[VZ] = 0.f;
+
+ // Use area of triangle to determine backfacing
+ F32 area_1a2, area_1ba, area_21b, area_2ab;
+ area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+ (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+ (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+
+ area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+ (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+
+ area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+ (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+ (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ BOOL use_tri1a2 = TRUE;
+ BOOL tri_1a2 = TRUE;
+ BOOL tri_21b = TRUE;
+
+ if (area_1a2 < 0)
+ {
+ tri_1a2 = FALSE;
+ }
+ if (area_2ab < 0)
+ {
+ // Can't use, because it contains point b
+ tri_1a2 = FALSE;
+ }
+ if (area_21b < 0)
+ {
+ tri_21b = FALSE;
+ }
+ if (area_1ba < 0)
+ {
+ // Can't use, because it contains point b
+ tri_21b = FALSE;
+ }
+
+ if (!tri_1a2)
+ {
+ use_tri1a2 = FALSE;
+ }
+ else if (!tri_21b)
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ LLVector3 d1 = p1 - pa;
+ LLVector3 d2 = p2 - pb;
+
+ if (d1.magVecSquared() < d2.magVecSquared())
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ use_tri1a2 = FALSE;
+ }
+ }
+
+ if (use_tri1a2)
+ {
+ index[count++] = pt1 + i;
+ index[count++] = pt1 + 1 + i;
+ index[count++] = pt2 + i;
+ pt1++;
+ }
+ else
+ {
+ index[count++] = pt1 + i;
+ index[count++] = pt2 - 1 + i;
+ index[count++] = pt2 + i;
+ pt2--;
+ }
+ }
+
+ // Bottom cap
+ pt1 = 0;
+ pt2 = size_s-1;
+ while (pt2 - pt1 > 1)
+ {
+ // Use the profile points instead of the mesh, since you want
+ // the un-transformed profile distances.
+ LLVector3 p1 = getProfile().mProfile[pt1];
+ LLVector3 p2 = getProfile().mProfile[pt2];
+ LLVector3 pa = getProfile().mProfile[pt1+1];
+ LLVector3 pb = getProfile().mProfile[pt2-1];
+
+ p1.mV[VZ] = 0.f;
+ p2.mV[VZ] = 0.f;
+ pa.mV[VZ] = 0.f;
+ pb.mV[VZ] = 0.f;
+
+ // Use area of triangle to determine backfacing
+ F32 area_1a2, area_1ba, area_21b, area_2ab;
+ area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+ (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+ (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+
+ area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+ (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+
+ area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+ (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+ (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ BOOL use_tri1a2 = TRUE;
+ BOOL tri_1a2 = TRUE;
+ BOOL tri_21b = TRUE;
+
+ if (area_1a2 < 0)
+ {
+ tri_1a2 = FALSE;
+ }
+ if (area_2ab < 0)
+ {
+ // Can't use, because it contains point b
+ tri_1a2 = FALSE;
+ }
+ if (area_21b < 0)
+ {
+ tri_21b = FALSE;
+ }
+ if (area_1ba < 0)
+ {
+ // Can't use, because it contains point b
+ tri_21b = FALSE;
+ }
+
+ if (!tri_1a2)
+ {
+ use_tri1a2 = FALSE;
+ }
+ else if (!tri_21b)
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ LLVector3 d1 = p1 - pa;
+ LLVector3 d2 = p2 - pb;
+
+ if (d1.magVecSquared() < d2.magVecSquared())
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ use_tri1a2 = FALSE;
+ }
+ }
+
+ if (use_tri1a2)
+ {
+ index[count++] = pt1;
+ index[count++] = pt2;
+ index[count++] = pt1 + 1;
+ pt1++;
+ }
+ else
+ {
+ index[count++] = pt1;
+ index[count++] = pt2;
+ index[count++] = pt2 - 1;
+ pt2--;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Closed solid. Easy case.
+ for (t = 0; t < size_t - 1; t++)
+ {
+ for (s = 0; s < size_s - 1; s++)
+ {
+ // Should wrap properly, but for now...
+ i = s + t*size_s;
+
+ index[count++] = i; // x,y
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + size_s; // x,y+1
+
+ index[count++] = i + size_s; // x,y+1
+ index[count++] = i + 1; // x+1,y
+ index[count++] = i + size_s + 1; // x+1,y+1
+ }
+ }
+
+ // Do the top and bottom caps, if necessary
+ if (path_open)
+ {
+ // bottom cap
+ for (s = 1; s < size_s - 2; s++)
+ {
+ index[count++] = s+1;
+ index[count++] = s;
+ index[count++] = 0;
+ }
+
+ // top cap
+ S32 offset = (size_t - 1)*size_s;
+ for (s = 1; s < size_s - 2; s++)
+ {
+ // Inverted ordering from bottom cap.
+ index[count++] = offset;
+ index[count++] = offset + s;
+ index[count++] = offset + s + 1;
+ }
+ }
+ }
+
+#ifdef LL_DEBUG
+ // assert that we computed the correct number of indices
+ if (count != expected_num_triangle_indices )
+ {
+ llerrs << "bad index count prediciton:"
+ << " expected=" << expected_num_triangle_indices
+ << " actual=" << count << llendl;
+ }
+#endif
+
+#if 0
+ // verify that each index does not point beyond the size of the mesh
+ S32 num_vertices = mMesh.size();
+ for (i = 0; i < count; i+=3)
+ {
+ llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl;
+ llassert(index[i] < num_vertices);
+ llassert(index[i+1] < num_vertices);
+ llassert(index[i+2] < num_vertices);
+ }
+#endif
+
+ num_indices = count;
+ return index;
+}
+
+S32 LLVolume::getNumTriangleIndices() const
+{
+ BOOL profile_open = getProfile().isOpen();
+ BOOL hollow = (mParams.getProfileParams().getHollow() > 0);
+ BOOL path_open = getPath().isOpen();
+
+ S32 size_s, size_s_out, size_t;
+ size_s = getProfile().getTotal();
+ size_s_out = getProfile().getTotalOut();
+ size_t = getPath().mPath.size();
+
+ S32 count = 0;
+ if (profile_open) /* Flawfinder: ignore */
+ {
+ if (hollow)
+ {
+ // Open hollow -- much like the closed solid, except we
+ // we need to stitch up the gap between s=0 and s=size_s-1
+ count = (size_t - 1) * (((size_s -1) * 6) + 6);
+ }
+ else
+ {
+ count = (size_t - 1) * (((size_s -1) * 6) + 6);
+ }
+ }
+ else if (hollow)
+ {
+ // Closed hollow
+ // Outer face
+ count = (size_t - 1) * (size_s_out - 1) * 6;
+
+ // Inner face
+ count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6;
+ }
+ else
+ {
+ // Closed solid. Easy case.
+ count = (size_t - 1) * (size_s - 1) * 6;
+ }
+
+ if (path_open)
+ {
+ S32 cap_triangle_count = size_s - 3;
+ if ( profile_open
+ || hollow )
+ {
+ cap_triangle_count = size_s - 2;
+ }
+ if ( cap_triangle_count > 0 )
+ {
+ // top and bottom caps
+ count += cap_triangle_count * 2 * 3;
+ }
+ }
+ return count;
+}
+
+
+S32 LLVolume::getNumTriangles() const
+{
+ U32 triangle_count = 0;
+
+ for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+ {
+ triangle_count += getVolumeFace(i).mNumIndices/3;
+ }
+
+ return triangle_count;
+}
+
+
+//-----------------------------------------------------------------------------
+// generateSilhouetteVertices()
+//-----------------------------------------------------------------------------
+void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
+ std::vector<LLVector3> &normals,
+ std::vector<S32> &segments,
+ const LLVector3& obj_cam_vec_in,
+ const LLMatrix4& mat_in,
+ const LLMatrix3& norm_mat_in,
+ S32 face_mask)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ LLMatrix4a mat;
+ mat.loadu(mat_in);
+
+ LLMatrix4a norm_mat;
+ norm_mat.loadu(norm_mat_in);
+
+ LLVector4a obj_cam_vec;
+ obj_cam_vec.load3(obj_cam_vec_in.mV);
+
+ vertices.clear();
+ normals.clear();
+ segments.clear();
+
+ if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ {
+ return;
+ }
+
+ S32 cur_index = 0;
+ //for each face
+ for (face_list_t::iterator iter = mVolumeFaces.begin();
+ iter != mVolumeFaces.end(); ++iter)
+ {
+ LLVolumeFace& face = *iter;
+
+ if (!(face_mask & (0x1 << cur_index++)) ||
+ face.mNumIndices == 0 || face.mEdge.empty())
+ {
+ continue;
+ }
+
+ if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
+
+ }
+ else {
+
+ //==============================================
+ //DEBUG draw edge map instead of silhouette edge
+ //==============================================
+
+#if DEBUG_SILHOUETTE_EDGE_MAP
+
+ //for each triangle
+ U32 count = face.mNumIndices;
+ for (U32 j = 0; j < count/3; j++) {
+ //get vertices
+ S32 v1 = face.mIndices[j*3+0];
+ S32 v2 = face.mIndices[j*3+1];
+ S32 v3 = face.mIndices[j*3+2];
+
+ //get current face center
+ LLVector3 cCenter = (face.mVertices[v1].getPosition() +
+ face.mVertices[v2].getPosition() +
+ face.mVertices[v3].getPosition()) / 3.0f;
+
+ //for each edge
+ for (S32 k = 0; k < 3; k++) {
+ S32 nIndex = face.mEdge[j*3+k];
+ if (nIndex <= -1) {
+ continue;
+ }
+
+ if (nIndex >= (S32) count/3) {
+ continue;
+ }
+ //get neighbor vertices
+ v1 = face.mIndices[nIndex*3+0];
+ v2 = face.mIndices[nIndex*3+1];
+ v3 = face.mIndices[nIndex*3+2];
+
+ //get neighbor face center
+ LLVector3 nCenter = (face.mVertices[v1].getPosition() +
+ face.mVertices[v2].getPosition() +
+ face.mVertices[v3].getPosition()) / 3.0f;
+
+ //draw line
+ vertices.push_back(cCenter);
+ vertices.push_back(nCenter);
+ normals.push_back(LLVector3(1,1,1));
+ normals.push_back(LLVector3(1,1,1));
+ segments.push_back(vertices.size());
+ }
+ }
+
+ continue;
+
+ //==============================================
+ //DEBUG
+ //==============================================
+
+ //==============================================
+ //DEBUG draw normals instead of silhouette edge
+ //==============================================
+#elif DEBUG_SILHOUETTE_NORMALS
+
+ //for each vertex
+ for (U32 j = 0; j < face.mNumVertices; j++) {
+ vertices.push_back(face.mVertices[j].getPosition());
+ vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f);
+ normals.push_back(LLVector3(0,0,1));
+ normals.push_back(LLVector3(0,0,1));
+ segments.push_back(vertices.size());
+#if DEBUG_SILHOUETTE_BINORMALS
+ vertices.push_back(face.mVertices[j].getPosition());
+ vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f);
+ normals.push_back(LLVector3(0,0,1));
+ normals.push_back(LLVector3(0,0,1));
+ segments.push_back(vertices.size());
+#endif
+ }
+
+ continue;
+#else
+ //==============================================
+ //DEBUG
+ //==============================================
+
+ static const U8 AWAY = 0x01,
+ TOWARDS = 0x02;
+
+ //for each triangle
+ std::vector<U8> fFacing;
+ vector_append(fFacing, face.mNumIndices/3);
+
+ LLVector4a* v = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (U32 j = 0; j < face.mNumIndices/3; j++)
+ {
+ //approximate normal
+ S32 v1 = face.mIndices[j*3+0];
+ S32 v2 = face.mIndices[j*3+1];
+ S32 v3 = face.mIndices[j*3+2];
+
+ LLVector4a c1,c2;
+ c1.setSub(v[v1], v[v2]);
+ c2.setSub(v[v2], v[v3]);
+
+ LLVector4a norm;
+
+ norm.setCross3(c1, c2);
+
+ if (norm.dot3(norm) < 0.00000001f)
+ {
+ fFacing[j] = AWAY | TOWARDS;
+ }
+ else
+ {
+ //get view vector
+ LLVector4a view;
+ view.setSub(obj_cam_vec, v[v1]);
+ bool away = view.dot3(norm) > 0.0f;
+ if (away)
+ {
+ fFacing[j] = AWAY;
+ }
+ else
+ {
+ fFacing[j] = TOWARDS;
+ }
+ }
+ }
+
+ //for each triangle
+ for (U32 j = 0; j < face.mNumIndices/3; j++)
+ {
+ if (fFacing[j] == (AWAY | TOWARDS))
+ { //this is a degenerate triangle
+ //take neighbor facing (degenerate faces get facing of one of their neighbors)
+ // *FIX IF NEEDED: this does not deal with neighboring degenerate faces
+ for (S32 k = 0; k < 3; k++)
+ {
+ S32 index = face.mEdge[j*3+k];
+ if (index != -1)
+ {
+ fFacing[j] = fFacing[index];
+ break;
+ }
+ }
+ continue; //skip degenerate face
+ }
+
+ //for each edge
+ for (S32 k = 0; k < 3; k++) {
+ S32 index = face.mEdge[j*3+k];
+ if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) {
+ //our neighbor is degenerate, make him face our direction
+ fFacing[face.mEdge[j*3+k]] = fFacing[j];
+ continue;
+ }
+
+ if (index == -1 || //edge has no neighbor, MUST be a silhouette edge
+ (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge
+
+ S32 v1 = face.mIndices[j*3+k];
+ S32 v2 = face.mIndices[j*3+((k+1)%3)];
+
+ LLVector4a t;
+ mat.affineTransform(v[v1], t);
+ vertices.push_back(LLVector3(t[0], t[1], t[2]));
+
+ norm_mat.rotate(n[v1], t);
+
+ t.normalize3fast();
+ normals.push_back(LLVector3(t[0], t[1], t[2]));
+
+ mat.affineTransform(v[v2], t);
+ vertices.push_back(LLVector3(t[0], t[1], t[2]));
+
+ norm_mat.rotate(n[v2], t);
+ t.normalize3fast();
+ normals.push_back(LLVector3(t[0], t[1], t[2]));
+
+ segments.push_back(vertices.size());
+ }
+ }
+ }
+#endif
+ }
+ }
+}
+
+S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+ S32 face,
+ LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+{
+ LLVector4a starta, enda;
+ starta.load3(start.mV);
+ enda.load3(end.mV);
+
+ return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal);
+
+}
+
+
+S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+ S32 face,
+ LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+{
+ S32 hit_face = -1;
+
+ S32 start_face;
+ S32 end_face;
+
+ if (face == -1) // ALL_SIDES
+ {
+ start_face = 0;
+ end_face = getNumVolumeFaces() - 1;
+ }
+ else
+ {
+ start_face = face;
+ end_face = face;
+ }
+
+ LLVector4a dir;
+ dir.setSub(end, start);
+
+ F32 closest_t = 2.f; // must be larger than 1
+
+ end_face = llmin(end_face, getNumVolumeFaces()-1);
+
+ for (S32 i = start_face; i <= end_face; i++)
+ {
+ LLVolumeFace &face = mVolumeFaces[i];
+
+ LLVector4a box_center;
+ box_center.setAdd(face.mExtents[0], face.mExtents[1]);
+ box_center.mul(0.5f);
+
+ LLVector4a box_size;
+ box_size.setSub(face.mExtents[1], face.mExtents[0]);
+
+ if (LLLineSegmentBoxIntersect(start, end, box_center, box_size))
+ {
+ if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them
+ {
+ genBinormals(i);
+ }
+
+ if (!face.mOctree)
+ {
+ face.createOctree();
+ }
+
+ //LLVector4a* p = (LLVector4a*) face.mPositions;
+
+ LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
+ intersect.traverse(face.mOctree);
+ if (intersect.mHitFace)
+ {
+ hit_face = i;
+ }
+ }
+ }
+
+
+ return hit_face;
+}
+
+class LLVertexIndexPair
+{
+public:
+ LLVertexIndexPair(const LLVector3 &vertex, const S32 index);
+
+ LLVector3 mVertex;
+ S32 mIndex;
+};
+
+LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index)
+{
+ mVertex = vertex;
+ mIndex = index;
+}
+
+const F32 VERTEX_SLOP = 0.00001f;
+const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP;
+
+struct lessVertex
+{
+ bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b)
+ {
+ const F32 slop = VERTEX_SLOP;
+
+ if (a->mVertex.mV[0] + slop < b->mVertex.mV[0])
+ {
+ return TRUE;
+ }
+ else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0])
+ {
+ return FALSE;
+ }
+
+ if (a->mVertex.mV[1] + slop < b->mVertex.mV[1])
+ {
+ return TRUE;
+ }
+ else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1])
+ {
+ return FALSE;
+ }
+
+ if (a->mVertex.mV[2] + slop < b->mVertex.mV[2])
+ {
+ return TRUE;
+ }
+ else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2])
+ {
+ return FALSE;
+ }
+
+ return FALSE;
+ }
+};
+
+struct lessTriangle
+{
+ bool operator()(const S32 *a, const S32 *b)
+ {
+ if (*a < *b)
+ {
+ return TRUE;
+ }
+ else if (*a > *b)
+ {
+ return FALSE;
+ }
+
+ if (*(a+1) < *(b+1))
+ {
+ return TRUE;
+ }
+ else if (*(a+1) > *(b+1))
+ {
+ return FALSE;
+ }
+
+ if (*(a+2) < *(b+2))
+ {
+ return TRUE;
+ }
+ else if (*(a+2) > *(b+2))
+ {
+ return FALSE;
+ }
+
+ return FALSE;
+ }
+};
+
+BOOL equalTriangle(const S32 *a, const S32 *b)
+{
+ if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2)))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
+ const std::vector<Point>& input_vertices,
+ const S32 num_input_triangles,
+ S32 *input_triangles,
+ S32 &num_output_vertices,
+ LLVector3 **output_vertices,
+ S32 &num_output_triangles,
+ S32 **output_triangles)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ /* Testing: avoid any cleanup
+ static BOOL skip_cleanup = TRUE;
+ if ( skip_cleanup )
+ {
+ num_output_vertices = num_input_vertices;
+ num_output_triangles = num_input_triangles;
+
+ *output_vertices = new LLVector3[num_input_vertices];
+ for (S32 index = 0; index < num_input_vertices; index++)
+ {
+ (*output_vertices)[index] = input_vertices[index].mPos;
+ }
+
+ *output_triangles = new S32[num_input_triangles*3];
+ memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32)); // Flawfinder: ignore
+ return TRUE;
+ }
+ */
+
+ // Here's how we do this:
+ // Create a structure which contains the original vertex index and the
+ // LLVector3 data.
+ // "Sort" the data by the vectors
+ // Create an array the size of the old vertex list, with a mapping of
+ // old indices to new indices.
+ // Go through triangles, shift so the lowest index is first
+ // Sort triangles by first index
+ // Remove duplicate triangles
+ // Allocate and pack new triangle data.
+
+ //LLTimer cleanupTimer;
+ //llinfos << "In vertices: " << num_input_vertices << llendl;
+ //llinfos << "In triangles: " << num_input_triangles << llendl;
+
+ S32 i;
+ typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t;
+ vertex_set_t vertex_list;
+
+ LLVertexIndexPair *pairp = NULL;
+ for (i = 0; i < num_input_vertices; i++)
+ {
+ LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i);
+ vertex_list.insert(new_pairp);
+ }
+
+ // Generate the vertex mapping and the list of vertices without
+ // duplicates. This will crash if there are no vertices.
+ llassert(num_input_vertices > 0); // check for no vertices!
+ S32 *vertex_mapping = new S32[num_input_vertices];
+ LLVector3 *new_vertices = new LLVector3[num_input_vertices];
+ LLVertexIndexPair *prev_pairp = NULL;
+
+ S32 new_num_vertices;
+
+ new_num_vertices = 0;
+ for (vertex_set_t::iterator iter = vertex_list.begin(),
+ end = vertex_list.end();
+ iter != end; iter++)
+ {
+ pairp = *iter;
+ if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD))
+ {
+ new_vertices[new_num_vertices] = pairp->mVertex;
+ //llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl;
+ new_num_vertices++;
+ // Update the previous
+ prev_pairp = pairp;
+ }
+ else
+ {
+ //llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl;
+ }
+ vertex_mapping[pairp->mIndex] = new_num_vertices - 1;
+ }
+
+ // Iterate through triangles and remove degenerates, re-ordering vertices
+ // along the way.
+ S32 *new_triangles = new S32[num_input_triangles * 3];
+ S32 new_num_triangles = 0;
+
+ for (i = 0; i < num_input_triangles; i++)
+ {
+ S32 v1 = i*3;
+ S32 v2 = v1 + 1;
+ S32 v3 = v1 + 2;
+
+ //llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
+ input_triangles[v1] = vertex_mapping[input_triangles[v1]];
+ input_triangles[v2] = vertex_mapping[input_triangles[v2]];
+ input_triangles[v3] = vertex_mapping[input_triangles[v3]];
+
+ if ((input_triangles[v1] == input_triangles[v2])
+ || (input_triangles[v1] == input_triangles[v3])
+ || (input_triangles[v2] == input_triangles[v3]))
+ {
+ //llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
+ // Degenerate triangle, skip
+ continue;
+ }
+
+ if (input_triangles[v1] < input_triangles[v2])
+ {
+ if (input_triangles[v1] < input_triangles[v3])
+ {
+ // (0 < 1) && (0 < 2)
+ new_triangles[new_num_triangles*3] = input_triangles[v1];
+ new_triangles[new_num_triangles*3+1] = input_triangles[v2];
+ new_triangles[new_num_triangles*3+2] = input_triangles[v3];
+ }
+ else
+ {
+ // (0 < 1) && (2 < 0)
+ new_triangles[new_num_triangles*3] = input_triangles[v3];
+ new_triangles[new_num_triangles*3+1] = input_triangles[v1];
+ new_triangles[new_num_triangles*3+2] = input_triangles[v2];
+ }
+ }
+ else if (input_triangles[v2] < input_triangles[v3])
+ {
+ // (1 < 0) && (1 < 2)
+ new_triangles[new_num_triangles*3] = input_triangles[v2];
+ new_triangles[new_num_triangles*3+1] = input_triangles[v3];
+ new_triangles[new_num_triangles*3+2] = input_triangles[v1];
+ }
+ else
+ {
+ // (1 < 0) && (2 < 1)
+ new_triangles[new_num_triangles*3] = input_triangles[v3];
+ new_triangles[new_num_triangles*3+1] = input_triangles[v1];
+ new_triangles[new_num_triangles*3+2] = input_triangles[v2];
+ }
+ new_num_triangles++;
+ }
+
+ if (new_num_triangles == 0)
+ {
+ llwarns << "Created volume object with 0 faces." << llendl;
+ delete[] new_triangles;
+ delete[] vertex_mapping;
+ delete[] new_vertices;
+ return FALSE;
+ }
+
+ typedef std::set<S32*, lessTriangle> triangle_set_t;
+ triangle_set_t triangle_list;
+
+ for (i = 0; i < new_num_triangles; i++)
+ {
+ triangle_list.insert(&new_triangles[i*3]);
+ }
+
+ // Sort through the triangle list, and delete duplicates
+
+ S32 *prevp = NULL;
+ S32 *curp = NULL;
+
+ S32 *sorted_tris = new S32[new_num_triangles*3];
+ S32 cur_tri = 0;
+ for (triangle_set_t::iterator iter = triangle_list.begin(),
+ end = triangle_list.end();
+ iter != end; iter++)
+ {
+ curp = *iter;
+ if (!prevp || !equalTriangle(prevp, curp))
+ {
+ //llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
+ sorted_tris[cur_tri*3] = *curp;
+ sorted_tris[cur_tri*3+1] = *(curp+1);
+ sorted_tris[cur_tri*3+2] = *(curp+2);
+ cur_tri++;
+ prevp = curp;
+ }
+ else
+ {
+ //llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
+ }
+ }
+
+ *output_vertices = new LLVector3[new_num_vertices];
+ num_output_vertices = new_num_vertices;
+ for (i = 0; i < new_num_vertices; i++)
+ {
+ (*output_vertices)[i] = new_vertices[i];
+ }
+
+ *output_triangles = new S32[cur_tri*3];
+ num_output_triangles = cur_tri;
+ memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32)); /* Flawfinder: ignore */
+
+ /*
+ llinfos << "Out vertices: " << num_output_vertices << llendl;
+ llinfos << "Out triangles: " << num_output_triangles << llendl;
+ for (i = 0; i < num_output_vertices; i++)
+ {
+ llinfos << i << ":" << (*output_vertices)[i] << llendl;
+ }
+ for (i = 0; i < num_output_triangles; i++)
+ {
+ llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl;
+ }
+ */
+
+ //llinfos << "Out vertices: " << num_output_vertices << llendl;
+ //llinfos << "Out triangles: " << num_output_triangles << llendl;
+ delete[] vertex_mapping;
+ vertex_mapping = NULL;
+ delete[] new_vertices;
+ new_vertices = NULL;
+ delete[] new_triangles;
+ new_triangles = NULL;
+ delete[] sorted_tris;
+ sorted_tris = NULL;
+ triangle_list.clear();
+ std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer());
+ vertex_list.clear();
+
+ return TRUE;
+}
+
+
+BOOL LLVolumeParams::importFile(LLFILE *fp)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ //llinfos << "importing volume" << llendl;
+ const S32 BUFSIZE = 16384;
+ char buffer[BUFSIZE]; /* Flawfinder: ignore */
+ // *NOTE: changing the size or type of this buffer will require
+ // changing the sscanf below.
+ char keyword[256]; /* Flawfinder: ignore */
+ keyword[0] = 0;
+
+ while (!feof(fp))
+ {
+ if (fgets(buffer, BUFSIZE, fp) == NULL)
+ {
+ buffer[0] = '\0';
+ }
+
+ sscanf(buffer, " %255s", keyword); /* Flawfinder: ignore */
+ if (!strcmp("{", keyword))
+ {
+ continue;
+ }
+ if (!strcmp("}",keyword))
+ {
+ break;
+ }
+ else if (!strcmp("profile", keyword))
+ {
+ mProfileParams.importFile(fp);
+ }
+ else if (!strcmp("path",keyword))
+ {
+ mPathParams.importFile(fp);
+ }
+ else
+ {
+ llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL LLVolumeParams::exportFile(LLFILE *fp) const
+{
+ fprintf(fp,"\tshape 0\n");
+ fprintf(fp,"\t{\n");
+ mPathParams.exportFile(fp);
+ mProfileParams.exportFile(fp);
+ fprintf(fp, "\t}\n");
+ return TRUE;
+}
+
+
+BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ //llinfos << "importing volume" << llendl;
+ const S32 BUFSIZE = 16384;
+ // *NOTE: changing the size or type of this buffer will require
+ // changing the sscanf below.
+ char buffer[BUFSIZE]; /* Flawfinder: ignore */
+ char keyword[256]; /* Flawfinder: ignore */
+ keyword[0] = 0;
+
+ while (input_stream.good())
+ {
+ input_stream.getline(buffer, BUFSIZE);
+ sscanf(buffer, " %255s", keyword);
+ if (!strcmp("{", keyword))
+ {
+ continue;
+ }
+ if (!strcmp("}",keyword))
+ {
+ break;
+ }
+ else if (!strcmp("profile", keyword))
+ {
+ mProfileParams.importLegacyStream(input_stream);
+ }
+ else if (!strcmp("path",keyword))
+ {
+ mPathParams.importLegacyStream(input_stream);
+ }
+ else
+ {
+ llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ output_stream <<"\tshape 0\n";
+ output_stream <<"\t{\n";
+ mPathParams.exportLegacyStream(output_stream);
+ mProfileParams.exportLegacyStream(output_stream);
+ output_stream << "\t}\n";
+ return TRUE;
+}
+
+LLSD LLVolumeParams::sculptAsLLSD() const
+{
+ LLSD sd = LLSD();
+ sd["id"] = getSculptID();
+ sd["type"] = getSculptType();
+
+ return sd;
+}
+
+bool LLVolumeParams::sculptFromLLSD(LLSD& sd)
+{
+ setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger());
+ return true;
+}
+
+LLSD LLVolumeParams::asLLSD() const
+{
+ LLSD sd = LLSD();
+ sd["path"] = mPathParams;
+ sd["profile"] = mProfileParams;
+ sd["sculpt"] = sculptAsLLSD();
+
+ return sd;
+}
+
+bool LLVolumeParams::fromLLSD(LLSD& sd)
+{
+ mPathParams.fromLLSD(sd["path"]);
+ mProfileParams.fromLLSD(sd["profile"]);
+ sculptFromLLSD(sd["sculpt"]);
+
+ return true;
+}
+
+void LLVolumeParams::reduceS(F32 begin, F32 end)
+{
+ begin = llclampf(begin);
+ end = llclampf(end);
+ if (begin > end)
+ {
+ F32 temp = begin;
+ begin = end;
+ end = temp;
+ }
+ F32 a = mProfileParams.getBegin();
+ F32 b = mProfileParams.getEnd();
+ mProfileParams.setBegin(a + begin * (b - a));
+ mProfileParams.setEnd(a + end * (b - a));
+}
+
+void LLVolumeParams::reduceT(F32 begin, F32 end)
+{
+ begin = llclampf(begin);
+ end = llclampf(end);
+ if (begin > end)
+ {
+ F32 temp = begin;
+ begin = end;
+ end = temp;
+ }
+ F32 a = mPathParams.getBegin();
+ F32 b = mPathParams.getEnd();
+ mPathParams.setBegin(a + begin * (b - a));
+ mPathParams.setEnd(a + end * (b - a));
+}
+
+const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity
+const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity
+
+// returns TRUE if the shape can be approximated with a convex shape
+// for collison purposes
+BOOL LLVolumeParams::isConvex() const
+{
+ if (!getSculptID().isNull())
+ {
+ // can't determine, be safe and say no:
+ return FALSE;
+ }
+
+ F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
+ F32 hollow = mProfileParams.getHollow();
+
+ U8 path_type = mPathParams.getCurveType();
+ if ( path_length > MIN_CONCAVE_PATH_WEDGE
+ && ( mPathParams.getTwist() != mPathParams.getTwistBegin()
+ || (hollow > 0.f
+ && LL_PCODE_PATH_LINE != path_type) ) )
+ {
+ // twist along a "not too short" path is concave
+ return FALSE;
+ }
+
+ F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin();
+ BOOL same_hole = hollow == 0.f
+ || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME;
+
+ F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE;
+ U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+ if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
+ {
+ // it is a sphere and spheres get twice the minimum profile wedge
+ min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE;
+ }
+
+ BOOL convex_profile = ( ( profile_length == 1.f
+ || profile_length <= 0.5f )
+ && hollow == 0.f ) // trivially convex
+ || ( profile_length <= min_profile_wedge
+ && same_hole ); // effectvely convex (even when hollow)
+
+ if (!convex_profile)
+ {
+ // profile is concave
+ return FALSE;
+ }
+
+ if ( LL_PCODE_PATH_LINE == path_type )
+ {
+ // straight paths with convex profile
+ return TRUE;
+ }
+
+ BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f);
+ if (concave_path)
+ {
+ return FALSE;
+ }
+
+ // we're left with spheres, toroids and tubes
+ if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
+ {
+ // at this stage all spheres must be convex
+ return TRUE;
+ }
+
+ // it's a toroid or tube
+ if ( path_length <= MIN_CONCAVE_PATH_WEDGE )
+ {
+ // effectively convex
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// debug
+void LLVolumeParams::setCube()
+{
+ mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE);
+ mProfileParams.setBegin(0.f);
+ mProfileParams.setEnd(1.f);
+ mProfileParams.setHollow(0.f);
+
+ mPathParams.setBegin(0.f);
+ mPathParams.setEnd(1.f);
+ mPathParams.setScale(1.f, 1.f);
+ mPathParams.setShear(0.f, 0.f);
+ mPathParams.setCurveType(LL_PCODE_PATH_LINE);
+ mPathParams.setTwistBegin(0.f);
+ mPathParams.setTwistEnd(0.f);
+ mPathParams.setRadiusOffset(0.f);
+ mPathParams.setTaper(0.f, 0.f);
+ mPathParams.setRevolutions(0.f);
+ mPathParams.setSkew(0.f);
+}
+
+LLFaceID LLVolume::generateFaceMask()
+{
+ LLFaceID new_mask = 0x0000;
+
+ switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK)
+ {
+ case LL_PCODE_PROFILE_CIRCLE:
+ case LL_PCODE_PROFILE_CIRCLE_HALF:
+ new_mask |= LL_FACE_OUTER_SIDE_0;
+ break;
+ case LL_PCODE_PROFILE_SQUARE:
+ {
+ for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++)
+ {
+ new_mask |= LL_FACE_OUTER_SIDE_0 << side;
+ }
+ }
+ break;
+ case LL_PCODE_PROFILE_ISOTRI:
+ case LL_PCODE_PROFILE_EQUALTRI:
+ case LL_PCODE_PROFILE_RIGHTTRI:
+ {
+ for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++)
+ {
+ new_mask |= LL_FACE_OUTER_SIDE_0 << side;
+ }
+ }
+ break;
+ default:
+ llerrs << "Unknown profile!" << llendl;
+ break;
+ }
+
+ // handle hollow objects
+ if (mParams.getProfileParams().getHollow() > 0)
+ {
+ new_mask |= LL_FACE_INNER_SIDE;
+ }
+
+ // handle open profile curves
+ if (mProfilep->isOpen())
+ {
+ new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END;
+ }
+
+ // handle open path curves
+ if (mPathp->isOpen())
+ {
+ new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END;
+ }
+
+ return new_mask;
+}
+
+BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask)
+{
+ LLFaceID test_mask = 0;
+ for(S32 i = 0; i < getNumFaces(); i++)
+ {
+ test_mask |= mProfilep->mFaces[i].mFaceID;
+ }
+
+ return test_mask == face_mask;
+}
+
+BOOL LLVolume::isConvex() const
+{
+ // mParams.isConvex() may return FALSE even though the final
+ // geometry is actually convex due to LOD approximations.
+ // TODO -- provide LLPath and LLProfile with isConvex() methods
+ // that correctly determine convexity. -- Leviathan
+ return mParams.isConvex();
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params)
+{
+ s << "{type=" << (U32) profile_params.mCurveType;
+ s << ", begin=" << profile_params.mBegin;
+ s << ", end=" << profile_params.mEnd;
+ s << ", hollow=" << profile_params.mHollow;
+ s << "}";
+ return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params)
+{
+ s << "{type=" << (U32) path_params.mCurveType;
+ s << ", begin=" << path_params.mBegin;
+ s << ", end=" << path_params.mEnd;
+ s << ", twist=" << path_params.mTwistEnd;
+ s << ", scale=" << path_params.mScale;
+ s << ", shear=" << path_params.mShear;
+ s << ", twist_begin=" << path_params.mTwistBegin;
+ s << ", radius_offset=" << path_params.mRadiusOffset;
+ s << ", taper=" << path_params.mTaper;
+ s << ", revolutions=" << path_params.mRevolutions;
+ s << ", skew=" << path_params.mSkew;
+ s << "}";
+ return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params)
+{
+ s << "{profileparams = " << volume_params.mProfileParams;
+ s << ", pathparams = " << volume_params.mPathParams;
+ s << "}";
+ return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLProfile &profile)
+{
+ s << " {open=" << (U32) profile.mOpen;
+ s << ", dirty=" << profile.mDirty;
+ s << ", totalout=" << profile.mTotalOut;
+ s << ", total=" << profile.mTotal;
+ s << "}";
+ return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLPath &path)
+{
+ s << "{open=" << (U32) path.mOpen;
+ s << ", dirty=" << path.mDirty;
+ s << ", step=" << path.mStep;
+ s << ", total=" << path.mTotal;
+ s << "}";
+ return s;
+}
+
+std::ostream& operator<<(std::ostream &s, const LLVolume &volume)
+{
+ s << "{params = " << volume.getParams();
+ s << ", path = " << *volume.mPathp;
+ s << ", profile = " << *volume.mProfilep;
+ s << "}";
+ return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
+{
+ s << "{params = " << volumep->getParams();
+ s << ", path = " << *(volumep->mPathp);
+ s << ", profile = " << *(volumep->mProfilep);
+ s << "}";
+ return s;
+}
+
+LLVolumeFace::LLVolumeFace() :
+ mID(0),
+ mTypeMask(0),
+ mBeginS(0),
+ mBeginT(0),
+ mNumS(0),
+ mNumT(0),
+ mNumVertices(0),
+ mNumIndices(0),
+ mPositions(NULL),
+ mNormals(NULL),
+ mBinormals(NULL),
+ mTexCoords(NULL),
+ mIndices(NULL),
+ mWeights(NULL),
+ mOctree(NULL)
+{
+ mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3);
+ mCenter = mExtents+2;
+}
+
+LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
+: mID(0),
+ mTypeMask(0),
+ mBeginS(0),
+ mBeginT(0),
+ mNumS(0),
+ mNumT(0),
+ mNumVertices(0),
+ mNumIndices(0),
+ mPositions(NULL),
+ mNormals(NULL),
+ mBinormals(NULL),
+ mTexCoords(NULL),
+ mIndices(NULL),
+ mWeights(NULL),
+ mOctree(NULL)
+{
+ mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3);
+ mCenter = mExtents+2;
+ *this = src;
+}
+
+LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
+{
+ if (&src == this)
+ { //self assignment, do nothing
+ return *this;
+ }
+
+ mID = src.mID;
+ mTypeMask = src.mTypeMask;
+ mBeginS = src.mBeginS;
+ mBeginT = src.mBeginT;
+ mNumS = src.mNumS;
+ mNumT = src.mNumT;
+
+ mExtents[0] = src.mExtents[0];
+ mExtents[1] = src.mExtents[1];
+ *mCenter = *src.mCenter;
+
+ mNumVertices = 0;
+ mNumIndices = 0;
+
+ freeData();
+
+ LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a));
+
+ resizeVertices(src.mNumVertices);
+ resizeIndices(src.mNumIndices);
+
+ if (mNumVertices)
+ {
+ S32 vert_size = mNumVertices*sizeof(LLVector4a);
+ S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF;
+
+ LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
+ LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
+ LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
+
+
+ if (src.mBinormals)
+ {
+ allocateBinormals(src.mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size);
+ }
+ else
+ {
+ free(mBinormals);
+ mBinormals = NULL;
+ }
+
+ if (src.mWeights)
+ {
+ allocateWeights(src.mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size);
+ }
+ else
+ {
+ free(mWeights);
+ mWeights = NULL;
+ }
+ }
+
+ if (mNumIndices)
+ {
+ S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF;
+
+ LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size);
+ }
+
+ //delete
+ return *this;
+}
+
+LLVolumeFace::~LLVolumeFace()
+{
+ free(mExtents);
+ mExtents = NULL;
+
+ freeData();
+}
+
+void LLVolumeFace::freeData()
+{
+ free(mPositions);
+ mPositions = NULL;
+ free( mNormals);
+ mNormals = NULL;
+ free(mTexCoords);
+ mTexCoords = NULL;
+ free(mIndices);
+ mIndices = NULL;
+ free(mBinormals);
+ mBinormals = NULL;
+ free(mWeights);
+ mWeights = NULL;
+
+ delete mOctree;
+ mOctree = NULL;
+}
+
+BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
+{
+ //tree for this face is no longer valid
+ delete mOctree;
+ mOctree = NULL;
+
+ if (mTypeMask & CAP_MASK)
+ {
+ return createCap(volume, partial_build);
+ }
+ else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
+ {
+ return createSide(volume, partial_build);
+ }
+ else
+ {
+ llerrs << "Unknown/uninitialized face type!" << llendl;
+ return FALSE;
+ }
+}
+
+void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv)
+{
+ cv.setPosition(mPositions[index]);
+ cv.setNormal(mNormals[index]);
+ cv.mTexCoord = mTexCoords[index];
+}
+
+bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const
+{
+ return getPosition().equals3(rhs.getPosition()) &&
+ mTexCoord == rhs.mTexCoord &&
+ getNormal().equals3(rhs.getNormal());
+}
+
+bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a, const LLVector3& b) const
+{
+ if (a.mV[0] != b.mV[0])
+ {
+ return a.mV[0] < b.mV[0];
+ }
+
+ if (a.mV[1] != b.mV[1])
+ {
+ return a.mV[1] < b.mV[1];
+ }
+
+ return a.mV[2] < b.mV[2];
+}
+
+void LLVolumeFace::optimize(F32 angle_cutoff)
+{
+ LLVolumeFace new_face;
+
+ //map of points to vector of vertices at that point
+ VertexMapData::PointMap point_map;
+
+ //remove redundant vertices
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ U16 index = mIndices[i];
+
+ LLVolumeFace::VertexData cv;
+ getVertexData(index, cv);
+
+ BOOL found = FALSE;
+ VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr()));
+ if (point_iter != point_map.end())
+ { //duplicate point might exist
+ for (U32 j = 0; j < point_iter->second.size(); ++j)
+ {
+ LLVolumeFace::VertexData& tv = (point_iter->second)[j];
+ if (tv.compareNormal(cv, angle_cutoff))
+ {
+ found = TRUE;
+ new_face.pushIndex((point_iter->second)[j].mIndex);
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ new_face.pushVertex(cv);
+ U16 index = (U16) new_face.mNumVertices-1;
+ new_face.pushIndex(index);
+
+ VertexMapData d;
+ d.setPosition(cv.getPosition());
+ d.mTexCoord = cv.mTexCoord;
+ d.setNormal(cv.getNormal());
+ d.mIndex = index;
+ if (point_iter != point_map.end())
+ {
+ point_iter->second.push_back(d);
+ }
+ else
+ {
+ point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d);
+ }
+ }
+ }
+
+ swapData(new_face);
+}
+
+class LLVCacheTriangleData;
+
+class LLVCacheVertexData
+{
+public:
+ S32 mIdx;
+ S32 mCacheTag;
+ F32 mScore;
+ U32 mActiveTriangles;
+ std::vector<LLVCacheTriangleData*> mTriangles;
+
+ LLVCacheVertexData()
+ {
+ mCacheTag = -1;
+ mScore = 0.f;
+ mActiveTriangles = 0;
+ mIdx = -1;
+ }
+};
+
+class LLVCacheTriangleData
+{
+public:
+ bool mActive;
+ F32 mScore;
+ LLVCacheVertexData* mVertex[3];
+
+ LLVCacheTriangleData()
+ {
+ mActive = true;
+ mScore = 0.f;
+ mVertex[0] = mVertex[1] = mVertex[2] = NULL;
+ }
+
+ void complete()
+ {
+ mActive = false;
+ for (S32 i = 0; i < 3; ++i)
+ {
+ if (mVertex[i])
+ {
+ llassert_always(mVertex[i]->mActiveTriangles > 0);
+ mVertex[i]->mActiveTriangles--;
+ }
+ }
+ }
+
+ bool operator<(const LLVCacheTriangleData& rhs) const
+ { //highest score first
+ return rhs.mScore < mScore;
+ }
+};
+
+const F32 FindVertexScore_CacheDecayPower = 1.5f;
+const F32 FindVertexScore_LastTriScore = 0.75f;
+const F32 FindVertexScore_ValenceBoostScale = 2.0f;
+const F32 FindVertexScore_ValenceBoostPower = 0.5f;
+const U32 MaxSizeVertexCache = 32;
+
+F32 find_vertex_score(LLVCacheVertexData& data)
+{
+ if (data.mActiveTriangles == 0)
+ { //no triangle references this vertex
+ return -1.f;
+ }
+
+ F32 score = 0.f;
+
+ S32 cache_idx = data.mCacheTag;
+
+ if (cache_idx < 0)
+ {
+ //not in cache
+ }
+ else
+ {
+ if (cache_idx < 3)
+ { //vertex was in the last triangle
+ score = FindVertexScore_LastTriScore;
+ }
+ else
+ { //more points for being higher in the cache
+ F32 scaler = 1.f/(MaxSizeVertexCache-3);
+ score = 1.f-((cache_idx-3)*scaler);
+ score = powf(score, FindVertexScore_CacheDecayPower);
+ }
+ }
+
+ //bonus points for having low valence
+ F32 valence_boost = powf(data.mActiveTriangles, -FindVertexScore_ValenceBoostPower);
+ score += FindVertexScore_ValenceBoostScale * valence_boost;
+
+ return score;
+}
+
+class LLVCacheFIFO
+{
+public:
+ LLVCacheVertexData* mCache[MaxSizeVertexCache];
+ U32 mMisses;
+
+ LLVCacheFIFO()
+ {
+ mMisses = 0;
+ for (U32 i = 0; i < MaxSizeVertexCache; ++i)
+ {
+ mCache[i] = NULL;
+ }
+ }
+
+ void addVertex(LLVCacheVertexData* data)
+ {
+ if (data->mCacheTag == -1)
+ {
+ mMisses++;
+
+ S32 end = MaxSizeVertexCache-1;
+
+ if (mCache[end])
+ {
+ mCache[end]->mCacheTag = -1;
+ }
+
+ for (S32 i = end; i > 0; --i)
+ {
+ mCache[i] = mCache[i-1];
+ if (mCache[i])
+ {
+ mCache[i]->mCacheTag = i;
+ }
+ }
+
+ mCache[0] = data;
+ data->mCacheTag = 0;
+ }
+ }
+};
+
+class LLVCacheLRU
+{
+public:
+ LLVCacheVertexData* mCache[MaxSizeVertexCache+3];
+
+ LLVCacheTriangleData* mBestTriangle;
+
+ U32 mMisses;
+
+ LLVCacheLRU()
+ {
+ for (U32 i = 0; i < MaxSizeVertexCache+3; ++i)
+ {
+ mCache[i] = NULL;
+ }
+
+ mBestTriangle = NULL;
+ mMisses = 0;
+ }
+
+ void addVertex(LLVCacheVertexData* data)
+ {
+ S32 end = MaxSizeVertexCache+2;
+ if (data->mCacheTag != -1)
+ { //just moving a vertex to the front of the cache
+ end = data->mCacheTag;
+ }
+ else
+ {
+ mMisses++;
+ if (mCache[end])
+ { //adding a new vertex, vertex at end of cache falls off
+ mCache[end]->mCacheTag = -1;
+ }
+ }
+
+ for (S32 i = end; i > 0; --i)
+ { //adjust cache pointers and tags
+ mCache[i] = mCache[i-1];
+
+ if (mCache[i])
+ {
+ mCache[i]->mCacheTag = i;
+ }
+ }
+
+ mCache[0] = data;
+ mCache[0]->mCacheTag = 0;
+ }
+
+ void addTriangle(LLVCacheTriangleData* data)
+ {
+ addVertex(data->mVertex[0]);
+ addVertex(data->mVertex[1]);
+ addVertex(data->mVertex[2]);
+ }
+
+ void updateScores()
+ {
+ for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i)
+ { //trailing 3 vertices aren't actually in the cache for scoring purposes
+ if (mCache[i])
+ {
+ mCache[i]->mCacheTag = -1;
+ }
+ }
+
+ for (U32 i = 0; i < MaxSizeVertexCache; ++i)
+ { //update scores of vertices in cache
+ if (mCache[i])
+ {
+ mCache[i]->mScore = find_vertex_score(*(mCache[i]));
+ llassert_always(mCache[i]->mCacheTag == i);
+ }
+ }
+
+ mBestTriangle = NULL;
+ //update triangle scores
+ for (U32 i = 0; i < MaxSizeVertexCache+3; ++i)
+ {
+ if (mCache[i])
+ {
+ for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j)
+ {
+ LLVCacheTriangleData* tri = mCache[i]->mTriangles[j];
+ if (tri->mActive)
+ {
+ tri->mScore = tri->mVertex[0]->mScore;
+ tri->mScore += tri->mVertex[1]->mScore;
+ tri->mScore += tri->mVertex[2]->mScore;
+
+ if (!mBestTriangle || mBestTriangle->mScore < tri->mScore)
+ {
+ mBestTriangle = tri;
+ }
+ }
+ }
+ }
+ }
+
+ //knock trailing 3 vertices off the cache
+ for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i)
+ {
+ if (mCache[i])
+ {
+ llassert_always(mCache[i]->mCacheTag == -1);
+ mCache[i] = NULL;
+ }
+ }
+ }
+};
+
+
+void LLVolumeFace::cacheOptimize()
+{ //optimize for vertex cache according to Forsyth method:
+ // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
+
+ LLVCacheLRU cache;
+
+ //mapping of vertices to triangles and indices
+ std::vector<LLVCacheVertexData> vertex_data;
+
+ //mapping of triangles do vertices
+ std::vector<LLVCacheTriangleData> triangle_data;
+
+ triangle_data.resize(mNumIndices/3);
+ vertex_data.resize(mNumVertices);
+
+ for (U32 i = 0; i < mNumIndices; i++)
+ { //populate vertex data and triangle data arrays
+ U16 idx = mIndices[i];
+ U32 tri_idx = i/3;
+
+ vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
+ vertex_data[idx].mIdx = idx;
+ triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]);
+ }
+
+ /*F32 pre_acmr = 1.f;
+ //measure cache misses from before rebuild
+ {
+ LLVCacheFIFO test_cache;
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ test_cache.addVertex(&vertex_data[mIndices[i]]);
+ }
+
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ vertex_data[i].mCacheTag = -1;
+ }
+
+ pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
+ }*/
+
+ for (U32 i = 0; i < mNumVertices; i++)
+ { //initialize score values (no cache -- might try a fifo cache here)
+ vertex_data[i].mScore = find_vertex_score(vertex_data[i]);
+ vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size();
+
+ for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j)
+ {
+ vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore;
+ }
+ }
+
+ //sort triangle data by score
+ std::sort(triangle_data.begin(), triangle_data.end());
+
+ std::vector<U16> new_indices;
+
+ LLVCacheTriangleData* tri;
+
+ //prime pump by adding first triangle to cache;
+ tri = &(triangle_data[0]);
+ cache.addTriangle(tri);
+ new_indices.push_back(tri->mVertex[0]->mIdx);
+ new_indices.push_back(tri->mVertex[1]->mIdx);
+ new_indices.push_back(tri->mVertex[2]->mIdx);
+ tri->complete();
+
+ U32 breaks = 0;
+ for (U32 i = 1; i < mNumIndices/3; ++i)
+ {
+ cache.updateScores();
+ tri = cache.mBestTriangle;
+ if (!tri)
+ {
+ breaks++;
+ for (U32 j = 0; j < triangle_data.size(); ++j)
+ {
+ if (triangle_data[j].mActive)
+ {
+ tri = &(triangle_data[j]);
+ break;
+ }
+ }
+ }
+
+ cache.addTriangle(tri);
+ new_indices.push_back(tri->mVertex[0]->mIdx);
+ new_indices.push_back(tri->mVertex[1]->mIdx);
+ new_indices.push_back(tri->mVertex[2]->mIdx);
+ tri->complete();
+ }
+
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ mIndices[i] = new_indices[i];
+ }
+
+ /*F32 post_acmr = 1.f;
+ //measure cache misses from after rebuild
+ {
+ LLVCacheFIFO test_cache;
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ vertex_data[i].mCacheTag = -1;
+ }
+
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ test_cache.addVertex(&vertex_data[mIndices[i]]);
+ }
+
+ post_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
+ }*/
+
+ //optimize for pre-TnL cache
+
+ //allocate space for new buffer
+ S32 num_verts = mNumVertices;
+ LLVector4a* pos = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+ LLVector4a* norm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+ S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
+ LLVector2* tc = (LLVector2*) malloc(size);
+
+ LLVector4a* wght = NULL;
+ if (mWeights)
+ {
+ wght = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+ }
+
+ LLVector4a* binorm = NULL;
+ if (mBinormals)
+ {
+ binorm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+ }
+
+ //allocate mapping of old indices to new indices
+ std::vector<S32> new_idx;
+ new_idx.resize(mNumVertices, -1);
+
+ S32 cur_idx = 0;
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ U16 idx = mIndices[i];
+ if (new_idx[idx] == -1)
+ { //this vertex hasn't been added yet
+ new_idx[idx] = cur_idx;
+
+ //copy vertex data
+ pos[cur_idx] = mPositions[idx];
+ norm[cur_idx] = mNormals[idx];
+ tc[cur_idx] = mTexCoords[idx];
+ if (mWeights)
+ {
+ wght[cur_idx] = mWeights[idx];
+ }
+ if (mBinormals)
+ {
+ binorm[cur_idx] = mBinormals[idx];
+ }
+
+ cur_idx++;
+ }
+ }
+
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ mIndices[i] = new_idx[mIndices[i]];
+ }
+
+ free(mPositions);
+ free(mNormals);
+ free(mTexCoords);
+ free(mWeights);
+ free(mBinormals);
+
+ mPositions = pos;
+ mNormals = norm;
+ mTexCoords = tc;
+ mWeights = wght;
+ mBinormals = binorm;
+
+ //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
+ //llinfos << result << llendl;
+
+}
+
+void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
+{
+ if (mOctree)
+ {
+ return;
+ }
+
+ mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
+ new LLVolumeOctreeListener(mOctree);
+
+ for (U32 i = 0; i < mNumIndices; i+= 3)
+ { //for each triangle
+ LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle();
+
+ const LLVector4a& v0 = mPositions[mIndices[i]];
+ const LLVector4a& v1 = mPositions[mIndices[i+1]];
+ const LLVector4a& v2 = mPositions[mIndices[i+2]];
+
+ //store pointers to vertex data
+ tri->mV[0] = &v0;
+ tri->mV[1] = &v1;
+ tri->mV[2] = &v2;
+
+ //store indices
+ tri->mIndex[0] = mIndices[i];
+ tri->mIndex[1] = mIndices[i+1];
+ tri->mIndex[2] = mIndices[i+2];
+
+ //get minimum point
+ LLVector4a min = v0;
+ min.setMin(min, v1);
+ min.setMin(min, v2);
+
+ //get maximum point
+ LLVector4a max = v0;
+ max.setMax(max, v1);
+ max.setMax(max, v2);
+
+ //compute center
+ LLVector4a center;
+ center.setAdd(min, max);
+ center.mul(0.5f);
+
+ tri->mPositionGroup = center;
+
+ //compute "radius"
+ LLVector4a size;
+ size.setSub(max,min);
+
+ tri->mRadius = size.getLength3().getF32() * scaler;
+
+ //insert
+ mOctree->insert(tri);
+ }
+
+ //remove unneeded octree layers
+ while (!mOctree->balance()) { }
+
+ //calculate AABB for each node
+ LLVolumeOctreeRebound rebound(this);
+ rebound.traverse(mOctree);
+
+ if (gDebugGL)
+ {
+ LLVolumeOctreeValidate validate;
+ validate.traverse(mOctree);
+ }
+}
+
+
+void LLVolumeFace::swapData(LLVolumeFace& rhs)
+{
+ llswap(rhs.mPositions, mPositions);
+ llswap(rhs.mNormals, mNormals);
+ llswap(rhs.mBinormals, mBinormals);
+ llswap(rhs.mTexCoords, mTexCoords);
+ llswap(rhs.mIndices,mIndices);
+ llswap(rhs.mNumVertices, mNumVertices);
+ llswap(rhs.mNumIndices, mNumIndices);
+}
+
+void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
+ LLVolumeFace::VertexData& v1,
+ LLVolumeFace::VertexData& v2,
+ LLVolumeFace::VertexData& vout,
+ F32 coef01,
+ F32 coef02)
+{
+
+ LLVector4a lhs;
+ lhs.setSub(v1.getPosition(), v0.getPosition());
+ lhs.mul(coef01);
+ LLVector4a rhs;
+ rhs.setSub(v2.getPosition(), v0.getPosition());
+ rhs.mul(coef02);
+
+ rhs.add(lhs);
+ rhs.add(v0.getPosition());
+
+ vout.setPosition(rhs);
+
+ vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02);
+ vout.setNormal(v0.getNormal());
+}
+
+BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ const std::vector<LLVolume::Point>& mesh = volume->getMesh();
+ const std::vector<LLVector3>& profile = volume->getProfile().mProfile;
+ S32 max_s = volume->getProfile().getTotal();
+ S32 max_t = volume->getPath().mPath.size();
+
+ // S32 i;
+ S32 num_vertices = 0, num_indices = 0;
+ S32 grid_size = (profile.size()-1)/4;
+ S32 quad_count = (grid_size * grid_size);
+
+ num_vertices = (grid_size+1)*(grid_size+1);
+ num_indices = quad_count * 4;
+
+ LLVector4a& min = mExtents[0];
+ LLVector4a& max = mExtents[1];
+
+ S32 offset = 0;
+ if (mTypeMask & TOP_MASK)
+ {
+ offset = (max_t-1) * max_s;
+ }
+ else
+ {
+ offset = mBeginS;
+ }
+
+ {
+ VertexData corners[4];
+ VertexData baseVert;
+ for(S32 t = 0; t < 4; t++)
+ {
+ corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV);
+ corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
+ corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
+ }
+
+ {
+ LLVector4a lhs;
+ lhs.setSub(corners[1].getPosition(), corners[0].getPosition());
+ LLVector4a rhs;
+ rhs.setSub(corners[2].getPosition(), corners[1].getPosition());
+ baseVert.getNormal().setCross3(lhs, rhs);
+ baseVert.getNormal().normalize3fast();
+ }
+
+ if(!(mTypeMask & TOP_MASK))
+ {
+ baseVert.getNormal().mul(-1.0f);
+ }
+ else
+ {
+ //Swap the UVs on the U(X) axis for top face
+ LLVector2 swap;
+ swap = corners[0].mTexCoord;
+ corners[0].mTexCoord=corners[3].mTexCoord;
+ corners[3].mTexCoord=swap;
+ swap = corners[1].mTexCoord;
+ corners[1].mTexCoord=corners[2].mTexCoord;
+ corners[2].mTexCoord=swap;
+ }
+
+ LLVector4a binormal;
+
+ calc_binormal_from_triangle( binormal,
+ corners[0].getPosition(), corners[0].mTexCoord,
+ corners[1].getPosition(), corners[1].mTexCoord,
+ corners[2].getPosition(), corners[2].mTexCoord);
+
+ binormal.normalize3fast();
+
+ S32 size = (grid_size+1)*(grid_size+1);
+ resizeVertices(size);
+ allocateBinormals(size);
+
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
+ LLVector2* tc = (LLVector2*) mTexCoords;
+
+ for(int gx = 0;gx<grid_size+1;gx++)
+ {
+ for(int gy = 0;gy<grid_size+1;gy++)
+ {
+ VertexData newVert;
+ LerpPlanarVertex(
+ corners[0],
+ corners[1],
+ corners[3],
+ newVert,
+ (F32)gx/(F32)grid_size,
+ (F32)gy/(F32)grid_size);
+
+ *pos++ = newVert.getPosition();
+ *norm++ = baseVert.getNormal();
+ *tc++ = newVert.mTexCoord;
+ *binorm++ = binormal;
+
+ if (gx == 0 && gy == 0)
+ {
+ min = newVert.getPosition();
+ max = min;
+ }
+ else
+ {
+ min.setMin(min, newVert.getPosition());
+ max.setMax(max, newVert.getPosition());
+ }
+ }
+ }
+
+ mCenter->setAdd(min, max);
+ mCenter->mul(0.5f);
+ }
+
+ if (!partial_build)
+ {
+ resizeIndices(grid_size*grid_size*6);
+
+ U16* out = mIndices;
+
+ S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
+ for(S32 gx = 0;gx<grid_size;gx++)
+ {
+
+ for(S32 gy = 0;gy<grid_size;gy++)
+ {
+ if (mTypeMask & TOP_MASK)
+ {
+ for(S32 i=5;i>=0;i--)
+ {
+ *out++ = ((gy*(grid_size+1))+gx+idxs[i]);
+ }
+ }
+ else
+ {
+ for(S32 i=0;i<6;i++)
+ {
+ *out++ = ((gy*(grid_size+1))+gx+idxs[i]);
+ }
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ if (!(mTypeMask & HOLLOW_MASK) &&
+ !(mTypeMask & OPEN_MASK) &&
+ ((volume->getParams().getPathParams().getBegin()==0.0f)&&
+ (volume->getParams().getPathParams().getEnd()==1.0f))&&
+ (volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE &&
+ volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE)
+ ){
+ return createUnCutCubeCap(volume, partial_build);
+ }
+
+ S32 num_vertices = 0, num_indices = 0;
+
+ const std::vector<LLVolume::Point>& mesh = volume->getMesh();
+ const std::vector<LLVector3>& profile = volume->getProfile().mProfile;
+
+ // All types of caps have the same number of vertices and indices
+ num_vertices = profile.size();
+ num_indices = (profile.size() - 2)*3;
+
+ if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
+ {
+ resizeVertices(num_vertices+1);
+ allocateBinormals(num_vertices+1);
+
+ if (!partial_build)
+ {
+ resizeIndices(num_indices+3);
+ }
+ }
+ else
+ {
+ resizeVertices(num_vertices);
+ allocateBinormals(num_vertices);
+
+ if (!partial_build)
+ {
+ resizeIndices(num_indices);
+ }
+ }
+
+ S32 max_s = volume->getProfile().getTotal();
+ S32 max_t = volume->getPath().mPath.size();
+
+ mCenter->clear();
+
+ S32 offset = 0;
+ if (mTypeMask & TOP_MASK)
+ {
+ offset = (max_t-1) * max_s;
+ }
+ else
+ {
+ offset = mBeginS;
+ }
+
+ // Figure out the normal, assume all caps are flat faces.
+ // Cross product to get normals.
+
+ LLVector2 cuv;
+ LLVector2 min_uv, max_uv;
+
+ LLVector4a& min = mExtents[0];
+ LLVector4a& max = mExtents[1];
+
+ LLVector2* tc = (LLVector2*) mTexCoords;
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
+
+ // Copy the vertices into the array
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ if (mTypeMask & TOP_MASK)
+ {
+ tc[i].mV[0] = profile[i].mV[0]+0.5f;
+ tc[i].mV[1] = profile[i].mV[1]+0.5f;
+ }
+ else
+ {
+ // Mirror for underside.
+ tc[i].mV[0] = profile[i].mV[0]+0.5f;
+ tc[i].mV[1] = 0.5f - profile[i].mV[1];
+ }
+
+ pos[i].load3(mesh[i + offset].mPos.mV);
+
+ if (i == 0)
+ {
+ max = pos[i];
+ min = max;
+ min_uv = max_uv = tc[i];
+ }
+ else
+ {
+ update_min_max(min,max,pos[i]);
+ update_min_max(min_uv, max_uv, tc[i]);
+ }
+ }
+
+ mCenter->setAdd(min, max);
+ mCenter->mul(0.5f);
+
+ cuv = (min_uv + max_uv)*0.5f;
+
+ LLVector4a binormal;
+ calc_binormal_from_triangle(binormal,
+ *mCenter, cuv,
+ pos[0], tc[0],
+ pos[1], tc[1]);
+ binormal.normalize3fast();
+
+ LLVector4a normal;
+ LLVector4a d0, d1;
+
+
+ d0.setSub(*mCenter, pos[0]);
+ d1.setSub(*mCenter, pos[1]);
+
+ if (mTypeMask & TOP_MASK)
+ {
+ normal.setCross3(d0, d1);
+ }
+ else
+ {
+ normal.setCross3(d1, d0);
+ }
+
+ normal.normalize3fast();
+
+ VertexData vd;
+ vd.setPosition(*mCenter);
+ vd.mTexCoord = cuv;
+
+ if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
+ {
+ pos[num_vertices] = *mCenter;
+ tc[num_vertices] = cuv;
+ num_vertices++;
+ }
+
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ binorm[i].load4a(binormal.getF32ptr());
+ norm[i].load4a(normal.getF32ptr());
+ }
+
+ if (partial_build)
+ {
+ return TRUE;
+ }
+
+ if (mTypeMask & HOLLOW_MASK)
+ {
+ if (mTypeMask & TOP_MASK)
+ {
+ // HOLLOW TOP
+ // Does it matter if it's open or closed? - djs
+
+ S32 pt1 = 0, pt2 = num_vertices - 1;
+ S32 i = 0;
+ while (pt2 - pt1 > 1)
+ {
+ // Use the profile points instead of the mesh, since you want
+ // the un-transformed profile distances.
+ LLVector3 p1 = profile[pt1];
+ LLVector3 p2 = profile[pt2];
+ LLVector3 pa = profile[pt1+1];
+ LLVector3 pb = profile[pt2-1];
+
+ p1.mV[VZ] = 0.f;
+ p2.mV[VZ] = 0.f;
+ pa.mV[VZ] = 0.f;
+ pb.mV[VZ] = 0.f;
+
+ // Use area of triangle to determine backfacing
+ F32 area_1a2, area_1ba, area_21b, area_2ab;
+ area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+ (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+ (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+
+ area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+ (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+
+ area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+ (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+ (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ BOOL use_tri1a2 = TRUE;
+ BOOL tri_1a2 = TRUE;
+ BOOL tri_21b = TRUE;
+
+ if (area_1a2 < 0)
+ {
+ tri_1a2 = FALSE;
+ }
+ if (area_2ab < 0)
+ {
+ // Can't use, because it contains point b
+ tri_1a2 = FALSE;
+ }
+ if (area_21b < 0)
+ {
+ tri_21b = FALSE;
+ }
+ if (area_1ba < 0)
+ {
+ // Can't use, because it contains point b
+ tri_21b = FALSE;
+ }
+
+ if (!tri_1a2)
+ {
+ use_tri1a2 = FALSE;
+ }
+ else if (!tri_21b)
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ LLVector3 d1 = p1 - pa;
+ LLVector3 d2 = p2 - pb;
+
+ if (d1.magVecSquared() < d2.magVecSquared())
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ use_tri1a2 = FALSE;
+ }
+ }
+
+ if (use_tri1a2)
+ {
+ mIndices[i++] = pt1;
+ mIndices[i++] = pt1 + 1;
+ mIndices[i++] = pt2;
+ pt1++;
+ }
+ else
+ {
+ mIndices[i++] = pt1;
+ mIndices[i++] = pt2 - 1;
+ mIndices[i++] = pt2;
+ pt2--;
+ }
+ }
+ }
+ else
+ {
+ // HOLLOW BOTTOM
+ // Does it matter if it's open or closed? - djs
+
+ llassert(mTypeMask & BOTTOM_MASK);
+ S32 pt1 = 0, pt2 = num_vertices - 1;
+
+ S32 i = 0;
+ while (pt2 - pt1 > 1)
+ {
+ // Use the profile points instead of the mesh, since you want
+ // the un-transformed profile distances.
+ LLVector3 p1 = profile[pt1];
+ LLVector3 p2 = profile[pt2];
+ LLVector3 pa = profile[pt1+1];
+ LLVector3 pb = profile[pt2-1];
+
+ p1.mV[VZ] = 0.f;
+ p2.mV[VZ] = 0.f;
+ pa.mV[VZ] = 0.f;
+ pb.mV[VZ] = 0.f;
+
+ // Use area of triangle to determine backfacing
+ F32 area_1a2, area_1ba, area_21b, area_2ab;
+ area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+ (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+ (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+
+ area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+ (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+
+ area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+ (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+ (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+ (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+ BOOL use_tri1a2 = TRUE;
+ BOOL tri_1a2 = TRUE;
+ BOOL tri_21b = TRUE;
+
+ if (area_1a2 < 0)
+ {
+ tri_1a2 = FALSE;
+ }
+ if (area_2ab < 0)
+ {
+ // Can't use, because it contains point b
+ tri_1a2 = FALSE;
+ }
+ if (area_21b < 0)
+ {
+ tri_21b = FALSE;
+ }
+ if (area_1ba < 0)
+ {
+ // Can't use, because it contains point b
+ tri_21b = FALSE;
+ }
+
+ if (!tri_1a2)
+ {
+ use_tri1a2 = FALSE;
+ }
+ else if (!tri_21b)
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ LLVector3 d1 = p1 - pa;
+ LLVector3 d2 = p2 - pb;
+
+ if (d1.magVecSquared() < d2.magVecSquared())
+ {
+ use_tri1a2 = TRUE;
+ }
+ else
+ {
+ use_tri1a2 = FALSE;
+ }
+ }
+
+ // Flipped backfacing from top
+ if (use_tri1a2)
+ {
+ mIndices[i++] = pt1;
+ mIndices[i++] = pt2;
+ mIndices[i++] = pt1 + 1;
+ pt1++;
+ }
+ else
+ {
+ mIndices[i++] = pt1;
+ mIndices[i++] = pt2;
+ mIndices[i++] = pt2 - 1;
+ pt2--;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Not hollow, generate the triangle fan.
+ U16 v1 = 2;
+ U16 v2 = 1;
+
+ if (mTypeMask & TOP_MASK)
+ {
+ v1 = 1;
+ v2 = 2;
+ }
+
+ for (S32 i = 0; i < (num_vertices - 2); i++)
+ {
+ mIndices[3*i] = num_vertices - 1;
+ mIndices[3*i+v1] = i;
+ mIndices[3*i+v2] = i + 1;
+ }
+
+
+ }
+
+ return TRUE;
+}
+
+void LLVolumeFace::createBinormals()
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ if (!mBinormals)
+ {
+ allocateBinormals(mNumVertices);
+
+ //generate binormals
+ LLVector4a* pos = mPositions;
+ LLVector2* tc = (LLVector2*) mTexCoords;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
+
+ LLVector4a* end = mBinormals+mNumVertices;
+ while (binorm < end)
+ {
+ (*binorm++).clear();
+ }
+
+ binorm = mBinormals;
+
+ for (U32 i = 0; i < mNumIndices/3; i++)
+ { //for each triangle
+ const U16& i0 = mIndices[i*3+0];
+ const U16& i1 = mIndices[i*3+1];
+ const U16& i2 = mIndices[i*3+2];
+
+ //calculate binormal
+ LLVector4a binormal;
+ calc_binormal_from_triangle(binormal,
+ pos[i0], tc[i0],
+ pos[i1], tc[i1],
+ pos[i2], tc[i2]);
+
+
+ //add triangle normal to vertices
+ binorm[i0].add(binormal);
+ binorm[i1].add(binormal);
+ binorm[i2].add(binormal);
+
+ //even out quad contributions
+ if (i % 2 == 0)
+ {
+ binorm[i2].add(binormal);
+ }
+ else
+ {
+ binorm[i1].add(binormal);
+ }
+ }
+
+ //normalize binormals
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ binorm[i].normalize3fast();
+ //bump map/planar projection code requires normals to be normalized
+ mNormals[i].normalize3fast();
+ }
+ }
+}
+
+void LLVolumeFace::resizeVertices(S32 num_verts)
+{
+ free(mPositions);
+ free(mNormals);
+ free(mBinormals);
+ free(mTexCoords);
+
+ mBinormals = NULL;
+
+ if (num_verts)
+ {
+ mPositions = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+ assert_aligned(mPositions, 16);
+ mNormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+ assert_aligned(mNormals, 16);
+
+ //pad texture coordinate block end to allow for QWORD reads
+ S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
+ mTexCoords = (LLVector2*) malloc(size);
+ assert_aligned(mTexCoords, 16);
+ }
+ else
+ {
+ mPositions = NULL;
+ mNormals = NULL;
+ mTexCoords = NULL;
+ }
+
+ mNumVertices = num_verts;
+}
+
+void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
+{
+ pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord);
+}
+
+void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc)
+{
+ S32 new_verts = mNumVertices+1;
+ S32 new_size = new_verts*16;
+// S32 old_size = mNumVertices*16;
+
+ //positions
+ mPositions = (LLVector4a*) realloc(mPositions, new_size);
+
+ //normals
+ mNormals = (LLVector4a*) realloc(mNormals, new_size);
+
+ //tex coords
+ new_size = ((new_verts*8)+0xF) & ~0xF;
+ mTexCoords = (LLVector2*) realloc(mTexCoords, new_size);
+
+
+ //just clear binormals
+ free(mBinormals);
+ mBinormals = NULL;
+
+ mPositions[mNumVertices] = pos;
+ mNormals[mNumVertices] = norm;
+ mTexCoords[mNumVertices] = tc;
+
+ mNumVertices++;
+}
+
+void LLVolumeFace::allocateBinormals(S32 num_verts)
+{
+ free(mBinormals);
+ mBinormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+}
+
+void LLVolumeFace::allocateWeights(S32 num_verts)
+{
+ free(mWeights);
+ mWeights = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+}
+
+void LLVolumeFace::resizeIndices(S32 num_indices)
+{
+ free(mIndices);
+
+ if (num_indices)
+ {
+ //pad index block end to allow for QWORD reads
+ S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF;
+
+ mIndices = (U16*) malloc(size);
+ }
+ else
+ {
+ mIndices = NULL;
+ }
+
+ mNumIndices = num_indices;
+}
+
+void LLVolumeFace::pushIndex(const U16& idx)
+{
+ S32 new_count = mNumIndices + 1;
+ S32 new_size = ((new_count*2)+0xF) & ~0xF;
+
+ S32 old_size = ((mNumIndices*2)+0xF) & ~0xF;
+ if (new_size != old_size)
+ {
+ mIndices = (U16*) realloc(mIndices, new_size);
+ }
+
+ mIndices[mNumIndices++] = idx;
+}
+
+void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx)
+{
+ resizeVertices(v.size());
+ resizeIndices(idx.size());
+
+ for (U32 i = 0; i < v.size(); ++i)
+ {
+ mPositions[i] = v[i].getPosition();
+ mNormals[i] = v[i].getNormal();
+ mTexCoords[i] = v[i].mTexCoord;
+ }
+
+ for (U32 i = 0; i < idx.size(); ++i)
+ {
+ mIndices[i] = idx[i];
+ }
+}
+
+void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in)
+{
+ U16 offset = mNumVertices;
+
+ S32 new_count = face.mNumVertices + mNumVertices;
+
+ if (new_count > 65536)
+ {
+ llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl;
+ }
+
+ if (face.mNumVertices == 0)
+ {
+ llerrs << "Cannot append empty face." << llendl;
+ }
+
+ //allocate new buffer space
+ mPositions = (LLVector4a*) realloc(mPositions, new_count*sizeof(LLVector4a));
+ assert_aligned(mPositions, 16);
+ mNormals = (LLVector4a*) realloc(mNormals, new_count*sizeof(LLVector4a));
+ assert_aligned(mNormals, 16);
+ mTexCoords = (LLVector2*) realloc(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF);
+ assert_aligned(mTexCoords, 16);
+
+ mNumVertices = new_count;
+
+ //get destination address of appended face
+ LLVector4a* dst_pos = mPositions+offset;
+ LLVector2* dst_tc = mTexCoords+offset;
+ LLVector4a* dst_norm = mNormals+offset;
+
+ //get source addresses of appended face
+ const LLVector4a* src_pos = face.mPositions;
+ const LLVector2* src_tc = face.mTexCoords;
+ const LLVector4a* src_norm = face.mNormals;
+
+ //load aligned matrices
+ LLMatrix4a mat, norm_mat;
+ mat.loadu(mat_in);
+ norm_mat.loadu(norm_mat_in);
+
+ for (U32 i = 0; i < face.mNumVertices; ++i)
+ {
+ //transform appended face position and store
+ mat.affineTransform(src_pos[i], dst_pos[i]);
+
+ //transform appended face normal and store
+ norm_mat.rotate(src_norm[i], dst_norm[i]);
+ dst_norm[i].normalize3fast();
+
+ //copy appended face texture coordinate
+ dst_tc[i] = src_tc[i];
+
+ if (offset == 0 && i == 0)
+ { //initialize bounding box
+ mExtents[0] = mExtents[1] = dst_pos[i];
+ }
+ else
+ {
+ //stretch bounding box
+ update_min_max(mExtents[0], mExtents[1], dst_pos[i]);
+ }
+ }
+
+
+ new_count = mNumIndices + face.mNumIndices;
+
+ //allocate new index buffer
+ mIndices = (U16*) realloc(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF);
+
+ //get destination address into new index buffer
+ U16* dst_idx = mIndices+mNumIndices;
+ mNumIndices = new_count;
+
+ for (U32 i = 0; i < face.mNumIndices; ++i)
+ { //copy indices, offsetting by old vertex count
+ dst_idx[i] = face.mIndices[i]+offset;
+ }
+}
+
+BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ BOOL flat = mTypeMask & FLAT_MASK;
+
+ U8 sculpt_type = volume->getParams().getSculptType();
+ U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
+ BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
+ BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
+ BOOL sculpt_reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR
+
+ S32 num_vertices, num_indices;
+
+ const std::vector<LLVolume::Point>& mesh = volume->getMesh();
+ const std::vector<LLVector3>& profile = volume->getProfile().mProfile;
+ const std::vector<LLPath::PathPt>& path_data = volume->getPath().mPath;
+
+ S32 max_s = volume->getProfile().getTotal();
+
+ S32 s, t, i;
+ F32 ss, tt;
+
+ num_vertices = mNumS*mNumT;
+ num_indices = (mNumS-1)*(mNumT-1)*6;
+
+ if (!partial_build)
+ {
+ resizeVertices(num_vertices);
+ resizeIndices(num_indices);
+
+ if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
+ {
+ mEdge.resize(num_indices);
+ }
+ }
+
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector2* tc = (LLVector2*) mTexCoords;
+ S32 begin_stex = llfloor( profile[mBeginS].mV[2] );
+ S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS;
+
+ S32 cur_vertex = 0;
+ // Copy the vertices into the array
+ for (t = mBeginT; t < mBeginT + mNumT; t++)
+ {
+ tt = path_data[t].mTexT;
+ for (s = 0; s < num_s; s++)
+ {
+ if (mTypeMask & END_MASK)
+ {
+ if (s)
+ {
+ ss = 1.f;
+ }
+ else
+ {
+ ss = 0.f;
+ }
+ }
+ else
+ {
+ // Get s value for tex-coord.
+ if (!flat)
+ {
+ ss = profile[mBeginS + s].mV[2];
+ }
+ else
+ {
+ ss = profile[mBeginS + s].mV[2] - begin_stex;
+ }
+ }
+
+ if (sculpt_reverse_horizontal)
+ {
+ ss = 1.f - ss;
+ }
+
+ // Check to see if this triangle wraps around the array.
+ if (mBeginS + s >= max_s)
+ {
+ // We're wrapping
+ i = mBeginS + s + max_s*(t-1);
+ }
+ else
+ {
+ i = mBeginS + s + max_s*t;
+ }
+
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
+
+ norm[cur_vertex].clear();
+ cur_vertex++;
+
+ if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
+ {
+
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
+
+ norm[cur_vertex].clear();
+
+ cur_vertex++;
+ }
+ }
+
+ if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2)
+ {
+ if (mTypeMask & OPEN_MASK)
+ {
+ s = num_s-1;
+ }
+ else
+ {
+ s = 0;
+ }
+
+ i = mBeginS + s + max_s*t;
+ ss = profile[mBeginS + s].mV[2] - begin_stex;
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
+ norm[cur_vertex].clear();
+
+ cur_vertex++;
+ }
+ }
+
+
+ //get bounding box for this side
+ LLVector4a& face_min = mExtents[0];
+ LLVector4a& face_max = mExtents[1];
+ mCenter->clear();
+
+ face_min = face_max = pos[0];
+
+ for (U32 i = 1; i < mNumVertices; ++i)
+ {
+ update_min_max(face_min, face_max, pos[i]);
+ }
+
+ mCenter->setAdd(face_min, face_max);
+ mCenter->mul(0.5f);
+
+ S32 cur_index = 0;
+ S32 cur_edge = 0;
+ BOOL flat_face = mTypeMask & FLAT_MASK;
+
+ if (!partial_build)
+ {
+ // Now we generate the indices.
+ for (t = 0; t < (mNumT-1); t++)
+ {
+ for (s = 0; s < (mNumS-1); s++)
+ {
+ mIndices[cur_index++] = s + mNumS*t; //bottom left
+ mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
+ mIndices[cur_index++] = s + mNumS*(t+1); //top left
+ mIndices[cur_index++] = s + mNumS*t; //bottom left
+ mIndices[cur_index++] = s+1 + mNumS*t; //bottom right
+ mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
+
+ mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face
+ if (t < mNumT-2) { //top right/top left neighbor face
+ mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
+ }
+ else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor
+ mEdge[cur_edge++] = -1;
+ }
+ else { //wrap on T
+ mEdge[cur_edge++] = s*2+1;
+ }
+ if (s > 0) { //top left/bottom left neighbor face
+ mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
+ }
+ else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor
+ mEdge[cur_edge++] = -1;
+ }
+ else { //wrap on S
+ mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
+ }
+
+ if (t > 0) { //bottom left/bottom right neighbor face
+ mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
+ }
+ else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor
+ mEdge[cur_edge++] = -1;
+ }
+ else { //wrap on T
+ mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
+ }
+ if (s < mNumS-2) { //bottom right/top right neighbor face
+ mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
+ }
+ else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor
+ mEdge[cur_edge++] = -1;
+ }
+ else { //wrap on S
+ mEdge[cur_edge++] = (mNumS-1)*2*t;
+ }
+ mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face
+ }
+ }
+ }
+
+ //clear normals
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ mNormals[i].clear();
+ }
+
+ //generate normals
+ for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle
+ {
+ const U16* idx = &(mIndices[i*3]);
+
+
+ LLVector4a* v[] =
+ { pos+idx[0], pos+idx[1], pos+idx[2] };
+
+ LLVector4a* n[] =
+ { norm+idx[0], norm+idx[1], norm+idx[2] };
+
+ //calculate triangle normal
+ LLVector4a a, b, c;
+
+ a.setSub(*v[0], *v[1]);
+ b.setSub(*v[0], *v[2]);
+ c.setCross3(a,b);
+
+ n[0]->add(c);
+ n[1]->add(c);
+ n[2]->add(c);
+
+ //even out quad contributions
+ n[i%2+1]->add(c);
+ }
+
+ // adjust normals based on wrapping and stitching
+
+ LLVector4a top;
+ top.setSub(pos[0], pos[mNumS*(mNumT-2)]);
+ BOOL s_bottom_converges = (top.dot3(top) < 0.000001f);
+
+ top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]);
+ BOOL s_top_converges = (top.dot3(top) < 0.000001f);
+
+ if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes
+ {
+ if (volume->getPath().isOpen() == FALSE)
+ { //wrap normals on T
+ for (S32 i = 0; i < mNumS; i++)
+ {
+ LLVector4a n;
+ n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+ norm[i] = n;
+ norm[mNumS*(mNumT-1)+i] = n;
+ }
+ }
+
+ if ((volume->getProfile().isOpen() == FALSE) && !(s_bottom_converges))
+ { //wrap normals on S
+ for (S32 i = 0; i < mNumT; i++)
+ {
+ LLVector4a n;
+ n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+ norm[mNumS * i] = n;
+ norm[mNumS * i+mNumS-1] = n;
+ }
+ }
+
+ if (volume->getPathType() == LL_PCODE_PATH_CIRCLE &&
+ ((volume->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF))
+ {
+ if (s_bottom_converges)
+ { //all lower S have same normal
+ for (S32 i = 0; i < mNumT; i++)
+ {
+ norm[mNumS*i].set(1,0,0);
+ }
+ }
+
+ if (s_top_converges)
+ { //all upper S have same normal
+ for (S32 i = 0; i < mNumT; i++)
+ {
+ norm[mNumS*i+mNumS-1].set(-1,0,0);
+ }
+ }
+ }
+ }
+ else // logic for sculpt volumes
+ {
+ BOOL average_poles = FALSE;
+ BOOL wrap_s = FALSE;
+ BOOL wrap_t = FALSE;
+
+ if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
+ average_poles = TRUE;
+
+ if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) ||
+ (sculpt_stitching == LL_SCULPT_TYPE_TORUS) ||
+ (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER))
+ wrap_s = TRUE;
+
+ if (sculpt_stitching == LL_SCULPT_TYPE_TORUS)
+ wrap_t = TRUE;
+
+
+ if (average_poles)
+ {
+ // average normals for north pole
+
+ LLVector4a average;
+ average.clear();
+
+ for (S32 i = 0; i < mNumS; i++)
+ {
+ average.add(norm[i]);
+ }
+
+ // set average
+ for (S32 i = 0; i < mNumS; i++)
+ {
+ norm[i] = average;
+ }
+
+ // average normals for south pole
+
+ average.clear();
+
+ for (S32 i = 0; i < mNumS; i++)
+ {
+ average.add(norm[i + mNumS * (mNumT - 1)]);
+ }
+
+ // set average
+ for (S32 i = 0; i < mNumS; i++)
+ {
+ norm[i + mNumS * (mNumT - 1)] = average;
+ }
+
+ }
+
+
+ if (wrap_s)
+ {
+ for (S32 i = 0; i < mNumT; i++)
+ {
+ LLVector4a n;
+ n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+ norm[mNumS * i] = n;
+ norm[mNumS * i+mNumS-1] = n;
+ }
+ }
+
+ if (wrap_t)
+ {
+ for (S32 i = 0; i < mNumS; i++)
+ {
+ LLVector4a n;
+ n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+ norm[i] = n;
+ norm[mNumS*(mNumT-1)+i] = n;
+ }
+ }
+
+ }
+
+ return TRUE;
+}
+
+// Finds binormal based on three vertices with texture coordinates.
+// Fills in dummy values if the triangle has degenerate texture coordinates.
+void calc_binormal_from_triangle(LLVector4a& binormal,
+
+ const LLVector4a& pos0,
+ const LLVector2& tex0,
+ const LLVector4a& pos1,
+ const LLVector2& tex1,
+ const LLVector4a& pos2,
+ const LLVector2& tex2)
+{
+ LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] );
+
+ LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] );
+
+ LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] );
+
+ LLVector4a lhs, rhs;
+
+ LLVector4a r0;
+ lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2);
+ r0.setCross3(lhs, rhs);
+
+ LLVector4a r1;
+ lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2);
+ r1.setCross3(lhs, rhs);
+
+ LLVector4a r2;
+ lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2);
+ r2.setCross3(lhs, rhs);
+
+ if( r0[VX] && r1[VX] && r2[VX] )
+ {
+ binormal.set(
+ -r0[VZ] / r0[VX],
+ -r1[VZ] / r1[VX],
+ -r2[VZ] / r2[VX]);
+ // binormal.normVec();
+ }
+ else
+ {
+ binormal.set( 0, 1 , 0 );
+ }
+}
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 32ac531306..eceaced9e2 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -792,39 +792,39 @@ public: class LLVolumeFace { public: - class VertexData
- {
- enum
- {
- POSITION = 0,
- NORMAL = 1
- };
-
- private:
- void init();
- public:
- VertexData();
- VertexData(const VertexData& rhs);
- const VertexData& operator=(const VertexData& rhs);
-
- ~VertexData();
- LLVector4a& getPosition();
- LLVector4a& getNormal();
- const LLVector4a& getPosition() const;
- const LLVector4a& getNormal() const;
- void setPosition(const LLVector4a& pos);
- void setNormal(const LLVector4a& norm);
-
-
- LLVector2 mTexCoord;
-
- bool operator<(const VertexData& rhs) const;
- bool operator==(const VertexData& rhs) const;
- bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const;
-
- private:
- LLVector4a* mData;
- };
+ class VertexData + { + enum + { + POSITION = 0, + NORMAL = 1 + }; + + private: + void init(); + public: + VertexData(); + VertexData(const VertexData& rhs); + const VertexData& operator=(const VertexData& rhs); + + ~VertexData(); + LLVector4a& getPosition(); + LLVector4a& getNormal(); + const LLVector4a& getPosition() const; + const LLVector4a& getNormal() const; + void setPosition(const LLVector4a& pos); + void setNormal(const LLVector4a& norm); + + + LLVector2 mTexCoord; + + bool operator<(const VertexData& rhs) const; + bool operator==(const VertexData& rhs) const; + bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const; + + private: + LLVector4a* mData; + }; LLVolumeFace(); LLVolumeFace(const LLVolumeFace& src); @@ -901,6 +901,7 @@ public: LLVector4a* mExtents; //minimum and maximum point of face LLVector4a* mCenter; + LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. S32 mNumVertices; S32 mNumIndices; diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h index f696cbd976..688d91dc40 100644 --- a/indra/llmath/llvolumeoctree.h +++ b/indra/llmath/llvolumeoctree.h @@ -34,6 +34,41 @@ #include "llvolume.h" #include "llvector4a.h" +class LLVolumeTriangle : public LLRefCount +{ +public: + LLVolumeTriangle() + { + + } + + LLVolumeTriangle(const LLVolumeTriangle& rhs) + { + *this = rhs; + } + + const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + + ~LLVolumeTriangle() + { + + } + + LLVector4a mPositionGroup; + + const LLVector4a* mV[3]; + U16 mIndex[3]; + + F32 mRadius; + + virtual const LLVector4a& getPositionGroup() const; + virtual const F32& getBinRadius() const; +}; + class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle> { public: @@ -91,41 +126,6 @@ public: virtual void visit(const LLOctreeNode<LLVolumeTriangle>* node); }; -class LLVolumeTriangle : public LLRefCount -{ -public: - LLVolumeTriangle() - { - - } - - LLVolumeTriangle(const LLVolumeTriangle& rhs) - { - *this = rhs; - } - - const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs) - { - llerrs << "Illegal operation!" << llendl; - return *this; - } - - ~LLVolumeTriangle() - { - - } - - LLVector4a mPositionGroup; - - const LLVector4a* mV[3]; - U16 mIndex[3]; - - F32 mRadius; - - virtual const LLVector4a& getPositionGroup() const; - virtual const F32& getBinRadius() const; -}; - class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle> { virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch); diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index 7a9f0f62cf..1b50749b3e 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -33,10 +33,10 @@ const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f const F32 MIN_OBJECT_Z = -256.f; const F32 DEFAULT_MAX_PRIM_SCALE = 64.f; +const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = 10.f; const F32 MIN_PRIM_SCALE = 0.01f; const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX - class LLXform { protected: diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 03c28eb2a5..767001b633 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -81,8 +81,11 @@ namespace LLAvatarNameCache // only need per-frame timing resolution LLFrameTimer sRequestTimer; - // Periodically clean out expired entries from the cache - //LLFrameTimer sEraseExpiredTimer; + /// Maximum time an unrefreshed cache entry is allowed + const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0; + + /// Time when unrefreshed cached names were checked last + static F64 sLastExpireCheck; //----------------------------------------------------------------------- // Internal methods @@ -99,8 +102,9 @@ namespace LLAvatarNameCache // Legacy name system callback void legacyNameCallback(const LLUUID& agent_id, - const std::string& full_name, - bool is_group); + const std::string& full_name, + bool is_group + ); void requestNamesViaLegacy(); @@ -117,7 +121,7 @@ namespace LLAvatarNameCache bool isRequestPending(const LLUUID& agent_id); // Erase expired names from cache - void eraseExpired(); + void eraseUnrefreshed(); bool expirationFromCacheControl(LLSD headers, F64 *expires); } @@ -187,6 +191,7 @@ public: { // Pull expiration out of headers if available F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders); + F64 now = LLFrameTimer::getTotalSeconds(); LLSD agents = content["agents"]; LLSD::array_const_iterator it = agents.beginArray(); @@ -207,84 +212,91 @@ public: av_name.mDisplayName = av_name.mUsername; } + LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << " " + << "user '" << av_name.mUsername << "' " + << "display '" << av_name.mDisplayName << "' " + << "expires in " << expires - now << " seconds" + << LL_ENDL; + // cache it and fire signals LLAvatarNameCache::processName(agent_id, av_name, true); } // Same logic as error response case LLSD unresolved_agents = content["bad_ids"]; - if (unresolved_agents.size() > 0) + S32 num_unresolved = unresolved_agents.size(); + if (num_unresolved > 0) { - const std::string DUMMY_NAME("\?\?\?"); - LLAvatarName av_name; - av_name.mUsername = DUMMY_NAME; - av_name.mDisplayName = DUMMY_NAME; - av_name.mIsDisplayNameDefault = false; - av_name.mIsDummy = true; - av_name.mExpires = expires; - + LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; " + << "expires in " << expires - now << " seconds" + << LL_ENDL; it = unresolved_agents.beginArray(); for ( ; it != unresolved_agents.endArray(); ++it) { const LLUUID& agent_id = *it; - // cache it and fire signals - LLAvatarNameCache::processName(agent_id, av_name, true); + + LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " + << "failed id " << agent_id + << LL_ENDL; + + LLAvatarNameCache::handleAgentError(agent_id); } } - } + LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result " + << LLAvatarNameCache::sCache.size() << " cached names" + << LL_ENDL; + } /*virtual*/ void error(U32 status, const std::string& reason) { // If there's an error, it might be caused by PeopleApi, // or when loading textures on startup and using a very slow - // network, this query may time out. Fallback to the legacy - // cache. - - llwarns << "LLAvatarNameResponder error " << status << " " << reason << llendl; + // network, this query may time out. + // What we should do depends on whether or not we have a cached name + LL_WARNS("AvNameCache") << "LLAvatarNameResponder::error " << status << " " << reason + << LL_ENDL; - // Add dummy records for all agent IDs in this request + // Add dummy records for any agent IDs in this request that we do not have cached already std::vector<LLUUID>::const_iterator it = mAgentIDs.begin(); for ( ; it != mAgentIDs.end(); ++it) { const LLUUID& agent_id = *it; - gCacheName->get(agent_id, false, // legacy compatibility - boost::bind(&LLAvatarNameCache::legacyNameCallback, - _1, _2, _3)); - } - } - - // Return time to retry a request that generated an error, based on - // error type and headers. Return value is seconds-since-epoch. - F64 errorRetryTimestamp(S32 status) - { - F64 now = LLFrameTimer::getTotalSeconds(); - - // Retry-After takes priority - LLSD retry_after = mHeaders["retry-after"]; - if (retry_after.isDefined()) - { - // We only support the delta-seconds type - S32 delta_seconds = retry_after.asInteger(); - if (delta_seconds > 0) - { - // ...valid delta-seconds - return now + F64(delta_seconds); - } + LLAvatarNameCache::handleAgentError(agent_id); } - - // If no Retry-After, look for Cache-Control max-age - F64 expires = 0.0; - if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires)) - { - return expires; - } - - // No information in header, make a guess - const F64 DEFAULT_DELAY = 120.0; // 2 mintues - return now + DEFAULT_DELAY; } }; +// Provide some fallback for agents that return errors +void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) +{ + std::map<LLUUID,LLAvatarName>::iterator existing = sCache.find(agent_id); + if (existing == sCache.end()) + { + // there is no existing cache entry, so make a temporary name from legacy + LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent " + << agent_id << LL_ENDL; + gCacheName->get(agent_id, false, // legacy compatibility + boost::bind(&LLAvatarNameCache::legacyNameCallback, + _1, _2, _3)); + } + else + { + // we have a chached (but probably expired) entry - since that would have + // been returned by the get method, there is no need to signal anyone + + // Clear this agent from the pending list + LLAvatarNameCache::sPendingQueue.erase(agent_id); + + const LLAvatarName& av_name = existing->second; + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " + << agent_id + << "user '" << av_name.mUsername << "' " + << "display '" << av_name.mDisplayName << "' " + << "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds" + << LL_ENDL; + } +} + void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& av_name, bool add_to_cache) @@ -326,6 +338,7 @@ void LLAvatarNameCache::requestNamesViaCapability() std::vector<LLUUID> agent_ids; agent_ids.reserve(128); + U32 ids = 0; ask_queue_t::const_iterator it = sAskQueue.begin(); for ( ; it != sAskQueue.end(); ++it) { @@ -336,11 +349,13 @@ void LLAvatarNameCache::requestNamesViaCapability() // ...starting new request url += sNameLookupURL; url += "?ids="; + ids = 1; } else { // ...continuing existing request url += "&ids="; + ids++; } url += agent_id.asString(); agent_ids.push_back(agent_id); @@ -350,8 +365,10 @@ void LLAvatarNameCache::requestNamesViaCapability() if (url.size() > NAME_URL_SEND_THRESHOLD) { - //llinfos << "requestNames " << url << llendl; - LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));//, LLSD(), 10.0f); + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first " + << ids << " ids" + << LL_ENDL; + LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); url.clear(); agent_ids.clear(); } @@ -359,8 +376,10 @@ void LLAvatarNameCache::requestNamesViaCapability() if (!url.empty()) { - //llinfos << "requestNames " << url << llendl; - LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));//, LLSD(), 10.0f); + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all " + << ids << " ids" + << LL_ENDL; + LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); url.clear(); agent_ids.clear(); } @@ -376,6 +395,11 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, // Construct a dummy record for this name. By convention, SLID is blank // Never expires, but not written to disk, so lasts until end of session. LLAvatarName av_name; + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameCallback " + << "agent " << agent_id << " " + << "full name '" << full_name << "'" + << ( is_group ? " [group]" : "" ) + << LL_ENDL; buildLegacyName(full_name, &av_name); // Don't add to cache, the data already exists in the legacy name system @@ -397,6 +421,8 @@ void LLAvatarNameCache::requestNamesViaLegacy() // invoked below. This should never happen in practice. sPendingQueue[agent_id] = now; + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaLegacy agent " << agent_id << LL_ENDL; + gCacheName->get(agent_id, false, // legacy compatibility boost::bind(&LLAvatarNameCache::legacyNameCallback, _1, _2, _3)); @@ -435,21 +461,24 @@ void LLAvatarNameCache::importFile(std::istream& istr) av_name.fromLLSD( it->second ); sCache[agent_id] = av_name; } - // entries may have expired since we last ran the viewer, just - // clean them out now - eraseExpired(); - llinfos << "loaded " << sCache.size() << llendl; + LL_INFOS("AvNameCache") << "loaded " << sCache.size() << LL_ENDL; + + // Some entries may have expired since the cache was stored, + // but they will be flushed in the first call to eraseUnrefreshed + // from LLAvatarNameResponder::idle } void LLAvatarNameCache::exportFile(std::ostream& ostr) { LLSD agents; + F64 max_unrefreshed = LLFrameTimer::getTotalSeconds() - MAX_UNREFRESHED_TIME; cache_t::const_iterator it = sCache.begin(); for ( ; it != sCache.end(); ++it) { const LLUUID& agent_id = it->first; const LLAvatarName& av_name = it->second; - if (!av_name.mIsDummy) + // Do not write temporary or expired entries to the stored cache + if (!av_name.mIsTemporaryName && av_name.mExpires >= max_unrefreshed) { // key must be a string agents[agent_id.asString()] = av_name.asLLSD(); @@ -484,62 +513,63 @@ void LLAvatarNameCache::idle() // return; //} - // Must be large relative to above - - // No longer deleting expired entries, just re-requesting in the get - // this way first synchronous get call on an expired entry won't return - // legacy name. LF - - //const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds - //if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) - //{ - // eraseExpired(); - //} - - if (sAskQueue.empty()) + if (!sAskQueue.empty()) { - return; + if (useDisplayNames()) + { + requestNamesViaCapability(); + } + else + { + // ...fall back to legacy name cache system + requestNamesViaLegacy(); + } } - if (useDisplayNames()) - { - requestNamesViaCapability(); - } - else - { - // ...fall back to legacy name cache system - requestNamesViaLegacy(); - } + // erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME + eraseUnrefreshed(); } bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id) { + bool isPending = false; const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; - F64 now = LLFrameTimer::getTotalSeconds(); - F64 expire_time = now - PENDING_TIMEOUT_SECS; pending_queue_t::const_iterator it = sPendingQueue.find(agent_id); if (it != sPendingQueue.end()) { - bool request_expired = (it->second < expire_time); - return !request_expired; + // in the list of requests in flight, retry if too old + F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; + isPending = (it->second > expire_time); } - return false; + return isPending; } -void LLAvatarNameCache::eraseExpired() +void LLAvatarNameCache::eraseUnrefreshed() { F64 now = LLFrameTimer::getTotalSeconds(); - cache_t::iterator it = sCache.begin(); - while (it != sCache.end()) - { - cache_t::iterator cur = it; - ++it; - const LLAvatarName& av_name = cur->second; - if (av_name.mExpires < now) - { - sCache.erase(cur); - } + F64 max_unrefreshed = now - MAX_UNREFRESHED_TIME; + + if (!sLastExpireCheck || sLastExpireCheck < max_unrefreshed) + { + sLastExpireCheck = now; + cache_t::iterator it = sCache.begin(); + while (it != sCache.end()) + { + cache_t::iterator cur = it; + ++it; + const LLAvatarName& av_name = cur->second; + if (av_name.mExpires < max_unrefreshed) + { + const LLUUID& agent_id = it->first; + LL_DEBUGS("AvNameCache") << agent_id + << " user '" << av_name.mUsername << "' " + << "expired " << now - av_name.mExpires << " secs ago" + << LL_ENDL; + sCache.erase(cur); + } + } + LL_INFOS("AvNameCache") << sCache.size() << " cached avatar names" << LL_ENDL; } } @@ -550,8 +580,11 @@ void LLAvatarNameCache::buildLegacyName(const std::string& full_name, av_name->mUsername = ""; av_name->mDisplayName = full_name; av_name->mIsDisplayNameDefault = true; - av_name->mIsDummy = true; - av_name->mExpires = F64_MAX; + av_name->mIsTemporaryName = true; + av_name->mExpires = F64_MAX; // not used because these are not cached + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName " + << full_name + << LL_ENDL; } // fills in av_name if it has it in the cache, even if expired (can check expiry time) @@ -574,6 +607,9 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) { if (!isRequestPending(agent_id)) { + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get " + << "refresh agent " << agent_id + << LL_ENDL; sAskQueue.insert(agent_id); } } @@ -595,6 +631,9 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) if (!isRequestPending(agent_id)) { + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get " + << "queue request for agent " << agent_id + << LL_ENDL; sAskQueue.insert(agent_id); } @@ -627,7 +666,6 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) { // ...name already exists in cache, fire callback now fireSignal(agent_id, slot, av_name); - return; } } @@ -723,6 +761,9 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) { + bool fromCacheControl = false; + F64 now = LLFrameTimer::getTotalSeconds(); + // Allow the header to override the default LLSD cache_control_header = headers["cache-control"]; if (cache_control_header.isDefined()) @@ -731,12 +772,16 @@ bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) std::string cache_control = cache_control_header.asString(); if (max_age_from_cache_control(cache_control, &max_age)) { - F64 now = LLFrameTimer::getTotalSeconds(); *expires = now + (F64)max_age; - return true; + fromCacheControl = true; } } - return false; + LL_DEBUGS("AvNameCache") + << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) + << "in " << *expires - now << " seconds" + << LL_ENDL; + + return fromCacheControl; } diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 8f21ace96a..59c1329ffa 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -82,6 +82,9 @@ namespace LLAvatarNameCache void erase(const LLUUID& agent_id); + /// Provide some fallback for agents that return errors + void handleAgentError(const LLUUID& agent_id); + // Force a re-fetch of the most recent data, but keep the current // data in cache void fetch(const LLUUID& agent_id); diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 3ba2dfb104..e0410906fb 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -87,6 +87,7 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, mPingDelayAveraged((F32)INITIAL_PING_VALUE_MSEC), mUnackedPacketCount(0), mUnackedPacketBytes(0), + mLastPacketInTime(0.0), mLocalEndPointID(), mPacketsOut(0), mPacketsIn(0), @@ -667,6 +668,8 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) mHighestPacketID = llmax(mHighestPacketID, id); } + // Save packet arrival time + mLastPacketInTime = LLMessageSystem::getMessageTimeSeconds(); // Have we received anything on this circuit yet? if (0 == mPacketsIn) diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h index 874c0c0bee..d1c400c6a2 100644 --- a/indra/llmessage/llcircuit.h +++ b/indra/llmessage/llcircuit.h @@ -122,7 +122,7 @@ public: U32 getPacketsLost() const; TPACKETID getPacketOutID() const; BOOL getTrusted() const; - F32 getAgeInSeconds() const; + F32 getAgeInSeconds() const; S32 getUnackedPacketCount() const { return mUnackedPacketCount; } S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; } F64 getNextPingSendTime() const { return mNextPingSendTime; } @@ -130,6 +130,7 @@ public: { return mOutOfOrderRate.meanValue(scale); } U32 getLastPacketGap() const { return mLastPacketGap; } LLHost getHost() const { return mHost; } + F64 getLastPacketInTime() const { return mLastPacketInTime; } LLThrottleGroup &getThrottleGroup() { return mThrottles; } @@ -248,6 +249,7 @@ protected: S32 mUnackedPacketCount; S32 mUnackedPacketBytes; + F64 mLastPacketInTime; // Time of last packet arrival LLUUID mLocalEndPointID; diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 1869e1dd47..3d03209eaf 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -950,6 +950,25 @@ void LLModel::normalizeVolumeFaces() LLVector4a size; size.setSub(max, min); + // Prevent division by zero. + F32 x = size[0]; + F32 y = size[1]; + F32 z = size[2]; + F32 w = size[3]; + if (fabs(x)<F_APPROXIMATELY_ZERO) + { + x = 1.0; + } + if (fabs(y)<F_APPROXIMATELY_ZERO) + { + y = 1.0; + } + if (fabs(z)<F_APPROXIMATELY_ZERO) + { + z = 1.0; + } + size.set(x,y,z,w); + // Compute scale as reciprocal of size LLVector4a scale; scale.splat(1.f); diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 3c1d031ff5..861bde5c89 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -403,7 +403,7 @@ S32 LLTextureEntry::setOffsetT(F32 t) S32 LLTextureEntry::setRotation(F32 theta) { - if (mRotation != theta) + if (mRotation != theta && llfinite(theta)) { mRotation = theta; return TEM_CHANGE_TEXTURE; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index ac43b53ecc..dfd72d13b0 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1063,16 +1063,6 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ { if (gGL.getTexUnit(0)->bind(this, false, true)) { - if(gGLManager.mDebugGPU) - { - llinfos << "Calling glCopyTexSubImage2D(...)" << llendl ; - checkTexSize(true) ; - llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height << - " : " << (S32)mComponents << llcallstacksendl ; - - log_glerror() ; - } - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); mGLTextureCreated = true; stop_glerror(); diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index cd0f0e36b0..cc9edfcdea 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1367,7 +1367,6 @@ LLNotifications::TemplateNames LLNotifications::getTemplateNames() const typedef std::map<std::string, std::string> StringMap; void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) { - //llwarns << "replaceSubstitutionStrings" << llendl; // walk the list of attributes looking for replacements for (LLXMLAttribList::iterator it=node->mAttributes.begin(); it != node->mAttributes.end(); ++it) @@ -1381,13 +1380,12 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) if (found != replacements.end()) { replacement = found->second; - //llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl; - + lldebugs << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << llendl; it->second->setValue(replacement); } else { - llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl; + llwarns << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << llendl; } } } diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 64556bcb4c..cb898e385f 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -101,10 +101,18 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) { if (0 != LLFile::remove(fullpath)) { + retry_count++; result = errno; llwarns << "Problem removing " << fullpath << " - errorcode: " << result << " attempt " << retry_count << llendl; - ms_sleep(1000); + + if(retry_count >= 5) + { + llwarns << "Failed to remove " << fullpath << llendl ; + return count ; + } + + ms_sleep(100); } else { @@ -113,8 +121,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) llwarns << "Successfully removed " << fullpath << llendl; } break; - } - retry_count++; + } } count++; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 437be15150..290e8ebbe0 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1753,6 +1753,17 @@ set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH if (LINUX) set(product SecondLife-${ARCH}-${viewer_VERSION}) + # These are the generated targets that are copied to package/ + set(COPY_INPUT_DEPENDENCIES + ${VIEWER_BINARY_NAME} + linux-crash-logger + linux-updater + SLPlugin + media_plugin_webkit + media_plugin_gstreamer010 + llcommon + ) + add_custom_command( OUTPUT ${product}.tar.bz2 COMMAND ${PYTHON_EXECUTABLE} @@ -1770,18 +1781,13 @@ if (LINUX) --login_channel=${VIEWER_LOGIN_CHANNEL} --source=${CMAKE_CURRENT_SOURCE_DIR} --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched - DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + ${COPY_INPUT_DEPENDENCIES} ) - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 media_plugin_webkit) - - if (NOT INSTALL) - add_custom_target(package ALL DEPENDS ${product}.tar.bz2) - add_dependencies(package linux-crash-logger-target) - add_dependencies(package linux-updater-target) - check_message_template(package) - endif (NOT INSTALL) - + if (PACKAGE) + endif (PACKAGE) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched COMMAND ${PYTHON_EXECUTABLE} @@ -1801,9 +1807,15 @@ if (LINUX) ${COPY_INPUT_DEPENDENCIES} COMMENT "Performing viewer_manifest copy" ) - + add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched) - add_dependencies(copy_l_viewer_manifest "${VIEWER_BINARY_NAME}" linux-crash-logger-target linux-updater-target) + + if (PACKAGE) + add_custom_target(package ALL DEPENDS ${product}.tar.bz2) + # Make sure we don't run two instances of viewer_manifest.py at the same time. + add_dependencies(package copy_l_viewer_manifest) + check_message_template(package) + endif (PACKAGE) endif (LINUX) if (DARWIN) diff --git a/indra/newview/app_settings/lindenlab.pem b/indra/newview/app_settings/lindenlab.pem index cf88d0e047..eddae0426d 100644 --- a/indra/newview/app_settings/lindenlab.pem +++ b/indra/newview/app_settings/lindenlab.pem @@ -24,4 +24,74 @@ xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9 e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu glmQ1A== -----END CERTIFICATE----- - +-----BEGIN CERTIFICATE----- +MIIEkDCCA3igAwIBAgICTSUwDQYJKoZIhvcNAQEFBQAwQDELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDkdlb1RydXN0LCBJbmMuMRgwFgYDVQQDEw9HZW9UcnVzdCBTU0wg +Q0EwHhcNMTAxMjIwMTkxMTI2WhcNMTIwMjIxMTI1NDAzWjCBnzEpMCcGA1UEBRMg +UkMteW9jbXIwdXRmRTdOMVBlaHJHQXdqL0lNc2hJZS0xCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMR0wGwYD +VQQKExRMaW5kZW4gUmVzZWFyY2ggSW5jLjEZMBcGA1UEAwwQKi5zZWNvbmRsaWZl +LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN/VCCu1SZ5x4vNp +XZZ8r3lzqeLwjxVZfMSQCKM4lV5DFbqiZMMBto4Y/ib7i0audzuTDnImCLsfzlTu +7iZLoJNy42/43Rq4xtaDZ7joxALFmzXUKEipgHiTTbAbLQNCS4wPXts3tScODVZY +/mhlmXdlLuGxJbqoyOEP6NEQbgXWDCKDERnAEG/FJBVHKyBfg3abrrIuQNwYCKCS +2OZ5Z5MveGmY4tSKUOOi/c0vV9HsanQn/ymybZjxR5Kmb1CvQr7VVtbpR1MhlGkc +sfJz1NFIFxdXkUggIny+XSG1dAAJRFFumyRM+X/eh0NHNmAI14JJ43hB6Zw3dzzl +An9BSeECAwEAAaOCATIwggEuMB8GA1UdIwQYMBaAFEJ5VBthzVUrPmPVPEhX9Z/7 +Rc5KMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH +AwIwKwYDVR0RBCQwIoIQKi5zZWNvbmRsaWZlLmNvbYIOc2Vjb25kbGlmZS5jb20w +PQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2d0c3NsLWNybC5nZW90cnVzdC5jb20v +Y3Jscy9ndHNzbC5jcmwwHQYDVR0OBBYEFK9UTMkc4Fh/Ug4fVs6UVhxP6my0MAwG +A1UdEwEB/wQCMAAwQwYIKwYBBQUHAQEENzA1MDMGCCsGAQUFBzAChidodHRwOi8v +Z3Rzc2wtYWlhLmdlb3RydXN0LmNvbS9ndHNzbC5jcnQwDQYJKoZIhvcNAQEFBQAD +ggEBACIR9yggGHDcZ60AMNdFmZ8XJeahTuv6q2X/It2JxqSQp5BVQUei0NGIYYOt +yg0JFBZn5KqXiQ5Zz84K4hdvh/6grCEAn4v37sozSbkeZ92Lec8NOZR42HfYIOCo +Hx9q7CNRxdhv6ehV4LekaRBxrtp5etVsIDaWvRZEswCWl46VuLrfjcpauj6DAdOQ +FfPVAW+4nPgLr8KapZMnXYnabIwrj9DQLQ88w/D7durenu/SYJEahWW9mb++n9is +eMjyuyzYW0PTUBTaDsj+2ZmHJtoR1tBiLqh0Q62UQnmDgsf5SK5PTb8jnta/1SvN +3pirsuvjMPV19zuH6b9NpJfXfd0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT +MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 +aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw +WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE +AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m +OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu +T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c +JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR +Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz +PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm +aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM +TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g +LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO +BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv +dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB +AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL +NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W +b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID2TCCAsGgAwIBAgIDAjbQMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTAwMjE5MjIzOTI2WhcNMjAwMjE4MjIzOTI2WjBAMQswCQYDVQQG +EwJVUzEXMBUGA1UEChMOR2VvVHJ1c3QsIEluYy4xGDAWBgNVBAMTD0dlb1RydXN0 +IFNTTCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJCzgMHk5Uat +cGA9uuUU3Z6KXot1WubKbUGlI+g5hSZ6p1V3mkihkn46HhrxJ6ujTDnMyz1Hr4Gu +FmpcN+9FQf37mpc8oEOdxt8XIdGKolbCA0mEEoE+yQpUYGa5jFTk+eb5lPHgX3UR +8im55IaisYmtph6DKWOy8FQchQt65+EuDa+kvc3nsVrXjAVaDktzKIt1XTTYdwvh +dGLicTBi2LyKBeUxY0pUiWozeKdOVSQdl+8a5BLGDzAYtDRN4dgjOyFbLTAZJQ50 +96QhS6CkIMlszZhWwPKoXz4mdaAN+DaIiixafWcwqQ/RmXAueOFRJq9VeiS+jDkN +d53eAsMMvR8CAwEAAaOB2TCB1jAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFEJ5 +VBthzVUrPmPVPEhX9Z/7Rc5KMB8GA1UdIwQYMBaAFMB6mGiNifurBWQMEX2qfWW4 +ysxOMBIGA1UdEwEB/wQIMAYBAf8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDov +L2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYBBQUHAQEE +KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20wDQYJKoZI +hvcNAQEFBQADggEBANTvU4ToGr2hiwTAqfVfoRB4RV2yV2pOJMtlTjGXkZrUJPji +J2ZwMZzBYlQG55cdOprApClICq8kx6jEmlTBfEx4TCtoLF0XplR4TEbigMMfOHES +0tdT41SFULgCy+5jOvhWiU1Vuy7AyBh3hjELC3DwfjWDpCoTZFZnNF0WX3OsewYk +2k9QbSqr0E1TQcKOu3EDSSmGGM8hQkx0YlEVxW+o78Qn5Rsz3VqI138S0adhJR/V +4NwdzxoQ2KDLX4z6DOW/cf/lXUQdpj6HR/oaToODEj+IZpWYeZqF6wJHzSXj8gYE +TpnKXKBuervdo5AaRTPvvz7SBMS24CqFZUE+ENQ= +-----END CERTIFICATE----- diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index bc181b5f8b..6f47d9c019 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -697,28 +697,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>BrowserUseDefaultCAFile</key> - <map> - <key>Comment</key> - <string>Tell the built-in web browser to use the CA.pem file shipped with the client.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>BrowserCAFilePath</key> - <map> - <key>Comment</key> - <string>Tell the built-in web browser the path to an alternative CA.pem file (only used if BrowserUseDefaultCAFile is false).</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string></string> - </map> <key>BlockAvatarAppearanceMessages</key> <map> <key>Comment</key> @@ -950,39 +928,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>BulkChangeIncludeAnimations</key> - <map> - <key>Comment</key> - <string>Bulk permission changes affect animations</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>BulkChangeIncludeAnimations</key> - <map> - <key>Comment</key> - <string>Bulk permission changes affect animations</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>BulkChangeIncludeAnimations</key> - <map> - <key>Comment</key> - <string>Bulk permission changes affect animations</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>BulkChangeIncludeBodyParts</key> <map> <key>Comment</key> @@ -1195,18 +1140,7 @@ <key>CacheLocationTopFolder</key> <map> <key>Comment</key> - <string>Controls the top folder location of the local disk cache</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string /> - </map> - <key>CacheLocationTopFolder</key> - <map> - <key>Comment</key> - <string>Controls the location of the local disk cache</string> + <string>Controls the top folder location of the the local disk cache</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -1223,7 +1157,7 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>20000</integer> + <integer>128</integer> </map> <key>CacheSize</key> <map> @@ -1945,6 +1879,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>DebugShowMemory</key> + <map> + <key>Comment</key> + <string>Show Total Allocated Memory</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>DebugShowRenderInfo</key> <map> <key>Comment</key> @@ -1978,10 +1923,21 @@ <key>Value</key> <integer>0</integer> </map> + <key>DebugShowTextureInfo</key> + <map> + <key>Comment</key> + <string>Show inertested texture info</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>DebugShowTime</key> <map> <key>Comment</key> - <string>Show depth buffer contents</string> + <string>Show time info</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -3179,17 +3135,6 @@ <string>http://viewer-settings.secondlife.com</string> </map> <key>FPSLogFrequency</key> - <map> - <key>Comment</key> - <string>Seconds between display of FPS in log (0 for never)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>F32</string> - <key>Value</key> - <real>60.0</real> - </map> - <key>FPSLogFrequency</key> <map> <key>Comment</key> <string>Seconds between display of FPS in log (0 for never)</string> @@ -6155,17 +6100,6 @@ <key>OutBandwidth</key> <map> <key>Comment</key> - <string>Expand render stats display</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>OutBandwidth</key> - <map> - <key>Comment</key> <string>Outgoing bandwidth throttle (bps)</string> <key>Persist</key> <integer>1</integer> @@ -11844,8 +11778,6 @@ <key>Type</key> <string>LLSD</string> <key>Value</key> - <map> - </map> </map> <key>VFSOldSize</key> <map> @@ -12001,17 +11933,6 @@ <key>Value</key> <string></string> </map> - <key>VivoxDebugSIPURIHostName</key> - <map> - <key>Comment</key> - <string>Hostname portion of vivox SIP URIs (empty string for the default).</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string></string> - </map> <key>VivoxDebugVoiceAccountServerURI</key> <map> <key>Comment</key> @@ -12837,16 +12758,5 @@ <key>Value</key> <string>name</string> </map> - <key>ReleaseNotesURL</key> - <map> - <key>Comment</key> - <string>Release notes URL template</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>String</string> - <key>Value</key> - <string>http://secondlife.com/app/releasenotes/?channel=[CHANNEL]&version=[VERSION]</string> - </map> </map> </llsd> diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index bf604d6805..66b3b97f00 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -302,12 +302,43 @@ NVIDIA NV43 .*NVIDIA.*NV43.* 1 1 NVIDIA NV44 .*NVIDIA.*NV44.* 1 1 NVIDIA nForce .*NVIDIA.*nForce.* 0 0 NVIDIA MCP78 .*NVIDIA.*MCP78.* 1 1 -NVIDIA Quadro2 .*Quadro2.* 0 1 -NVIDIA Quadro4 .*Quadro4.* 0 1 -NVIDIA Quadro DCC .*Quadro DCC.* 0 1 -NVIDIA Quadro FX 4500 .*Quadro.*FX.*4500.* 3 1 -NVIDIA Quadro FX .*Quadro FX.* 1 1 -NVIDIA Quadro NVS .*Quadro NVS.* 0 1 +NVIDIA Quadro2 .*Quadro2.* 0 1 +NVIDIA Quadro4 .*Quadro4.* 0 1 +NVIDIA Quadro DCC .*Quadro DCC.* 0 1 +NVIDIA Quadro FX 1400 .*Quadro.*FX.*1400.* 1 1 +NVIDIA Quadro FX 1500 .*Quadro.*FX.*1500.* 1 1 +NVIDIA Quadro FX 1700 .*Quadro.*FX.*1700.* 2 1 +NVIDIA Quadro FX 1800 .*Quadro.*FX.*1800.* 2 1 +NVIDIA Quadro FX 3400 .*Quadro.*FX.*3400.* 1 1 +NVIDIA Quadro FX 3450 .*Quadro.*FX.*3450.* 1 1 +NVIDIA Quadro FX 3500 .*Quadro.*FX.*3500.* 1 1 +NVIDIA Quadro FX 3700 .*Quadro.*FX.*3700.* 2 1 +NVIDIA Quadro FX 3800 .*Quadro.*FX.*3800.* 2 1 +NVIDIA Quadro FX 370 .*Quadro.*FX.*370.* 2 1 +NVIDIA Quadro FX 380 .*Quadro.*FX.*380.* 2 1 +NVIDIA Quadro FX 4000 .*Quadro.*FX.*4000.* 1 1 +NVIDIA Quadro FX 4500 .*Quadro.*FX.*4500.* 1 1 +NVIDIA Quadro FX 4600 .*Quadro.*FX.*4600.* 2 1 +NVIDIA Quadro FX 4700 .*Quadro.*FX.*4700.* 2 1 +NVIDIA Quadro FX 4800 .*Quadro.*FX.*4800.* 2 1 +NVIDIA Quadro FX 470 .*Quadro.*FX.*470.* 2 1 +NVIDIA Quadro FX 5500 .*Quadro.*FX.*5500.* 1 1 +NVIDIA Quadro FX 5600 .*Quadro.*FX.*5600.* 2 1 +NVIDIA Quadro FX 5700 .*Quadro.*FX.*5700.* 2 1 +NVIDIA Quadro FX 5800 .*Quadro.*FX.*5800.* 2 1 +NVIDIA Quadro FX 540 .*Quadro.*FX.*540.* 1 1 +NVIDIA Quadro FX 550 .*Quadro.*FX.*550.* 1 1 +NVIDIA Quadro FX 560 .*Quadro.*FX.*560.* 1 1 +NVIDIA Quadro FX 570 .*Quadro.*FX.*570.* 2 1 +NVIDIA Quadro FX 580 .*Quadro.*FX.*580.* 2 1 +NVIDIA Quadro FX .*Quadro FX.* 0 1 +NVIDIA Quadro VX 200 .*Quadro VX.*200.* 2 1 +NVIDIA Quadro 2000 .*Quadro.*2000.* 2 1 +NVIDIA Quadro 4000 .*Quadro.*4000.* 2 1 +NVIDIA Quadro 5000 .*Quadro.*5000.* 2 1 +NVIDIA Quadro 6000 .*Quadro.*6000.* 2 1 +NVIDIA Quadro 600 .*Quadro.*600.* 2 1 +NVIDIA Quadro NVS .*Quadro NVS.* 0 1 NVIDIA RIVA TNT .*RIVA TNT.* 0 0 S3 .*S3 Graphics.* 0 0 SiS SiS.* 0 0 diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index 13e1023185..afeba6bdf0 100644 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -178,6 +178,8 @@ void LLAgentPilot::stopPlayback() } } +#define SKIP_PILOT_LOGGING 1 + void LLAgentPilot::updateTarget() { if (mPlaying) @@ -195,7 +197,9 @@ void LLAgentPilot::updateTarget() { if (!mStarted) { +#if SKIP_PILOT_LOGGING llinfos << "At start, beginning playback" << llendl; +#endif mTimer.reset(); mStarted = TRUE; } @@ -218,17 +222,23 @@ void LLAgentPilot::updateTarget() { if ((mNumRuns < 0) || (mNumRuns > 0)) { +#if SKIP_PILOT_LOGGING llinfos << "Looping, restarting playback" << llendl; +#endif startPlayback(); } else if (mQuitAfterRuns) { +#if SKIP_PILOT_LOGGING llinfos << "Done with all runs, quitting viewer!" << llendl; +#endif LLAppViewer::instance()->forceQuit(); } else { +#if SKIP_PILOT_LOGGING llinfos << "Done with all runs, disabling pilot" << llendl; +#endif stopPlayback(); } } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 7e8c68632d..c1a311b170 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -475,13 +475,12 @@ static void settings_to_globals() gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale"); - - LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); } static void settings_modify() { LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred"); + LLPipeline::sRenderDeferred = gSavedSettings.getBOOL("RenderDeferred"); LLVOAvatar::sUseImpostors = gSavedSettings.getBOOL("RenderUseImpostors"); LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4] @@ -858,6 +857,9 @@ bool LLAppViewer::init() gGLActive = TRUE; initWindow(); + // initWindow also initializes the Feature List, so now we can initialize this global. + LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); + // call all self-registered classes LLInitClassList::instance().fireCallbacks(); @@ -895,6 +897,18 @@ bool LLAppViewer::init() return 0; } + // Without SSE2 support we will crash almost immediately, warn here. + if (!gSysCPU.hasSSE2()) + { + // can't use an alert here since we're exiting and + // all hell breaks lose. + OSMessageBox( + LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"), + LLStringUtil::null, + OSMB_OK); + return 0; + } + // alert the user if they are using unsupported hardware if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) { @@ -1300,7 +1314,7 @@ bool LLAppViewer::mainLoop() resumeMainloopTimeout(); pingMainloopTimeout("Main:End"); - } + } } catch(std::bad_alloc) { @@ -1416,16 +1430,6 @@ bool LLAppViewer::cleanup() } mPlugins.clear(); - //---------------------------------------------- - //this test code will be removed after the test - //test manual call stack tracer - if(gSavedSettings.getBOOL("QAMode")) - { - LLError::LLCallStacks::print() ; - } - //end of the test code - //---------------------------------------------- - //flag all elements as needing to be destroyed immediately // to ensure shutdown order LLMortician::setZealous(TRUE); @@ -1813,6 +1817,8 @@ bool LLAppViewer::cleanup() ll_close_fail_log(); + MEM_TRACK_RELEASE + llinfos << "Goodbye!" << llendflush; // return 0; @@ -2511,16 +2517,24 @@ namespace { if(data["required"].asBoolean()) { - apply_callback = &apply_update_ok_callback; if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT) { // The user never saw the progress bar. + apply_callback = &apply_update_ok_callback; notification_name = "RequiredUpdateDownloadedVerboseDialog"; } - else + else if(LLStartUp::getStartupState() < STATE_WORLD_INIT) { + // The user is logging in but blocked. + apply_callback = &apply_update_ok_callback; notification_name = "RequiredUpdateDownloadedDialog"; } + else + { + // The user is already logged in; treat like an optional update. + apply_callback = &apply_update_callback; + notification_name = "DownloadBackgroundTip"; + } } else { @@ -3110,35 +3124,32 @@ void LLAppViewer::initMarkerFile() std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning()) { gLastExecEvent = LAST_EXEC_FROZE; LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL; } - if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) { - LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << LL_ENDL; gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(logout_marker_file); } if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) { - llinfos << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << llendl; if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; else gLastExecEvent = LAST_EXEC_LLERROR_CRASH; + LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(llerror_marker_file); } if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) { - LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL; if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; else gLastExecEvent = LAST_EXEC_OTHER_CRASH; + LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + LLAPRFile::remove(error_marker_file); } - - LLAPRFile::remove(logout_marker_file); - LLAPRFile::remove(llerror_marker_file); - LLAPRFile::remove(error_marker_file); - + // No new markers if another instance is running. if(anotherInstanceRunning()) { @@ -3780,6 +3791,7 @@ void LLAppViewer::loadNameCache() // display names cache std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); + LL_INFOS("AvNameCache") << filename << LL_ENDL; llifstream name_cache_stream(filename); if(name_cache_stream.is_open()) { diff --git a/indra/newview/llcapabilityprovider.h b/indra/newview/llcapabilityprovider.h index a6e743f625..9d91245597 100644 --- a/indra/newview/llcapabilityprovider.h +++ b/indra/newview/llcapabilityprovider.h @@ -46,7 +46,7 @@ public: /** * Get host to which to send that capability request. */ - virtual LLHost getHost() const = 0; + virtual const LLHost& getHost() const = 0; /** * Describe this LLCapabilityProvider for logging etc. */ diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp index 4a1ba6f1b5..6f02192d0a 100644 --- a/indra/newview/llcolorswatch.cpp +++ b/indra/newview/llcolorswatch.cpp @@ -319,7 +319,7 @@ void LLColorSwatchCtrl::onColorChanged ( void* data, EColorPickOp pick_op ) // This is called when the main floatercustomize panel is closed. // Since this class has pointers up to its parents, we need to cleanup // this class first in order to avoid a crash. -void LLColorSwatchCtrl::onParentFloaterClosed() +void LLColorSwatchCtrl::closeFloaterColorPicker() { LLFloaterColorPicker* pickerp = (LLFloaterColorPicker*)mPickerHandle.get(); if (pickerp) diff --git a/indra/newview/llcolorswatch.h b/indra/newview/llcolorswatch.h index cd859ea128..5bdd1712d2 100644 --- a/indra/newview/llcolorswatch.h +++ b/indra/newview/llcolorswatch.h @@ -100,7 +100,7 @@ public: /*virtual*/ void setEnabled( BOOL enabled ); static void onColorChanged ( void* data, EColorPickOp pick_op = COLOR_CHANGE ); - void onParentFloaterClosed(); + void closeFloaterColorPicker(); protected: BOOL mValid; diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index a3d2941114..f781d5f3ff 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -177,10 +177,6 @@ void LLViewerDynamicTexture::postRender(BOOL success) generateGLTexture() ; } - if(gGLManager.mDebugGPU) - { - LLGLState::dumpStates() ; - } success = mGLTexturep->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight); } } @@ -220,12 +216,6 @@ BOOL LLViewerDynamicTexture::updateAllInstances() LLViewerDynamicTexture *dynamicTexture = *iter; if (dynamicTexture->needsRender()) { - if(gGLManager.mDebugGPU) - { - llinfos << "class type: " << (S32)dynamicTexture->getType() << llendl; - LLGLState::dumpStates() ; - } - glClear(GL_DEPTH_BUFFER_BIT); gDepthDirty = TRUE; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 15f59e84a6..1576ef0769 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1374,7 +1374,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a& norm = vf.mNormals[i]; LLVector4a& center = *(vf.mCenter); - + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { LLVector4a vec = vf.mPositions[i]; @@ -1598,7 +1598,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mTexExtents[0].setVec(0,0); mTexExtents[1].setVec(1,1); xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt); - xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); + xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt); + + F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ; + F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ; + mTexExtents[0][0] *= es ; + mTexExtents[1][0] *= es ; + mTexExtents[0][1] *= et ; + mTexExtents[1][1] *= et ; } mLastVertexBuffer = mVertexBuffer; diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index ca2ef5f5b8..4e16cc4217 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -290,11 +290,9 @@ BOOL LLFeatureManager::parseFeatureTable(std::string filename) mTableVersion = version; LLFeatureList *flp = NULL; - while (!file.eof() && file.good()) + while (file >> name) { char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - - file >> name; if (name.substr(0,2) == "//") { @@ -303,13 +301,6 @@ BOOL LLFeatureManager::parseFeatureTable(std::string filename) continue; } - if (name.empty()) - { - // This is a blank line - file.getline(buffer, MAX_STRING); - continue; - } - if (name == "list") { if (flp) diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index 4c17199895..4d252dc662 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -41,35 +41,36 @@ // static -std::set<std::string> LLFirstUse::sConfigVariables; +//std::set<std::string> LLFirstUse::sConfigVariables; +std::set<std::string> LLFirstUse::sConfigVariablesEnabled; // static -void LLFirstUse::addConfigVariable(const std::string& var) -{ - sConfigVariables.insert(var); -} +//void LLFirstUse::addConfigVariable(const std::string& var) +//{ +// sConfigVariables.insert(var); +//} // static -void LLFirstUse::disableFirstUse() -{ - // Set all first-use warnings to disabled - for (std::set<std::string>::iterator iter = sConfigVariables.begin(); - iter != sConfigVariables.end(); ++iter) - { - gWarningSettings.setBOOL(*iter, FALSE); - } -} +//void LLFirstUse::disableFirstUse() +//{ +// // Set all first-use warnings to disabled +// for (std::set<std::string>::iterator iter = sConfigVariables.begin(); +// iter != sConfigVariables.end(); ++iter) +// { +// gWarningSettings.setBOOL(*iter, FALSE); +// } +//} // static -void LLFirstUse::resetFirstUse() -{ - // Set all first-use warnings to disabled - for (std::set<std::string>::iterator iter = sConfigVariables.begin(); - iter != sConfigVariables.end(); ++iter) - { - gWarningSettings.setBOOL(*iter, TRUE); - } -} +//void LLFirstUse::resetFirstUse() +//{ +// // Set all first-use warnings to disabled +// for (std::set<std::string>::iterator iter = sConfigVariables.begin(); +// iter != sConfigVariables.end(); ++iter) +// { +// gWarningSettings.setBOOL(*iter, TRUE); +// } +//} // static void LLFirstUse::otherAvatarChatFirst(bool enable) @@ -151,13 +152,21 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl if (enable) { + if(sConfigVariablesEnabled.find(control_var) != sConfigVariablesEnabled.end()) + { + return ; //already added + } + if (gSavedSettings.getBOOL("EnableUIHints")) { LL_DEBUGS("LLFirstUse") << "Trigger first use notification " << notification_name << LL_ENDL; // if notification doesn't already exist and this notification hasn't been disabled... if (gWarningSettings.getBOOL(control_var)) - { // create new notification + { + sConfigVariablesEnabled.insert(control_var) ; + + // create new notification LLNotifications::instance().add(LLNotification::Params().name(notification_name).substitutions(args).payload(payload.with("control_var", control_var))); } } @@ -169,7 +178,6 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl // redundantly clear settings var here, in case there are no notifications to cancel gWarningSettings.setBOOL(control_var, FALSE); } - } // static diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h index 81659988e6..489f58626a 100644 --- a/indra/newview/llfirstuse.h +++ b/indra/newview/llfirstuse.h @@ -78,11 +78,11 @@ class LLFirstUse public: // Add a config variable to be reset on resetFirstUse() - static void addConfigVariable(const std::string& var); + //static void addConfigVariable(const std::string& var); // Sets all controls back to show the dialogs. - static void disableFirstUse(); - static void resetFirstUse(); + //static void disableFirstUse(); + //static void resetFirstUse(); static void otherAvatarChatFirst(bool enable = true); static void sit(bool enable = true); @@ -98,7 +98,8 @@ public: protected: static void firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args = LLSD(), LLSD payload = LLSD()); - static std::set<std::string> sConfigVariables; + //static std::set<std::string> sConfigVariables; + static std::set<std::string> sConfigVariablesEnabled; static void init(); static bool processNotification(const LLSD& notify); diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp index 1b94d8cbcd..80920c80d6 100644 --- a/indra/newview/llfloatermap.cpp +++ b/indra/newview/llfloatermap.cpp @@ -83,7 +83,8 @@ LLFloaterMap::~LLFloaterMap() BOOL LLFloaterMap::postBuild() { mMap = getChild<LLNetMap>("Net Map"); - mMap->setToolTipMsg(getString("ToolTipMsg")); + mMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? + getString("AltToolTipMsg") : getString("ToolTipMsg")); sendChildToBack(mMap); mTextBoxNorth = getChild<LLTextBox> ("floater_map_north"); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index cc2a8c8aac..dde470693c 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2205,9 +2205,12 @@ U32 LLModelPreview::calcResourceCost() rebuildUploadData(); - if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + if (mFMP && mModelLoader) { - mFMP->childEnable("ok_btn"); + if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + { + mFMP->childEnable("ok_btn"); + } } U32 cost = 0; @@ -2215,7 +2218,7 @@ U32 LLModelPreview::calcResourceCost() U32 num_points = 0; U32 num_hulls = 0; - F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); + F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; F32 streaming_cost = 0.f; F32 physics_cost = 0.f; @@ -2270,9 +2273,7 @@ U32 LLModelPreview::calcResourceCost() } } - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; + F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost); diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 71882fbb83..07f5220ab7 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -178,7 +178,7 @@ void LLFloaterSettingsDebug::onClickDefault() if (controlp) { - controlp->resetToDefault(); + controlp->resetToDefault(true); updateControl(controlp); } } diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 49e24f8e3d..c9b99d83ff 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -32,6 +32,7 @@ #include "llcoord.h" //#include "llgl.h" +#include "llagent.h" #include "llagentcamera.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -463,7 +464,8 @@ void LLFloaterTools::refresh() childSetEnabled("linked_set_cost", have_selection); childSetEnabled("object_cost", have_selection); - bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled"); + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + !gAgent.getRegion()->getCapability("GetMesh").empty(); getChildView("linked_set_count")->setVisible(enable_mesh); getChildView("linked_set_cost")->setVisible(enable_mesh); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 62ba746a02..b3b1ce5743 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1854,31 +1854,9 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) { if (mCallbackRegistrar) mCallbackRegistrar->pushScope(); - //menu->empty(); - const LLView::child_list_t *list = menu->getChildList(); - LLView::child_list_t::const_iterator menu_itor; - for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) - { - (*menu_itor)->setVisible(FALSE); - (*menu_itor)->pushVisible(TRUE); - (*menu_itor)->setEnabled(TRUE); - } - - // Successively filter out invalid options - - U32 flags = FIRST_SELECTED_ITEM; - for (selected_items_t::iterator item_itor = mSelectedItems.begin(); - item_itor != mSelectedItems.end(); - ++item_itor) - { - LLFolderViewItem* selected_item = (*item_itor); - selected_item->buildContextMenu(*menu, flags); - flags = 0x0; - } + updateMenuOptions(menu); - addNoOptions(menu); - menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, menu, x, y); if (mCallbackRegistrar) @@ -2365,6 +2343,45 @@ void LLFolderView::updateRenamerPosition() } } +// Update visibility and availability (i.e. enabled/disabled) of context menu items. +void LLFolderView::updateMenuOptions(LLMenuGL* menu) +{ + const LLView::child_list_t *list = menu->getChildList(); + + LLView::child_list_t::const_iterator menu_itor; + for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) + { + (*menu_itor)->setVisible(FALSE); + (*menu_itor)->pushVisible(TRUE); + (*menu_itor)->setEnabled(TRUE); + } + + // Successively filter out invalid options + + U32 flags = FIRST_SELECTED_ITEM; + for (selected_items_t::iterator item_itor = mSelectedItems.begin(); + item_itor != mSelectedItems.end(); + ++item_itor) + { + LLFolderViewItem* selected_item = (*item_itor); + selected_item->buildContextMenu(*menu, flags); + flags = 0x0; + } + + addNoOptions(menu); +} + +// Refresh the context menu (that is already shown). +void LLFolderView::updateMenu() +{ + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->getVisible()) + { + updateMenuOptions(menu); + menu->needsArrange(); // update menu height if needed + } +} + bool LLFolderView::selectFirstItem() { for (folders_t::iterator iter = mFolders.begin(); diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index afaac86b04..210ba9eb3c 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -269,7 +269,10 @@ public: virtual S32 notify(const LLSD& info) ; bool useLabelSuffix() { return mUseLabelSuffix; } + void updateMenu(); + private: + void updateMenuOptions(LLMenuGL* menu); void updateRenamerPosition(); protected: diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index afd565bb26..9623554200 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -279,7 +279,7 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& void LLIMModel::LLIMSession::onAdHocNameCache(const LLAvatarName& av_name) { - if (av_name.mIsDummy) + if (av_name.mIsTemporaryName) { S32 separator_index = mName.rfind(" "); std::string name = mName.substr(0, separator_index); diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 91ede6d221..17d0b0ffbb 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -47,6 +47,7 @@ #include "llvoiceclient.h" #include "llviewerobjectlist.h" #include "lltransientfloatermgr.h" +#include "llnotificationsutil.h" // Linden libraries #include "llfloater.h" @@ -126,16 +127,20 @@ private: void onClickReport(); void onClickFreeze(); void onClickEject(); + void onClickKick(); + void onClickCSR(); void onClickZoomIn(); void onClickFindOnMap(); bool onVisibleFindOnMap(); - bool onVisibleFreezeEject(); + bool onVisibleEject(); + bool onVisibleFreeze(); bool onVisibleZoomIn(); void onClickMuteVolume(); void onVolumeChange(const LLSD& data); bool enableMute(); bool enableUnmute(); bool enableTeleportOffer(); + bool godModeEnabled(); // Is used to determine if "Add friend" option should be enabled in gear menu bool isNotFriend(); @@ -214,20 +219,21 @@ LLInspectAvatar::LLInspectAvatar(const LLSD& sd) mCommitCallbackRegistrar.add("InspectAvatar.Pay", boost::bind(&LLInspectAvatar::onClickPay, this)); mCommitCallbackRegistrar.add("InspectAvatar.Share", boost::bind(&LLInspectAvatar::onClickShare, this)); mCommitCallbackRegistrar.add("InspectAvatar.ToggleMute", boost::bind(&LLInspectAvatar::onToggleMute, this)); - mCommitCallbackRegistrar.add("InspectAvatar.Freeze", - boost::bind(&LLInspectAvatar::onClickFreeze, this)); - mCommitCallbackRegistrar.add("InspectAvatar.Eject", - boost::bind(&LLInspectAvatar::onClickEject, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Freeze", boost::bind(&LLInspectAvatar::onClickFreeze, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Eject", boost::bind(&LLInspectAvatar::onClickEject, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Kick", boost::bind(&LLInspectAvatar::onClickKick, this)); + mCommitCallbackRegistrar.add("InspectAvatar.CSR", boost::bind(&LLInspectAvatar::onClickCSR, this)); mCommitCallbackRegistrar.add("InspectAvatar.Report", boost::bind(&LLInspectAvatar::onClickReport, this)); mCommitCallbackRegistrar.add("InspectAvatar.FindOnMap", boost::bind(&LLInspectAvatar::onClickFindOnMap, this)); mCommitCallbackRegistrar.add("InspectAvatar.ZoomIn", boost::bind(&LLInspectAvatar::onClickZoomIn, this)); mCommitCallbackRegistrar.add("InspectAvatar.DisableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, false)); mCommitCallbackRegistrar.add("InspectAvatar.EnableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, true)); + + mEnableCallbackRegistrar.add("InspectAvatar.EnableGod", boost::bind(&LLInspectAvatar::godModeEnabled, this)); mEnableCallbackRegistrar.add("InspectAvatar.VisibleFindOnMap", boost::bind(&LLInspectAvatar::onVisibleFindOnMap, this)); - mEnableCallbackRegistrar.add("InspectAvatar.VisibleFreezeEject", - boost::bind(&LLInspectAvatar::onVisibleFreezeEject, this)); - mEnableCallbackRegistrar.add("InspectAvatar.VisibleZoomIn", - boost::bind(&LLInspectAvatar::onVisibleZoomIn, this)); + mEnableCallbackRegistrar.add("InspectAvatar.VisibleEject", boost::bind(&LLInspectAvatar::onVisibleEject, this)); + mEnableCallbackRegistrar.add("InspectAvatar.VisibleFreeze", boost::bind(&LLInspectAvatar::onVisibleFreeze, this)); + mEnableCallbackRegistrar.add("InspectAvatar.VisibleZoomIn", boost::bind(&LLInspectAvatar::onVisibleZoomIn, this)); mEnableCallbackRegistrar.add("InspectAvatar.Gear.Enable", boost::bind(&LLInspectAvatar::isNotFriend, this)); mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableCall", boost::bind(&LLAvatarActions::canCall)); mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableTeleportOffer", boost::bind(&LLInspectAvatar::enableTeleportOffer, this)); @@ -656,11 +662,18 @@ bool LLInspectAvatar::onVisibleFindOnMap() return gAgent.isGodlike() || is_agent_mappable(mAvatarID); } -bool LLInspectAvatar::onVisibleFreezeEject() +bool LLInspectAvatar::onVisibleEject() { return enable_freeze_eject( LLSD(mAvatarID) ); } +bool LLInspectAvatar::onVisibleFreeze() +{ + // either user is a god and can do long distance freeze + // or check for target proximity and permissions + return gAgent.isGodlike() || enable_freeze_eject(LLSD(mAvatarID)); +} + bool LLInspectAvatar::onVisibleZoomIn() { return gObjectList.findObject(mAvatarID); @@ -704,7 +717,7 @@ void LLInspectAvatar::onClickShare() void LLInspectAvatar::onToggleMute() { - LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT); + LLMute mute(mAvatarID, mAvatarName.mDisplayName, LLMute::AGENT); if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName)) { @@ -725,9 +738,41 @@ void LLInspectAvatar::onClickReport() closeFloater(); } +bool godlike_freeze(const LLSD& notification, const LLSD& response) +{ + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + switch (option) + { + case 0: + LLAvatarActions::freeze(avatar_id); + break; + case 1: + LLAvatarActions::unfreeze(avatar_id); + break; + default: + break; + } + + return false; +} + void LLInspectAvatar::onClickFreeze() { - handle_avatar_freeze( LLSD(mAvatarID) ); + if (gAgent.isGodlike()) + { + // use godlike freeze-at-a-distance, with confirmation + LLNotificationsUtil::add("FreezeAvatar", + LLSD(), + LLSD().with("avatar_id", mAvatarID), + godlike_freeze); + } + else + { + // use default "local" version of freezing that requires avatar to be in range + handle_avatar_freeze( LLSD(mAvatarID) ); + } closeFloater(); } @@ -737,6 +782,20 @@ void LLInspectAvatar::onClickEject() closeFloater(); } +void LLInspectAvatar::onClickKick() +{ + LLAvatarActions::kick(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onClickCSR() +{ + std::string name; + gCacheName->getFullName(mAvatarID, name); + LLAvatarActions::csr(mAvatarID, name); + closeFloater(); +} + void LLInspectAvatar::onClickZoomIn() { handle_zoom_to_object(mAvatarID); @@ -785,6 +844,11 @@ bool LLInspectAvatar::enableTeleportOffer() return LLAvatarActions::canOfferTeleport(mAvatarID); } +bool LLInspectAvatar::godModeEnabled() +{ + return gAgent.isGodlike(); +} + ////////////////////////////////////////////////////////////////////////////// // LLInspectAvatarUtil ////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index ef4774a06d..e22363c2f6 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -393,18 +393,22 @@ void LLInventoryFilter::setFilterUUID(const LLUUID& object_id) void LLInventoryFilter::setFilterSubString(const std::string& string) { - if (mFilterSubString != string) + std::string filter_sub_string_new = string; + mFilterSubStringOrig = string; + LLStringUtil::trimHead(filter_sub_string_new); + LLStringUtil::toUpper(filter_sub_string_new); + + if (mFilterSubString != filter_sub_string_new) { // hitting BACKSPACE, for example - const BOOL less_restrictive = mFilterSubString.size() >= string.size() && !mFilterSubString.substr(0, string.size()).compare(string); + const BOOL less_restrictive = mFilterSubString.size() >= filter_sub_string_new.size() + && !mFilterSubString.substr(0, filter_sub_string_new.size()).compare(filter_sub_string_new); // appending new characters - const BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString); + const BOOL more_restrictive = mFilterSubString.size() < filter_sub_string_new.size() + && !filter_sub_string_new.substr(0, mFilterSubString.size()).compare(mFilterSubString); - mFilterSubStringOrig = string; - LLStringUtil::trimHead(mFilterSubStringOrig); - mFilterSubString = mFilterSubStringOrig; - LLStringUtil::toUpper(mFilterSubString); + mFilterSubString = filter_sub_string_new; if (less_restrictive) { setModified(FILTER_LESS_RESTRICTIVE); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 5a9d1524f3..1dcb91ad4d 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -60,6 +60,7 @@ static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; // // Bridge to support knowing when the inventory has changed. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + class LLInventoryPanelObserver : public LLInventoryObserver { public: @@ -73,9 +74,57 @@ protected: LLInventoryPanel* mIP; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInvPanelComplObserver +// +// Calls specified callback when all specified items become complete. +// +// Usage: +// observer = new LLInvPanelComplObserver(boost::bind(onComplete)); +// inventory->addObserver(observer); +// observer->reset(); // (optional) +// observer->watchItem(incomplete_item1_id); +// observer->watchItem(incomplete_item2_id); +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInvPanelComplObserver : public LLInventoryCompletionObserver +{ +public: + typedef boost::function<void()> callback_t; + + LLInvPanelComplObserver(callback_t cb) + : mCallback(cb) + { + } + + void reset(); + +private: + /*virtual*/ void done(); + + /// Called when all the items are complete. + callback_t mCallback; +}; + +void LLInvPanelComplObserver::reset() +{ + mIncomplete.clear(); + mComplete.clear(); +} + +void LLInvPanelComplObserver::done() +{ + mCallback(); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryPanel +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : LLPanel(p), mInventoryObserver(NULL), + mCompletionObserver(NULL), mFolderRoot(NULL), mScroller(NULL), mSortOrderSetting(p.sort_order_setting), @@ -152,6 +201,9 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) mInventoryObserver = new LLInventoryPanelObserver(this); mInventory->addObserver(mInventoryObserver); + mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this)); + mInventory->addObserver(mCompletionObserver); + // Build view of inventory if we need default full hierarchy and inventory ready, // otherwise wait for idle callback. if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mViewsInitialized) @@ -189,7 +241,10 @@ LLInventoryPanel::~LLInventoryPanel() // LLView destructor will take care of the sub-views. mInventory->removeObserver(mInventoryObserver); + mInventory->removeObserver(mCompletionObserver); delete mInventoryObserver; + delete mCompletionObserver; + mScroller = NULL; } @@ -654,6 +709,11 @@ void LLInventoryPanel::openStartFolderOrMyInventory() } } +void LLInventoryPanel::onItemsCompletion() +{ + if (mFolderRoot) mFolderRoot->updateMenu(); +} + void LLInventoryPanel::openSelected() { LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem(); @@ -757,6 +817,19 @@ void LLInventoryPanel::clearSelection() void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action) { + // Schedule updating the folder view context menu when all selected items become complete (STORM-373). + mCompletionObserver->reset(); + for (std::deque<LLFolderViewItem*>::const_iterator it = items.begin(); it != items.end(); ++it) + { + LLUUID id = (*it)->getListener()->getUUID(); + LLViewerInventoryItem* inv_item = mInventory->getItem(id); + + if (inv_item && !inv_item->isFinished()) + { + mCompletionObserver->watchItem(id); + } + } + LLFolderView* fv = getRootFolder(); if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename { diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 6545fc0d5e..9da9f7d8ba 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -52,6 +52,7 @@ class LLIconCtrl; class LLSaveFolderState; class LLFilterEditor; class LLTabContainer; +class LLInvPanelComplObserver; class LLInventoryPanel : public LLPanel { @@ -167,9 +168,11 @@ public: protected: void openStartFolderOrMyInventory(); // open the first level of inventory + void onItemsCompletion(); // called when selected items are complete LLInventoryModel* mInventory; LLInventoryObserver* mInventoryObserver; + LLInvPanelComplObserver* mCompletionObserver; BOOL mAllowMultiSelect; BOOL mShowItemLinkOverlays; // Shows link graphic over inventory item icons diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index d866db1829..33e051bfab 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -214,6 +214,9 @@ void MandatoryUpdateMachine::start(void) case LLUpdaterService::CHECKING_FOR_UPDATE: setCurrentState(new CheckingForUpdate(*this)); break; + case LLUpdaterService::TEMPORARY_ERROR: + setCurrentState(new Error(*this)); + break; case LLUpdaterService::DOWNLOADING: setCurrentState(new WaitingForDownload(*this)); break; @@ -289,6 +292,7 @@ bool MandatoryUpdateMachine::CheckingForUpdate::onEvent(LLSD const & event) case LLUpdaterService::DOWNLOADING: mMachine.setCurrentState(new WaitingForDownload(mMachine)); break; + case LLUpdaterService::TEMPORARY_ERROR: case LLUpdaterService::UP_TO_DATE: case LLUpdaterService::TERMINAL: case LLUpdaterService::FAILURE: @@ -324,7 +328,7 @@ MandatoryUpdateMachine::Error::Error(MandatoryUpdateMachine & machine): void MandatoryUpdateMachine::Error::enter(void) { llinfos << "entering error" << llendl; - LLNotificationsUtil::add("FailedUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2)); + LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2)); } @@ -468,7 +472,6 @@ LLLoginInstance::LLLoginInstance() : mLoginModule(new LLLogin()), mNotifications(NULL), mLoginState("offline"), - mUserInteraction(true), mSkipOptionalUpdate(false), mAttemptComplete(false), mTransferRate(0.0f), @@ -637,64 +640,57 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) LLSD response = event["data"]; std::string reason_response = response["reason"].asString(); std::string message_response = response["message"].asString(); - if(mUserInteraction) + // For the cases of critical message or TOS agreement, + // start the TOS dialog. The dialog response will be handled + // by the LLLoginInstance::handleTOSResponse() callback. + // The callback intiates the login attempt next step, either + // to reconnect or to end the attempt in failure. + if(reason_response == "tos") { - // For the cases of critical message or TOS agreement, - // start the TOS dialog. The dialog response will be handled - // by the LLLoginInstance::handleTOSResponse() callback. - // The callback intiates the login attempt next step, either - // to reconnect or to end the attempt in failure. - if(reason_response == "tos") - { - LLSD data(LLSD::emptyMap()); - data["message"] = message_response; - data["reply_pump"] = TOS_REPLY_PUMP; - gViewerWindow->setShowProgress(FALSE); - LLFloaterReg::showInstance("message_tos", data); - LLEventPumps::instance().obtain(TOS_REPLY_PUMP) - .listen(TOS_LISTENER_NAME, - boost::bind(&LLLoginInstance::handleTOSResponse, - this, _1, "agree_to_tos")); - } - else if(reason_response == "critical") - { - LLSD data(LLSD::emptyMap()); - data["message"] = message_response; - data["reply_pump"] = TOS_REPLY_PUMP; - if(response.has("error_code")) - { - data["error_code"] = response["error_code"]; - } - if(response.has("certificate")) - { - data["certificate"] = response["certificate"]; - } - - gViewerWindow->setShowProgress(FALSE); - LLFloaterReg::showInstance("message_critical", data); - LLEventPumps::instance().obtain(TOS_REPLY_PUMP) - .listen(TOS_LISTENER_NAME, - boost::bind(&LLLoginInstance::handleTOSResponse, - this, _1, "read_critical")); - } - else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate")) + LLSD data(LLSD::emptyMap()); + data["message"] = message_response; + data["reply_pump"] = TOS_REPLY_PUMP; + gViewerWindow->setShowProgress(FALSE); + LLFloaterReg::showInstance("message_tos", data); + LLEventPumps::instance().obtain(TOS_REPLY_PUMP) + .listen(TOS_LISTENER_NAME, + boost::bind(&LLLoginInstance::handleTOSResponse, + this, _1, "agree_to_tos")); + } + else if(reason_response == "critical") + { + LLSD data(LLSD::emptyMap()); + data["message"] = message_response; + data["reply_pump"] = TOS_REPLY_PUMP; + if(response.has("error_code")) { - gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE); - updateApp(true, message_response); + data["error_code"] = response["error_code"]; } - else if(reason_response == "optional") + if(response.has("certificate")) { - updateApp(false, message_response); + data["certificate"] = response["certificate"]; } - else - { - attemptComplete(); - } + + gViewerWindow->setShowProgress(FALSE); + LLFloaterReg::showInstance("message_critical", data); + LLEventPumps::instance().obtain(TOS_REPLY_PUMP) + .listen(TOS_LISTENER_NAME, + boost::bind(&LLLoginInstance::handleTOSResponse, + this, _1, "read_critical")); } - else // no user interaction + else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate")) { - attemptComplete(); + gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE); + updateApp(true, message_response); } + else if(reason_response == "optional") + { + updateApp(false, message_response); + } + else + { + attemptComplete(); + } } void LLLoginInstance::handleLoginSuccess(const LLSD& event) diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index b872d7d1b1..8b53431219 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -61,12 +61,6 @@ public: // Only valid when authSuccess == true. const F64 getLastTransferRateBPS() { return mTransferRate; } - // Set whether this class will drive user interaction. - // If not, login failures like 'need tos agreement' will - // end the login attempt. - void setUserInteraction(bool state) { mUserInteraction = state; } - bool getUserInteraction() { return mUserInteraction; } - // Whether to tell login to skip optional update request. // False by default. void setSkipOptionalUpdate(bool state) { mSkipOptionalUpdate = state; } @@ -100,7 +94,6 @@ private: std::string mLoginState; LLSD mRequestData; LLSD mResponseData; - bool mUserInteraction; bool mSkipOptionalUpdate; bool mAttemptComplete; F64 mTransferRate; diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 060677f9f3..67ab7ab462 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -85,6 +85,17 @@ const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] = }; +F32 get_default_max_prim_scale() +{ + if (gSavedSettings.getBOOL("MeshEnabled")) + { + return DEFAULT_MAX_PRIM_SCALE; + } + else + { + return DEFAULT_MAX_PRIM_SCALE_NO_MESH; + } +} // static void LLManipScale::setUniform(BOOL b) @@ -950,8 +961,8 @@ void LLManipScale::dragCorner( S32 x, S32 y ) mInSnapRegime = FALSE; } - F32 max_scale_factor = DEFAULT_MAX_PRIM_SCALE / MIN_PRIM_SCALE; - F32 min_scale_factor = MIN_PRIM_SCALE / DEFAULT_MAX_PRIM_SCALE; + F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE; + F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale(); // find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale for (LLObjectSelection::iterator iter = mObjectSelection->begin(); @@ -963,7 +974,7 @@ void LLManipScale::dragCorner( S32 x, S32 y ) { const LLVector3& scale = selectNode->mSavedScale; - F32 cur_max_scale_factor = llmin( DEFAULT_MAX_PRIM_SCALE / scale.mV[VX], DEFAULT_MAX_PRIM_SCALE / scale.mV[VY], DEFAULT_MAX_PRIM_SCALE / scale.mV[VZ] ); + F32 cur_max_scale_factor = llmin( get_default_max_prim_scale() / scale.mV[VX], get_default_max_prim_scale() / scale.mV[VY], get_default_max_prim_scale() / scale.mV[VZ] ); max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor ); F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] ); @@ -1260,7 +1271,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto F32 denom = axis * dir_local; F32 desired_delta_size = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom); // in meters - F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); + F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, get_default_max_prim_scale()); // propagate scale constraint back to position offset desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position @@ -1960,7 +1971,7 @@ F32 LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const max_extent = bbox_extents.mV[i]; } } - max_scale_factor = bbox_extents.magVec() * DEFAULT_MAX_PRIM_SCALE / max_extent; + max_scale_factor = bbox_extents.magVec() * get_default_max_prim_scale() / max_extent; if (getUniform()) { @@ -1975,7 +1986,7 @@ F32 LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const { LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox ); bbox_extents.abs(); - F32 min_extent = DEFAULT_MAX_PRIM_SCALE; + F32 min_extent = get_default_max_prim_scale(); for (U32 i = VX; i <= VZ; i++) { if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent) diff --git a/indra/newview/llmanipscale.h b/indra/newview/llmanipscale.h index 5559f557c0..2762433abf 100644 --- a/indra/newview/llmanipscale.h +++ b/indra/newview/llmanipscale.h @@ -39,6 +39,9 @@ #include "llviewerobject.h" #include "llbbox.h" + +F32 get_default_max_prim_scale(); + class LLToolComposite; class LLColor4; diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp index 9a244e2562..7e9c3c84a7 100644 --- a/indra/newview/llmemoryview.cpp +++ b/indra/newview/llmemoryview.cpp @@ -37,9 +37,11 @@ #include <sstream> #include <boost/algorithm/string/split.hpp> +#include "llmemory.h" LLMemoryView::LLMemoryView(const LLMemoryView::Params& p) : LLView(p), + mPaused(FALSE), //mDelay(120), mAlloc(NULL) { @@ -59,6 +61,7 @@ BOOL LLMemoryView::handleMouseDown(S32 x, S32 y, MASK mask) } else { + mPaused = !mPaused; } return TRUE; } @@ -148,13 +151,14 @@ void LLMemoryView::draw() // cut off lines on bottom U32 max_lines = U32((height - 2 * line_height) / line_height); - std::vector<LLWString>::const_iterator end = mLines.end(); + y_pos = height - MARGIN_AMT - line_height; + y_off = 0.f; + +#if !MEM_TRACK_MEM + std::vector<LLWString>::const_iterator end = mLines.end(); if(mLines.size() > max_lines) { end = mLines.begin() + max_lines; } - - y_pos = height - MARGIN_AMT - line_height; - y_off = 0.f; for (std::vector<LLWString>::const_iterator i = mLines.begin(); i != end; ++i) { font->render(*i, 0, MARGIN_AMT, y_pos - y_off, @@ -169,6 +173,47 @@ void LLMemoryView::draw() y_off += line_height; } +#else + LLMemTracker::getInstance()->preDraw(mPaused) ; + + { + F32 x_pos = MARGIN_AMT ; + U32 lines = 0 ; + const char* str = LLMemTracker::getInstance()->getNextLine() ; + while(str != NULL) + { + lines++ ; + font->renderUTF8(str, 0, x_pos, y_pos - y_off, + LLColor4::white, + LLFontGL::LEFT, + LLFontGL::BASELINE, + LLFontGL::NORMAL, + LLFontGL::DROP_SHADOW, + S32_MAX, + target_width, + NULL, FALSE); + + str = LLMemTracker::getInstance()->getNextLine() ; + y_off += line_height; + + if(lines >= max_lines) + { + lines = 0 ; + x_pos += 512.f ; + if(x_pos + 512.f > target_width) + { + break ; + } + + y_pos = height - MARGIN_AMT - line_height; + y_off = 0.f; + } + } + } + + LLMemTracker::getInstance()->postDraw() ; +#endif + #if MEM_TRACK_TYPE S32 left, top, right, bottom; diff --git a/indra/newview/llmemoryview.h b/indra/newview/llmemoryview.h index 24ea058279..9bdc59ab10 100644 --- a/indra/newview/llmemoryview.h +++ b/indra/newview/llmemoryview.h @@ -55,6 +55,7 @@ public: private: std::vector<LLWString> mLines; LLAllocator* mAlloc; + BOOL mPaused ; }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index b772999ee2..edcf249a21 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2160,7 +2160,7 @@ S32 LLMeshRepository::update() return size ; } -S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail) +S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod) { if (detail < 0 || detail > 4) { @@ -2201,7 +2201,19 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para if (group) { - //first see what the next lowest LOD available might be + //first, see if last_lod is available (don't transition down to avoid funny popping a la SH-641) + if (last_lod >= 0) + { + LLVolume* lod = group->refLOD(last_lod); + if (lod && !lod->isTetrahedron() && lod->getNumVolumeFaces() > 0) + { + group->derefLOD(lod); + return last_lod; + } + group->derefLOD(lod); + } + + //next, see what the next lowest LOD available might be for (S32 i = detail-1; i >= 0; --i) { LLVolume* lod = group->refLOD(i); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index eccb82b661..b642a89192 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -456,7 +456,7 @@ public: S32 update() ; //mesh management functions - S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0); + S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1); void notifyLoadedMeshes(); void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume); diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 1a8ec4991d..93039d935d 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -47,6 +47,7 @@ #include "llagentcamera.h" #include "llappviewer.h" // for gDisconnected #include "llcallingcard.h" // LLAvatarTracker +#include "llfloaterworldmap.h" #include "lltracker.h" #include "llsurface.h" #include "llviewercamera.h" @@ -91,7 +92,8 @@ LLNetMap::LLNetMap (const Params & p) mObjectImagep(), mClosestAgentToCursor(), mClosestAgentAtLastRightClick(), - mToolTipMsg() + mToolTipMsg(), + mPopupMenu(NULL) { mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS); setScale(gSavedSettings.getF32("MiniMapScale")); @@ -102,6 +104,21 @@ LLNetMap::~LLNetMap() gSavedSettings.setF32("MiniMapScale", mScale); } +BOOL LLNetMap::postBuild() +{ + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("Minimap.Zoom", boost::bind(&LLNetMap::handleZoom, this, _2)); + registrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2)); + + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (mPopupMenu && !LLTracker::isTracking(0)) + { + mPopupMenu->setItemEnabled ("Stop Tracking", false); + } + return TRUE; +} + void LLNetMap::setScale( F32 scale ) { scale = llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX); @@ -354,16 +371,49 @@ void LLNetMap::draw() pos_map = globalPosToView(pos_global); + LLUUID uuid(NULL); BOOL show_as_friend = FALSE; if( i < regionp->mMapAvatarIDs.count()) { - show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL); + uuid = regionp->mMapAvatarIDs.get(i); + show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL); } + + LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; LLWorldMapView::drawAvatar( pos_map.mV[VX], pos_map.mV[VY], - show_as_friend ? map_avatar_friend_color : map_avatar_color, + color, pos_map.mV[VZ], mDotRadius); + if(uuid.notNull()) + { + bool selected = false; + uuid_vec_t::iterator sel_iter = gmSelected.begin(); + for (; sel_iter != gmSelected.end(); sel_iter++) + { + if(*sel_iter == uuid) + { + selected = true; + break; + } + } + if(selected) + { + if( (pos_map.mV[VX] < 0) || + (pos_map.mV[VY] < 0) || + (pos_map.mV[VX] >= getRect().getWidth()) || + (pos_map.mV[VY] >= getRect().getHeight()) ) + { + S32 x = llround( pos_map.mV[VX] ); + S32 y = llround( pos_map.mV[VY] ); + LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10); + } else + { + LLWorldMapView::drawTrackingDot(pos_map.mV[VX],pos_map.mV[VY],color,0.f); + } + } + } + F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y)); if(dist_to_cursor < min_pick_dist && dist_to_cursor < closest_dist) @@ -460,6 +510,13 @@ void LLNetMap::draw() gGL.popUIMatrix(); LLUICtrl::draw(); + + if (LLTracker::isTracking(0)) + { + mPopupMenu->setItemEnabled ("Stop Tracking", true); + } + + } void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent) @@ -600,7 +657,6 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) args["[REGION]"] = region_name; std::string msg = mToolTipMsg; LLStringUtil::format(msg, args); - LLToolTipMgr::instance().show(LLToolTip::Params() .message(msg) .sticky_rect(sticky_rect)); @@ -793,6 +849,9 @@ BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) { + if(abs(mMouseDown.mX-x)<3 && abs(mMouseDown.mY-y)<3) + handleClick(x,y,mask); + if (hasMouseCapture()) { if (mPanning) @@ -821,6 +880,53 @@ BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) return FALSE; } +BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPopupMenu) + { + mPopupMenu->buildDrawLabels(); + mPopupMenu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, mPopupMenu, x, y); + } + return TRUE; +} + +BOOL LLNetMap::handleClick(S32 x, S32 y, MASK mask) +{ + // TODO: allow clicking an avatar on minimap to select avatar in the nearby avatar list + // if(mClosestAgentToCursor.notNull()) + // mNearbyList->selectUser(mClosestAgentToCursor); + // Needs a registered observer i guess to accomplish this without using + // globals to tell the mNearbyList in llpeoplepanel to select the user + return TRUE; +} + +BOOL LLNetMap::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + LLVector3d pos_global = viewPosToGlobal(x, y); + + // If we're not tracking a beacon already, double-click will set one + if (!LLTracker::isTracking(NULL)) + { + LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance(); + if (world_map) + { + world_map->trackLocation(pos_global); + } + } + + if (gSavedSettings.getBOOL("DoubleClickTeleport")) + { + // If DoubleClickTeleport is on, double clicking the minimap will teleport there + gAgent.teleportViaLocationLookAt(pos_global); + } + else + { + LLFloaterReg::showInstance("world_map"); + } + return TRUE; +} + // static bool LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop ) { @@ -871,3 +977,38 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask ) return TRUE; } + +void LLNetMap::handleZoom(const LLSD& userdata) +{ + std::string level = userdata.asString(); + + F32 scale = 0.0f; + if (level == std::string("default")) + { + LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale"); + if(pvar) + { + pvar->resetToDefault(); + scale = gSavedSettings.getF32("MiniMapScale"); + } + } + else if (level == std::string("close")) + scale = LLNetMap::MAP_SCALE_MAX; + else if (level == std::string("medium")) + scale = LLNetMap::MAP_SCALE_MID; + else if (level == std::string("far")) + scale = LLNetMap::MAP_SCALE_MIN; + if (scale != 0.0f) + { + setScale(scale); + } +} + +void LLNetMap::handleStopTracking (const LLSD& userdata) +{ + if (mPopupMenu) + { + mPopupMenu->setItemEnabled ("Stop Tracking", false); + LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL)); + } +} diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h index e053b1c177..20fcee0814 100644 --- a/indra/newview/llnetmap.h +++ b/indra/newview/llnetmap.h @@ -39,6 +39,7 @@ class LLCoordGL; class LLImageRaw; class LLViewerTexture; class LLFloaterMap; +class LLMenuGL; class LLNetMap : public LLUICtrl { @@ -72,7 +73,12 @@ public: /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); /*virtual*/ BOOL handleToolTip( S32 x, S32 y, MASK mask); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - + + /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + void setScale( F32 scale ); void setToolTipMsg(const std::string& msg) { mToolTipMsg = msg; } void renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius ); @@ -120,6 +126,16 @@ private: LLUUID mClosestAgentAtLastRightClick; std::string mToolTipMsg; + +public: + void setSelected(uuid_vec_t uuids) { gmSelected=uuids; }; + +private: + void handleZoom(const LLSD& userdata); + void handleStopTracking (const LLSD& userdata); + + LLMenuGL* mPopupMenu; + uuid_vec_t gmSelected; }; diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 94b2340c93..73c4722b82 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -625,10 +625,15 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g getChild<LLUICtrl>("sl_groups")->setValue(groups); } -void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group )
-{
- LLStringUtil::format_map_t args;
-
+static void got_full_name_callback( LLHandle<LLPanel> profile_panel_handle, const std::string& full_name ) +{ + if (profile_panel_handle.isDead() ) return; + + LLPanelAvatarProfile* profile_panel = dynamic_cast<LLPanelAvatarProfile*>(profile_panel_handle.get()); + if ( ! profile_panel ) return; + + LLStringUtil::format_map_t args; + std::string name; if (LLAvatarNameCache::useDisplayNames()) { @@ -637,21 +642,21 @@ void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std:: else { name = full_name; - }
-
- args["[NAME]"] = name;
-
- std::string linden_name = getString("name_text_args", args);
- getChild<LLUICtrl>("name_descr_text")->setValue(linden_name);
-}
+ } + + args["[NAME]"] = name; + + std::string linden_name = profile_panel->getString("name_text_args", args); + profile_panel->getChild<LLUICtrl>("name_descr_text")->setValue(linden_name); +} void LLPanelAvatarProfile::onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) { - LLStringUtil::format_map_t args;
- args["[DISPLAY_NAME]"] = av_name.mDisplayName;
-
- std::string display_name = getString("display_name_text_args", args);
- getChild<LLUICtrl>("display_name_descr_text")->setValue(display_name);
+ LLStringUtil::format_map_t args; + args["[DISPLAY_NAME]"] = av_name.mDisplayName; + + std::string display_name = getString("display_name_text_args", args); + getChild<LLUICtrl>("display_name_descr_text")->setValue(display_name); } void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data) @@ -667,22 +672,23 @@ void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data) } // ask (asynchronously) for the avatar name - std::string full_name;
- if (gCacheName->getFullName(avatar_data->agent_id, full_name))
- {
- // name in cache, call callback directly
- got_full_name_callback( avatar_data->agent_id, full_name, false );
- }
- else
- {
- // not in cache, lookup name
- gCacheName->get(avatar_data->agent_id, false, boost::bind( &LLPanelAvatarProfile::got_full_name_callback, this, _1, _2, _3 ));
- }
-
- // get display name
+ LLHandle<LLPanel> profile_panel_handle = getHandle(); + std::string full_name; + if (gCacheName->getFullName(avatar_data->agent_id, full_name)) + { + // name in cache, call callback directly + got_full_name_callback( profile_panel_handle, full_name ); + } + else + { + // not in cache, lookup name + gCacheName->get(avatar_data->agent_id, false, boost::bind( got_full_name_callback, profile_panel_handle, _2 )); + } + + // get display name LLAvatarNameCache::get(avatar_data->avatar_id, - boost::bind(&LLPanelAvatarProfile::onNameCache, this, _1, _2));
-
+ boost::bind(&LLPanelAvatarProfile::onNameCache, this, _1, _2)); + args["[AGE]"] = LLDateUtil::ageFromDate( avatar_data->born_on, LLDate::now()); std::string register_date = getString("RegisterDateFormat", args); getChild<LLUICtrl>("register_date")->setValue(register_date ); diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 070fe4579a..e95441cd58 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -1,298 +1,297 @@ -/**
- * @file llpanelavatar.h
- * @brief LLPanelAvatar and related class definitions
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPANELAVATAR_H
-#define LL_LLPANELAVATAR_H
-
-#include "llpanel.h"
-#include "llavatarpropertiesprocessor.h"
-#include "llcallingcard.h"
-#include "llvoiceclient.h"
-#include "llavatarnamecache.h"
-
-class LLComboBox;
-class LLLineEditor;
-
-enum EOnlineStatus
-{
- ONLINE_STATUS_NO = 0,
- ONLINE_STATUS_YES = 1
-};
-
-/**
-* Base class for any Profile View or My Profile Panel.
-*/
-class LLPanelProfileTab
- : public LLPanel
- , public LLAvatarPropertiesObserver
-{
-public:
-
- /**
- * Sets avatar ID, sets panel as observer of avatar related info replies from server.
- */
- virtual void setAvatarId(const LLUUID& id);
-
- /**
- * Returns avatar ID.
- */
- virtual const LLUUID& getAvatarId() { return mAvatarId; }
-
- /**
- * Sends update data request to server.
- */
- virtual void updateData() = 0;
-
- /**
- * Clears panel data if viewing avatar info for first time and sends update data request.
- */
- virtual void onOpen(const LLSD& key);
-
- /**
- * Profile tabs should close any opened panels here.
- *
- * Called from LLPanelProfile::onOpen() before opening new profile.
- * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel
- * before new profile is displayed, otherwise new profile will
- * be hidden behind picture info panel.
- */
- virtual void onClosePanel() {}
-
- /**
- * Resets controls visibility, state, etc.
- */
- virtual void resetControls(){};
-
- /**
- * Clears all data received from server.
- */
- virtual void resetData(){};
-
- /*virtual*/ ~LLPanelProfileTab();
-
-protected:
-
- LLPanelProfileTab();
-
- /**
- * Scrolls panel to top when viewing avatar info for first time.
- */
- void scrollToTop();
-
- virtual void onMapButtonClick();
-
- virtual void updateButtons();
-
-private:
-
- LLUUID mAvatarId;
-};
-
-/**
-* Panel for displaying Avatar's first and second life related info.
-*/
-class LLPanelAvatarProfile
- : public LLPanelProfileTab
- , public LLFriendObserver
- , public LLVoiceClientStatusObserver
-{
-public:
- LLPanelAvatarProfile();
- /*virtual*/ ~LLPanelAvatarProfile();
-
- /*virtual*/ void onOpen(const LLSD& key);
-
- /**
- * LLFriendObserver trigger
- */
- virtual void changed(U32 mask);
-
- // Implements LLVoiceClientStatusObserver::onChange() to enable the call
- // button when voice is available
- /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
-
- /*virtual*/ void setAvatarId(const LLUUID& id);
-
- /**
- * Processes data received from server.
- */
- /*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
- /*virtual*/ BOOL postBuild();
-
- /*virtual*/ void updateData();
-
- /*virtual*/ void resetControls();
-
- /*virtual*/ void resetData();
-
-protected:
-
- /**
- * Process profile related data received from server.
- */
- virtual void processProfileProperties(const LLAvatarData* avatar_data);
-
- /**
- * Processes group related data received from server.
- */
- virtual void processGroupProperties(const LLAvatarGroups* avatar_groups);
-
- /**
- * Fills common for Avatar profile and My Profile fields.
- */
- virtual void fillCommonData(const LLAvatarData* avatar_data);
-
- /**
- * Fills partner data.
- */
- virtual void fillPartnerData(const LLAvatarData* avatar_data);
-
- /**
- * Fills account status.
- */
- virtual void fillAccountStatus(const LLAvatarData* avatar_data);
-
- /**
- * Opens "Pay Resident" dialog.
- */
- void pay();
-
- /**
- * opens inventory and IM for sharing items
- */
- void share();
-
- /**
- * Add/remove resident to/from your block list.
- */
- void toggleBlock();
-
- void kick();
- void freeze();
- void unfreeze();
- void csr();
-
- bool enableShowOnMap();
- bool enableBlock();
- bool enableUnblock();
- bool enableGod();
-
- void onSeeProfileBtnClick();
- void onAddFriendButtonClick();
- void onIMButtonClick();
- void onCallButtonClick();
- void onTeleportButtonClick();
- void onShareButtonClick();
-
-private:
- void got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group );
- void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
-
- typedef std::map< std::string,LLUUID> group_map_t;
- group_map_t mGroups;
-};
-
-/**
- * Panel for displaying own first and second life related info.
- */
-class LLPanelMyProfile
- : public LLPanelAvatarProfile
-{
-public:
- LLPanelMyProfile();
-
- /*virtual*/ BOOL postBuild();
-
-protected:
-
- /*virtual*/ void onOpen(const LLSD& key);
-
- /*virtual*/ void processProfileProperties(const LLAvatarData* avatar_data);
-
- /*virtual*/ void resetControls();
-
-protected:
- void onStatusMessageChanged();
-};
-
-/**
- * Panel for displaying Avatar's notes and modifying friend's rights.
- */
-class LLPanelAvatarNotes
- : public LLPanelProfileTab
- , public LLFriendObserver
- , public LLVoiceClientStatusObserver
-{
-public:
- LLPanelAvatarNotes();
- /*virtual*/ ~LLPanelAvatarNotes();
-
- virtual void setAvatarId(const LLUUID& id);
-
- /**
- * LLFriendObserver trigger
- */
- virtual void changed(U32 mask);
-
- // Implements LLVoiceClientStatusObserver::onChange() to enable the call
- // button when voice is available
- /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
-
- /*virtual*/ void onOpen(const LLSD& key);
-
- /*virtual*/ BOOL postBuild();
-
- /*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
- /*virtual*/ void updateData();
-
-protected:
-
- /*virtual*/ void resetControls();
-
- /*virtual*/ void resetData();
-
- /**
- * Fills rights data for friends.
- */
- void fillRightsData();
-
- void rightsConfirmationCallback(const LLSD& notification,
- const LLSD& response, S32 rights);
- void confirmModifyRights(bool grant, S32 rights);
- void onCommitRights();
- void onCommitNotes();
-
- void onAddFriendButtonClick();
- void onIMButtonClick();
- void onCallButtonClick();
- void onTeleportButtonClick();
- void onShareButtonClick();
- void enableCheckboxes(bool enable);
-};
-
-#endif // LL_LLPANELAVATAR_H
+/** + * @file llpanelavatar.h + * @brief LLPanelAvatar and related class definitions + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELAVATAR_H +#define LL_LLPANELAVATAR_H + +#include "llpanel.h" +#include "llavatarpropertiesprocessor.h" +#include "llcallingcard.h" +#include "llvoiceclient.h" +#include "llavatarnamecache.h" + +class LLComboBox; +class LLLineEditor; + +enum EOnlineStatus +{ + ONLINE_STATUS_NO = 0, + ONLINE_STATUS_YES = 1 +}; + +/** +* Base class for any Profile View or My Profile Panel. +*/ +class LLPanelProfileTab + : public LLPanel + , public LLAvatarPropertiesObserver +{ +public: + + /** + * Sets avatar ID, sets panel as observer of avatar related info replies from server. + */ + virtual void setAvatarId(const LLUUID& id); + + /** + * Returns avatar ID. + */ + virtual const LLUUID& getAvatarId() { return mAvatarId; } + + /** + * Sends update data request to server. + */ + virtual void updateData() = 0; + + /** + * Clears panel data if viewing avatar info for first time and sends update data request. + */ + virtual void onOpen(const LLSD& key); + + /** + * Profile tabs should close any opened panels here. + * + * Called from LLPanelProfile::onOpen() before opening new profile. + * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel + * before new profile is displayed, otherwise new profile will + * be hidden behind picture info panel. + */ + virtual void onClosePanel() {} + + /** + * Resets controls visibility, state, etc. + */ + virtual void resetControls(){}; + + /** + * Clears all data received from server. + */ + virtual void resetData(){}; + + /*virtual*/ ~LLPanelProfileTab(); + +protected: + + LLPanelProfileTab(); + + /** + * Scrolls panel to top when viewing avatar info for first time. + */ + void scrollToTop(); + + virtual void onMapButtonClick(); + + virtual void updateButtons(); + +private: + + LLUUID mAvatarId; +}; + +/** +* Panel for displaying Avatar's first and second life related info. +*/ +class LLPanelAvatarProfile + : public LLPanelProfileTab + , public LLFriendObserver + , public LLVoiceClientStatusObserver +{ +public: + LLPanelAvatarProfile(); + /*virtual*/ ~LLPanelAvatarProfile(); + + /*virtual*/ void onOpen(const LLSD& key); + + /** + * LLFriendObserver trigger + */ + virtual void changed(U32 mask); + + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + + /*virtual*/ void setAvatarId(const LLUUID& id); + + /** + * Processes data received from server. + */ + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void updateData(); + + /*virtual*/ void resetControls(); + + /*virtual*/ void resetData(); + +protected: + + /** + * Process profile related data received from server. + */ + virtual void processProfileProperties(const LLAvatarData* avatar_data); + + /** + * Processes group related data received from server. + */ + virtual void processGroupProperties(const LLAvatarGroups* avatar_groups); + + /** + * Fills common for Avatar profile and My Profile fields. + */ + virtual void fillCommonData(const LLAvatarData* avatar_data); + + /** + * Fills partner data. + */ + virtual void fillPartnerData(const LLAvatarData* avatar_data); + + /** + * Fills account status. + */ + virtual void fillAccountStatus(const LLAvatarData* avatar_data); + + /** + * Opens "Pay Resident" dialog. + */ + void pay(); + + /** + * opens inventory and IM for sharing items + */ + void share(); + + /** + * Add/remove resident to/from your block list. + */ + void toggleBlock(); + + void kick(); + void freeze(); + void unfreeze(); + void csr(); + + bool enableShowOnMap(); + bool enableBlock(); + bool enableUnblock(); + bool enableGod(); + + void onSeeProfileBtnClick(); + void onAddFriendButtonClick(); + void onIMButtonClick(); + void onCallButtonClick(); + void onTeleportButtonClick(); + void onShareButtonClick(); + +private: + void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + + typedef std::map< std::string,LLUUID> group_map_t; + group_map_t mGroups; +}; + +/** + * Panel for displaying own first and second life related info. + */ +class LLPanelMyProfile + : public LLPanelAvatarProfile +{ +public: + LLPanelMyProfile(); + + /*virtual*/ BOOL postBuild(); + +protected: + + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ void processProfileProperties(const LLAvatarData* avatar_data); + + /*virtual*/ void resetControls(); + +protected: + void onStatusMessageChanged(); +}; + +/** + * Panel for displaying Avatar's notes and modifying friend's rights. + */ +class LLPanelAvatarNotes + : public LLPanelProfileTab + , public LLFriendObserver + , public LLVoiceClientStatusObserver +{ +public: + LLPanelAvatarNotes(); + /*virtual*/ ~LLPanelAvatarNotes(); + + virtual void setAvatarId(const LLUUID& id); + + /** + * LLFriendObserver trigger + */ + virtual void changed(U32 mask); + + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + /*virtual*/ void updateData(); + +protected: + + /*virtual*/ void resetControls(); + + /*virtual*/ void resetData(); + + /** + * Fills rights data for friends. + */ + void fillRightsData(); + + void rightsConfirmationCallback(const LLSD& notification, + const LLSD& response, S32 rights); + void confirmModifyRights(bool grant, S32 rights); + void onCommitRights(); + void onCommitNotes(); + + void onAddFriendButtonClick(); + void onIMButtonClick(); + void onCallButtonClick(); + void onTeleportButtonClick(); + void onShareButtonClick(); + void enableCheckboxes(bool enable); +}; + +#endif // LL_LLPANELAVATAR_H diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 90ed8b9e58..4a74b7925c 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -569,6 +569,7 @@ static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, if (color_swatch_ctrl) { color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex)); + color_swatch_ctrl->closeFloaterColorPicker(); } } diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index d1362d7922..3dbc637318 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1843,7 +1843,8 @@ bool LLPanelGroupRolesSubTab::apply(std::string& mesg) { lldebugs << "LLPanelGroupRolesSubTab::apply()" << llendl; - saveRoleChanges(); + saveRoleChanges(true); + LLGroupMgr::getInstance()->sendGroupRoleChanges(mGroupID); notifyObservers(); @@ -2022,7 +2023,7 @@ void LLPanelGroupRolesSubTab::handleRoleSelect() return; } - saveRoleChanges(); + saveRoleChanges(false); // Check if there is anything selected. LLScrollListItem* item = mRolesList->getFirstSelected(); @@ -2385,7 +2386,7 @@ void LLPanelGroupRolesSubTab::handleDeleteRole() notifyObservers(); } -void LLPanelGroupRolesSubTab::saveRoleChanges() +void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role) { LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); @@ -2400,13 +2401,23 @@ void LLPanelGroupRolesSubTab::saveRoleChanges() rd.mRoleDescription = mRoleDescription->getText(); rd.mRoleTitle = mRoleTitle->getText(); + S32 role_members_count = 0; + if (mSelectedRole.isNull()) + { + role_members_count = gdatap->mMemberCount; + } + else if(LLGroupRoleData* grd = get_ptr_in_map(gdatap->mRoles, mSelectedRole)) + { + role_members_count = grd->getTotalMembersInRole(); + } + gdatap->setRoleData(mSelectedRole,rd); mRolesList->deleteSingleItem(mRolesList->getItemIndex(mSelectedRole)); - LLSD row = createRoleItem(mSelectedRole,rd.mRoleName,rd.mRoleTitle,0); + LLSD row = createRoleItem(mSelectedRole,rd.mRoleName,rd.mRoleTitle,role_members_count); LLScrollListItem* item = mRolesList->addElement(row, ADD_BOTTOM, this); - item->setSelected(TRUE); + item->setSelected(select_saved_role); mHasRoleChange = FALSE; } diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 270259c16f..a55e264150 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -257,7 +257,7 @@ public: static void onDeleteRole(void*); void handleDeleteRole(); - void saveRoleChanges(); + void saveRoleChanges(bool select_saved_role); virtual void setGroupID(const LLUUID& id); protected: diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index e8c8273a9d..80f6862169 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -71,6 +71,7 @@ static void collapse_all_folders(LLFolderView* root_folder); static void expand_all_folders(LLFolderView* root_folder); static bool has_expanded_folders(LLFolderView* root_folder); static bool has_collapsed_folders(LLFolderView* root_folder); +static void toggle_restore_menu(LLMenuGL* menu, BOOL visible, BOOL enabled); /** * Functor counting expanded and collapsed folders in folder view tree to know @@ -708,6 +709,9 @@ void LLLandmarksPanel::initListCommandsHandlers() mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mGearLandmarkMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); + mGearFolderMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); + mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::showActionMenu, this, mMenuAdd, ADD_BUTTON_NAME)); } @@ -1079,6 +1083,60 @@ void LLLandmarksPanel::onCustomAction(const LLSD& userdata) { doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doCreatePick, this, _1)); } + else if ("restore" == command_name && mCurrentSelectedList) + { + mCurrentSelectedList->doToSelected(userdata); + } +} + +void LLLandmarksPanel::onMenuVisibilityChange(LLUICtrl* ctrl, const LLSD& param) +{ + bool new_visibility = param["visibility"].asBoolean(); + + // We don't have to update items visibility if the menu is hiding. + if (!new_visibility) return; + + BOOL are_any_items_in_trash = FALSE; + BOOL are_all_items_in_trash = TRUE; + + LLFolderView* root_folder_view = mCurrentSelectedList ? mCurrentSelectedList->getRootFolder() : NULL; + if(root_folder_view) + { + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + + std::set<LLUUID> selected_uuids = root_folder_view->getSelectionList(); + + // Iterate through selected items to find out if any of these items are in Trash + // or all the items are in Trash category. + for (std::set<LLUUID>::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter) + { + LLFolderViewItem* item = root_folder_view->getItemByID(*iter); + + // If no item is found it might be a folder id. + if (!item) + { + item = root_folder_view->getFolderByID(*iter); + } + if (!item) continue; + + LLFolderViewEventListener* listenerp = item->getListener(); + if(!listenerp) continue; + + // Trash category itself should not be included because it can't be + // actually restored from trash. + are_all_items_in_trash &= listenerp->isItemInTrash() && *iter != trash_id; + + // If there are any selected items in Trash including the Trash category itself + // we show "Restore Item" in context menu and hide other irrelevant items. + are_any_items_in_trash |= listenerp->isItemInTrash(); + } + } + + // Display "Restore Item" menu entry if at least one of the selected items + // is in Trash or the Trash category itself is among selected items. + // Hide other menu entries in this case. + // Enable this menu entry only if all selected items are in the Trash category. + toggle_restore_menu((LLMenuGL*)ctrl, are_any_items_in_trash, are_all_items_in_trash); } /* @@ -1414,4 +1472,31 @@ static bool has_collapsed_folders(LLFolderView* root_folder) return true; } + +// Displays "Restore Item" context menu entry while hiding +// all other entries or vice versa. +// Sets "Restore Item" enabled state. +void toggle_restore_menu(LLMenuGL *menu, BOOL visible, BOOL enabled) +{ + if (!menu) return; + + const LLView::child_list_t *list = menu->getChildList(); + for (LLView::child_list_t::const_iterator itor = list->begin(); + itor != list->end(); + ++itor) + { + LLView *menu_item = (*itor); + std::string name = menu_item->getName(); + + if ("restore_item" == name) + { + menu_item->setVisible(visible); + menu_item->setEnabled(enabled); + } + else + { + menu_item->setVisible(!visible); + } + } +} // EOF diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 8dcbca0440..b2f4e92473 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -129,6 +129,14 @@ private: void onCustomAction(const LLSD& command_name); /** + * Updates context menu depending on the selected items location. + * + * For items in Trash category the menu includes the "Restore Item" + * context menu entry. + */ + void onMenuVisibilityChange(LLUICtrl* ctrl, const LLSD& param); + + /** * Determines if an item can be modified via context/gear menu. * * It validates Places Landmarks rules first. And then LLFolderView permissions. diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index c143aff2d4..8d3b1fd7a0 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -35,6 +35,7 @@ #include "llsecondlifeurls.h" #include "v4color.h" +#include "llappviewer.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcommandhandler.h" // for secondlife:///app/login/ @@ -859,6 +860,13 @@ void LLPanelLogin::loadLoginPage() char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLabel().c_str(), 0); oStr << "&grid=" << curl_grid; curl_free(curl_grid); + + // add OS info + char * os_info = curl_escape(LLAppViewer::instance()->getOSInfo().getOSStringSimple().c_str(), 0); + oStr << "&os=" << os_info; + curl_free(os_info); + + gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid()); gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor()); diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index c4ae82ccdf..fc6bc09b82 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -958,7 +958,7 @@ void LLPanelNearByMedia::onAdvancedButtonClick() void LLPanelNearByMedia::onMoreLess() { - bool is_more = getChild<LLUICtrl>("more_btn")->getVisible(); + bool is_more = getChild<LLButton>("more_btn")->getToggleState(); mNearbyMediaPanel->setVisible(is_more); // enable resizing when expanded @@ -969,8 +969,7 @@ void LLPanelNearByMedia::onMoreLess() setShape(new_rect); - getChild<LLUICtrl>("more_btn")->setVisible(!is_more); - getChild<LLUICtrl>("less_btn")->setVisible(is_more); + getChild<LLUICtrl>("more_btn")->setVisible(true); } void LLPanelNearByMedia::updateControls() diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 73a8fbe3aa..8fa6beb474 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -135,23 +135,24 @@ BOOL LLPanelObject::postBuild() // PhysicsShapeType combobox mComboPhysicsShapeType = getChild<LLComboBox>("Physics Shape Type Combo Ctrl"); - childSetCommitCallback("Physics Shape Type Combo Ctrl", onCommitPhysicsParam, this); - + mComboPhysicsShapeType->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsShapeType, this, _1, mComboPhysicsShapeType)); + // PhysicsGravity mSpinPhysicsGravity = getChild<LLSpinCtrl>("Physics Gravity"); - childSetCommitCallback("Physics Gravity", onCommitPhysicsParam, this); + mSpinPhysicsGravity->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsGravity, this, _1, mSpinPhysicsGravity)); // PhysicsFriction mSpinPhysicsFriction = getChild<LLSpinCtrl>("Physics Friction"); - childSetCommitCallback("Physics Friction", onCommitPhysicsParam, this); - + mSpinPhysicsFriction->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsFriction, this, _1, mSpinPhysicsFriction)); + // PhysicsDensity mSpinPhysicsDensity = getChild<LLSpinCtrl>("Physics Density"); - childSetCommitCallback("Physics Density", onCommitPhysicsParam, this); + mSpinPhysicsDensity->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsDensity, this, _1, mSpinPhysicsDensity)); // PhysicsRestitution mSpinPhysicsRestitution = getChild<LLSpinCtrl>("Physics Restitution"); - childSetCommitCallback("Physics Restitution", onCommitPhysicsParam, this); + mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelObject::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution)); + // Position mLabelPosition = getChild<LLTextBox>("label position"); @@ -1281,35 +1282,46 @@ void LLPanelObject::sendIsPhantom() } } -#include "llsdutil.h" -class CostResponder : public LLHTTPClient::Responder +void LLPanelObject::sendPhysicsShapeType(LLUICtrl* ctrl, void* userdata) { -public: - CostResponder(U32 id) { mID = id; } - virtual void result(const LLSD& content) { llinfos << ll_pretty_print_sd(content) << llendl; } + U8 type = ctrl->getValue().asInteger(); + LLSelectMgr::getInstance()->selectionSetPhysicsType(type); - U32 mID; -}; + refreshCost(); +} -void LLPanelObject::sendPhysicsParam() +void LLPanelObject::sendPhysicsGravity(LLUICtrl* ctrl, void* userdata) { - LLSD physicsType = mComboPhysicsShapeType->getValue(); - - U8 type = physicsType.asInteger(); - F32 gravity = mSpinPhysicsGravity->get(); - F32 friction = mSpinPhysicsFriction->get(); - F32 density = mSpinPhysicsDensity->get(); - F32 restitution = mSpinPhysicsRestitution->get(); - - LLSelectMgr::getInstance()->selectionUpdatePhysicsParam(type, gravity, friction, - density, restitution); + F32 val = ctrl->getValue().asReal(); + LLSelectMgr::getInstance()->selectionSetGravity(val); +} - std::string url = gAgent.getRegion()->getCapability("GetObjectCost"); - LLSD body = LLSD::emptyArray(); - - body.append(LLSelectMgr::getInstance()->getSelection()->getFirstObject()->getID()); +void LLPanelObject::sendPhysicsFriction(LLUICtrl* ctrl, void* userdata) +{ + F32 val = ctrl->getValue().asReal(); + LLSelectMgr::getInstance()->selectionSetFriction(val); +} + +void LLPanelObject::sendPhysicsRestitution(LLUICtrl* ctrl, void* userdata) +{ + F32 val = ctrl->getValue().asReal(); + LLSelectMgr::getInstance()->selectionSetRestitution(val); +} + +void LLPanelObject::sendPhysicsDensity(LLUICtrl* ctrl, void* userdata) +{ + F32 val = ctrl->getValue().asReal(); + LLSelectMgr::getInstance()->selectionSetDensity(val); +} + +void LLPanelObject::refreshCost() +{ + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - LLHTTPClient::post( url, body, new CostResponder(body[0].asInteger()) ); + if (obj) + { + obj->getObjectCost(); + } } void LLPanelObject::sendCastShadows() @@ -1911,7 +1923,8 @@ void LLPanelObject::refresh() mRootObject = NULL; } - bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled"); + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + !gAgent.getRegion()->getCapability("GetMesh").empty(); getChildView("label physicsshapetype")->setVisible(enable_mesh); getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh); @@ -1921,10 +1934,10 @@ void LLPanelObject::refresh() getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); - // if mesh isn't enabled we want to the scale max to be 10 - getChild<LLSpinCtrl>("Scale X")->setMaxValue(enable_mesh ? 64 : 10); - getChild<LLSpinCtrl>("Scale Y")->setMaxValue(enable_mesh ? 64 : 10); - getChild<LLSpinCtrl>("Scale Z")->setMaxValue(enable_mesh ? 64 : 10); + F32 max_scale = DEFAULT_MAX_PRIM_SCALE_NO_MESH; + getChild<LLSpinCtrl>("Scale X")->setMaxValue(max_scale); + getChild<LLSpinCtrl>("Scale Y")->setMaxValue(max_scale); + getChild<LLSpinCtrl>("Scale Z")->setMaxValue(max_scale); LLComboBox* sculpt_combo = getChild<LLComboBox>("sculpt type control"); BOOL found = sculpt_combo->itemExists("Mesh"); @@ -2121,13 +2134,6 @@ void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata ) } // static -void LLPanelObject::onCommitPhysicsParam(LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - self->sendPhysicsParam(); -} - -// static void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) { LLPanelObject* self = (LLPanelObject*) userdata; diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index b43b1cc261..54bb5df8bf 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -81,6 +81,7 @@ public: protected: void getState(); + void refreshCost(); void sendRotation(BOOL btn_down); void sendScale(BOOL btn_down); @@ -88,7 +89,12 @@ protected: void sendIsPhysical(); void sendIsTemporary(); void sendIsPhantom(); - void sendPhysicsParam(); + void sendPhysicsShapeType(LLUICtrl* ctrl, void* userdata); + void sendPhysicsGravity(LLUICtrl* ctrl, void* userdata); + void sendPhysicsFriction(LLUICtrl* ctrl, void* userdata); + void sendPhysicsRestitution(LLUICtrl* ctrl, void* userdata); + void sendPhysicsDensity(LLUICtrl* ctrl, void* userdata); + void sendCastShadows(); void sendSculpt(); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index c4d1495a31..bfe6cab52f 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -766,22 +766,12 @@ BOOL LLTaskCategoryBridge::startDrag(EDragAndDropType* type, LLUUID* id) const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { - const LLInventoryItem *inv = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mUUID)); - if (inv) + const LLInventoryObject* cat = object->getInventoryObject(mUUID); + if ( (cat) && (move_inv_category_world_to_agent(mUUID, LLUUID::null, FALSE)) ) { - const LLPermissions& perm = inv->getPermissions(); - bool can_copy = gAgent.allowOperation(PERM_COPY, perm, - GP_OBJECT_MANIPULATE); - if((can_copy && perm.allowTransferTo(gAgent.getID())) - || object->permYouOwner()) -// || gAgent.isGodlike()) - - { - *type = LLViewerAssetType::lookupDragAndDropType(inv->getType()); - - *id = inv->getUUID(); - return TRUE; - } + *type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); + *id = mUUID; + return TRUE; } } } diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 54198d6aa4..b07a46a222 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -54,6 +54,7 @@ #include "llgroupactions.h" #include "llgrouplist.h" #include "llinventoryobserver.h" +#include "llnetmap.h" #include "llpanelpeoplemenus.h" #include "llsidetray.h" #include "llsidetraypanelcontainer.h" @@ -494,7 +495,8 @@ LLPanelPeople::LLPanelPeople() mNearbyGearButton(NULL), mFriendsGearButton(NULL), mGroupsGearButton(NULL), - mRecentGearButton(NULL) + mRecentGearButton(NULL), + mMiniMap(NULL) { mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); @@ -567,6 +569,9 @@ BOOL LLPanelPeople::postBuild() mNearbyList->setNoItemsMsg(getString("no_one_near")); mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); mNearbyList->setShowIcons("NearbyListShowIcons"); + mMiniMap = (LLNetMap*)getChildView("Net Map",true); + mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? + getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list"); mRecentList->setNoItemsCommentText(getString("no_recent_people")); @@ -1088,6 +1093,12 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl) void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list) { + if (getActiveTabName() == NEARBY_TAB_NAME) + { + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + mMiniMap->setSelected(selected_uuids); + } else // Make sure only one of the friends lists (online/all) has selection. if (getActiveTabName() == FRIENDS_TAB_NAME) { diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index b496bb3779..46c58cd139 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -142,6 +142,7 @@ private: LLAvatarList* mNearbyList; LLAvatarList* mRecentList; LLGroupList* mGroupList; + LLNetMap* mMiniMap; LLHandle<LLView> mGroupPlusMenuHandle; LLHandle<LLView> mNearbyViewSortMenuHandle; diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 7657cccd4e..6cfb708112 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -273,6 +273,8 @@ void LLPreviewTexture::saveAs() mSaveFileName = file_picker.getFirstFile(); mLoadingFullImage = TRUE; getWindow()->incBusyCount(); + + mImage->forceToSaveRawImage(0) ;//re-fetch the raw image if the old one is removed. mImage->setLoadedCallback( LLPreviewTexture::onFileLoadedForSave, 0, TRUE, FALSE, new LLUUID( mItemUUID ), &mCallbackTextureList ); } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 305b629cf7..8ffbd5510d 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1889,6 +1889,103 @@ BOOL LLSelectMgr::selectionGetGlow(F32 *glow) return identical; } + +void LLSelectMgr::selectionSetPhysicsType(U8 type) +{ + struct f : public LLSelectedObjectFunctor + { + U8 mType; + f(const U8& t) : mType(t) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsShapeType(mType); + object->updateFlags(); + } + return true; + } + } sendfunc(type); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetFriction(F32 friction) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mFriction; + f(const F32& friction) : mFriction(friction) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsFriction(mFriction); + object->updateFlags(); + } + return true; + } + } sendfunc(friction); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetGravity(F32 gravity ) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mGravity; + f(const F32& gravity) : mGravity(gravity) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsGravity(mGravity); + object->updateFlags(); + } + return true; + } + } sendfunc(gravity); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetDensity(F32 density ) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mDensity; + f(const F32& density ) : mDensity(density) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsDensity(mDensity); + object->updateFlags(); + } + return true; + } + } sendfunc(density); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetRestitution(F32 restitution) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mRestitution; + f(const F32& restitution ) : mRestitution(restitution) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsRestitution(mRestitution); + object->updateFlags(); + } + return true; + } + } sendfunc(restitution); + getSelection()->applyToObjects(&sendfunc); +} + + //----------------------------------------------------------------------------- // selectionSetMaterial() //----------------------------------------------------------------------------- @@ -3936,45 +4033,6 @@ void LLSelectMgr::selectionUpdateCastShadows(BOOL cast_shadows) getSelection()->applyToObjects(&func); } -struct LLSelectMgrApplyPhysicsParam : public LLSelectedObjectFunctor -{ - LLSelectMgrApplyPhysicsParam(U8 type, F32 gravity, F32 friction, - F32 density, F32 restitution) : - mType(type), - mGravity(gravity), - mFriction(friction), - mDensity(density), - mRestitution(restitution) - {} - U8 mType; - F32 mGravity; - F32 mFriction; - F32 mDensity; - F32 mRestitution; - virtual bool apply(LLViewerObject* object) - { - if ( object->permModify() ) // preemptive permissions check - { - object->setPhysicsShapeType( mType ); - object->setPhysicsGravity(mGravity); - object->setPhysicsFriction(mFriction); - object->setPhysicsDensity(mDensity); - object->setPhysicsRestitution(mRestitution); - object->updateFlags(); - } - return true; - } -}; - - -void LLSelectMgr::selectionUpdatePhysicsParam(U8 type, F32 gravity, F32 friction, - F32 density, F32 restitution) -{ - llwarns << "physics shape type ->" << (U32)type << llendl; - LLSelectMgrApplyPhysicsParam func(type, gravity, friction, density, restitution); - getSelection()->applyToObjects(&func); -} - //---------------------------------------------------------------------- // Helpful packing functions for sendObjectMessage() //---------------------------------------------------------------------- @@ -5432,13 +5490,15 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) glMatrixMode(GL_MODELVIEW); gGL.pushMatrix(); - + BOOL is_hud_object = objectp->isHUDAttachment(); if (!is_hud_object) { glLoadIdentity(); glMultMatrixd(gGLModelView); + LLVector3 trans = objectp->getRegion()->getOriginAgent(); + glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]); } if (drawable->isActive()) diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 0cf582062d..85d8d3212d 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -236,7 +236,7 @@ public: { bool operator()(LLSelectNode* node); }; - typedef boost::filter_iterator<is_root, list_t::iterator > valid_root_iterator; + typedef boost::filter_iterator<is_valid_root, list_t::iterator > valid_root_iterator; valid_root_iterator valid_root_begin() { return valid_root_iterator(mList.begin(), mList.end()); } valid_root_iterator valid_root_end() { return valid_root_iterator(mList.end(), mList.end()); } @@ -489,8 +489,6 @@ public: void saveSelectedObjectTextures(); void selectionUpdatePhysics(BOOL use_physics); - void selectionUpdatePhysicsParam(U8 type, F32 gravity, F32 friction, - F32 density, F32 restitution); void selectionUpdateTemporary(BOOL is_temporary); void selectionUpdatePhantom(BOOL is_ghost); void selectionUpdateCastShadows(BOOL cast_shadows); @@ -501,6 +499,11 @@ public: bool selectionGetIncludeInSearch(bool* include_in_search_out); // true if all selected objects have same BOOL selectionGetGlow(F32 *glow); + void selectionSetPhysicsType(U8 type); + void selectionSetGravity(F32 gravity); + void selectionSetFriction(F32 friction); + void selectionSetDensity(F32 density); + void selectionSetRestitution(F32 restitution); void selectionSetMaterial(U8 material); void selectionSetImage(const LLUUID& imageid); // could be item or asset id void selectionSetColor(const LLColor4 &color); diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index b316171604..363fe5f12b 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -185,7 +185,7 @@ void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility) { LLSD visibility; visibility["visible"] = new_visibility.asBoolean(); - visibility["reset_accordion"] = true; + visibility["reset_accordion"] = false; updateToVisibility(visibility); } diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 19d1bdee86..eb537c7d7b 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -141,6 +141,8 @@ public: void toggleTabDocked(); + BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + LLPanel *getPanel(); private: std::string mTabTitle; @@ -269,6 +271,15 @@ void LLSideTrayTab::toggleTabDocked() LLFloaterReg::toggleInstance("side_bar_tab", tab_name); } +BOOL LLSideTrayTab::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + // Let children handle the event + LLUICtrl::handleScrollWheel(x, y, clicks); + + // and then eat it to prevent in-world scrolling (STORM-351). + return TRUE; +} + void LLSideTrayTab::dock(LLFloater* floater_tab) { LLSideTray* side_tray = getSideTray(); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index b9063b3c81..af6064ad20 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -64,6 +64,12 @@ const F32 SG_OCCLUSION_FUDGE = 0.25f; static U32 sZombieGroups = 0; U32 LLSpatialGroup::sNodeCount = 0; + +#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0 + +std::set<GLuint> LLSpatialGroup::sPendingQueries; + + BOOL LLSpatialGroup::sNoDelete = FALSE; static F32 sLastMaxTexPriority = 1.f; @@ -81,6 +87,9 @@ protected: virtual void releaseName(GLuint name) { +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + LLSpatialGroup::sPendingQueries.erase(name); +#endif glDeleteQueriesARB(1, &name); } }; @@ -361,9 +370,15 @@ LLSpatialGroup::~LLSpatialGroup() sNodeCount--; - if (gGLManager.mHasOcclusionQuery && mOcclusionQuery[LLViewerCamera::sCurCameraID]) + if (gGLManager.mHasOcclusionQuery) { - sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i) + { + if (mOcclusionQuery[i]) + { + sQueryPool.release(mOcclusionQuery[i]); + } + } } mOcclusionVerts = NULL; @@ -507,7 +522,7 @@ BOOL LLSpatialGroup::isRecentlyVisible() const BOOL LLSpatialGroup::isVisible() const { - return mVisible[LLViewerCamera::sCurCameraID] == LLDrawable::getCurrentFrame() ? TRUE : FALSE; + return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE; } void LLSpatialGroup::setVisible() @@ -1096,12 +1111,23 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode) for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) { mOcclusionState[i] |= state; + + if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) + { + sQueryPool.release(mOcclusionQuery[i]); + mOcclusionQuery[i] = 0; + } } } } else { mOcclusionState[LLViewerCamera::sCurCameraID] |= state; + if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; + } } } @@ -1319,7 +1345,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const } else { - return (gFrameTimeSeconds - mLastUpdateTime+4.f)/mDistance; + F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f; + return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance; } } @@ -1330,8 +1357,8 @@ BOOL LLSpatialGroup::needsUpdate() BOOL LLSpatialGroup::changeLOD() { - if (isState(ALPHA_DIRTY)) - { ///an alpha sort is going to happen, update distance and LOD + if (isState(ALPHA_DIRTY | OBJECT_DIRTY)) + { ///a rebuild is going to happen, update distance and LoD return TRUE; } @@ -1344,7 +1371,7 @@ BOOL LLSpatialGroup::changeLOD() return TRUE; } - if (mDistance > mRadius) + if (mDistance > mRadius*2.f) { return FALSE; } @@ -1540,15 +1567,31 @@ void LLSpatialGroup::checkOcclusion() { //otherwise, if a query is pending, read it back GLuint available = 0; - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + } + else + { + available = 1; + } + if (available) { //result is available, read it back, otherwise wait until next frame GLuint res = 1; if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) { glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res); +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +#endif } - + else if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { //delete the query to avoid holding onto hundreds of pending queries + sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; + } + if (isOcclusionState(DISCARD_QUERY)) { res = 2; @@ -1621,6 +1664,13 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) } #if !LL_DARWIN U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; +#else + U32 mode = GL_SAMPLES_PASSED_ARB; +#endif + +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +#endif glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); @@ -1637,7 +1687,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) } glEndQueryARB(mode); -#endif + if (use_depth_clamp) { glDisable(GL_DEPTH_CLAMP); @@ -3580,6 +3630,8 @@ void renderRaycast(LLDrawable* drawablep) if (volume) { + LLVector3 trans = drawablep->getRegion()->getOriginAgent(); + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { const LLVolumeFace& face = volume->getVolumeFace(i); @@ -3589,6 +3641,7 @@ void renderRaycast(LLDrawable* drawablep) } gGL.pushMatrix(); + glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]); glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix); LLVector3 start, end; @@ -3613,7 +3666,7 @@ void renderRaycast(LLDrawable* drawablep) LLRenderOctreeRaycast render(starta, dir, &t); gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); { //render face positions @@ -3672,7 +3725,7 @@ void renderRaycast(LLDrawable* drawablep) LLGLDepthTest depth(GL_FALSE, GL_TRUE); gGL.color4f(0,0.5f,0.5f,1); - drawBoxOutline(pos, size); + drawBoxOutline(pos, size); } } } @@ -4048,7 +4101,7 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_RAYCAST | LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | LLPipeline::RENDER_DEBUG_AGENT_TARGET | - LLPipeline::RENDER_DEBUG_BUILD_QUEUE | + //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) { return; @@ -4088,7 +4141,7 @@ void LLSpatialGroup::drawObjectBox(LLColor4 col) { gGL.color4fv(col.mV); LLVector4a size; - size = mObjectBounds[0]; + size = mObjectBounds[1]; size.mul(1.01f); size.add(LLVector4a(0.001f)); drawBox(mObjectBounds[0], size); diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 85fd66b297..664d957e49 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -187,6 +187,7 @@ public: return *this; } + static std::set<GLuint> sPendingQueries; //pending occlusion queries static U32 sNodeCount; static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 029a48480f..c6efaf4afe 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -981,7 +981,6 @@ bool idle_startup() login->setSkipOptionalUpdate(true); } - login->setUserInteraction(show_connect_box); login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); login->setLastExecEvent(gLastExecEvent); login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance())); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 6a213309a0..f54214b95c 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -326,6 +326,7 @@ bool LLTextureCacheRemoteWorker::doRead() // First state / stage : find out if the file is local if (mState == INIT) { +#if 0 std::string filename = mCache->getLocalFileName(mID); // Is it a JPEG2000 file? { @@ -360,6 +361,11 @@ bool LLTextureCacheRemoteWorker::doRead() } // Determine the next stage: if we found a file, then LOCAL else CACHE mState = (local_size > 0 ? LOCAL : CACHE); + + llassert_always(mState == CACHE) ; +#else + mState = CACHE; +#endif } // Second state / stage : if the file is local, load it and leave @@ -1592,7 +1598,7 @@ void LLTextureCache::purgeTextures(bool validate) if (validate) { validate_idx = gSavedSettings.getU32("CacheValidateCounter"); - U32 next_idx = (++validate_idx) % 256; + U32 next_idx = (validate_idx + 1) % 256; gSavedSettings.setU32("CacheValidateCounter", next_idx); LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL; } @@ -1858,8 +1864,22 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id) //called after mHeaderMutex is locked. void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) { + bool file_maybe_exists = true; // Always attempt to remove when idx is invalid. + if(idx >= 0) //valid entry { + if (entry.mBodySize == 0) // Always attempt to remove when mBodySize > 0. + { + if (LLAPRFile::isExist(filename, getLocalAPRFilePool())) // Sanity check. Shouldn't exist when body size is 0. + { + LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL; + } + else + { + file_maybe_exists = false; + } + } + entry.mImageSize = -1; entry.mBodySize = 0; mHeaderIDMap.erase(entry.mID); @@ -1869,7 +1889,10 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) mFreeList.insert(idx); } - LLAPRFile::remove(filename, getLocalAPRFilePool()); + if (file_maybe_exists) + { + LLAPRFile::remove(filename, getLocalAPRFilePool()); + } } bool LLTextureCache::removeFromCache(const LLUUID& id) diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 4f63abb152..18c3a3b87d 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1141,7 +1141,7 @@ bool LLTextureFetchWorker::doWork(S32 param) //1, not openning too many file descriptors at the same time; //2, control the traffic of http so udp gets bandwidth. // - static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 32 ; + static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ; if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE) { return false ; //wait. @@ -1822,6 +1822,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), mHTTPTextureBits(0), + mTotalHTTPRequests(0), mCurlGetRequest(NULL), mQAMode(qa_mode) { @@ -1973,6 +1974,7 @@ void LLTextureFetch::addToHTTPQueue(const LLUUID& id) { LLMutexLock lock(&mNetworkQueueMutex); mHTTPTextureQueue.insert(id); + mTotalHTTPRequests++; } void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size) @@ -2035,6 +2037,15 @@ S32 LLTextureFetch::getNumHTTPRequests() return size ; } +U32 LLTextureFetch::getTotalNumHTTPRequests() +{ + mNetworkQueueMutex.lock() ; + U32 size = mTotalHTTPRequests ; + mNetworkQueueMutex.unlock() ; + + return size ; +} + // call lockQueue() first! LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id) { diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index ad00a7ea36..d101da1f4b 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -79,6 +79,7 @@ public: void dump(); S32 getNumRequests() ; S32 getNumHTTPRequests() ; + U32 getTotalNumHTTPRequests() ; // Public for access by callbacks S32 getPending(); @@ -183,6 +184,9 @@ private: U32 mHTTPTextureBits; + //debug use + U32 mTotalHTTPRequests ; + // Out-of-band cross-thread command queue. This command queue // is logically tied to LLQueuedThread's list of // QueuedRequest instances and so must be covered by the diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index b9a15fd1f4..0115115a23 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -516,6 +516,7 @@ void LLGLTexMemBar::draw() S32 v_offset = (S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f); F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024); F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024); + U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests() ; //---------------------------------------------------------------------------- LLGLSUIDefault gls_ui; LLColor4 text_color(1.f, 1.f, 1.f, 0.75f); @@ -526,13 +527,13 @@ void LLGLTexMemBar::draw() LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6, text_color, LLFontGL::LEFT, LLFontGL::TOP); - text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB", + text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d", total_mem, max_total_mem, bound_mem, max_bound_mem, LLImageRaw::sGlobalRawMemory >> 20, discard_bias, - cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded); + cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded, total_http_requests); //, cache_entries, cache_max_entries LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3, diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 444d5cb902..414036c597 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -372,6 +372,12 @@ static bool handleRenderDynamicLODChanged(const LLSD& newvalue) return true; } +static bool handleRenderLocalLightsChanged(const LLSD& newvalue) +{ + gPipeline.setLightingDetail(-1); + return true; +} + static bool handleRenderDeferredChanged(const LLSD& newvalue) { LLRenderTarget::sUseFBO = newvalue.asBoolean(); @@ -380,6 +386,7 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue) gPipeline.updateRenderDeferred(); gPipeline.releaseGLBuffers(); gPipeline.createGLBuffers(); + gPipeline.resetVertexBuffers(); if (LLPipeline::sRenderDeferred && LLRenderTarget::sUseFBO) { LLViewerShaderMgr::instance()->setShaders(); @@ -591,6 +598,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _2)); gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _2)); gSavedSettings.getControl("RenderDynamicLOD")->getSignal()->connect(boost::bind(&handleRenderDynamicLODChanged, _2)); + gSavedSettings.getControl("RenderLocalLights")->getSignal()->connect(boost::bind(&handleRenderLocalLightsChanged, _2)); gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index cd72e69055..b36b5aa9ee 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1436,9 +1436,12 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid) // static void LLViewerMedia::createSpareBrowserMediaSource() { - if(!sSpareBrowserMediaSource) + // If we don't have a spare browser media source, create one. + // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare + // SLPlugin process in order to not be confused by an unrelated gdb terminal + // popping up at the moment we start a media plugin. + if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) { - // If we don't have a spare browser media source, create one. // The null owner will keep the browser plugin from fully initializing // (specifically, it keeps LLPluginClassMedia from negotiating a size change, // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) @@ -1694,7 +1697,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ LLPluginClassMedia* media_source = NULL; // HACK: we always try to keep a spare running webkit plugin around to improve launch times. - if(plugin_basename == "media_plugin_webkit") + // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it. + if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) { media_source = LLViewerMedia::getSpareBrowserMediaSource(); if(media_source) @@ -1828,16 +1832,17 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) media_source->ignore_ssl_cert_errors(true); } - // start by assuming the default CA file will be used - std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "lindenlab.pem" ); - - // default turned off so pick up the user specified path - if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile")) - { - ca_path = gSavedSettings.getString("BrowserCAFilePath"); - } - // set the path to the CA.pem file - media_source->addCertificateFilePath( ca_path ); + // NOTE: Removed as per STORM-927 - SSL handshake failed - setting local self-signed certs like this + // seems to screw things up big time. For now, devs will need to add these certs locally and Qt will pick them up. +// // start by assuming the default CA file will be used +// std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "lindenlab.pem" ); +// // default turned off so pick up the user specified path +// if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile")) +// { +// ca_path = gSavedSettings.getString("BrowserCAFilePath"); +// } +// // set the path to the CA.pem file +// media_source->addCertificateFilePath( ca_path ); media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a152ab4aa0..e9e0268587 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -937,6 +937,10 @@ U32 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_FACE_AREA; } + else if ("build queue" == info_display) + { + return LLPipeline::RENDER_DEBUG_BUILD_QUEUE; + } else if ("lights" == info_display) { return LLPipeline::RENDER_DEBUG_LIGHTS; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 4ba1d007fe..9ecb11d253 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -53,6 +53,7 @@ #include "llvfs.h" #include "llviewerinventory.h" #include "llviewermenu.h" // gMenuHolder +#include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" @@ -102,6 +103,16 @@ class LLMeshEnabled : public view_listener_t } }; +class LLMeshUploadVisible : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + return gSavedSettings.getBOOL("MeshEnabled") && + LLViewerParcelMgr::getInstance()->allowAgentBuild() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); + } +}; + LLMutex* LLFilePickerThread::sMutex = NULL; std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ; @@ -1390,6 +1401,7 @@ void init_menu_file() view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); + view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index a4b5143a02..f3cbb8cce3 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -171,31 +171,6 @@ const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = FALSE // ControlYourCamera }; -// Extract channel and version from a string like "SL Web Viewer Beta 10.11.29.215604". -// (channel: "SL Web Viewer Beta", version: "10.11.29.215604") -static bool parse_version_info(const std::string& version_info, std::string& channel, std::string& ver) -{ - size_t last_space = version_info.rfind(" "); - channel = version_info; - - if (last_space != std::string::npos) - { - try - { - ver = version_info.substr(last_space + 1); - channel.replace(last_space, ver.length() + 1, ""); // strip version - } - catch (std::out_of_range) - { - return false; - } - - return true; - } - - return false; -} - bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -2746,6 +2721,14 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLSD args; args["slurl"] = location; args["type"] = LLNotificationsUI::NT_NEARBYCHAT; + + // Look for IRC-style emotes here so object name formatting is correct + std::string prefix = message.substr(0, 4); + if (prefix == "/me " || prefix == "/me'") + { + chat.mChatStyle = CHAT_STYLE_IRC; + } + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); } @@ -3848,31 +3831,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) return; } - if (!gLastVersionChannel.empty()) - { - std::string url = regionp->getCapability("ServerReleaseNotes"); - if (url.empty()) - { - // The capability hasn't arrived yet or is not supported, - // fall back to parsing server version channel. - std::string channel, ver; - if (!parse_version_info(version_channel, channel, ver)) - { - llwarns << "Failed to parse server version channel (" << version_channel << ")" << llendl; - } - - url = gSavedSettings.getString("ReleaseNotesURL"); - LLSD args; - args["CHANNEL"] = LLWeb::escapeURL(channel); - args["VERSION"] = LLWeb::escapeURL(ver); - LLStringUtil::format(url, args); - } - - LLSD args; - args["URL"] = url; - LLNotificationsUtil::add("ServerVersionChanged", args); - } - gLastVersionChannel = version_channel; } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index bf550e9c70..d723fc0a8e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -217,7 +217,6 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mLastInterpUpdateSecs(0.f), mLastMessageUpdateSecs(0.f), mLatestRecvPacketID(0), - mCircuitPacketCount(0), mData(NULL), mAudioSourcep(NULL), mAudioGain(1.f), @@ -1908,7 +1907,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } mLatestRecvPacketID = packet_id; - mCircuitPacketCount = 0; // Set the change flags for scale if (new_scale != getScale()) @@ -2231,7 +2229,8 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; LLVector3 new_v = accel * dt; - if (time_since_last_update > sPhaseOutUpdateInterpolationTime) + if (time_since_last_update > sPhaseOutUpdateInterpolationTime && + sPhaseOutUpdateInterpolationTime > 0.0) { // Haven't seen a viewer update in a while, check to see if the ciruit is still active if (mRegionp) { // The simulator will NOT send updates if the object continues normally on the path @@ -2240,9 +2239,12 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit( mRegionp->getHost() ); if (cdp) { + // Find out how many seconds since last packet arrived on the circuit + F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime(); + if (!cdp->isAlive() || // Circuit is dead or blocked cdp->isBlocked() || // or doesn't seem to be getting any packets - (mCircuitPacketCount > 0 && mCircuitPacketCount == cdp->getPacketsIn())) + (time_since_last_packet > sPhaseOutUpdateInterpolationTime)) { // Start to reduce motion interpolation since we haven't seen a server update in a while F64 time_since_last_interpolation = time - mLastInterpUpdateSecs; @@ -2273,9 +2275,6 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) new_pos = new_pos * ((F32) phase_out); new_v = new_v * ((F32) phase_out); } - - // Save current circuit packet count to see if it changes - mCircuitPacketCount = cdp->getPacketsIn(); } } } @@ -5252,7 +5251,6 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp) } mLatestRecvPacketID = 0; - mCircuitPacketCount = 0; mRegionp = regionp; for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) @@ -5306,11 +5304,6 @@ void LLViewerObject::updateFlags() gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); gMessageSystem->sendReliable( regionp->getHost() ); - - if (getPhysicsShapeType() != 0) - { - llwarns << "sent non default physics rep " << (S32) getPhysicsShapeType() << llendl; - } } BOOL LLViewerObject::setFlags(U32 flags, BOOL state) @@ -5346,6 +5339,7 @@ void LLViewerObject::setPhysicsShapeType(U8 type) { mPhysicsShapeUnknown = false; mPhysicsShapeType = type; + mCostStale = true; } void LLViewerObject::setPhysicsGravity(F32 gravity) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 8883272cde..2b2b7bd59d 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -656,7 +656,6 @@ protected: F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation F64 mLastMessageUpdateSecs; // Last update from a message from the simulator TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator - U32 mCircuitPacketCount; // Packet tracking for early detection of a stopped simulator circuit // extra data sent from the sim...currently only used for tree species info U8* mData; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index ca32ee4202..8c3bf5bf12 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -161,19 +161,13 @@ U64 LLViewerObjectList::getIndex(const U32 local_id, return (((U64)index) << 32) | (U64)local_id; } -BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) +BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) { - if(object.getRegion()) + if(objectp && objectp->getRegion()) { - U32 local_id = object.mLocalID; - LLHost region_host = object.getRegion()->getHost(); - if(!region_host.isOk()) - { - return FALSE ; - } - - U32 ip = region_host.getAddress(); - U32 port = region_host.getPort(); + U32 local_id = objectp->mLocalID; + U32 ip = objectp->getRegion()->getHost().getAddress(); + U32 port = objectp->getRegion()->getHost().getPort(); U64 ipport = (((U64)ip) << 32) | (U64)port; U32 index = sIPAndPortToIndex[ipport]; @@ -188,7 +182,7 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) } // Found existing entry - if (iter->second == object.getID()) + if (iter->second == objectp->getID()) { // Full UUIDs match, so remove the entry sIndexAndLocalIDToUUID.erase(iter); return TRUE; @@ -478,7 +472,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, // << ", regionp " << (U32) regionp << ", object region " << (U32) objectp->getRegion() // << llendl; //} - removeFromLocalIDTable(*objectp); + removeFromLocalIDTable(objectp); setUUIDAndLocal(fullid, local_id, gMessageSystem->getSenderIP(), @@ -1210,7 +1204,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) // << objectp->getRegion()->getHost().getPort() << llendl; //} - removeFromLocalIDTable(*objectp); + removeFromLocalIDTable(objectp); if (objectp->onActiveList()) { diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 2c5f789eb1..7d0653b3b4 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -176,7 +176,7 @@ public: const U32 ip, const U32 port); // Requires knowledge of message system info! - static BOOL removeFromLocalIDTable(const LLViewerObject &object); + static BOOL removeFromLocalIDTable(const LLViewerObject* objectp); // Used ONLY by the orphaned object code. static U64 getIndex(const U32 local_id, const U32 ip, const U32 port); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 7fd6979702..1d18858750 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -322,6 +322,12 @@ LLViewerRegion::~LLViewerRegion() std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer()); } +/*virtual*/ +const LLHost& LLViewerRegion::getHost() const +{ + return mHost; +} + void LLViewerRegion::loadObjectCache() { if (mCacheLoaded) diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 7c6559203e..dd40b876cd 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -245,7 +245,7 @@ public: LLEventPump& getCapAPI() { return mCapabilityListener.getCapAPI(); } /// implements LLCapabilityProvider - virtual LLHost getHost() const { return mHost; } + /*virtual*/ const LLHost& getHost() const; const U64 &getHandle() const { return mHandle; } LLSurface &getLand() const { return *mLandp; } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 092edafdbb..34b0ae9f02 100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1214,12 +1214,15 @@ void LLViewerFetchedTexture::cleanup() void LLViewerFetchedTexture::setForSculpt() { + static const S32 MAX_INTERVAL = 8 ; //frames + mForSculpt = TRUE ; if(isForSculptOnly() && !getBoundRecently()) { destroyGLTexture() ; //sculpt image does not need gl texture. } checkCachedRawSculptImage() ; + setMaxVirtualSizeResetInterval(MAX_INTERVAL) ; } BOOL LLViewerFetchedTexture::isForSculptOnly() const diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index dcfac012f6..42d4878cac 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -298,13 +298,15 @@ private: line_list_t mLineList; LLColor4 mTextColor; -public: - LLDebugText(LLViewerWindow* window) : mWindow(window) {} - void addText(S32 x, S32 y, const std::string &text) { mLineList.push_back(Line(text, x, y)); } + + void clearText() { mLineList.clear(); } + +public: + LLDebugText(LLViewerWindow* window) : mWindow(window) {} void update() { @@ -325,6 +327,8 @@ public: U32 ypos = 64; const U32 y_inc = 20; + clearText(); + if (gSavedSettings.getBOOL("DebugShowTime")) { const U32 y_inc2 = 15; @@ -349,6 +353,14 @@ public: addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc; } +#if LL_WINDOWS + if (gSavedSettings.getBOOL("DebugShowMemory")) + { + addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024)); + ypos += y_inc; + } +#endif + if (gDisplayCameraPos) { std::string camera_view_text; @@ -497,6 +509,12 @@ public: ypos += y_inc; + if (!LLSpatialGroup::sPendingQueries.empty()) + { + addText(xpos,ypos, llformat("%d Queries pending", LLSpatialGroup::sPendingQueries.size())); + ypos += y_inc; + } + addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars)); @@ -670,6 +688,50 @@ public: ypos += y_inc; } + + if (gSavedSettings.getBOOL("DebugShowTextureInfo")) + { + LLViewerObject* objectp = NULL ; + //objectp = = gAgentCamera.getFocusObject(); + + LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode(); + if (nodep) + { + objectp = nodep->getObject(); + } + if (objectp && !objectp->isDead()) + { + S32 num_faces = objectp->mDrawable->getNumFaces() ; + + for(S32 i = 0 ; i < num_faces; i++) + { + LLFace* facep = objectp->mDrawable->getFace(i) ; + if(facep) + { + //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0], + // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1])); + //ypos += y_inc; + + addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea())); + ypos += y_inc; + + //const LLTextureEntry *tep = facep->getTextureEntry(); + //if(tep) + //{ + // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ; + // ypos += y_inc; + //} + + LLViewerTexture* tex = facep->getTexture() ; + if(tex) + { + addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize())); + ypos += y_inc; + } + } + } + } + } } void draw() diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index feb6db4700..dd6f7011a1 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -63,6 +63,7 @@ #include "llkeyframefallmotion.h" #include "llkeyframestandmotion.h" #include "llkeyframewalkmotion.h" +#include "llmanipscale.h" // for get_default_max_prim_scale() #include "llmeshrepository.h" #include "llmutelist.h" #include "llmoveview.h" @@ -1383,7 +1384,7 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) newMin.setSub(pos, buffer); newMax.setAdd(pos, buffer); - float max_attachment_span = DEFAULT_MAX_PRIM_SCALE * 5.0f; + float max_attachment_span = get_default_max_prim_scale() * 5.0f; //stretch bounding box by joint positions for (polymesh_map_t::iterator i = mMeshes.begin(); i != mMeshes.end(); ++i) @@ -8163,12 +8164,16 @@ BOOL LLVOAvatar::updateLOD() mNeedsSkin = TRUE; mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY); } - updateVisibility(); return res; } +void LLVOAvatar::updateLODRiggedAttachments( void ) +{ + updateLOD(); + rebuildRiggedAttachments(); +} U32 LLVOAvatar::getPartitionType() const { // Avatars merely exist as drawables in the bridge partition diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 7ef35178ca..99d0ed76e5 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -122,6 +122,7 @@ public: virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
virtual BOOL updateLOD();
BOOL updateJointLODs();
+ void updateLODRiggedAttachments( void );
virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate.
virtual void updateTextures();
virtual S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim.
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 3c66c4860e..75966a0f96 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -625,7 +625,7 @@ BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent) mScreenp->updateWorldMatrixChildren(); resetHUDAttachments(); } - LLVOAvatar::rebuildRiggedAttachments(); + return LLVOAvatar::updateCharacter(agent); } @@ -1139,6 +1139,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view LLAppearanceMgr::instance().registerAttachment(attachment_id); // Clear any pending requests once the attachment arrives. removeAttachmentRequest(attachment_id); + updateLODRiggedAttachments(); } return attachment; diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 10d6b009ae..d0738a789f 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -225,8 +225,9 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const // Format string used to construct filename for the object cache
static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
-// Throw out 1/20 (5%) of our cache entries if we run out of room.
-const U32 ENTRIES_PURGE_FACTOR = 20;
+const U32 MAX_NUM_OBJECT_ENTRIES = 128 ;
+const U32 MIN_ENTRIES_TO_PURGE = 16 ;
+const U32 INVALID_TIME = 0 ;
const char* object_cache_dirname = "objectcache";
const char* header_filename = "object.cache";
@@ -261,6 +262,7 @@ void LLVOCache::destroyClass() LLVOCache::LLVOCache():
mInitialized(FALSE),
mReadOnly(TRUE),
+ mNumEntries(0),
mCacheSize(1)
{
mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled");
@@ -298,17 +300,16 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) llwarns << "Cache already initialized." << llendl;
return ;
}
+ mInitialized = TRUE ;
setDirNames(location);
if (!mReadOnly)
{
LLFile::mkdir(mObjectCacheDirName);
}
-
- mCacheSize = size;
-
- readCacheHeader();
- mInitialized = TRUE ;
+ mCacheSize = llclamp(size, MIN_ENTRIES_TO_PURGE, MAX_NUM_OBJECT_ENTRIES);
+ mMetaInfo.mVersion = cache_version;
+ readCacheHeader();
if(mMetaInfo.mVersion != cache_version)
{
@@ -332,6 +333,8 @@ void LLVOCache::removeCache(ELLPath location) return ;
}
+ llinfos << "about to remove the object cache due to settings." << llendl ;
+
std::string delem = gDirUtilp->getDirDelimiter();
std::string mask = delem + "*";
std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
@@ -352,6 +355,8 @@ void LLVOCache::removeCache() return ;
}
+ llinfos << "about to remove the object cache due to some error." << llendl ;
+
std::string delem = gDirUtilp->getDirDelimiter();
std::string mask = delem + "*";
llinfos << "Removing cache at " << mObjectCacheDirName << llendl;
@@ -361,62 +366,80 @@ void LLVOCache::removeCache() writeCacheHeader();
}
-void LLVOCache::clearCacheInMemory()
-{
- std::for_each(mHandleEntryMap.begin(), mHandleEntryMap.end(), DeletePairedPointer());
- mHandleEntryMap.clear();
-}
-
-void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)
+void LLVOCache::removeEntry(HeaderEntryInfo* entry)
{
- U32 region_x, region_y;
+ llassert_always(mInitialized) ;
+ if(mReadOnly)
+ {
+ return ;
+ }
+ if(!entry)
+ {
+ return ;
+ }
- grid_from_region_handle(handle, ®ion_x, ®ion_y);
- filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, object_cache_dirname,
- llformat(OBJECT_CACHE_FILENAME, region_x, region_y));
+ header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry) ;
+ if(iter != mHeaderEntryQueue.end())
+ {
+ mHandleEntryMap.erase(entry->mHandle) ;
+ mHeaderEntryQueue.erase(iter) ;
+ removeFromCache(entry) ;
+ delete entry ;
- return ;
+ mNumEntries = mHandleEntryMap.size() ;
+ }
}
-void LLVOCache::removeFromCache(U64 handle)
+void LLVOCache::removeEntry(U64 handle)
{
- if(mReadOnly)
+ handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
+ if(iter == mHandleEntryMap.end()) //no cache
{
- llwarns << "Not removing cache for handle " << handle << ": Cache is currently in read-only mode." << llendl;
return ;
}
-
- std::string filename;
- getObjectCacheFilename(handle, filename);
- LLAPRFile::remove(filename, mLocalAPRFilePoolp);
+ HeaderEntryInfo* entry = iter->second ;
+ removeEntry(entry) ;
}
-BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error)
+void LLVOCache::clearCacheInMemory()
{
- if(!check_read(apr_file, src, n_bytes))
+ if(!mHeaderEntryQueue.empty())
{
- if (remove_cache_on_error)
+ for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin(); iter != mHeaderEntryQueue.end(); ++iter)
{
- removeCache() ;
+ delete *iter ;
}
- return FALSE ;
+ mHeaderEntryQueue.clear();
+ mHandleEntryMap.clear();
+ mNumEntries = 0 ;
}
- return TRUE ;
}
-BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error)
+void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)
+{
+ U32 region_x, region_y;
+
+ grid_from_region_handle(handle, ®ion_x, ®ion_y);
+ filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, object_cache_dirname,
+ llformat(OBJECT_CACHE_FILENAME, region_x, region_y));
+
+ return ;
+}
+
+void LLVOCache::removeFromCache(HeaderEntryInfo* entry)
{
- if(!check_write(apr_file, src, n_bytes))
+ if(mReadOnly)
{
- if (remove_cache_on_error)
- {
- removeCache() ;
- }
- return FALSE ;
+ llwarns << "Not removing cache for handle " << entry->mHandle << ": Cache is currently in read-only mode." << llendl;
+ return ;
}
- return TRUE ;
+ std::string filename;
+ getObjectCacheFilename(entry->mHandle, filename);
+ LLAPRFile::remove(filename, mLocalAPRFilePoolp);
+ entry->mTime = INVALID_TIME ;
+ updateEntry(entry) ; //update the head file.
}
void LLVOCache::readCacheHeader()
@@ -430,45 +453,76 @@ void LLVOCache::readCacheHeader() //clear stale info.
clearCacheInMemory();
+ bool success = true ;
if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
{
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
+ LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
//read the meta element
- bool remove_cache_on_error = false;
- if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo), remove_cache_on_error))
- {
- llwarns << "Error reading meta information from cache header." << llendl;
- delete apr_file;
- return;
- }
-
- HeaderEntryInfo* entry ;
- for(U32 entry_index = 0; entry_index < mCacheSize; ++entry_index)
+ success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
+
+ if(success)
{
- entry = new HeaderEntryInfo() ;
- if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo), remove_cache_on_error))
+ HeaderEntryInfo* entry = NULL ;
+ mNumEntries = 0 ;
+ U32 num_read = 0 ;
+ while(num_read++ < MAX_NUM_OBJECT_ENTRIES)
{
- llwarns << "Error reading cache header entry. (entry_index=" << entry_index << ")" << llendl;
- delete entry ;
- break;
+ if(!entry)
+ {
+ entry = new HeaderEntryInfo() ;
+ }
+ success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo));
+
+ if(!success) //failed
+ {
+ llwarns << "Error reading cache header entry. (entry_index=" << mNumEntries << ")" << llendl;
+ delete entry ;
+ entry = NULL ;
+ break ;
+ }
+ else if(entry->mTime == INVALID_TIME)
+ {
+ continue ; //an empty entry
+ }
+
+ entry->mIndex = mNumEntries++ ;
+ mHeaderEntryQueue.insert(entry) ;
+ mHandleEntryMap[entry->mHandle] = entry ;
+ entry = NULL ;
}
- else if(!entry->mTime) //end of the cache.
+ if(entry)
{
delete entry ;
- break;
}
-
- entry->mIndex = entry_index;
- mHandleEntryMap[entry->mHandle] = entry;
}
- delete apr_file ;
+ //---------
+ //debug code
+ //----------
+ //std::string name ;
+ //for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter)
+ //{
+ // getObjectCacheFilename((*iter)->mHandle, name) ;
+ // llinfos << name << llendl ;
+ //}
+ //-----------
}
else
{
writeCacheHeader() ;
}
+
+ if(!success)
+ {
+ removeCache() ; //failed to read header, clear the cache
+ }
+ else if(mNumEntries >= mCacheSize)
+ {
+ purgeEntries(mCacheSize) ;
+ }
+
+ return ;
}
void LLVOCache::writeCacheHeader()
@@ -485,60 +539,50 @@ void LLVOCache::writeCacheHeader() return;
}
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp);
-
- //write the meta element
- if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
+ bool success = true ;
{
- llwarns << "Error writing meta information to cache header." << llendl;
- delete apr_file;
- return;
- }
+ LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
- U32 entry_index = 0;
- handle_entry_map_t::iterator iter_end = mHandleEntryMap.end();
- for(handle_entry_map_t::iterator iter = mHandleEntryMap.begin();
- iter != iter_end;
- ++iter)
- {
- HeaderEntryInfo* entry = iter->second;
- entry->mIndex = entry_index++;
- if(!checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)))
+ //write the meta element
+ success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
+
+
+ mNumEntries = 0 ;
+ for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter)
{
- llwarns << "Failed to write cache header for entry " << entry->mHandle << " (entry_index = " << entry_index << ")" << llendl;
- delete apr_file;
- return;
+ (*iter)->mIndex = mNumEntries++ ;
+ success = check_write(&apr_file, (void*)*iter, sizeof(HeaderEntryInfo));
}
- }
-
- // Why do we need to fill the cache header with default entries? DK 2010-12-14
- // It looks like we currently rely on the file being pre-allocated so we can seek during updateEntry().
- if(entry_index < mCacheSize)
- {
- HeaderEntryInfo* entry = new HeaderEntryInfo() ;
- for(; entry_index < mCacheSize; ++entry_index)
+
+ mNumEntries = mHeaderEntryQueue.size() ;
+ if(success && mNumEntries < MAX_NUM_OBJECT_ENTRIES)
{
- //fill the cache with the default entry.
- if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo)))
+ HeaderEntryInfo* entry = new HeaderEntryInfo() ;
+ entry->mTime = INVALID_TIME ;
+ for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++)
{
- llwarns << "Failed to fill cache header with default entries (entry_index = " << entry_index << "). Switching to read-only mode." << llendl;
- mReadOnly = TRUE ; //disable the cache.
- break;
+ //fill the cache with the default entry.
+ success = check_write(&apr_file, entry, sizeof(HeaderEntryInfo)) ;
+
}
+ delete entry ;
}
- delete entry ;
}
- delete apr_file ;
+
+ if(!success)
+ {
+ clearCacheInMemory() ;
+ mReadOnly = TRUE ; //disable the cache.
+ }
+ return ;
}
BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
{
- LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_FOPEN_WRITE|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
- apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
+ LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+ apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
- BOOL result = checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
- delete apr_file;
- return result;
+ return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
}
void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)
@@ -557,76 +601,66 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca return ;
}
- std::string filename;
- getObjectCacheFilename(handle, filename);
- LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_READ|APR_FOPEN_BINARY, mLocalAPRFilePoolp);
-
- LLUUID cache_id ;
- if(!checkRead(apr_file, cache_id.mData, UUID_BYTES))
- {
- llwarns << "Error reading cache_id from " << filename << llendl;
- delete apr_file;
- return ;
- }
- if(cache_id != id)
+ bool success = true ;
{
- llwarns << "Cache ID (" << cache_id << ") doesn't match id for this region (" << id << "), discarding. handle = " << handle << llendl;
- delete apr_file ;
- return ;
- }
+ std::string filename;
+ getObjectCacheFilename(handle, filename);
+ LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+
+ LLUUID cache_id ;
+ success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ;
+
+ if(success)
+ {
+ if(cache_id != id)
+ {
+ llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
+ success = false ;
+ }
- S32 num_entries;
- if(!checkRead(apr_file, &num_entries, sizeof(S32)))
- {
- llwarns << "Error reading num_entries from " << filename << llendl;
- delete apr_file;
- return ;
+ if(success)
+ {
+ S32 num_entries;
+ success = check_read(&apr_file, &num_entries, sizeof(S32)) ;
+
+ for (S32 i = 0; success && i < num_entries; i++)
+ {
+ LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file);
+ if (!entry->getLocalID())
+ {
+ llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
+ delete entry ;
+ success = false ;
+ }
+ cache_entry_map[entry->getLocalID()] = entry;
+ }
+ }
+ }
}
- for (S32 i = 0; i < num_entries; i++)
+ if(!success)
{
- LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file);
- if (!entry->getLocalID())
+ if(cache_entry_map.empty())
{
- llwarns << "Aborting cache file load for " << filename << ", cache file corruption! (entry number = " << i << ")" << llendl;
- delete entry ;
- break;
+ removeEntry(iter->second) ;
}
- cache_entry_map[entry->getLocalID()] = entry;
}
- delete apr_file ;
return ;
}
-void LLVOCache::purgeEntries()
+void LLVOCache::purgeEntries(U32 size)
{
- U32 limit = mCacheSize - (mCacheSize / ENTRIES_PURGE_FACTOR);
- limit = llclamp(limit, (U32)1, mCacheSize);
- // Construct a vector of entries out of the map so we can sort by time.
- std::vector<HeaderEntryInfo*> header_vector;
- handle_entry_map_t::iterator iter_end = mHandleEntryMap.end();
- for (handle_entry_map_t::iterator iter = mHandleEntryMap.begin();
- iter != iter_end;
- ++iter)
- {
- header_vector.push_back(iter->second);
- }
- // Sort by time, oldest first.
- std::sort(header_vector.begin(), header_vector.end(), header_entry_less());
- while(header_vector.size() > limit)
- {
- HeaderEntryInfo* entry = header_vector.front();
-
- removeFromCache(entry->mHandle);
+ while(mHeaderEntryQueue.size() >= size)
+ {
+ header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
+ HeaderEntryInfo* entry = *iter ;
mHandleEntryMap.erase(entry->mHandle);
- header_vector.erase(header_vector.begin());
+ mHeaderEntryQueue.erase(iter) ;
+ removeFromCache(entry) ;
delete entry;
}
-
- writeCacheHeader() ;
- // *TODO: Verify that we can avoid re-reading the cache header. DK 2010-12-14
- readCacheHeader() ;
+ mNumEntries = mHandleEntryMap.size() ;
}
void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache)
@@ -642,31 +676,34 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: {
llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl;
return ;
- }
+ }
- U32 num_handle_entries = mHandleEntryMap.size();
-
HeaderEntryInfo* entry;
handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
if(iter == mHandleEntryMap.end()) //new entry
- {
- if(num_handle_entries >= mCacheSize)
+ {
+ if(mNumEntries >= mCacheSize - 1)
{
- purgeEntries() ;
- num_handle_entries = mHandleEntryMap.size();
+ purgeEntries(mCacheSize - 1) ;
}
-
+
entry = new HeaderEntryInfo();
entry->mHandle = handle ;
entry->mTime = time(NULL) ;
- entry->mIndex = num_handle_entries++;
+ entry->mIndex = mNumEntries++;
+ mHeaderEntryQueue.insert(entry) ;
mHandleEntryMap[handle] = entry ;
}
else
{
// Update access time.
- entry = iter->second ;
+ entry = iter->second ;
+
+ //resort
+ mHeaderEntryQueue.erase(entry) ;
+
entry->mTime = time(NULL) ;
+ mHeaderEntryQueue.insert(entry) ;
}
//update cache header
@@ -683,37 +720,33 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: }
//write to cache file
- std::string filename;
- getObjectCacheFilename(handle, filename);
- LLAPRFile* apr_file = new LLAPRFile(filename, APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_BINARY|APR_FOPEN_TRUNCATE, mLocalAPRFilePoolp);
-
- if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES))
+ bool success = true ;
{
- llwarns << "Error writing id to " << filename << llendl;
- delete apr_file;
- return ;
- }
+ std::string filename;
+ getObjectCacheFilename(handle, filename);
+ LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+
+ success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ;
- S32 num_entries = cache_entry_map.size() ;
- if(!checkWrite(apr_file, &num_entries, sizeof(S32)))
- {
- llwarns << "Error writing num_entries to " << filename << llendl;
- delete apr_file;
- return ;
+
+ if(success)
+ {
+ S32 num_entries = cache_entry_map.size() ;
+ success = check_write(&apr_file, &num_entries, sizeof(S32));
+
+ for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter)
+ {
+ success = iter->second->writeToFile(&apr_file) ;
+ }
+ }
}
- for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); iter != cache_entry_map.end(); ++iter)
+ if(!success)
{
- if(!iter->second->writeToFile(apr_file))
- {
- llwarns << "Aborting cache file write for " << filename << ", error writing to file!" << llendl;
- //failed
- removeCache() ;
- break;
- }
+ removeEntry(entry) ;
+
}
- delete apr_file ;
return ;
}
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index e103007979..14e3b4c793 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -95,13 +95,15 @@ private: { bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const { - if (lhs->mTime == rhs->mTime) + if(lhs->mTime == rhs->mTime) { - return lhs->mHandle < rhs->mHandle; + return lhs < rhs ; } - return lhs->mTime < rhs->mTime; // older entry in front + + return lhs->mTime < rhs->mTime ; // older entry in front of queue (set) } }; + typedef std::set<HeaderEntryInfo*, header_entry_less> header_entry_queue_t; typedef std::map<U64, HeaderEntryInfo*> handle_entry_map_t; private: LLVOCache() ; @@ -114,6 +116,7 @@ public: void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) ; + void removeEntry(U64 handle) ; void setReadOnly(BOOL read_only) {mReadOnly = read_only;} @@ -121,15 +124,14 @@ private: void setDirNames(ELLPath location); // determine the cache filename for the region from the region handle void getObjectCacheFilename(U64 handle, std::string& filename); - void removeFromCache(U64 handle); + void removeFromCache(HeaderEntryInfo* entry); void readCacheHeader(); void writeCacheHeader(); void clearCacheInMemory(); void removeCache() ; - void purgeEntries(); + void removeEntry(HeaderEntryInfo* entry) ; + void purgeEntries(U32 size); BOOL updateEntry(const HeaderEntryInfo* entry); - BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ; - BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes, bool remove_cache_on_error = true) ; private: BOOL mEnabled; @@ -137,9 +139,11 @@ private: BOOL mReadOnly ; HeaderMetaInfo mMetaInfo; U32 mCacheSize; + U32 mNumEntries; std::string mHeaderFileName ; std::string mObjectCacheDirName; LLVolatileAPRPool* mLocalAPRFilePoolp ; + header_entry_queue_t mHeaderEntryQueue; handle_entry_map_t mHandleEntryMap; static LLVOCache* sInstance ; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 5277e073a3..fe48bf5493 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -399,10 +399,12 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // There's something bogus in the data that we're unpacking.
dp->dumpBufferToLog();
llwarns << "Flushing cache files" << llendl;
- std::string mask;
- mask = gDirUtilp->getDirDelimiter() + "*.slc";
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), mask);
-// llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl;
+
+ if(LLVOCache::hasInstance() && getRegion())
+ {
+ LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ;
+ }
+
llwarns << "Bogus TE data in " << getID() << llendl;
}
else
@@ -678,12 +680,33 @@ void LLVOVolume::updateTextures() }
}
+BOOL LLVOVolume::isVisible() const
+{
+ if(mDrawable.notNull() && mDrawable->isVisible())
+ {
+ return TRUE ;
+ }
+
+ if(isAttachment())
+ {
+ LLViewerObject* objp = (LLViewerObject*)getParent() ;
+ while(objp && !objp->isAvatar())
+ {
+ objp = (LLViewerObject*)objp->getParent() ;
+ }
+
+ return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ;
+ }
+
+ return FALSE ;
+}
+
void LLVOVolume::updateTextureVirtualSize()
{
LLFastTimer ftm(FTM_VOLUME_TEXTURES);
// Update the pixel area of all faces
- if(mDrawable.isNull() || !mDrawable->isVisible())
+ if(!isVisible())
{
return ;
}
@@ -936,6 +959,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo {
LLVolumeParams volume_params = params_in;
+ S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
S32 lod = mLOD;
BOOL is404 = FALSE;
@@ -1014,7 +1038,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo {
//load request not yet issued, request pipeline load this mesh
LLUUID asset_id = volume_params.getSculptID();
- S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod);
+ S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod);
if (available_lod != lod)
{
LLPrimitive::setVolume(volume_params, available_lod);
@@ -1075,7 +1099,6 @@ void LLVOVolume::notifyMeshLoaded() {
mSculptChanged = TRUE;
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
- dirtySpatialGroup(TRUE);
}
// sculpt replaces generate() for sculpted surfaces
@@ -1228,7 +1251,7 @@ BOOL LLVOVolume::updateLOD() mLODChanged = TRUE;
}
- lod_changed |= LLViewerObject::updateLOD();
+ lod_changed = lod_changed || LLViewerObject::updateLOD();
return lod_changed;
}
@@ -1608,6 +1631,17 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) regenFaces();
}
genBBoxes(FALSE);
+
+ if (mSculptChanged)
+ { //changes in sculpt maps can thrash an object bounding box without
+ //triggering a spatial group bounding box update -- force spatial group
+ //to update bounding boxes
+ LLSpatialGroup* group = mDrawable->getSpatialGroup();
+ if (group)
+ {
+ group->unbound();
+ }
+ }
}
}
}
@@ -1632,7 +1666,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) mLODChanged = FALSE;
mSculptChanged = FALSE;
mFaceMappingChanged = FALSE;
-
+
return LLViewerObject::updateGeometry(drawable);
}
@@ -2871,14 +2905,7 @@ void LLVOVolume::updateRadius() BOOL LLVOVolume::isAttachment() const
{
- if (mState == 0)
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
+ return mState != 0 ;
}
BOOL LLVOVolume::isHUDAttachment() const
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 9e1d0328a9..5af88c6cbd 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -116,6 +116,7 @@ public: void animateTextures(); /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + BOOL isVisible() const ; /*virtual*/ BOOL isActive() const; /*virtual*/ BOOL isAttachment() const; /*virtual*/ BOOL isRootEdit() const; // overridden for sake of attachments treating themselves as a root object diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index a49dc1b59d..66a6ab5e94 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -287,6 +287,9 @@ BOOL LLPanelBodyPartsListItem::postBuild() addWidgetToRightSide("btn_lock"); addWidgetToRightSide("btn_edit_panel"); + setWidgetsVisible(false); + reshapeWidgets(); + return TRUE; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c1b3ad99b2..ec3d0c10ab 100644..100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -330,6 +330,8 @@ LLPipeline::LLPipeline() : mRenderDebugFeatureMask(0), mRenderDebugMask(0), mOldRenderDebugMask(0), + mGroupQ1Locked(false), + mGroupQ2Locked(false), mLastRebuildPool(NULL), mAlphaPool(NULL), mSkyPool(NULL), @@ -2118,6 +2120,7 @@ void LLPipeline::rebuildPriorityGroups() gMeshRepo.notifyLoadedMeshes(); + mGroupQ1Locked = true; // Iterate through all drawables on the priority build queue, for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin(); iter != mGroupQ1.end(); ++iter) @@ -2128,11 +2131,18 @@ void LLPipeline::rebuildPriorityGroups() } mGroupQ1.clear(); + mGroupQ1Locked = false; } void LLPipeline::rebuildGroups() { + if (mGroupQ2.empty()) + { + return; + } + + mGroupQ2Locked = true; // Iterate through some drawables on the non-priority build queue S32 size = (S32) mGroupQ2.size(); S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size); @@ -2142,33 +2152,30 @@ void LLPipeline::rebuildGroups() std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency()); LLSpatialGroup::sg_vector_t::iterator iter; + LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin(); + for (iter = mGroupQ2.begin(); - iter != mGroupQ2.end(); ++iter) + iter != mGroupQ2.end() && count <= min_count; ++iter) { LLSpatialGroup* group = *iter; + last_iter = iter; - if (group->isDead()) + if (!group->isDead()) { - continue; + group->rebuildGeom(); + + if (group->mSpatialPartition->mRenderByGroup) + { + count++; + } } - group->rebuildGeom(); - - if (group->mSpatialPartition->mRenderByGroup) - { - count++; - } - group->clearState(LLSpatialGroup::IN_BUILD_Q2); - - if (count > min_count) - { - ++iter; - break; - } } - mGroupQ2.erase(mGroupQ2.begin(), iter); + mGroupQ2.erase(mGroupQ2.begin(), ++last_iter); + + mGroupQ2Locked = false; updateMovedList(mMovedBridge); } @@ -2288,7 +2295,7 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable; llassert(root); // trying to catch a bad assumption if (root && // // this test may not be needed, see above - root->getVObj()->isAttachment()) + root->getVObj()->isAttachment()) { LLDrawable* rootparent = root->getParent(); if (rootparent) // this IS sometimes NULL @@ -2463,6 +2470,8 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) { if (!group->isState(LLSpatialGroup::IN_BUILD_Q1)) { + llassert_always(!mGroupQ1Locked); + mGroupQ1.push_back(group); group->setState(LLSpatialGroup::IN_BUILD_Q1); @@ -2479,11 +2488,7 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) } else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) { - //llerrs << "Non-priority updates not yet supported!" << llendl; - if (std::find(mGroupQ2.begin(), mGroupQ2.end(), group) != mGroupQ2.end()) - { - llerrs << "WTF?" << llendl; - } + llassert_always(!mGroupQ2Locked); mGroupQ2.push_back(group); group->setState(LLSpatialGroup::IN_BUILD_Q2); @@ -2495,11 +2500,6 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f { LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD); - if (drawablep) - { - LLVOVolume* volume = drawablep->getVOVolume(); - } - if (drawablep && !drawablep->isDead() && assertInitialized()) { if (!drawablep->isState(LLDrawable::BUILT)) @@ -2568,6 +2568,42 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } } } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { + LLSpatialGroup* last_group = NULL; + for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + { + LLCullResult::bridge_list_t::iterator cur_iter = i; + LLSpatialBridge* bridge = *cur_iter; + LLSpatialGroup* group = bridge->getSpatialGroup(); + + if (last_group == NULL) + { + last_group = group; + } + + if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + stateSort(bridge, camera); + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + last_group != group && last_group->changeLOD()) + { + last_group->mLastUpdateDistance = last_group->mDistance; + } + + last_group = group; + } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && + last_group && last_group->changeLOD()) + { + last_group->mLastUpdateDistance = last_group->mDistance; + } + } + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { LLSpatialGroup* group = *iter; @@ -2583,19 +2619,6 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } } - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) - { - for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLCullResult::bridge_list_t::iterator cur_iter = i; - LLSpatialBridge* bridge = *cur_iter; - LLSpatialGroup* group = bridge->getSpatialGroup(); - if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - stateSort(bridge, camera); - } - } - } { LLFastTimer ftm(FTM_STATESORT_DRAWABLE); for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); @@ -2626,6 +2649,11 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) LLDrawable* drawablep = *i; stateSort(drawablep, camera); } + + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + { //avoid redundant stateSort calls + group->mLastUpdateDistance = group->mDistance; + } } } @@ -2692,21 +2720,17 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) { - LLSpatialGroup* group = drawablep->getSpatialGroup(); - if (!group || group->changeLOD()) + if (drawablep->isVisible()) { - if (drawablep->isVisible()) + if (!drawablep->isActive()) { - if (!drawablep->isActive()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); - } - else if (drawablep->isAvatar()) - { - bool force_update = false; - drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() - } + bool force_update = false; + drawablep->updateDistance(camera, force_update); + } + else if (drawablep->isAvatar()) + { + bool force_update = false; + drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility() } } } @@ -4196,13 +4220,19 @@ void LLPipeline::renderDebug() if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE) { U32 count = 0; - U32 size = mBuildQ2.size(); + U32 size = mGroupQ2.size(); LLColor4 col; + LLVertexBuffer::unbind(); LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); LLGLDepthTest depth(GL_TRUE, GL_FALSE); gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); + gGL.pushMatrix(); + glLoadMatrixd(gGLModelView); + gGLLastMatrix = NULL; + for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter) { LLSpatialGroup* group = *iter; @@ -4224,7 +4254,7 @@ void LLPipeline::renderDebug() glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); } - F32 alpha = (F32) (size-count)/size; + F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f); LLVector2 c(1.f-alpha, alpha); @@ -4232,7 +4262,7 @@ void LLPipeline::renderDebug() ++count; - col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.1f); + col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f); group->drawObjectBox(col); if (bridge) @@ -4242,6 +4272,7 @@ void LLPipeline::renderDebug() } } + gGL.popMatrix(); gGL.flush(); gPipeline.renderPhysicsDisplay(); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 7ae83e9816..0eb020605e 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -632,6 +632,8 @@ protected: LLDrawable::drawable_list_t mBuildQ2; // non-priority LLSpatialGroup::sg_vector_t mGroupQ1; //priority LLSpatialGroup::sg_vector_t mGroupQ2; // non-priority + bool mGroupQ2Locked; + bool mGroupQ1Locked; LLViewerObject::vobj_list_t mCreateQ; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index d351c442d3..10aeef7c8a 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -123,6 +123,7 @@ with the same filename but different name <texture name="ComboButton_Selected" file_name="widgets/ComboButton_Selected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> <texture name="ComboButton_UpSelected" file_name="widgets/ComboButton_UpSelected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> <texture name="ComboButton_Up_On_Selected" file_name="widgets/ComboButton_Up_On_Selected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> + <texture name="ComboButton_On" file_name="widgets/ComboButton_On.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> <texture name="ComboButton_Off" file_name="widgets/ComboButton_Off.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> <texture name="ComboButton_UpOff" file_name="widgets/ComboButton_UpOff.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" /> <texture name="Container" file_name="containers/Container.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/da/notifications.xml b/indra/newview/skins/default/xui/da/notifications.xml index 593e686d4c..27024f4eaa 100644 --- a/indra/newview/skins/default/xui/da/notifications.xml +++ b/indra/newview/skins/default/xui/da/notifications.xml @@ -1580,9 +1580,6 @@ Klik på Acceptér for at deltage eller Afvis for at afvise invitationen. Klik p <notification name="VoiceCallGenericError"> En fejl er opstået under forsøget på at koble sig på stemme chatten [VOICE_CHANNEL_NAME]. Pråv venligst senere. </notification> - <notification name="ServerVersionChanged"> - Du er netop ankommet til en region der benytter en anden server version, hvilket kan influere på hastigheden. [[URL] For at se yderligere.] - </notification> <notification name="UnsupportedCommandSLURL"> Den SLurl du klikkede på understøttes ikke. </notification> diff --git a/indra/newview/skins/default/xui/da/panel_people.xml b/indra/newview/skins/default/xui/da/panel_people.xml index 599686d360..b85a33279a 100644 --- a/indra/newview/skins/default/xui/da/panel_people.xml +++ b/indra/newview/skins/default/xui/da/panel_people.xml @@ -1,23 +1,23 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <!-- Side tray panel --> <panel label="Personer" name="people_panel"> - <string name="no_recent_people" value="Ingen tidligere personer. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Search] eller [secondlife:///app/worldmap World Map]."/> - <string name="no_filtered_recent_people" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search]."/> - <string name="no_one_near" value="Ingen i nærheden. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Search] eller [secondlife:///app/worldmap World Map]."/> - <string name="no_one_filtered_near" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search]."/> + <string name="no_recent_people" value="Ingen tidligere personer. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Søg] eller [secondlife:///app/worldmap Verdenskort]."/> + <string name="no_filtered_recent_people" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Søg]."/> + <string name="no_one_near" value="Ingen i nærheden. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Søg] eller [secondlife:///app/worldmap Verdenskort]."/> + <string name="no_one_filtered_near" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Søg]."/> <string name="no_friends_online" value="Ingen venner online"/> <string name="no_friends" value="Ingen venner"/> <string name="no_friends_msg"> - Find venner via [secondlife:///app/search/people Search] eller højre-klik på en beboer og tilføj dem som venner. -Leder du efter nogen at være sammen med? Prøv [secondlife:///app/worldmap World Map]. + Find venner via [secondlife:///app/search/people Søg] eller højre-klik på en beboer og tilføj dem som venner. +Leder du efter nogen at være sammen med? Prøv [secondlife:///app/worldmap Verdenskort]. </string> <string name="no_filtered_friends_msg"> - Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search]. + Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Søg]. </string> <string name="people_filter_label" value="Filtrér personer"/> <string name="groups_filter_label" value="Filtrér grupper"/> - <string name="no_filtered_groups_msg" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/groups/[SEARCH_TERM] Search]."/> - <string name="no_groups_msg" value="Leder du efter grupper at være med i? Prøv [secondlife:///app/search/groups Search]."/> + <string name="no_filtered_groups_msg" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/groups/[SEARCH_TERM] Søg]."/> + <string name="no_groups_msg" value="Leder du efter grupper at være med i? Prøv [secondlife:///app/search/groups Søg]."/> <filter_editor label="Filtrér" name="filter_input"/> <tab_container name="tabs"> <panel label="TÆT PÅ" name="nearby_panel"> diff --git a/indra/newview/skins/default/xui/de/floater_web_content.xml b/indra/newview/skins/default/xui/de/floater_web_content.xml new file mode 100644 index 0000000000..6ab119eeab --- /dev/null +++ b/indra/newview/skins/default/xui/de/floater_web_content.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="floater_web_content" title=""> + <layout_stack name="stack1"> + <layout_panel name="nav_controls"> + <button name="back" tool_tip="Rückwärts"/> + <button name="forward" tool_tip="Vorwärts"/> + <button name="stop" tool_tip="Navigation stoppen"/> + <button name="reload" tool_tip="Seite neu laden"/> + <combo_box name="address" tool_tip="URL hier eingeben"/> + <icon name="media_secure_lock_flag" tool_tip="Sicheres Browsen"/> + <button name="popexternal" tool_tip="Aktuelle URL im Desktop-Browser öffnen"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/de/menu_login.xml b/indra/newview/skins/default/xui/de/menu_login.xml index 70d31f93de..a373e15338 100644 --- a/indra/newview/skins/default/xui/de/menu_login.xml +++ b/indra/newview/skins/default/xui/de/menu_login.xml @@ -17,7 +17,8 @@ <menu_item_call label="Fenstergröße einstellen..." name="Set Window Size..."/> <menu_item_call label="Servicebedingungen anzeigen" name="TOS"/> <menu_item_call label="Wichtige Meldung anzeigen" name="Critical"/> - <menu_item_call label="Web-Browser-Test" name="Web Browser Test"/> + <menu_item_call label="Test Medienbrowser" name="Web Browser Test"/> + <menu_item_call label="Test Webinhalt-Floater" name="Web Content Floater Test"/> <menu_item_check label="Grid-Auswahl anzeigen" name="Show Grid Picker"/> <menu_item_call label="Benachrichtigungs-Konsole anzeigen" name="Show Notifications Console"/> </menu> diff --git a/indra/newview/skins/default/xui/de/menu_mini_map.xml b/indra/newview/skins/default/xui/de/menu_mini_map.xml index bec79be34d..2e0d72c40c 100644 --- a/indra/newview/skins/default/xui/de/menu_mini_map.xml +++ b/indra/newview/skins/default/xui/de/menu_mini_map.xml @@ -3,6 +3,7 @@ <menu_item_call label="Zoom Nah" name="Zoom Close"/> <menu_item_call label="Zoom Mittel" name="Zoom Medium"/> <menu_item_call label="Zoom Weit" name="Zoom Far"/> + <menu_item_call label="Zoom-Standard" name="Zoom Default"/> <menu_item_check label="Karte drehen" name="Rotate Map"/> <menu_item_check label="Automatisch zentrieren" name="Auto Center"/> <menu_item_call label="Verfolgung abschalten" name="Stop Tracking"/> diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index 9eeeaccdea..4a043e1233 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -121,13 +121,15 @@ <menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/> <menu_item_call label="Mehrfach-Upload ([COST] L$ pro Datei)..." name="Bulk Upload"/> </menu> + <menu_item_call label="Rückgängig" name="Undo"/> + <menu_item_call label="Wiederholen" name="Redo"/> </menu> <menu label="Hilfe" name="Help"> <menu_item_call label="[SECOND_LIFE]-Hilfe" name="Second Life Help"/> + <menu_item_check label="Hinweise aktivieren" name="Enable Hints"/> <menu_item_call label="Missbrauch melden" name="Report Abuse"/> <menu_item_call label="Fehler melden" name="Report Bug"/> <menu_item_call label="INFO ÜBER [APP_NAME]" name="About Second Life"/> - <menu_item_check label="Hinweise aktivieren" name="Enable Hints"/> </menu> <menu label="Erweitert" name="Advanced"> <menu_item_call label="Textur neu laden" name="Rebake Texture"/> @@ -308,7 +310,8 @@ <menu_item_call label="Regionsobjekt-Cache ausgeben" name="Dump Region Object Cache"/> </menu> <menu label="UI" name="UI"> - <menu_item_call label="Web-Browser-Test" name="Web Browser Test"/> + <menu_item_call label="Test Medienbrowser" name="Web Browser Test"/> + <menu_item_call label="Webinhaltsbrowser" name="Web Content Browser"/> <menu_item_call label="SelectMgr ausgeben" name="Dump SelectMgr"/> <menu_item_call label="Inventarinfo ausgeben" name="Dump Inventory"/> <menu_item_call label="Timer ausgeben" name="Dump Timers"/> diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index a2d0b5a170..b0ad989a59 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -109,6 +109,10 @@ Wählen Sie ein einzelnes Objekt aus und versuchen Sie es erneut. Leute, die nicht auf Ihrer Freundesliste stehen, werden nicht wissen, dass Sie deren Anrufe oder Sofortnachrichten ignoriert haben. <usetemplate name="okbutton" yestext="Ja"/> </notification> + <notification name="FavoritesOnLogin"> + Hinweis: Bei Aktivierung dieser Option sehen alle Personen, die diesen Computer benutzen, Ihre Lieblingsorte. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="GrantModifyRights"> Wenn Sie einem anderen Einwohner Änderungsrechte gewähren, dann kann dieser JEDES Objekt, das Sie inworld besitzen, ändern, löschen oder an sich nehmen. Seien Sie daher beim Gewähren dieser Rechte sehr vorsichtig! Möchten Sie [NAME] Änderungsrechte gewähren? @@ -957,7 +961,7 @@ Sie sind nicht berechtigt, Land für die aktive Gruppe zu kaufen. <input name="message"> [DESC] (neu) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Abbrechen"/> </form> </notification> @@ -967,7 +971,7 @@ Sie sind nicht berechtigt, Land für die aktive Gruppe zu kaufen. <input name="message"> [DESC] (neu) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Abbrechen"/> </form> </notification> @@ -977,7 +981,7 @@ Sie sind nicht berechtigt, Land für die aktive Gruppe zu kaufen. <input name="new_name"> [NAME] </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Abbrechen"/> </form> </notification> @@ -1355,9 +1359,39 @@ In Ihren Anwendungsordner herunterladen? Laden Sie den neuesten Viewer von http://secondlife.com/download herunter und installieren Sie ihn. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="DownloadBackground"> - Eine aktualisierte Version von [APP_NAME] wurde heruntergeladen. -Sie wird beim nächsten Neustart von [APP_NAME] verwendet. + <notification name="FailedRequiredUpdateInstall"> + Ein erforderliches Update konnte nicht installiert werden. +Sie können sich erst anmelden, wenn [APP_NAME] aktualisiert wurde. + +Laden Sie den neuesten Viewer von http://secondlife.com/download herunter und installieren Sie ihn. + <usetemplate name="okbutton" yestext="Beenden"/> + </notification> + <notification name="UpdaterServiceNotRunning"> + Für Ihre SecondLife-Installation ist ein Update erforderlich. + +Sie können dieses Update von http://www.secondlife.com/downloads herunterladen oder jetzt installieren. + <usetemplate name="okcancelbuttons" notext="Second Life beenden" yestext="Jetzt herunterladen und installieren"/> + </notification> + <notification name="DownloadBackgroundTip"> + Für Ihre [APP_NAME]-Installation wurde ein Update heruntergeladen. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Informationen zu diesem Update] + <usetemplate name="okcancelbuttons" notext="Später..." yestext="Jetzt installieren und [APP_NAME] neu starten"/> + </notification> + <notification name="DownloadBackgroundDialog"> + Für Ihre [APP_NAME]-Installation wurde ein Update heruntergeladen. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Informationen zu diesem Update] + <usetemplate name="okcancelbuttons" notext="Später..." yestext="Jetzt installieren und [APP_NAME] neu starten"/> + </notification> + <notification name="RequiredUpdateDownloadedVerboseDialog"> + Ein erforderliches Softwareupdate wurde heruntergeladen. +Version [VERSION] + +Zur Installation des Updates muss [APP_NAME] neu gestartet werden. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="RequiredUpdateDownloadedDialog"> + Zur Installation des Updates muss [APP_NAME] neu gestartet werden. + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="DeedObjectToGroup"> Bei Übertragung dieses Objekts erhält die Gruppe: @@ -2225,14 +2259,6 @@ Wählen Sie eine kleinere Landfläche. <notification name="NoContentToSearch"> Bitte wählen Sie mindestens eine Inhaltsart für die Suche aus (Generell, Moderat oder Adult). </notification> - <notification name="GroupVote"> - [NAME] hat eine Abstimmung vorgeschlagen über: -[MESSAGE] - <form name="form"> - <button name="VoteNow" text="Abstimmen"/> - <button name="Later" text="Später"/> - </form> - </notification> <notification name="SystemMessage"> [MESSAGE] </notification> @@ -2691,9 +2717,6 @@ Klicken Sie auf 'Akzeptieren ', um dem Chat beizutreten, oder auf &a <notification name="VoiceCallGenericError"> Fehler beim Versuch, eine Voice-Chat-Verbindung zu [VOICE_CHANNEL_NAME] herzustellen. Bitte versuchen Sie es erneut. </notification> - <notification name="ServerVersionChanged"> - Sie haben eine Region betreten, die eine andere Server-Version verwendet. Dies kann sich auf die Leistung auswirken. [[URL] Versionshinweise anzeigen.] - </notification> <notification name="UnsupportedCommandSLURL"> Die SLurl, auf die Sie geklickt haben, wird nicht unterstützt. </notification> @@ -2796,9 +2819,7 @@ Avatar '[NAME]' hat Modus „Aussehen bearbeiten" verlassen. <notification name="NoConnect"> Es gibt Probleme mit der Verbindung mit [PROTOCOL] [HOSTID]. Bitte überprüfen Sie Ihre Netzwerk- und Firewalleinstellungen. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="NoVoiceConnect"> Verbindung mit Voice-Server ist leider nicht möglich: @@ -2807,9 +2828,7 @@ Bitte überprüfen Sie Ihre Netzwerk- und Firewalleinstellungen. Voice-Kommunikation ist leider nicht verfügbar. Bitte überprüfen Sie Ihr Netzwerk- und Firewall-Setup. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="AvatarRezLeftNotification"> (Seit [EXISTENCE] Sekunden inworld ) @@ -2844,6 +2863,9 @@ Alle stummschalten? <notification label="Welt erkunden" name="HintDestinationGuide"> Im Reiseführer finden Sie Tausende von interessanten Orten. Wählen Sie einfach einen Ort aus und klicken Sie auf „Teleportieren“. </notification> + <notification label="Aussehen ändern" name="HintAvatarPicker"> + Möchten Sie einen neuen Look ausprobieren? Klicken Sie auf die Schaltfläche unten, um mehr Avatare zu sehen. + </notification> <notification label="Seitenleiste" name="HintSidePanel"> In der Seitenleiste können Sie schnell auf Ihr Inventar, Ihre Outfits, Ihre Profile u. ä. zugreifen. </notification> @@ -2853,6 +2875,12 @@ Alle stummschalten? <notification label="Anzeigename" name="HintDisplayName"> Hier können Sie Ihren anpassbaren Anzeigenamen festlegen. Der Anzeigename unterscheidet sich von Ihrem eindeutigen Benutzernamen, der nicht geändert werden kann. In den Einstellungen können Sie festlegen, welcher Name von anderen Einwohnern angezeigt wird. </notification> + <notification label="Bewegen" name="HintMoveArrows"> + Verwenden Sie zum Gehen die Pfeiltasten auf Ihrer Tastatur. Drücken Sie die Nach-oben-Taste zweimal, um zu rennen. + </notification> + <notification label="Ansicht" name="HintView"> + Um die Kameraansicht zu ändern, verwenden Sie die Schwenk- und Kreissteuerungen. Um die Ansicht zurückzusetzen, drücken Sie die Esc-Taste oder laufen Sie einfach. + </notification> <notification label="Inventar" name="HintInventory"> In Ihrem Inventar befinden sich verschiedene Objekte. Die neuesten Objekte finden Sie in der Registerkarte „Aktuell“. </notification> @@ -2866,6 +2894,15 @@ Alle stummschalten? <button name="open" text="Popup-Fenster öffnen"/> </form> </notification> + <notification name="AuthRequest"> + Für die Site „<nolink>[HOST_NAME]</nolink>“ in der Domäne „[REALM]“ ist ein Benutzername und Kennwort erforderlich. + <form name="form"> + <input name="username" text="Benutzername"/> + <input name="password" text="Kennwort"/> + <button name="ok" text="Senden"/> + <button name="cancel" text="Abbrechen"/> + </form> + </notification> <global name="UnsupportedCPU"> - Ihre CPU-Geschwindigkeit entspricht nicht den Mindestanforderungen. </global> diff --git a/indra/newview/skins/default/xui/de/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/de/panel_avatar_list_item.xml index 2db8cf7c09..dcfcffa6e2 100644 --- a/indra/newview/skins/default/xui/de/panel_avatar_list_item.xml +++ b/indra/newview/skins/default/xui/de/panel_avatar_list_item.xml @@ -21,7 +21,7 @@ <string name="FormatYears"> [COUNT]J </string> - <text name="avatar_name" value="Unbekannt"/> + <text name="avatar_name" value="(laden)"/> <text name="last_interaction" value="0s"/> <icon name="permission_edit_theirs_icon" tool_tip="Sie können die Objekte dieses Freunds bearbeiten"/> <icon name="permission_edit_mine_icon" tool_tip="Dieser Freund kann Ihre Objekte bearbeiten, löschen und an sich nehmen"/> diff --git a/indra/newview/skins/default/xui/de/panel_edit_alpha.xml b/indra/newview/skins/default/xui/de/panel_edit_alpha.xml index 4b48950341..4c6facf5e3 100644 --- a/indra/newview/skins/default/xui/de/panel_edit_alpha.xml +++ b/indra/newview/skins/default/xui/de/panel_edit_alpha.xml @@ -1,10 +1,12 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_alpha_panel"> - <panel name="avatar_alpha_color_panel"> - <texture_picker label="Alpha: Unten" name="Lower Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/> - <texture_picker label="Alpha: Oben" name="Upper Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/> - <texture_picker label="Kopf: Alpha" name="Head Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/> - <texture_picker label="Alpha: Augen" name="Eye Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/> - <texture_picker label="Alpha: Haare" name="Hair Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/> - </panel> + <scroll_container name="avatar_alpha_color_panel_scroll"> + <panel name="avatar_alpha_color_panel"> + <texture_picker label="Alpha: Unten" name="Lower Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Alpha: Oben" name="Upper Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Alpha: Kopf" name="Head Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Alpha: Augen" name="Eye Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/> + <texture_picker label="Alpha: Haare" name="Hair Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/de/panel_login.xml b/indra/newview/skins/default/xui/de/panel_login.xml index 0fc4fa7117..1bee6b1ead 100644 --- a/indra/newview/skins/default/xui/de/panel_login.xml +++ b/indra/newview/skins/default/xui/de/panel_login.xml @@ -11,7 +11,7 @@ <text name="username_text"> Benutzername: </text> - <line_editor label="berndschmidt12 oder Liebe Sonne" name="username_edit" tool_tip="Bei der Registrierung gewählter Benutzername wie „berndschmidt12“ oder „Liebe Sonne“"/> + <combo_box name="username_combo" tool_tip="Bei der Registrierung gewählter Benutzername wie „berndschmidt12“ oder „Liebe Sonne“"/> <text name="password_text"> Kennwort: </text> diff --git a/indra/newview/skins/default/xui/de/panel_my_profile.xml b/indra/newview/skins/default/xui/de/panel_my_profile.xml index aea87cc2c4..89a4dfdaba 100644 --- a/indra/newview/skins/default/xui/de/panel_my_profile.xml +++ b/indra/newview/skins/default/xui/de/panel_my_profile.xml @@ -16,34 +16,27 @@ <string name="RegisterDateFormat"> [REG_DATE] ([AGE]) </string> + <string name="name_text_args"> + [NAME] + </string> + <string name="display_name_text_args"> + [DISPLAY_NAME] + </string> <layout_stack name="layout"> <layout_panel name="profile_stack"> <scroll_container name="profile_scroll"> <panel name="scroll_content_panel"> <panel name="second_life_image_panel"> - <icon label="" name="2nd_life_edit_icon" tool_tip="Klicken Sie unten auf die Schaltfläche Profil bearbeiten, um das Bild zu ändern."/> - <text name="title_sl_descr_text" value="[SECOND_LIFE]:"/> - </panel> - <panel name="first_life_image_panel"> - <icon label="" name="real_world_edit_icon" tool_tip="Klicken Sie unten auf die Schaltfläche Profil bearbeiten, um das Bild zu ändern."/> - <text name="title_rw_descr_text" value="Echtes Leben:"/> - </panel> - <text name="title_member_text" value="Einwohner seit:"/> - <text name="title_acc_status_text" value="Kontostatus:"/> - <text_editor name="acc_status_text"> - Einwohner. Keine Zahlungsinfo archiviert. - Linden. - </text_editor> - <text name="title_partner_text" value="Partner:"/> - <panel name="partner_data_panel"> - <name_box initial_value="(wird in Datenbank gesucht)" name="partner_text"/> + <text name="display_name_descr_text"> + Benutzername + </text> + <text name="name_descr_text"> + Anzeigename + </text> + <button label="Profil" name="see_profile_btn" tool_tip="Profil zu diesem Avatar anzeigen"/> </panel> - <text name="title_groups_text" value="Gruppen:"/> </panel> </scroll_container> </layout_panel> </layout_stack> - <panel name="profile_me_buttons_panel"> - <button label="Profil bearbeiten" name="edit_profile_btn" tool_tip="Ihre persönlichen Informationen bearbeiten"/> - </panel> </panel> diff --git a/indra/newview/skins/default/xui/de/panel_notify_textbox.xml b/indra/newview/skins/default/xui/de/panel_notify_textbox.xml index 7187be570c..da672a0309 100644 --- a/indra/newview/skins/default/xui/de/panel_notify_textbox.xml +++ b/indra/newview/skins/default/xui/de/panel_notify_textbox.xml @@ -3,8 +3,9 @@ <string name="message_max_lines_count" value="7"/> <panel label="info_panel" name="info_panel"> <text_editor name="message" value="message"/> - parse_urls="false" + </panel> + <panel label="control_panel" name="control_panel"> <button label="Senden" name="btn_submit"/> + <button label="Ignorieren" name="ignore_btn"/> </panel> - <panel label="control_panel" name="control_panel"/> </panel> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_colors.xml b/indra/newview/skins/default/xui/de/panel_preferences_colors.xml index d9e5c7f2b5..22681ffdf2 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_colors.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_colors.xml @@ -29,10 +29,10 @@ URLs </text> <text name="bubble_chat"> - Hintergrund für Blasen-Chat: + Hintergrundfarbe für Avatarnamen (wirkt sich auch auf Blasen-Chat aus): </text> - <color_swatch name="background" tool_tip="Farbe für Blasen-Chat auswählen"/> - <slider label="Deckkraft:" name="bubble_chat_opacity"/> + <color_swatch name="background" tool_tip="Farbe für Avatarnamen auswählen"/> + <slider label="Deckkraft:" name="bubble_chat_opacity" tool_tip="Deckkraft für Avatarnamen auswählen"/> <text name="floater_opacity"> Floater-Deckkraft: </text> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/de/panel_preferences_privacy.xml index d78064833b..b56f150394 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_privacy.xml @@ -7,9 +7,11 @@ <text name="cache_size_label_l"> (Standorte, Bilder, Web, Suchverlauf) </text> + <check_box label="In Suchergebnissen anzeigen" name="online_searchresults"/> <check_box label="Nur Freunde und Gruppen wissen, dass ich online bin" name="online_visibility"/> <check_box label="Nur Freunde und Gruppen können mich anrufen oder mir eine IM schicken" name="voice_call_friends_only_check"/> <check_box label="Mikrofon ausschalten, wenn Anrufe beendet werden" name="auto_disengage_mic_check"/> + <check_box label="Meine Lieblingslandmarken bei Anmeldung anzeigen (im Dropdown-Menü „Hier anfangen“)" name="favorites_on_login_check"/> <text name="Logs:"> Chatprotokolle: </text> diff --git a/indra/newview/skins/default/xui/de/panel_preferences_setup.xml b/indra/newview/skins/default/xui/de/panel_preferences_setup.xml index c4d095dde5..490cead17d 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_setup.xml @@ -39,5 +39,11 @@ </text> <line_editor name="web_proxy_editor" tool_tip="Name oder IP Adresse des Proxyservers, den Sie benutzen möchten"/> <spinner label="Portnummer:" name="web_proxy_port"/> - <check_box initial_value="true" label="Updates für [APP_NAME] automatisch herunterladen und installieren" name="updater_service_active"/> + <text name="Software updates:"> + Softwareupdates: + </text> + <combo_box name="updater_service_combobox"> + <combo_box.item label="Automatisch installieren" name="Install_automatically"/> + <combo_box.item label="Updates manuell herunterladen und installieren" name="Install_manual"/> + </combo_box> </panel> diff --git a/indra/newview/skins/default/xui/de/panel_status_bar.xml b/indra/newview/skins/default/xui/de/panel_status_bar.xml index 005290c1ff..04ed58f944 100644 --- a/indra/newview/skins/default/xui/de/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/de/panel_status_bar.xml @@ -22,7 +22,7 @@ [AMT] L$ </panel.string> <panel name="balance_bg"> - <text name="balance" tool_tip="Mein Kontostand" value="20 L$"/> + <text name="balance" tool_tip="Klicken, um L$-Guthaben zu aktualisieren" value="20 L$"/> <button label="L$ kaufen" name="buyL" tool_tip="Hier klicken, um mehr L$ zu kaufen"/> </panel> <text name="TimeText" tool_tip="Aktuelle Zeit (Pazifik)"> diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml index 6370ff9243..ae99fa8dd5 100644 --- a/indra/newview/skins/default/xui/en/floater_map.xml +++ b/indra/newview/skins/default/xui/en/floater_map.xml @@ -22,7 +22,11 @@ name="ToolTipMsg"> [REGION](Double-click to open Map, shift-drag to pan) </floater.string> - <floater.string name="mini_map_caption"> + <floater.string + name="AltToolTipMsg"> + [REGION](Double-click to teleport, shift-drag to pan) + </floater.string> + <floater.string name="mini_map_caption"> MINIMAP </floater.string> <net_map diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 1554ae390f..60cd82d227 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -928,12 +928,13 @@ length="1" follows="left|top" left_pad="0" - height="30" + height="20" layout="topleft" name="Creator Name" top_delta="0" width="190" - word_wrap="true"> + word_wrap="true" + use_ellipses="ture"> Mrs. Esbee Linden (esbee.linden) </text> <text @@ -944,7 +945,7 @@ height="19" layout="topleft" name="Owner:" - top_pad="3" + top_pad="13" width="90"> Owner: </text> @@ -953,13 +954,14 @@ type="string" length="1" follows="left|top" - height="30" + height="20" layout="topleft" name="Owner Name" left_pad="0" top_delta="0" width="190" - word_wrap="true"> + word_wrap="true" + use_ellipses="true"> Mrs. Erica "Moose" Linden (erica.linden) </text> <text @@ -970,7 +972,7 @@ left="10" height="18" name="Group:" - top_pad="7" + top_pad="17" width="75"> Group: </text> diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml index d90d0feda9..e04a72cbc0 100644 --- a/indra/newview/skins/default/xui/en/floater_web_content.xml +++ b/indra/newview/skins/default/xui/en/floater_web_content.xml @@ -2,26 +2,26 @@ <floater legacy_header_height="18" can_resize="true" - height="440" + height="775" layout="topleft" - min_height="140" - min_width="467" + min_height="400" + min_width="500" name="floater_web_content" help_topic="floater_web_content" save_rect="true" auto_tile="true" title="" initial_mime_type="text/html" - width="820"> + width="780"> <layout_stack - bottom="440" + bottom="775" follows="left|right|top|bottom" layout="topleft" left="5" name="stack1" orientation="vertical" top="20" - width="810"> + width="770"> <layout_panel auto_resize="false" default_tab_group="1" @@ -32,14 +32,14 @@ name="nav_controls" top="400" user_resize="false" - width="800"> + width="770"> <button image_overlay="Arrow_Left_Off" - image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled" - image_selected="PushButton_Selected" - image_unselected="PushButton_Off" - hover_glow_amount="0.15" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" + hover_glow_amount="0.15" tool_tip="Navigate back" follows="left|top" height="22" @@ -53,10 +53,10 @@ </button> <button image_overlay="Arrow_Right_Off" - image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled" - image_selected="PushButton_Selected" - image_unselected="PushButton_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" tool_tip="Navigate forward" follows="left|top" height="22" @@ -70,10 +70,10 @@ </button> <button image_overlay="Stop_Off" - image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled" - image_selected="PushButton_Selected" - image_unselected="PushButton_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" tool_tip="Stop navigation" enabled="true" follows="left|top" @@ -88,10 +88,10 @@ </button> <button image_overlay="Refresh_Off" - image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled" - image_selected="PushButton_Selected" - image_unselected="PushButton_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" tool_tip="Reload page" follows="left|top" height="22" @@ -115,7 +115,7 @@ combo_editor.select_on_focus="true" tool_tip="Enter URL here" top_delta="0" - width="702"> + width="672"> <combo_box.commit_callback function="WebContent.EnterAddress" /> </combo_box> @@ -125,24 +125,24 @@ follows="top|right" image_name="Lock2" layout="topleft" - left_delta="656" + left_delta="620" top_delta="2" visible="false" tool_tip="Secured Browsing" width="16" /> <button image_overlay="ExternalBrowser_Off" - image_disabled="PushButton_Disabled" - image_disabled_selected="PushButton_Disabled" - image_selected="PushButton_Selected" - image_unselected="PushButton_Off" + image_disabled="PushButton_Disabled" + image_disabled_selected="PushButton_Disabled" + image_selected="PushButton_Selected" + image_unselected="PushButton_Off" tool_tip="Open current URL in your desktop browser" follows="right|top" enabled="true" height="22" layout="topleft" name="popexternal" - right="800" + right="770" top_delta="-2" width="22"> <button.commit_callback @@ -156,7 +156,7 @@ name="external_controls" top_delta="0" user_resize="false" - width="540"> + width="585"> <web_browser bottom="-22" follows="all" @@ -166,16 +166,16 @@ top="0"/> <text type="string" - length="100" + length="200" follows="bottom|left" height="20" layout="topleft" left_delta="0" name="statusbartext" parse_urls="false" - text_color="0.4 0.4 0.4 1" + text_color="0.4 0.4 0.4 1" top_pad="5" - width="452"/> + width="495"/> <progress_bar color_bar="0.3 1.0 0.3 1" follows="bottom|right" diff --git a/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml index 58d58a6ca9..76b188220d 100644 --- a/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml @@ -78,7 +78,7 @@ <menu_item_call.on_click function="InspectAvatar.Freeze"/> <menu_item_call.on_visible - function="InspectAvatar.VisibleFreezeEject"/> + function="InspectAvatar.VisibleFreeze"/> </menu_item_call> <menu_item_call label="Eject" @@ -86,7 +86,23 @@ <menu_item_call.on_click function="InspectAvatar.Eject"/> <menu_item_call.on_visible - function="InspectAvatar.VisibleFreezeEject"/> + function="InspectAvatar.VisibleEject"/> + </menu_item_call> + <menu_item_call + label="Kick" + name="kick"> + <menu_item_call.on_click + function="InspectAvatar.Kick"/> + <menu_item_call.on_visible + function="InspectAvatar.EnableGod"/> + </menu_item_call> + <menu_item_call + label="CSR" + name="csr"> + <menu_item_call.on_click + function="InspectAvatar.CSR" /> + <menu_item_call.on_visible + function="InspectAvatar.EnableGod" /> </menu_item_call> <menu_item_call label="Debug Textures" diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index e0e6567872..62db15d456 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -52,7 +52,7 @@ <menu_item_call.on_enable function="File.EnableUploadModel" /> <menu_item_call.on_visible - function="File.MeshEnabled"/> + function="File.VisibleUploadModel"/> </menu_item_call> <menu_item_call label="Bulk (L$[COST] per file)..." diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml index 6f46165883..1aeb166e01 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml @@ -25,6 +25,14 @@ function="Places.LandmarksGear.Enable" parameter="category" /> </menu_item_call> + <menu_item_call + label="Restore Item" + layout="topleft" + name="restore_item"> + <menu_item_call.on_click + function="Places.LandmarksGear.Custom.Action" + parameter="restore" /> + </menu_item_call> <menu_item_separator layout="topleft" /> <menu_item_call diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml index 121e7cc07a..ff5fdd3795 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml @@ -60,6 +60,14 @@ function="Places.LandmarksGear.Enable" parameter="category" /> </menu_item_call> + <menu_item_call + label="Restore Item" + layout="topleft" + name="restore_item"> + <menu_item_call.on_click + function="Places.LandmarksGear.Custom.Action" + parameter="restore" /> + </menu_item_call> <menu_item_separator layout="topleft" /> <menu_item_call diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 6211561a5d..0a6be2899b 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -970,7 +970,7 @@ <menu_item_call.on_enable function="File.EnableUploadModel" /> <menu_item_call.on_visible - function="File.MeshEnabled"/> + function="File.VisibleUploadModel"/> </menu_item_call> <menu_item_call label="Model Wizard..." @@ -982,7 +982,7 @@ <menu_item_call.on_enable function="File.EnableUploadModel" /> <menu_item_call.on_visible - function="File.MeshEnabled"/> + function="File.VisibleUploadModel"/> </menu_item_call> <menu_item_call label="Bulk (L$[COST] per file)..." @@ -1995,6 +1995,16 @@ function="ToggleControl" parameter="DebugShowRenderInfo" /> </menu_item_check> + <menu_item_check + label="Show Texture Info" + name="Show Texture Info"> + <menu_item_check.on_check + function="CheckControl" + parameter="DebugShowTextureInfo" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="DebugShowTextureInfo" /> + </menu_item_check> <menu_item_check label="Show Matrices" name="Show Matrices"> @@ -2015,6 +2025,16 @@ function="ToggleControl" parameter="DebugShowColor" /> </menu_item_check> + <menu_item_check + label="Show Memory" + name="Show Memory"> + <menu_item_check.on_check + function="CheckControl" + parameter="DebugShowMemory" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="DebugShowMemory" /> + </menu_item_check> <menu_item_separator/> @@ -2258,6 +2278,16 @@ parameter="face area" /> </menu_item_check> <menu_item_check + label="Build Queue" + name="Build Queue"> + <menu_item_check.on_check + function="Advanced.CheckInfoDisplay" + parameter="build queue" /> + <menu_item_check.on_click + function="Advanced.ToggleInfoDisplay" + parameter="build queue" /> + </menu_item_check> + <menu_item_check label="Lights" name="Lights"> <menu_item_check.on_check @@ -2571,18 +2601,6 @@ function="ToggleControl" parameter="PingInterpolate" /> </menu_item_check> - <menu_item_check - label="Region Debug Console" - name="Region Debug Console" - shortcut="control|shift|`" - use_mac_ctrl="true"> - <menu_item_check.on_check - function="Floater.Visible" - parameter="region_debug_console" /> - <menu_item_check.on_click - function="Floater.Toggle" - parameter="region_debug_console" /> - </menu_item_check> <menu_item_separator/> @@ -2781,26 +2799,6 @@ function="Floater.Toggle" parameter="region_debug_console" /> </menu_item_check> - <menu_item_check - <menu_item_separator /> - - <menu_item_check - label="Region Debug Console" - name="Region Debug Console" - shortcut="control|shift|`" - use_mac_ctrl="true"> - <menu_item_check.on_check - function="Floater.Visible" - parameter="region_debug_console" /> - <menu_item_check.on_click - function="Floater.Toggle" - parameter="region_debug_console" /> - </menu_item_check> - - <menu_item_separator /> - - <menu_item_check - <menu_item_separator /> <menu_item_check @@ -3198,7 +3196,7 @@ <menu_item_call.on_click function="Advanced.LeaveAdminStatus" /> </menu_item_call> - <menu_item_check + <menu_item_check label="Show Admin Menu" name="View Admin Options"> <menu_item_check.on_enable diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index cac25b9312..de13379099 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6304,15 +6304,6 @@ An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_N </notification> <notification - duration="10" - icon="notifytip.tga" - name="ServerVersionChanged" - priority="high" - type="notifytip"> -You just entered a region using a different server version, which may affect performance. [[URL] View the release notes.] - </notification> - - <notification icon="notifytip.tga" name="UnsupportedCommandSLURL" priority="high" @@ -6746,6 +6737,12 @@ The site at '<nolink>[HOST_NAME]</nolink>' in realm ' - Your CPU speed does not meet the minimum requirements. </global> + <global name="UnsupportedCPUSSE2"> +Your CPU does not seem to have the required support for SSE2 operations. + +Please see http://www.secondlife.com/corporate/sysreqs.php for information about system requirements. + </global> + <global name="UnsupportedGLRequirements"> You do not appear to have the proper hardware requirements for [APP_NAME]. [APP_NAME] requires an OpenGL graphics card that has multitexture support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system. diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml index 5871eb0654..21c627cdfb 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml @@ -45,9 +45,9 @@ left_pad="4" image_disabled="ComboButton_UpOff" image_unselected="ComboButton_UpOff" - image_selected="ComboButton_Up_On_Selected" + image_selected="ComboButton_On" image_pressed="ComboButton_UpSelected" - image_pressed_selected="ComboButton_Up_On_Selected" + image_pressed_selected="ComboButton_Selected" height="23" name="show_nearby_chat" tool_tip="Shows/hides nearby chat log"> diff --git a/indra/newview/skins/default/xui/en/panel_nearby_media.xml b/indra/newview/skins/default/xui/en/panel_nearby_media.xml index 8c13ced8f3..9bd60b935f 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_media.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_media.xml @@ -68,24 +68,12 @@ right="-8" width="66" height="22" + is_toggle="true" label="More >>" - label_selected="Less <<"> + label_selected="<< Less"> <button.commit_callback function="MediaListCtrl.MoreLess" /> </button> - <button - name="less_btn" - follows="right" - tool_tip="Advanced Controls" - top_delta="0" - right="-8" - width="66" - height="22" - label="More >>" - label_selected="Less <<"> - <button.commit_callback - function="MediaListCtrl.MoreLess" /> - </button> </panel> <panel name="nearby_media_panel" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 6a8bf87bc5..43431ea7c1 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -54,7 +54,13 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M <string name="no_groups_msg" value="Looking for Groups to join? Try [secondlife:///app/search/groups Search]." /> - <filter_editor + <string + name="MiniMapToolTipMsg" + value="[REGION](Double-click to open Map, shift-drag to pan)"/> + <string + name="AltMiniMapToolTipMsg" + value="[REGION](Double-click to teleport, shift-drag to pan)"/> + <filter_editor follows="left|top|right" height="23" layout="topleft" @@ -93,16 +99,26 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M name="nearby_panel" top="0" width="313"> - <avatar_list + <net_map + bg_color="NetMapBackgroundColor" + follows="top|left|right" + layout="topleft" + left="3" + mouse_opaque="false" + name="Net Map" + width="307" + height="140" + top="0"/> + <avatar_list allow_select="true" - follows="all" - height="356" + follows="top|left|bottom|right" + height="216" ignore_online_status="true" layout="topleft" left="3" multi_select="true" name="avatar_list" - top="0" + top="145" width="307" /> <panel background_visible="true" diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index 61e3bb354f..d36220385d 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -34,6 +34,14 @@ name="RegisterDateFormat"> [REG_DATE] ([AGE]) </string> + <string + name="name_text_args"> + [NAME] + </string> + <string + name="display_name_text_args"> + [DISPLAY_NAME] + </string> <layout_stack name="layout" orientation="vertical" diff --git a/indra/newview/skins/default/xui/en/widgets/talk_button.xml b/indra/newview/skins/default/xui/en/widgets/talk_button.xml index a7e271a1ff..d792e9f29c 100644 --- a/indra/newview/skins/default/xui/en/widgets/talk_button.xml +++ b/indra/newview/skins/default/xui/en/widgets/talk_button.xml @@ -23,11 +23,11 @@ bottom="0" tab_stop="false" is_toggle="true" - image_selected="SegmentedBtn_Right_Selected_Press" - image_unselected="SegmentedBtn_Right_Off" - image_pressed="SegmentedBtn_Right_Press" - image_pressed_selected="SegmentedBtn_Right_Selected_Press" - image_overlay="Arrow_Small_Up" + image_disabled="ComboButton_UpOff" + image_unselected="ComboButton_UpOff" + image_selected="ComboButton_On" + image_pressed="ComboButton_UpSelected" + image_pressed_selected="ComboButton_Selected" /> <monitor follows="right" diff --git a/indra/newview/skins/default/xui/es/floater_web_content.xml b/indra/newview/skins/default/xui/es/floater_web_content.xml new file mode 100644 index 0000000000..5e02fad2dd --- /dev/null +++ b/indra/newview/skins/default/xui/es/floater_web_content.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="floater_web_content" title=""> + <layout_stack name="stack1"> + <layout_panel name="nav_controls"> + <button name="back" tool_tip="Navegar hacia atrás"/> + <button name="forward" tool_tip="Navegar hacia adelante"/> + <button name="stop" tool_tip="Detener la navegación"/> + <button name="reload" tool_tip="Recargar página"/> + <combo_box name="address" tool_tip="Introducir URL aquí"/> + <icon name="media_secure_lock_flag" tool_tip="Navegación segura"/> + <button name="popexternal" tool_tip="Abrir URL actual en tu navegador de escritorio"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/es/menu_login.xml b/indra/newview/skins/default/xui/es/menu_login.xml index 5386f82ee5..c27d624732 100644 --- a/indra/newview/skins/default/xui/es/menu_login.xml +++ b/indra/newview/skins/default/xui/es/menu_login.xml @@ -16,7 +16,8 @@ <menu_item_call label="Definir el tamaño de la ventana..." name="Set Window Size..."/> <menu_item_call label="Mostrar los 'TOS'" name="TOS"/> <menu_item_call label="Mostrar mensaje crítico" name="Critical"/> - <menu_item_call label="Web Browser Test" name="Web Browser Test"/> + <menu_item_call label="Prueba de navegadores de medios" name="Web Browser Test"/> + <menu_item_call label="Prueba de ventanas de contenidos web" name="Web Content Floater Test"/> <menu_item_check label="Mostrar el selector de Grid" name="Show Grid Picker"/> <menu_item_call label="Mostrar la consola de notificaciones" name="Show Notifications Console"/> </menu> diff --git a/indra/newview/skins/default/xui/es/menu_mini_map.xml b/indra/newview/skins/default/xui/es/menu_mini_map.xml index 41dc817551..07d1b08572 100644 --- a/indra/newview/skins/default/xui/es/menu_mini_map.xml +++ b/indra/newview/skins/default/xui/es/menu_mini_map.xml @@ -3,6 +3,7 @@ <menu_item_call label="Zoom cerca" name="Zoom Close"/> <menu_item_call label="Zoom medio" name="Zoom Medium"/> <menu_item_call label="Zoom lejos" name="Zoom Far"/> + <menu_item_call label="Zoom por defecto" name="Zoom Default"/> <menu_item_check label="Girar el mapa" name="Rotate Map"/> <menu_item_check label="Centrar automáticamente" name="Auto Center"/> <menu_item_call label="Parar la búsqueda" name="Stop Tracking"/> diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml index 3dd940c331..2fe7db1041 100644 --- a/indra/newview/skins/default/xui/es/menu_viewer.xml +++ b/indra/newview/skins/default/xui/es/menu_viewer.xml @@ -121,13 +121,15 @@ <menu_item_call label="Animación ([COST] L$)..." name="Upload Animation"/> <menu_item_call label="Masivo ([COST] L$ por archivo)..." name="Bulk Upload"/> </menu> + <menu_item_call label="Deshacer" name="Undo"/> + <menu_item_call label="Rehacer" name="Redo"/> </menu> <menu label="Ayuda" name="Help"> <menu_item_call label="Ayuda de [SECOND_LIFE]" name="Second Life Help"/> + <menu_item_check label="Permitir consejos" name="Enable Hints"/> <menu_item_call label="Denunciar una infracción" name="Report Abuse"/> <menu_item_call label="Informar de un fallo" name="Report Bug"/> <menu_item_call label="Acerca de [APP_NAME]" name="About Second Life"/> - <menu_item_check label="Permitir consejos" name="Enable Hints"/> </menu> <menu label="Avanzado" name="Advanced"> <menu_item_call label="Recargar las texturas" name="Rebake Texture"/> @@ -268,7 +270,8 @@ <menu_item_call label="Dump Region Object Cache" name="Dump Region Object Cache"/> </menu> <menu label="UI" name="UI"> - <menu_item_call label="Web Browser Test" name="Web Browser Test"/> + <menu_item_call label="Prueba de navegadores de medios" name="Web Browser Test"/> + <menu_item_call label="Navegador de contenido web" name="Web Content Browser"/> <menu_item_call label="Print Selected Object Info" name="Print Selected Object Info"/> <menu_item_call label="Memory Stats" name="Memory Stats"/> <menu_item_check label="Consola de depuración de región" name="Region Debug Console"/> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 14ce39e8fc..2bf36bb763 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -108,6 +108,10 @@ Asegúrate de que tu conexión a Internet está funcionando adecuadamente. Quienes no sean tus amigos no sabrán que has elegido ignorar sus llamadas y mensajes instantáneos. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FavoritesOnLogin"> + Nota: Al activar esta opción, cualquiera que utilice este ordenador podrá ver tu lista de lugares favoritos. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="GrantModifyRights"> Al conceder permisos de modificación a otro Residente, le estás permitiendo cambiar, borrar o tomar CUALQUIER objeto que tengas en el mundo. Sé MUY cuidadoso al conceder este permiso. ¿Quieres conceder permisos de modificación a [NAME]? @@ -946,7 +950,7 @@ no tienes el permiso de comprar terreno para el grupo que tienes activado actual <input name="message"> [DESC] (nuevo) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Cancelar"/> </form> </notification> @@ -956,7 +960,7 @@ no tienes el permiso de comprar terreno para el grupo que tienes activado actual <input name="message"> [DESC] (nuevo) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Cancelar"/> </form> </notification> @@ -966,7 +970,7 @@ no tienes el permiso de comprar terreno para el grupo que tienes activado actual <input name="new_name"> [NAME] </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Cancelar"/> </form> </notification> @@ -1347,9 +1351,41 @@ Descarga e instala el último visor a través de http://secondlife.com/download. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="DownloadBackground"> - Se ha descargado una versión actualizada de [APP_NAME]. -Se aplicará la próxima vez que reinicies [APP_NAME] + <notification name="FailedRequiredUpdateInstall"> + No hemos podido instalar una actualización necesaria. +No podrás iniciar sesión hasta que [APP_NAME] se haya actualizado. + +Descarga e instala el último visor a través de +http://secondlife.com/download. + <usetemplate name="okbutton" yestext="Salir"/> + </notification> + <notification name="UpdaterServiceNotRunning"> + Hay una actualización necesaria para la instalación de Second Life. + +Puedes descargar esta actualización de http://www.secondlife.com/downloads +o instalarla ahora. + <usetemplate name="okcancelbuttons" notext="Salir de Second Life" yestext="Descargar e instalar ahora"/> + </notification> + <notification name="DownloadBackgroundTip"> + Hemos descargado una actualización para la instalación de [APP_NAME]. +Versión [VERSION] [[RELEASE_NOTES_FULL_URL]; información acerca de esta actualización] + <usetemplate name="okcancelbuttons" notext="Más tarde..." yestext="Instalar ahora y reiniciar [NOMBRE_APL]"/> + </notification> + <notification name="DownloadBackgroundDialog"> + Hemos descargado una actualización para la instalación de [APP_NAME]. +Versión [VERSION] [[RELEASE_NOTES_FULL_URL]; información acerca de esta actualización] + <usetemplate name="okcancelbuttons" notext="Más tarde..." yestext="Instalar ahora y reiniciar [APP_NAME]"/> + </notification> + <notification name="RequiredUpdateDownloadedVerboseDialog"> + Hemos descargado una actualización de software necesaria. +Versión [VERSION] + +Debemos reiniciar [APP_NAME] para instalar la actualización. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="RequiredUpdateDownloadedDialog"> + Debemos reiniciar [APP_NAME] para instalar la actualización. + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="DeedObjectToGroup"> Transferir este objeto al grupo hará que: @@ -2217,14 +2253,6 @@ Inténtalo seleccionando un trozo más pequeño de terreno. <notification name="NoContentToSearch"> Por favor, elige al menos un tipo de contenido a buscar ('PG', 'Mature', o 'Adult'). </notification> - <notification name="GroupVote"> - [NAME] ha propuesto votar: -[MESSAGE] - <form name="form"> - <button name="VoteNow" text="Votar ahora"/> - <button name="Later" text="Más tarde"/> - </form> - </notification> <notification name="SystemMessage"> [MESSAGE] </notification> @@ -2678,9 +2706,6 @@ Pulsa Aceptar o Rehusar para coger o no la llamada. Pulsa Ignorar para ignorar a <notification name="VoiceCallGenericError"> Se ha producido un error al intentar conectarte al [VOICE_CHANNEL_NAME]. Por favor, inténtalo más tarde. </notification> - <notification name="ServerVersionChanged"> - Acabas de entrar en una región que usa un servidor con una versión distinta, y esto puede influir en el funcionamiento. [[URL] Ver las notas de desarrollo]. - </notification> <notification name="UnsupportedCommandSLURL"> No se admite el formato de la SLurl que has pulsado. </notification> @@ -2783,9 +2808,7 @@ El avatar '[NAME]' desactivó el modo de apariencia. <notification name="NoConnect"> Tenemos problemas de conexión con [PROTOCOL] [HOSTID]. Comprueba la configuración de la red y del servidor de seguridad. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="NoVoiceConnect"> Tenemos problemas de conexión con tu servidor de voz: @@ -2794,9 +2817,7 @@ Comprueba la configuración de la red y del servidor de seguridad. No podrás establecer comunicaciones de voz. Comprueba la configuración de la red y del servidor de seguridad. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="AvatarRezLeftNotification"> ( [EXISTENCE] segundos vivo) @@ -2830,6 +2851,9 @@ Si lo haces, todos los residentes que se unan posteriormente a la llamada tambi <notification label="Explora el mundo" name="HintDestinationGuide"> La Guía de destinos contiene miles de nuevos lugares por descubrir. Selecciona una ubicación y elige Teleportarme para iniciar la exploración. </notification> + <notification label="Cambiar de apariencia" name="HintAvatarPicker"> + ¿Te gustaría cambiar de apariencia? Haz clic en el botón que aparece a continuación para ver más avatares. + </notification> <notification label="Panel lateral" name="HintSidePanel"> Accede de manera rápida a tu inventario, así como a tu ropa, los perfiles y el resto de la información disponible en el panel lateral. </notification> @@ -2839,6 +2863,12 @@ Si lo haces, todos los residentes que se unan posteriormente a la llamada tambi <notification label="Nombre mostrado" name="HintDisplayName"> Configura y personaliza aquí tu nombre mostrado. Esto se añadirá a tu nombre de usuario personal, que no puedes modificar. Puedes cambiar la manera en que ves los nombres de otras personas en tus preferencias. </notification> + <notification label="Mover" name="HintMoveArrows"> + Para caminar, utiliza las flechas de dirección del teclado. Para correr, pulsa dos veces la flecha hacia arriba. + </notification> + <notification label="Visión" name="HintView"> + Para cambiar la vista de la cámara, utiliza los controles Orbital y Panorámica. Para restablecer tu vista, pulsa Esc o camina. + </notification> <notification label="Inventario" name="HintInventory"> Accede a tu inventario para buscar ítems. Los ítems más recientes se pueden encontrar fácilmente en la pestaña Recientes. </notification> @@ -2852,6 +2882,15 @@ Si lo haces, todos los residentes que se unan posteriormente a la llamada tambi <button name="open" text="Abrir ventana emergente"/> </form> </notification> + <notification name="AuthRequest"> + El sitio en '<nolink>[HOST_NAME]</nolink>' de la plataforma '[REALM]' requiere un nombre de usuario y una contraseña. + <form name="form"> + <input name="username" text="Nombre de usuario"/> + <input name="password" text="Contraseña"/> + <button name="ok" text="Enviar"/> + <button name="cancel" text="Cancelar"/> + </form> + </notification> <global name="UnsupportedCPU"> - La velocidad de tu CPU no cumple los requerimientos mínimos. </global> diff --git a/indra/newview/skins/default/xui/es/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/es/panel_avatar_list_item.xml index 09221c5599..5220df5d21 100644 --- a/indra/newview/skins/default/xui/es/panel_avatar_list_item.xml +++ b/indra/newview/skins/default/xui/es/panel_avatar_list_item.xml @@ -21,7 +21,7 @@ <string name="FormatYears"> [COUNT] año/s </string> - <text name="avatar_name" value="Desconocido"/> + <text name="avatar_name" value="(cargando...)"/> <icon name="permission_edit_theirs_icon" tool_tip="Puedes editar los objetos de este amigo"/> <icon name="permission_edit_mine_icon" tool_tip="Este amigo puede editar, eliminar o manipular tus objetos"/> <icon name="permission_map_icon" tool_tip="Este amigo puede encontrarte en el mapa"/> diff --git a/indra/newview/skins/default/xui/es/panel_edit_alpha.xml b/indra/newview/skins/default/xui/es/panel_edit_alpha.xml index 3f238da9d0..829c206ae1 100644 --- a/indra/newview/skins/default/xui/es/panel_edit_alpha.xml +++ b/indra/newview/skins/default/xui/es/panel_edit_alpha.xml @@ -1,10 +1,12 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_alpha_panel"> - <panel name="avatar_alpha_color_panel"> - <texture_picker label="Alfa inferior" name="Lower Alpha" tool_tip="Pulsa para elegir una imagen"/> - <texture_picker label="Alfa superior" name="Upper Alpha" tool_tip="Pulsa para elegir una imagen"/> - <texture_picker label="Alfa de la cabeza" name="Head Alpha" tool_tip="Pulsa para elegir una imagen"/> - <texture_picker label="Alfa de los ojos" name="Eye Alpha" tool_tip="Pulsa para elegir una imagen"/> - <texture_picker label="Alfa del pelo" name="Hair Alpha" tool_tip="Pulsa para elegir una imagen"/> - </panel> + <scroll_container name="avatar_alpha_color_panel_scroll"> + <panel name="avatar_alpha_color_panel"> + <texture_picker label="Alfa inferior" name="Lower Alpha" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Alfa superior" name="Upper Alpha" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Alfa de la cabeza" name="Head Alpha" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Alfa de los ojos" name="Eye Alpha" tool_tip="Pulsa para elegir una imagen"/> + <texture_picker label="Alfa del pelo" name="Hair Alpha" tool_tip="Pulsa para elegir una imagen"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_login.xml b/indra/newview/skins/default/xui/es/panel_login.xml index 49d4881737..ada964f33e 100644 --- a/indra/newview/skins/default/xui/es/panel_login.xml +++ b/indra/newview/skins/default/xui/es/panel_login.xml @@ -11,7 +11,7 @@ <text name="username_text"> Nombre de usuario: </text> - <line_editor label="bobsmith12 o Steller Sunshine" name="username_edit" tool_tip="El nombre de usuario que elegiste al registrarte, como bobsmith12 o Steller Sunshine"/> + <combo_box name="username_combo" tool_tip="El nombre de usuario que elegiste al registrarte, como bobsmith12 o Steller Sunshine"/> <text name="password_text"> Contraseña: </text> diff --git a/indra/newview/skins/default/xui/es/panel_my_profile.xml b/indra/newview/skins/default/xui/es/panel_my_profile.xml index 14c94acf5b..29e5e6f652 100644 --- a/indra/newview/skins/default/xui/es/panel_my_profile.xml +++ b/indra/newview/skins/default/xui/es/panel_my_profile.xml @@ -5,30 +5,27 @@ <string name="RegisterDateFormat"> [REG_DATE] ([AGE]) </string> + <string name="name_text_args"> + [NAME] + </string> + <string name="display_name_text_args"> + [DISPLAY_NAME] + </string> <layout_stack name="layout"> <layout_panel name="profile_stack"> <scroll_container name="profile_scroll"> <panel name="scroll_content_panel"> <panel name="second_life_image_panel"> - <icon label="" name="2nd_life_edit_icon" tool_tip="Pulsa el botón Editar el perfil para cambiar la imagen"/> - <text name="title_sl_descr_text" value="[SECOND_LIFE]:"/> - </panel> - <panel name="first_life_image_panel"> - <icon label="" name="real_world_edit_icon" tool_tip="Pulsa el botón Editar el perfil para cambiar la imagen"/> - <text name="title_rw_descr_text" value="Mundo real:"/> - </panel> - <text name="title_member_text" value="Residente desde:"/> - <text name="title_acc_status_text" value="Estado de la cuenta:"/> - <text name="title_partner_text" value="Compañero/a:"/> - <panel name="partner_data_panel"> - <name_box initial_value="(obteniendo)" name="partner_text"/> + <text name="display_name_descr_text"> + Nombre de usuario + </text> + <text name="name_descr_text"> + Nombre mostrado + </text> + <button label="Perfil" name="see_profile_btn" tool_tip="Ver el perfil de este avatar"/> </panel> - <text name="title_groups_text" value="Grupos:"/> </panel> </scroll_container> </layout_panel> </layout_stack> - <panel name="profile_me_buttons_panel"> - <button label="Editar el perfil" name="edit_profile_btn" tool_tip="Modificar tu información personal"/> - </panel> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_notify_textbox.xml b/indra/newview/skins/default/xui/es/panel_notify_textbox.xml index 10aaa288d7..dc7c873303 100644 --- a/indra/newview/skins/default/xui/es/panel_notify_textbox.xml +++ b/indra/newview/skins/default/xui/es/panel_notify_textbox.xml @@ -3,8 +3,9 @@ <string name="message_max_lines_count" value="7"/> <panel label="info_panel" name="info_panel"> <text_editor name="message" value="message"/> - parse_urls="false" + </panel> + <panel label="control_panel" name="control_panel"> <button label="Enviar" name="btn_submit"/> + <button label="Ignorar" name="ignore_btn"/> </panel> - <panel label="control_panel" name="control_panel"/> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_colors.xml b/indra/newview/skins/default/xui/es/panel_preferences_colors.xml index 4fa5c4ce63..edd417d564 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_colors.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_colors.xml @@ -29,10 +29,10 @@ URL </text> <text name="bubble_chat"> - Fondo de los bocadillos del chat: + Color de fondo de la etiqueta del nombre (afectará también a los bocadillos del chat): </text> - <color_swatch name="background" tool_tip="Elegir el color de los bocadillos del chat"/> - <slider label="Opacidad:" name="bubble_chat_opacity"/> + <color_swatch name="background" tool_tip="Seleccionar el color de la etiqueta del nombre"/> + <slider label="Opacidad:" name="bubble_chat_opacity" tool_tip="Seleccionar opacidad de la etiqueta del nombre"/> <text name="floater_opacity"> Opacidad de la ventana: </text> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/es/panel_preferences_privacy.xml index abff72c346..5eaa345c98 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_privacy.xml @@ -7,9 +7,11 @@ <text name="cache_size_label_l"> (Localizaciones, imágenes, web, historial de búsqueda) </text> + <check_box label="Mostrarme en los resultados de la búsqueda" name="online_searchresults"/> <check_box label="Sólo saben si estoy conectado mis amigos y grupos" name="online_visibility"/> <check_box label="Sólo pueden llamarme o mandarme un MI mis amigos y grupos" name="voice_call_friends_only_check"/> <check_box label="Desconectar el micrófono cuando finalicen las llamadas" name="auto_disengage_mic_check"/> + <check_box label="Mostrar mis Hitos favoritos en Inicio de sesión (mediante el menú desplegable "Empezar en")" name="favorites_on_login_check"/> <text name="Logs:"> Registros de chat: </text> diff --git a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml index f968f48910..68484645b7 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml @@ -39,5 +39,11 @@ </text> <line_editor name="web_proxy_editor" tool_tip="Nombre o dirección IP del proxy que quieres usar"/> <spinner label="Nº del puerto:" name="web_proxy_port"/> - <check_box initial_value="verdadero" label="Descargar e instalar automáticamente actualizaciones de [APP_NAME]" name="updater_service_active"/> + <text name="Software updates:"> + Actualizaciones de software: + </text> + <combo_box name="updater_service_combobox"> + <combo_box.item label="Instalar automáticamente" name="Install_automatically"/> + <combo_box.item label="Descargar e instalar actualizaciones manualmente" name="Install_manual"/> + </combo_box> </panel> diff --git a/indra/newview/skins/default/xui/es/panel_status_bar.xml b/indra/newview/skins/default/xui/es/panel_status_bar.xml index 13ed1acf0b..ab76d3f994 100644 --- a/indra/newview/skins/default/xui/es/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/es/panel_status_bar.xml @@ -22,7 +22,7 @@ [AMT] L$ </panel.string> <panel name="balance_bg"> - <text name="balance" tool_tip="Mi saldo" value="20 L$"/> + <text name="balance" tool_tip="Haz clic para actualizar tu saldo en L$" value="20 L$"/> <button label="COMPRAR L$" name="buyL" tool_tip="Pulsa para comprar más L$"/> </panel> <text name="TimeText" tool_tip="Hora actual (Pacífico)"> diff --git a/indra/newview/skins/default/xui/fr/floater_web_content.xml b/indra/newview/skins/default/xui/fr/floater_web_content.xml new file mode 100644 index 0000000000..65dfafe760 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/floater_web_content.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="floater_web_content" title=""> + <layout_stack name="stack1"> + <layout_panel name="nav_controls"> + <button name="back" tool_tip="Précédente"/> + <button name="forward" tool_tip="Suivante"/> + <button name="stop" tool_tip="Arrêt de la navigation"/> + <button name="reload" tool_tip="Recharger la page"/> + <combo_box name="address" tool_tip="Entrer une URL ici"/> + <icon name="media_secure_lock_flag" tool_tip="Navigation sécurisée"/> + <button name="popexternal" tool_tip="Ouvrir l'URL actuelle dans votre navigateur de bureau"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/fr/menu_login.xml b/indra/newview/skins/default/xui/fr/menu_login.xml index b712c008cd..400c77e51a 100644 --- a/indra/newview/skins/default/xui/fr/menu_login.xml +++ b/indra/newview/skins/default/xui/fr/menu_login.xml @@ -17,7 +17,8 @@ <menu_item_call label="Définir la taille de la fenêtre..." name="Set Window Size..."/> <menu_item_call label="Afficher les conditions d'utilisation" name="TOS"/> <menu_item_call label="Afficher le message critique" name="Critical"/> - <menu_item_call label="Test du navigateur Web" name="Web Browser Test"/> + <menu_item_call label="Test du navigateur de médias" name="Web Browser Test"/> + <menu_item_call label="Test de la fenêtre flottante du contenu Web" name="Web Content Floater Test"/> <menu_item_check label="Afficher le sélecteur de grille" name="Show Grid Picker"/> <menu_item_call label="Afficher la console des notifications" name="Show Notifications Console"/> </menu> diff --git a/indra/newview/skins/default/xui/fr/menu_mini_map.xml b/indra/newview/skins/default/xui/fr/menu_mini_map.xml index 7530f31d4e..b9d0a70383 100644 --- a/indra/newview/skins/default/xui/fr/menu_mini_map.xml +++ b/indra/newview/skins/default/xui/fr/menu_mini_map.xml @@ -3,6 +3,7 @@ <menu_item_call label="Zoom rapproché" name="Zoom Close"/> <menu_item_call label="Zoom moyen" name="Zoom Medium"/> <menu_item_call label="Zoom éloigné" name="Zoom Far"/> + <menu_item_call label="Zoom par défaut" name="Zoom Default"/> <menu_item_check label="Faire pivoter la carte" name="Rotate Map"/> <menu_item_check label="Centrage auto" name="Auto Center"/> <menu_item_call label="Arrêter de suivre" name="Stop Tracking"/> diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml index fb4ab314af..65a00c2e6c 100644 --- a/indra/newview/skins/default/xui/fr/menu_viewer.xml +++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml @@ -121,13 +121,15 @@ <menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/> <menu_item_call label="Lot ([COST] L$ par fichier)..." name="Bulk Upload"/> </menu> + <menu_item_call label="Annuler" name="Undo"/> + <menu_item_call label="Refaire" name="Redo"/> </menu> <menu label="Aide" name="Help"> <menu_item_call label="Aide de [SECOND_LIFE]" name="Second Life Help"/> + <menu_item_check label="Activer les astuces" name="Enable Hints"/> <menu_item_call label="Signaler une infraction" name="Report Abuse"/> <menu_item_call label="Signaler un bug" name="Report Bug"/> <menu_item_call label="À propos de [APP_NAME]" name="About Second Life"/> - <menu_item_check label="Activer les astuces" name="Enable Hints"/> </menu> <menu label="Avancé" name="Advanced"> <menu_item_call label="Refixer les textures" name="Rebake Texture"/> @@ -307,7 +309,8 @@ <menu_item_call label="Dump Region Object Cache" name="Dump Region Object Cache"/> </menu> <menu label="Interface" name="UI"> - <menu_item_call label="Test du navigateur Web" name="Web Browser Test"/> + <menu_item_call label="Test du navigateur de médias" name="Web Browser Test"/> + <menu_item_call label="Navigateur du contenu Web" name="Web Content Browser"/> <menu_item_call label="Dump SelectMgr" name="Dump SelectMgr"/> <menu_item_call label="Dump inventaire" name="Dump Inventory"/> <menu_item_call label="Dump Timers" name="Dump Timers"/> diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index f0b0e63af0..603b8f0edc 100644 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -109,6 +109,10 @@ Veuillez ne sélectionner qu'un seul objet. Les résidents qui ne sont pas vos amis ne sauront pas que vous avez choisi d'ignorer leurs appels et leurs messages instantanés. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FavoritesOnLogin"> + Remarque : si vous activez cette option, toutes les personnes utilisant cet ordinateur pourront voir votre liste d'endroits favoris. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="GrantModifyRights"> Lorsque vous accordez des droits de modification à un autre résident, vous lui permettez de changer, supprimer ou prendre n'importe lequel de vos objets dans Second Life. Réfléchissez bien avant d'accorder ces droits. Voulez-vous vraiment accorder des droits de modification à [NAME] ? @@ -945,7 +949,7 @@ Proposer à [NAME] de devenir votre ami(e) ? <input name="message"> [DESC] (nouv.) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Annuler"/> </form> </notification> @@ -955,7 +959,7 @@ Proposer à [NAME] de devenir votre ami(e) ? <input name="message"> [DESC] (nouv.) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Annuler"/> </form> </notification> @@ -965,7 +969,7 @@ Proposer à [NAME] de devenir votre ami(e) ? <input name="new_name"> [NAME] </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Annuler"/> </form> </notification> @@ -1338,9 +1342,41 @@ Veuillez télécharger et installer la dernière version du client à la page We http://secondlife.com/download. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="DownloadBackground"> - Une mise à jour de [APP_NAME] a été téléchargée. -Elle sera appliquée au prochain redémarrage de [APP_NAME]. + <notification name="FailedRequiredUpdateInstall"> + Impossible d'installer une mise à jour requise. +Vous ne pourrez pas vous connecter tant que [APP_NAME] ne sera pas mis à jour. + +Veuillez télécharger et installer la dernière version du client à la page Web +http://secondlife.com/download. + <usetemplate name="okbutton" yestext="Quitter"/> + </notification> + <notification name="UpdaterServiceNotRunning"> + Une mise à jour requise pour votre installation Second Life existe. + +Pour la télécharger, accédez à http://www.secondlife.com/downloads. +Vous pouvez également l'installer dès maintenant. + <usetemplate name="okcancelbuttons" notext="Quitter Second Life" yestext="Télécharger et installer maintenant"/> + </notification> + <notification name="DownloadBackgroundTip"> + Nous avons téléchargé une mise à jour de votre installation [APP_NAME]. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Informations relatives à cette mise à jour] + <usetemplate name="okcancelbuttons" notext="Ultérieurement..." yestext="Installer maintenant et redémarrer [APP_NAME]"/> + </notification> + <notification name="DownloadBackgroundDialog"> + Nous avons téléchargé une mise à jour de votre installation [APP_NAME]. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Informations relatives à cette mise à jour] + <usetemplate name="okcancelbuttons" notext="Ultérieurement..." yestext="Installer maintenant et redémarrer [APP_NAME]"/> + </notification> + <notification name="RequiredUpdateDownloadedVerboseDialog"> + Nous avons téléchargé une mise à jour logicielle requise. +Version [VERSION] + +[APP_NAME] doit être redémarré pour que la mise à jour soit installée. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="RequiredUpdateDownloadedDialog"> + [APP_NAME] doit être redémarré pour que la mise à jour soit installée. + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="DeedObjectToGroup"> Si vous cédez cet objet, le groupe : @@ -2209,14 +2245,6 @@ Veuillez sélectionner un terrain plus petit. <notification name="NoContentToSearch"> Veuillez sélectionner au moins un type de contenu à rechercher (Général, Modéré ou Adulte) </notification> - <notification name="GroupVote"> - [NAME] a proposé un vote pour : -[MESSAGE] - <form name="form"> - <button name="VoteNow" text="Voter"/> - <button name="Later" text="Plus tard"/> - </form> - </notification> <notification name="SystemMessage"> [MESSAGE] </notification> @@ -2674,9 +2702,6 @@ Pour y participer, cliquez sur Accepter. Sinon, cliquez sur Refuser. Pour ignore <notification name="VoiceCallGenericError"> Une erreur est survenue pendant la connexion au chat vocal pour [VOICE_CHANNEL_NAME]. Veuillez réessayer ultérieurement. </notification> - <notification name="ServerVersionChanged"> - La région dans laquelle vous avez pénétré utilise une version de serveur différente, ce qui peut avoir un impact sur votre performance. [[URL] Consultez les notes de version.] - </notification> <notification name="UnsupportedCommandSLURL"> La SLurl que vous avez saisie n'est pas prise en charge. </notification> @@ -2779,9 +2804,7 @@ L'avatar [NAME] a quitté le mode Apparence. <notification name="NoConnect"> Problèmes de connexion via [PROTOCOL] [HOSTID]. Veuillez vérifier la configuration de votre réseau et de votre pare-feu. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="NoVoiceConnect"> Problèmes de connexion à votre serveur vocal : @@ -2790,9 +2813,7 @@ Veuillez vérifier la configuration de votre réseau et de votre pare-feu. Aucune communication vocale n'est disponible. Veuillez vérifier la configuration de votre réseau et de votre pare-feu. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="AvatarRezLeftNotification"> ([EXISTENCE] secondes d'existence) @@ -2827,6 +2848,9 @@ Ignorer les autres ? <notification label="Explorer le monde" name="HintDestinationGuide"> Le Guide des destinations comprend des milliers d'endroits nouveaux à découvrir. Sélectionnez-en un, puis cliquez sur Téléporter pour commencer à l'explorer. </notification> + <notification label="Changer d'apparence" name="HintAvatarPicker"> + Vous souhaitez changer de look ? Cliquez sur le bouton ci-dessous pour voir plus d'avatars. + </notification> <notification label="Panneau latéral" name="HintSidePanel"> Obtenir un accès rapide à votre inventaire, à vos habits, à vos profils et bien plus encore dans le panneau latéral. </notification> @@ -2836,6 +2860,12 @@ Ignorer les autres ? <notification label="Nom d'affichage" name="HintDisplayName"> Définissez ici votre nom d'affichage personnalisable. Cette fonctionnalité vous est fournie en plus de votre nom d'utilisateur unique qui, lui, ne peut être changé. Vous pouvez modifier l'apparence des noms des autres résidents dans vos préférences. </notification> + <notification label="Bouger" name="HintMoveArrows"> + Pour marcher, utilisez les touches fléchées de votre clavier. Pour courir, appuyez deux fois sur la flèche vers le haut. + </notification> + <notification label="Affichage" name="HintView"> + Pour changer d'angle de vision, utilisez les contrôles Faire tourner et Faire un panoramique. Pour réinitialiser la vue, appuyez sur Échap ou marchez. + </notification> <notification label="Inventaire" name="HintInventory"> Permet de rechercher des articles dans l'inventaire. Pour accéder aux derniers articles ajoutés, cliquez sur l'onglet Récent. </notification> @@ -2849,6 +2879,15 @@ Ignorer les autres ? <button name="open" text="Ouvrir la fenêtre popup"/> </form> </notification> + <notification name="AuthRequest"> + Nom d'utilisateur et mot de passe requis pour le site se trouvant à l'emplacement suivant : '<nolink>[HOST_NAME]</nolink>', domaine '[REALM]'. + <form name="form"> + <input name="username" text="Nom d'utilisateur"/> + <input name="password" text="Mot de passe"/> + <button name="ok" text="Soumettre"/> + <button name="cancel" text="Annuler"/> + </form> + </notification> <global name="UnsupportedCPU"> - Votre processeur ne remplit pas les conditions minimum requises. </global> diff --git a/indra/newview/skins/default/xui/fr/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/fr/panel_avatar_list_item.xml index 607665ddd8..54b8f53e59 100644 --- a/indra/newview/skins/default/xui/fr/panel_avatar_list_item.xml +++ b/indra/newview/skins/default/xui/fr/panel_avatar_list_item.xml @@ -21,7 +21,7 @@ <string name="FormatYears"> [COUNT] a </string> - <text name="avatar_name" value="Inconnu"/> + <text name="avatar_name" value="(chargement)"/> <text name="last_interaction" value="0s"/> <icon name="permission_edit_theirs_icon" tool_tip="Vous pouvez modifier les objets de cet(te) ami(e)."/> <icon name="permission_edit_mine_icon" tool_tip="Cet(te) ami(e) peut modifier, supprimer ou prendre vos objets."/> diff --git a/indra/newview/skins/default/xui/fr/panel_edit_alpha.xml b/indra/newview/skins/default/xui/fr/panel_edit_alpha.xml index 3b81ef2a5f..a8b95c66fb 100644 --- a/indra/newview/skins/default/xui/fr/panel_edit_alpha.xml +++ b/indra/newview/skins/default/xui/fr/panel_edit_alpha.xml @@ -1,10 +1,12 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_alpha_panel"> - <panel name="avatar_alpha_color_panel"> - <texture_picker label="Alpha bas" name="Lower Alpha" tool_tip="Cliquez pour sélectionner une image"/> - <texture_picker label="Alpha haut" name="Upper Alpha" tool_tip="Cliquez pour sélectionner une image"/> - <texture_picker label="Alpha tête" name="Head Alpha" tool_tip="Cliquez pour sélectionner une image"/> - <texture_picker label="Alpha yeux" name="Eye Alpha" tool_tip="Cliquez pour sélectionner une image"/> - <texture_picker label="Alpha cheveux" width="80" name="Hair Alpha" tool_tip="Cliquez pour sélectionner une image"/> - </panel> + <scroll_container name="avatar_alpha_color_panel_scroll"> + <panel name="avatar_alpha_color_panel"> + <texture_picker label="Alpha bas" name="Lower Alpha" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Alpha haut" name="Upper Alpha" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Alpha tête" name="Head Alpha" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Alpha yeux" name="Eye Alpha" tool_tip="Cliquer pour sélectionner une image."/> + <texture_picker label="Alpha cheveux" name="Hair Alpha" tool_tip="Cliquer pour sélectionner une image."/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml index b667780180..ef55ba7991 100644 --- a/indra/newview/skins/default/xui/fr/panel_login.xml +++ b/indra/newview/skins/default/xui/fr/panel_login.xml @@ -11,7 +11,7 @@ <text name="username_text"> Nom d'utilisateur : </text> - <line_editor label="bobsmith12 ou Steller Sunshine" name="username_edit" tool_tip="Nom d'utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/> + <combo_box name="username_combo" tool_tip="Nom d'utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/> <text name="password_text"> Mot de passe : </text> diff --git a/indra/newview/skins/default/xui/fr/panel_my_profile.xml b/indra/newview/skins/default/xui/fr/panel_my_profile.xml index 8dbc22d3c7..5207c5a28e 100644 --- a/indra/newview/skins/default/xui/fr/panel_my_profile.xml +++ b/indra/newview/skins/default/xui/fr/panel_my_profile.xml @@ -16,34 +16,27 @@ <string name="RegisterDateFormat"> [REG_DATE] ([AGE]) </string> + <string name="name_text_args"> + [NAME] + </string> + <string name="display_name_text_args"> + [DISPLAY_NAME] + </string> <layout_stack name="layout"> <layout_panel name="profile_stack"> <scroll_container name="profile_scroll"> <panel name="scroll_content_panel"> <panel name="second_life_image_panel"> - <icon label="" name="2nd_life_edit_icon" tool_tip="Cliquez sur le bouton Modifier le profil ci-dessous pour changer d'image"/> - <text name="title_sl_descr_text" value="[SECOND_LIFE]:"/> - </panel> - <panel name="first_life_image_panel"> - <icon label="" name="real_world_edit_icon" tool_tip="Cliquez sur le bouton Modifier le profil ci-dessous pour changer d'image"/> - <text name="title_rw_descr_text" value="Vie réelle :"/> - </panel> - <text name="title_member_text" value="Résident depuis :"/> - <text name="title_acc_status_text" value="Statut du compte :"/> - <text_editor name="acc_status_text"> - Résident. Aucune info de paiement enregistrée. - Linden. - </text_editor> - <text name="title_partner_text" value="Partenaire :"/> - <panel name="partner_data_panel"> - <name_box initial_value="(récupération en cours)" name="partner_text"/> + <text name="display_name_descr_text"> + Nom d'utilisateur + </text> + <text name="name_descr_text"> + Nom d'affichage + </text> + <button label="Profil" name="see_profile_btn" tool_tip="Afficher le profil de cet avatar."/> </panel> - <text name="title_groups_text" value="Groupes :"/> </panel> </scroll_container> </layout_panel> </layout_stack> - <panel name="profile_me_buttons_panel"> - <button label="Modifier le profil" name="edit_profile_btn" tool_tip="Modifier vos informations personnelles"/> - </panel> </panel> diff --git a/indra/newview/skins/default/xui/fr/panel_notify_textbox.xml b/indra/newview/skins/default/xui/fr/panel_notify_textbox.xml index a37770e184..6ce09cde4b 100644 --- a/indra/newview/skins/default/xui/fr/panel_notify_textbox.xml +++ b/indra/newview/skins/default/xui/fr/panel_notify_textbox.xml @@ -3,8 +3,9 @@ <string name="message_max_lines_count" value="7"/> <panel label="info_panel" name="info_panel"> <text_editor name="message" value="message"/> - parse_urls="false" + </panel> + <panel label="control_panel" name="control_panel"> <button label="Soumettre" name="btn_submit"/> + <button label="Ignorer" name="ignore_btn"/> </panel> - <panel label="control_panel" name="control_panel"/> </panel> diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_colors.xml b/indra/newview/skins/default/xui/fr/panel_preferences_colors.xml index e94bb08c9c..4e7d75e1b9 100644 --- a/indra/newview/skins/default/xui/fr/panel_preferences_colors.xml +++ b/indra/newview/skins/default/xui/fr/panel_preferences_colors.xml @@ -29,10 +29,10 @@ URL </text> <text name="bubble_chat"> - Arrière-plan des bulles de chat : + Couleur de fond des noms (bulles de chat comprises) : </text> - <color_swatch name="background" tool_tip="Choisir la couleur des bulles de chat."/> - <slider label="Opacité :" name="bubble_chat_opacity"/> + <color_swatch name="background" tool_tip="Choisir une couleur pour les noms."/> + <slider label="Opacité :" name="bubble_chat_opacity" tool_tip="Choisir une opacité pour les noms."/> <text name="floater_opacity"> Opacité des fenêtres flottantes : </text> diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/fr/panel_preferences_privacy.xml index 6a4c77a10e..202ec779f5 100644 --- a/indra/newview/skins/default/xui/fr/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/fr/panel_preferences_privacy.xml @@ -7,9 +7,11 @@ <text name="cache_size_label_l"> (Endroits, images, web, historique des recherches) </text> + <check_box label="M'afficher dans les résultats de recherche" name="online_searchresults"/> <check_box label="Seuls mes amis et groupes voient quand je suis en ligne" name="online_visibility"/> <check_box label="Seuls mes amis et groupes peuvent m'appeler ou m'envoyer un IM" name="voice_call_friends_only_check"/> <check_box label="Fermer le micro à la fin d'un appel" name="auto_disengage_mic_check"/> + <check_box label="Afficher mes repères favoris à la connexion (liste déroulante Lieu de départ)" name="favorites_on_login_check"/> <text name="Logs:"> Journaux de chat : </text> diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_setup.xml b/indra/newview/skins/default/xui/fr/panel_preferences_setup.xml index 8fa499d14a..bfe0defd56 100644 --- a/indra/newview/skins/default/xui/fr/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/fr/panel_preferences_setup.xml @@ -39,5 +39,11 @@ </text> <line_editor name="web_proxy_editor" tool_tip="Le nom ou adresse IP du proxy que vous souhaitez utiliser"/> <spinner label="Numéro de port :" label_width="95" name="web_proxy_port" width="170"/> - <check_box initial_value="true" label="Télécharger et installer automatiquement les mises à jour [APP_NAME]" name="updater_service_active"/> + <text name="Software updates:"> + Mises à jour logicielles : + </text> + <combo_box name="updater_service_combobox"> + <combo_box.item label="Installation automatique" name="Install_automatically"/> + <combo_box.item label="Téléchargement et installation manuels" name="Install_manual"/> + </combo_box> </panel> diff --git a/indra/newview/skins/default/xui/fr/panel_status_bar.xml b/indra/newview/skins/default/xui/fr/panel_status_bar.xml index 85429a18c7..69aec99e1d 100644 --- a/indra/newview/skins/default/xui/fr/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/fr/panel_status_bar.xml @@ -22,7 +22,7 @@ [AMT] L$ </panel.string> <panel name="balance_bg"> - <text name="balance" tool_tip="Mon solde" value="20 L$"/> + <text name="balance" tool_tip="Cliquer sur ce bouton pour actualiser votre solde en L$." value="20 L$"/> <button label="ACHETER L$" name="buyL" tool_tip="Cliquer pour acheter plus de L$"/> </panel> <text name="TimeText" tool_tip="Heure actuelle (Pacifique)"> diff --git a/indra/newview/skins/default/xui/it/notifications.xml b/indra/newview/skins/default/xui/it/notifications.xml index 5e53080c77..cce5888598 100644 --- a/indra/newview/skins/default/xui/it/notifications.xml +++ b/indra/newview/skins/default/xui/it/notifications.xml @@ -2623,9 +2623,6 @@ Clicca su Accetta per unirti alla chat oppure su Declina per declinare l'in <notification name="VoiceCallGenericError"> Si è verificato un errore durante il tentativo di collegarti a una voice chat con [VOICE_CHANNEL_NAME]. Riprova più tardi. </notification> - <notification name="ServerVersionChanged"> - Sei appena entrato in una regione che usa una versione differente del server: ciò potrebbe incidere sule prestazioni. [[URL] Visualizza le note sulla versione.] - </notification> <notification name="UnsupportedCommandSLURL"> Lo SLurl su cui hai cliccato non è valido. </notification> diff --git a/indra/newview/skins/default/xui/ja/notifications.xml b/indra/newview/skins/default/xui/ja/notifications.xml index f133bb361a..baec8c073c 100644 --- a/indra/newview/skins/default/xui/ja/notifications.xml +++ b/indra/newview/skins/default/xui/ja/notifications.xml @@ -2675,9 +2675,6 @@ M キーを押して変更します。 <notification name="VoiceCallGenericError"> [VOICE_CHANNEL_NAME] のボイスチャットに接続中に、エラーが発生しました。後でもう一度お試しください。 </notification> - <notification name="ServerVersionChanged"> - サーバーのバージョンが異なるリージョンに来ました。パフォーマンスに影響することがあります。 [[URL] リリースノートを確認] - </notification> <notification name="UnsupportedCommandSLURL"> クリックした SLurl はサポートされていません。 </notification> diff --git a/indra/newview/skins/default/xui/nl/notifications.xml b/indra/newview/skins/default/xui/nl/notifications.xml index be0c17d2ff..f27b83d3f9 100644 --- a/indra/newview/skins/default/xui/nl/notifications.xml +++ b/indra/newview/skins/default/xui/nl/notifications.xml @@ -3012,9 +3012,6 @@ Klik Accepteren om deel te nemen aan de chat of Afwijzen om de uitnodiging af te <notification name="VoiceCallGenericError"> Er is een fout opgetreden tijdens het verbinden met voice chat voor [VOICE_CHANNEL_NAME]. Probeert u het later alstublieft opnieuw. </notification> - <notification name="ServerVersionChanged"> - De regio die u bent binnengetreden wordt onder een andere simulatorversie uitgevoerd. Klik dit bericht voor meer details. - </notification> <notification name="UnableToOpenCommandURL"> De URL die u heeft geklikt kan niet binnen deze webbrowser worden geopend. </notification> diff --git a/indra/newview/skins/default/xui/pl/floater_hardware_settings.xml b/indra/newview/skins/default/xui/pl/floater_hardware_settings.xml index bd5dd7e7d2..471d2c39ba 100644 --- a/indra/newview/skins/default/xui/pl/floater_hardware_settings.xml +++ b/indra/newview/skins/default/xui/pl/floater_hardware_settings.xml @@ -14,6 +14,9 @@ <combo_box.item label="8x" name="8x"/> <combo_box.item label="16x" name="16x"/> </combo_box> + <text name="antialiasing restart"> + (Restart wymagany) + </text> <spinner label="Gamma:" name="gamma"/> <text name="(brightness, lower is brighter)"> (0=domyślna jaskrawość, niższa wartość=jaśniej) diff --git a/indra/newview/skins/default/xui/pl/floater_preferences.xml b/indra/newview/skins/default/xui/pl/floater_preferences.xml index 3f62d764c6..930a5c76b0 100644 --- a/indra/newview/skins/default/xui/pl/floater_preferences.xml +++ b/indra/newview/skins/default/xui/pl/floater_preferences.xml @@ -5,10 +5,12 @@ <tab_container name="pref core"> <panel label="Ogólne" name="general"/> <panel label="Grafika" name="display"/> - <panel label="Prywatność" name="im"/> <panel label="Dźwięk & Media" name="audio"/> <panel label="Czat" name="chat"/> + <panel label="Ruch & Widok" name="move"/> <panel label="Powiadomienia" name="msgs"/> + <panel label="Kolory" name="colors"/> + <panel label="Prywatność" name="im"/> <panel label="Ustawienie" name="input"/> <panel label="Zaawansowane" name="advanced1"/> </tab_container> diff --git a/indra/newview/skins/default/xui/pl/floater_region_debug_console.xml b/indra/newview/skins/default/xui/pl/floater_region_debug_console.xml new file mode 100644 index 0000000000..ce1f3c0ac7 --- /dev/null +++ b/indra/newview/skins/default/xui/pl/floater_region_debug_console.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="region_debug_console" title="Debugowanie regionu"/> diff --git a/indra/newview/skins/default/xui/pl/floater_web_content.xml b/indra/newview/skins/default/xui/pl/floater_web_content.xml new file mode 100644 index 0000000000..4cc8d0b27b --- /dev/null +++ b/indra/newview/skins/default/xui/pl/floater_web_content.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="floater_web_content" title=""> + <layout_stack name="stack1"> + <layout_panel name="nav_controls"> + <button name="back" tool_tip="Do tyłu"/> + <button name="forward" tool_tip="Do przodu"/> + <button name="stop" tool_tip="Zatrzymaj"/> + <button name="reload" tool_tip="Odśwież stronę"/> + <combo_box name="address" tool_tip="Wprowadź URL tutaj"/> + <icon name="media_secure_lock_flag" tool_tip="Funkcja bezpiecznego przeglądania (Secured Browsing)"/> + <button name="popexternal" tool_tip="Otwórz bieżący URL w zewnętrznej przeglądarce"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/pl/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/pl/menu_inventory_gear_default.xml index d110a2f02e..491b4deeaa 100644 --- a/indra/newview/skins/default/xui/pl/menu_inventory_gear_default.xml +++ b/indra/newview/skins/default/xui/pl/menu_inventory_gear_default.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_gear_default"> +<toggleable_menu name="menu_gear_default"> <menu_item_call label="Nowe okno Szafy" name="new_window"/> - <menu_item_call label="Porządkuj według nazwy" name="sort_by_name"/> - <menu_item_call label="Porządkuj według daty" name="sort_by_recent"/> + <menu_item_check label="Porządkuj według nazwy" name="sort_by_name"/> + <menu_item_check label="Porządkuj według daty" name="sort_by_recent"/> + <menu_item_check label="Posortuj foldery systemowe od góry" name="sort_system_folders_to_top"/> <menu_item_call label="Pokaż filtry" name="show_filters"/> <menu_item_call label="Zresetuj filtry" name="reset_filters"/> <menu_item_call label="Zamknij wszystkie foldery" name="close_folders"/> @@ -12,4 +13,4 @@ <menu_item_call label="Znajdź oryginał" name="Find Original"/> <menu_item_call label="Znajdź wszystkie linki" name="Find All Links"/> <menu_item_call label="Opróżnij Kosz" name="empty_trash"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/pl/menu_login.xml b/indra/newview/skins/default/xui/pl/menu_login.xml index 0dd6117b85..e50b694641 100644 --- a/indra/newview/skins/default/xui/pl/menu_login.xml +++ b/indra/newview/skins/default/xui/pl/menu_login.xml @@ -16,7 +16,8 @@ <menu_item_call label="Ustaw rozmiar interfejsu..." name="Set Window Size..."/> <menu_item_call label="Wyświetl TOS" name="TOS"/> <menu_item_call label="Wyświetl wiadomość krytyczną" name="Critical"/> - <menu_item_call label="Test przeglądarki internetowej" name="Web Browser Test"/> + <menu_item_call label="Test przeglądarki mediów" name="Web Browser Test"/> + <menu_item_call label="Test zawartości strony" name="Web Content Floater Test"/> <menu_item_check label="Pokaż siatkę" name="Show Grid Picker"/> <menu_item_call label="Pokaż konsolę Zawiadomień" name="Show Notifications Console"/> </menu> diff --git a/indra/newview/skins/default/xui/pl/menu_mini_map.xml b/indra/newview/skins/default/xui/pl/menu_mini_map.xml index 148adfba0d..8f86965416 100644 --- a/indra/newview/skins/default/xui/pl/menu_mini_map.xml +++ b/indra/newview/skins/default/xui/pl/menu_mini_map.xml @@ -3,6 +3,7 @@ <menu_item_call label="Zoom blisko" name="Zoom Close"/> <menu_item_call label="Zoom średnio" name="Zoom Medium"/> <menu_item_call label="Zoom daleko" name="Zoom Far"/> + <menu_item_call label="Zoom domyślny" name="Zoom Default"/> <menu_item_check label="Obróć mapę" name="Rotate Map"/> <menu_item_check label="Autocentrowanie" name="Auto Center"/> <menu_item_call label="Zatrzymaj" name="Stop Tracking"/> diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml index a359180ffb..e6a9d360c4 100644 --- a/indra/newview/skins/default/xui/pl/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml @@ -10,6 +10,12 @@ <menu_item_check label="Moja Szafa" name="ShowSidetrayInventory"/> <menu_item_check label="Moje gesturki" name="Gestures"/> <menu_item_check label="Mój głos" name="ShowVoice"/> + <menu label="Ruch" name="Movement"> + <menu_item_call label="Usiądź" name="Sit Down Here"/> + <menu_item_check label="Zacznij latać" name="Fly"/> + <menu_item_check label="Zawsze biegnij" name="Always Run"/> + <menu_item_call label="Zatrzymaj animacje" name="Stop Animating My Avatar"/> + </menu> <menu label="Mój Status" name="Status"> <menu_item_call label="Tryb oddalenia" name="Set Away"/> <menu_item_call label="Tryb pracy" name="Set Busy"/> @@ -45,6 +51,7 @@ <menu_item_check label="Właściciele posiadłości" name="Land Owners"/> <menu_item_check label="Współrzędne" name="Coordinates"/> <menu_item_check label="Właściwości posiadłości" name="Parcel Properties"/> + <menu_item_check label="Menu Zaawansowane" name="Show Advanced Menu"/> </menu> <menu_item_call label="Teleportuj do Miejsca Startu" name="Teleport Home"/> <menu_item_call label="Ustaw Miejsce Startu" name="Set Home to Here"/> @@ -112,16 +119,17 @@ <menu_item_call label="animację (L$[COST])..." name="Upload Animation"/> <menu_item_call label="zbiór plików (L$[COST] za jeden plik)..." name="Bulk Upload"/> </menu> + <menu_item_call label="Cofnij" name="Undo"/> + <menu_item_call label="Ponów" name="Redo"/> </menu> <menu label="Pomoc" name="Help"> <menu_item_call label="[SECOND_LIFE] Portal Pomocy" name="Second Life Help"/> + <menu_item_check label="Włącz podpowiedzi" name="Enable Hints"/> <menu_item_call label="Złóż Raport o Nadużyciu" name="Report Abuse"/> <menu_item_call label="Zgłoś błędy klienta" name="Report Bug"/> <menu_item_call label="O [APP_NAME]" name="About Second Life"/> - <menu_item_check label="Włącz podpowiedzi" name="Enable Hints"/> </menu> <menu label="Zaawansowane" name="Advanced"> - <menu_item_call label="Zatrzymaj wszystkie animacje" name="Stop Animating My Avatar"/> <menu_item_call label="Odswież wyświetlanie tekstur" name="Rebake Texture"/> <menu_item_call label="Domyślne ustawienia rozmiaru interfejsu" name="Set UI Size to Default"/> <menu_item_call label="Ustaw rozmiar interfejsu..." name="Set Window Size..."/> @@ -175,8 +183,7 @@ <menu_item_check label="Szukaj" name="Search"/> <menu_item_call label="Zwolnij klawisze" name="Release Keys"/> <menu_item_call label="Domyślne ustawienia rozmiaru interfejsu" name="Set UI Size to Default"/> - <menu_item_check label="Biegnij" name="Always Run"/> - <menu_item_check label="Zacznij latać" name="Fly"/> + <menu_item_check label="Pokaż menu Zaawansowane - skrót" name="Show Advanced Menu - legacy shortcut"/> <menu_item_call label="Zamknij okno" name="Close Window"/> <menu_item_call label="Zamknij wszystkie okna" name="Close All Windows"/> <menu_item_call label="Zapisz zdjęcie na dysk twardy" name="Snapshot to Disk"/> @@ -194,7 +201,6 @@ <menu_item_call label="Przybliż" name="Zoom In"/> <menu_item_call label="Domyślne przybliżenie" name="Zoom Default"/> <menu_item_call label="Oddal" name="Zoom Out"/> - <menu_item_check label="Pokaż menu Zaawansowane" name="Show Advanced Menu"/> </menu> <menu_item_call label="Pokaż ustawienia debugowania" name="Debug Settings"/> <menu_item_check label="Pokaż menu progresu" name="Debug Mode"/> @@ -262,19 +268,17 @@ <menu_item_call label="Zachowaj bufor pamięci obiektów regionu" name="Dump Region Object Cache"/> </menu> <menu label="UI" name="UI"> - <menu_item_call label="Test przeglądarki internetowej" name="Web Browser Test"/> + <menu_item_call label="Test przeglądarki mediów" name="Web Browser Test"/> + <menu_item_call label="Przeglądarka zawartości strony" name="Web Content Browser"/> <menu_item_call label="Drukuj zaznaczone informacje o obiekcie" name="Print Selected Object Info"/> <menu_item_call label="Statystyki pamięci" name="Memory Stats"/> - <menu_item_check label="Auto-pilot na podwójne kliknięcie" name="Double-ClickAuto-Pilot"/> - <menu_item_check label="Podwójne kliknięcie - Teleportuj" name="DoubleClick Teleport"/> + <menu_item_check label="Konsola debugowania regionu" name="Region Debug Console"/> <menu_item_check label="Debugowanie zdarzeń klikania" name="Debug Clicks"/> <menu_item_check label="Debugowanie zdarzeń myszy" name="Debug Mouse Events"/> </menu> <menu label="XUI" name="XUI"> <menu_item_call label="Załaduj ustawienia koloru" name="Reload Color Settings"/> <menu_item_call label="Pokaż test czcionki" name="Show Font Test"/> - <menu_item_call label="Załaduj z XML" name="Load from XML"/> - <menu_item_call label="Zapisz jako XML" name="Save to XML"/> <menu_item_check label="Pokaż nazwy XUI" name="Show XUI Names"/> <menu_item_call label="Wyślij wiadomość (IM) testową" name="Send Test IMs"/> <menu_item_call label="Wyczyść bufor pamięci nazw" name="Flush Names Caches"/> @@ -301,9 +305,9 @@ </menu> <menu_item_check label="Tekstury HTTP" name="HTTP Textures"/> <menu_item_check label="Aktywacja okna konsoli podczas następnego uruchomienia" name="Console Window"/> - <menu_item_check label="Pokaż menu administratora" name="View Admin Options"/> <menu_item_call label="Uzyskaj status administratora" name="Request Admin Options"/> <menu_item_call label="Opuść status administratora" name="Leave Admin Options"/> + <menu_item_check label="Pokaż menu administratora" name="View Admin Options"/> </menu> <menu label="Administrator" name="Admin"> <menu label="Object"> diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml index 57a6b8b8ef..25fa5da3ab 100644 --- a/indra/newview/skins/default/xui/pl/notifications.xml +++ b/indra/newview/skins/default/xui/pl/notifications.xml @@ -109,6 +109,10 @@ Wybierz pojedynczy obiekt i spróbuj jeszcze raz. Osoby spoza listy znajomych, których rozmowy głosowe i IM są ignorowane, nie wiedzą o tym. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FavoritesOnLogin"> + Pamiętaj: kiedy wyłączysz tą opcję, każdy kto używa tego komputera, może zobaczyć Twoją listę ulubionych miejsc. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="GrantModifyRights"> Udzielenie praw modyfikacji innemu Rezydentowi umożliwia modyfikację, usuwanie lub wzięcie JAKIEGOKOLWIEK z Twoich obiektów. Używaj tej opcji z rozwagą! Czy chcesz udzielić prawa do modyfikacji [NAME]? @@ -383,6 +387,9 @@ Pamiętaj: Opcja ta wyczyszcza bufor danych. <notification name="ChangeSkin"> Nowa skórka zostanie wczytana po restarcie aplikacji [APP_NAME]. </notification> + <notification name="ChangeLanguage"> + Zmiana języka zadziała po restarcie [APP_NAME]. + </notification> <notification name="GoToAuctionPage"> Odwiedzić stronę internetową [SECOND_LIFE] żeby zobaczyć szczgóły aukcji lub zrobić ofertę? <usetemplate name="okcancelbuttons" notext="Anuluj" yestext="OK"/> @@ -580,6 +587,10 @@ Oczekiwana - [VALIDS] Brak bloku 'data' w nagłówku pliku WAV: [FILE] </notification> + <notification name="SoundFileInvalidChunkSize"> + Niewłaściwy rozmiar "chunk" w pliku WAV: +[FILE] + </notification> <notification name="SoundFileInvalidTooLong"> Plik audio jest zbyt długi (10 sekund maksimum): [FILE] @@ -917,7 +928,7 @@ Zaproponować znajomość [NAME]? <input name="message"> [DESC] (nowe) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Anuluj"/> </form> </notification> @@ -927,7 +938,7 @@ Zaproponować znajomość [NAME]? <input name="message"> [DESC] (nowy) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Anuluj"/> </form> </notification> @@ -937,7 +948,7 @@ Zaproponować znajomość [NAME]? <input name="new_name"> [NAME] </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Anuluj"/> </form> </notification> @@ -1303,6 +1314,40 @@ Aktualizacja nie jest wymagana ale jest zalecana w celu poprawy prędkości i st Pobrać i zapisać w folderze Aplikacji? <usetemplate name="okcancelbuttons" notext="Kontynuuj" yestext="Załaduj"/> </notification> + <notification name="FailedUpdateInstall"> + Podczas aktualizacji pojawił się błąd. Proszę pobrać i zainstalować najnowszego klienta z http://secondlife.com/download. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="FailedRequiredUpdateInstall"> + Nie można zainstalować wymaganej aktualizacji. Nie będzie można zalogować się dopóki [APP_NAME] nie zostanie zaktualizowana. + Proszę pobrać i zainstalować najnowszą wersję z http://secondlife.com/download. + <usetemplate name="okbutton" yestext="Rezygnuj"/> + </notification> + <notification name="UpdaterServiceNotRunning"> + Istnieje obowiązkowa aktualizacja dla Second Life. Możesz ją pobrać z http://www.secondlife.com/downloads lub zainstalować teraz. + <usetemplate name="okcancelbuttons" notext="Opuść Second Life" yestext="Pobierz i zainstaluj teraz"/> + </notification> + <notification name="DownloadBackgroundTip"> + Aktualizacja dla [APP_NAME] została pobrana. +Wersja [VERSION] [[RELEASE_NOTES_FULL_URL] Informacja o tej aktualizacji] + <usetemplate name="okcancelbuttons" notext="Później..." yestext="Zainstaluj teraz i restartuj [APP_NAME]"/> + </notification> + <notification name="DownloadBackgroundDialog"> + Aktualizacja [APP_NAME] została pobrana. +Wersja [VERSION] [[RELEASE_NOTES_FULL_URL] Informacja o aktualizacji] + <usetemplate name="okcancelbuttons" notext="Później..." yestext="Zainstaluj teraz i restartuj [APP_NAME]"/> + </notification> + <notification name="RequiredUpdateDownloadedVerboseDialog"> + Pobrano wymaganą aktualizację. +Wersja [VERSION] + +W celu instalacji aktualizacji musi zostać wykonany restart [APP_NAME]. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="RequiredUpdateDownloadedDialog"> + W celu instalacji aktualizacji musi zostać wykonany restart [APP_NAME]. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="DeedObjectToGroup"> Przekazanie tego obiektu spowoduje, że grupa: * Otrzyma L$ zapłacone temu obiektowi @@ -2171,14 +2216,6 @@ Spróbuj wybrać mniejszy obszar. <notification name="NoContentToSearch"> Proszę wybrać przynajmiej jeden z podanych rodzajów treści jaką zawiera region podczas wyszukiwania ('General', 'Moderate', lub 'Adult'). </notification> - <notification name="GroupVote"> - [NAME] zaprasza do głosowania nad propozycją: -[MESSAGE] - <form name="form"> - <button name="VoteNow" text="Głosuj Teraz"/> - <button name="Later" text="Później"/> - </form> - </notification> <notification name="SystemMessage"> [MESSAGE] </notification> @@ -2440,8 +2477,8 @@ Spróbuj ponowanie za kilka minut. Propozycja znajomości została odrzucona. </notification> <notification name="OfferCallingCard"> - [NAME] daje Tobie swoją wizytówkę. -Wizytówka będzie znajdowała się w Szafie i umożliwi szybkie wysłanie IM do tego Rezydenta. + [NAME] oferuje swoją wizytówkę. +Wizytówka w Twojej Szafie umożliwi szybki kontakt IM z tym Rezydentem. <form name="form"> <button name="Accept" text="Zaakceptuj"/> <button name="Decline" text="Odmów"/> @@ -2635,9 +2672,6 @@ Wybierz Zaakceptuj żeby zacząć czat albo Odmów żeby nie przyjąć zaproszen <notification name="VoiceCallGenericError"> Błąd podczas łączenia z rozmową [VOICE_CHANNEL_NAME]. Spróbuj póżniej. </notification> - <notification name="ServerVersionChanged"> - Ten region używa innej wersji symulatora. Kliknij na tą wiadomość żeby uzyskać więcej informacji: [[URL] View the release notes.] - </notification> <notification name="UnsupportedCommandSLURL"> Nie można otworzyć wybranego SLurl. </notification> @@ -2740,9 +2774,7 @@ Awatar '[NAME]' opuścił edycję wyglądu. <notification name="NoConnect"> Występuje problem z połączeniem [PROTOCOL] [HOSTID]. Proszę sprawdź swoją sieć i ustawienia firewall. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="NoVoiceConnect"> Występuje problem z Twoim połączniem głosowym: @@ -2751,9 +2783,7 @@ Proszę sprawdź swoją sieć i ustawienia firewall. Komunikacja głosowa nie będzie dostępna. Proszę sprawdź swoją sieć i ustawienia firewall. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="AvatarRezLeftNotification"> ( [EXISTENCE] sekund w Second Life) @@ -2787,6 +2817,9 @@ Wyciszyć wszystkich? <notification label="Odkrywaj Świat" name="HintDestinationGuide"> Destination Guide zawiera tysiące nowych miejsc do odkrycia. Wybierz lokalizację i teleportuj się aby rozpocząć zwiedzanie. </notification> + <notification label="Zmień wygląd swojego awatara" name="HintAvatarPicker"> + Czy chcesz inaczej wyglądać? Kliknij poniższy przycisk aby zobaczyć więcej przykładów awatarów. + </notification> <notification label="Schowek" name="HintSidePanel"> Schowek umożliwia szybki dostęp do Twojej Szafy, ubrań, profili i innych w panelu bocznym. </notification> @@ -2796,6 +2829,12 @@ Wyciszyć wszystkich? <notification label="Wyświetlana nazwa" name="HintDisplayName"> Ustaw wyświetlaną nazwę, którą możesz zmieniać tutaj. Jest ona dodatkiem do unikatowej nazwy użytkownika, która nie może być zmieniona. Możesz zmienić sposób w jaki widzisz nazwy innych osób w Twoich Ustawieniach. </notification> + <notification label="Ruch" name="HintMoveArrows"> + Użyj przycisków ze strzałkami z klawiatury aby chodzić. Jeśli wciśniesz strzałkę 'do góry' podwójnie, zaczniesz biec. + </notification> + <notification label="Widok" name="HintView"> + To change your camera view, use the Orbit and Pan controls. Zresetuj widok poprzez wciśnięcie klawisza Esc lub chodzenie. + </notification> <notification label="Szafa" name="HintInventory"> Sprawdź swoją Szafę aby znaleźć obiekty. Najnowsze obiekty mogą być łatwo odnalezione w zakładce Nowe obiekty. </notification> @@ -2809,6 +2848,15 @@ Wyciszyć wszystkich? <button name="open" text="Otwórz wyskakujące okno."/> </form> </notification> + <notification name="AuthRequest"> + Strpna '<nolink>[HOST_NAME]</nolink>' w domenie '[REALM]' wymaga nazwy użytkownika i hasła. + <form name="form"> + <input name="username" text="Nazwa użytkownika"/> + <input name="password" text="Hasło"/> + <button name="ok" text="Wyślij"/> + <button name="cancel" text="Anuluj"/> + </form> + </notification> <global name="UnsupportedCPU"> - Prędkość Twojego CPU nie spełnia minimalnych wymagań. </global> diff --git a/indra/newview/skins/default/xui/pl/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/pl/panel_avatar_list_item.xml index 1ab95eec00..c43a9bed81 100644 --- a/indra/newview/skins/default/xui/pl/panel_avatar_list_item.xml +++ b/indra/newview/skins/default/xui/pl/panel_avatar_list_item.xml @@ -21,7 +21,7 @@ <string name="FormatYears"> [COUNT]lat </string> - <text name="avatar_name" value="Nieznane"/> + <text name="avatar_name" value="(ładowanie)"/> <icon name="permission_edit_theirs_icon" tool_tip="Możesz edytować obiekty tego Znajomego"/> <icon name="permission_edit_mine_icon" tool_tip="Ten Znajomy może edytować, kasować lub wziąć Twoje obiekty"/> <icon name="permission_map_icon" tool_tip="Ten Znajomy może zlokalizować Ciebie na mapie"/> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_alpha.xml b/indra/newview/skins/default/xui/pl/panel_edit_alpha.xml index a22d4b0482..51ee3af00d 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_alpha.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_alpha.xml @@ -1,10 +1,12 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_alpha_panel"> - <panel name="avatar_alpha_color_panel"> - <texture_picker label="Alpha dolnej części ciała" name="Lower Alpha" tool_tip="Kliknij aby wybrać teksturę"/> - <texture_picker label="Alpha górnej części ciała" name="Upper Alpha" tool_tip="Kliknij aby wybrać teksturę"/> - <texture_picker label="Alpha głowy" name="Head Alpha" tool_tip="Kliknij aby wybrać teksturę"/> - <texture_picker label="Alpha oka" name="Eye Alpha" tool_tip="Kliknij aby wybrać teksturę"/> - <texture_picker label="Alpha włosów" name="Hair Alpha" tool_tip="Kliknij aby wybrać teksturę"/> - </panel> + <scroll_container name="avatar_alpha_color_panel_scroll"> + <panel name="avatar_alpha_color_panel"> + <texture_picker label="Alpha dolnej części ciała" name="Lower Alpha" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Alpha górnej części ciała" name="Upper Alpha" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Alpha głowy" name="Head Alpha" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Alpha oka" name="Eye Alpha" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Alpha włosów" name="Hair Alpha" tool_tip="Kliknij aby wybrać teksturę"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_gloves.xml b/indra/newview/skins/default/xui/pl/panel_edit_gloves.xml index 166e3c4551..d32646d1a3 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_gloves.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_gloves.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_gloves_panel"> <panel name="avatar_gloves_color_panel"> - <texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> <color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać teksturę"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_jacket.xml b/indra/newview/skins/default/xui/pl/panel_edit_jacket.xml index ba0b908394..7653e84cc0 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_jacket.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_jacket.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_jacket_panel"> <panel name="avatar_jacket_color_panel"> - <texture_picker label="Górny materiał" name="Upper Fabric" tool_tip="Kliknij aby wybrać teksturę"/> - <texture_picker label="Dolny materiał" name="Lower Fabric" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Górna tekstura" name="Upper Fabric" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Dolna tekstura" name="Lower Fabric" tool_tip="Kliknij aby wybrać teksturę"/> <color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_pants.xml b/indra/newview/skins/default/xui/pl/panel_edit_pants.xml index 4adac604f4..7975e55746 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_pants.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_pants.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_pants_panel"> <panel name="avatar_pants_color_panel"> - <texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> <color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_shirt.xml b/indra/newview/skins/default/xui/pl/panel_edit_shirt.xml index 3bcf992d4d..9530c781ab 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_shirt.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_shirt.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_shirt_panel"> <panel name="avatar_shirt_color_panel"> - <texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij by wybrać grafikę"/> + <texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij by wybrać grafikę"/> <color_swatch label="Kolor/Odcień" name="Color/Tint" tool_tip="Kliknij by wybrać kolor"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_shoes.xml b/indra/newview/skins/default/xui/pl/panel_edit_shoes.xml index e2c00c0506..d90a6d8726 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_shoes.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_shoes.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_shoes_panel"> <panel name="avatar_shoes_color_panel"> - <texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> <color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_skirt.xml b/indra/newview/skins/default/xui/pl/panel_edit_skirt.xml index 3fa9cefeb6..f74ad916cd 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_skirt.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_skirt.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_skirt_panel"> <panel name="avatar_skirt_color_panel"> - <texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> <color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_socks.xml b/indra/newview/skins/default/xui/pl/panel_edit_socks.xml index bb2cd637b5..b41069e8d7 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_socks.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_socks.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_socks_panel"> <panel name="avatar_socks_color_panel"> - <texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> <color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_underpants.xml b/indra/newview/skins/default/xui/pl/panel_edit_underpants.xml index 010d9b53d9..f2a9b10f17 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_underpants.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_underpants.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_underpants_panel"> <panel name="avatar_underpants_color_panel"> - <texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać kolor"/> + <texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać kolor"/> <color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/pl/panel_edit_undershirt.xml index 63ae1215e0..7da1341e96 100644 --- a/indra/newview/skins/default/xui/pl/panel_edit_undershirt.xml +++ b/indra/newview/skins/default/xui/pl/panel_edit_undershirt.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_undershirt_panel"> <panel name="avatar_undershirt_color_panel"> - <texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> + <texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/> <color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/> </panel> <panel name="accordion_panel"> diff --git a/indra/newview/skins/default/xui/pl/panel_login.xml b/indra/newview/skins/default/xui/pl/panel_login.xml index 30432c509d..81da94a659 100644 --- a/indra/newview/skins/default/xui/pl/panel_login.xml +++ b/indra/newview/skins/default/xui/pl/panel_login.xml @@ -1,8 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="panel_login"> - <panel.string name="real_url"> - http://secondlife.com/app/login/ - </panel.string> <panel.string name="forgot_password_url"> http://secondlife.com/account/request.php </panel.string> @@ -11,7 +8,7 @@ <text name="username_text"> Użytkownik: </text> - <line_editor label="bobsmith12 lub Steller Sunshine" name="username_edit" tool_tip="Nazwę użytkownika wybierasz podczas rejestracji, np: like bobsmith12 lub Steller Sunshine"/> + <combo_box name="username_combo" tool_tip="Nazwę użytkownika wybierasz przy rejestracji, np. bobsmith12 lub Steller Sunshine"/> <text name="password_text"> Hasło: </text> diff --git a/indra/newview/skins/default/xui/pl/panel_my_profile.xml b/indra/newview/skins/default/xui/pl/panel_my_profile.xml index 6b0ba44bb4..cdc833241d 100644 --- a/indra/newview/skins/default/xui/pl/panel_my_profile.xml +++ b/indra/newview/skins/default/xui/pl/panel_my_profile.xml @@ -5,30 +5,27 @@ <string name="RegisterDateFormat"> [REG_DATE] ([AGE]) </string> + <string name="name_text_args"> + [NAME] + </string> + <string name="display_name_text_args"> + [DISPLAY_NAME] + </string> <layout_stack name="layout"> <layout_panel name="profile_stack"> <scroll_container name="profile_scroll"> <panel name="scroll_content_panel"> <panel name="second_life_image_panel"> - <icon label="" name="2nd_life_edit_icon" tool_tip="Kliknij przycisk Edytuj profil by zmienić zdjęcie"/> - <text name="title_sl_descr_text" value="[SECOND_LIFE]:"/> - </panel> - <panel name="first_life_image_panel"> - <icon label="" name="real_world_edit_icon" tool_tip="Kliknij przycisk Edytuj profil by zmienić zdjęcie"/> - <text name="title_rw_descr_text" value="Życie#1:"/> - </panel> - <text name="title_member_text" value="Urodziny:"/> - <text name="title_acc_status_text" value="Konto:"/> - <text name="title_partner_text" value="Partner:"/> - <panel name="partner_data_panel"> - <name_box initial_value="(przetwarzanie)" name="partner_text"/> + <text name="display_name_descr_text"> + Nazwa użytkownika + </text> + <text name="name_descr_text"> + Wyświetlana nazwa + </text> + <button label="Profil" name="see_profile_btn" tool_tip="Zobacz profil tego awatara"/> </panel> - <text name="title_groups_text" value="Grupy:"/> </panel> </scroll_container> </layout_panel> </layout_stack> - <panel name="profile_me_buttons_panel"> - <button label="Edytuj profil" name="edit_profile_btn" tool_tip="Edytuj informacje o sobie"/> - </panel> </panel> diff --git a/indra/newview/skins/default/xui/pl/panel_notify_textbox.xml b/indra/newview/skins/default/xui/pl/panel_notify_textbox.xml new file mode 100644 index 0000000000..e1668e1ef1 --- /dev/null +++ b/indra/newview/skins/default/xui/pl/panel_notify_textbox.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="instant_message" name="panel_notify_textbox"> + <string name="message_max_lines_count" value="7"/> + <panel label="info_panel" name="info_panel"> + <text_editor name="message" value="wiadomość"/> + </panel> + <panel label="control_panel" name="control_panel"> + <button label="Wyślij" name="btn_submit"/> + <button label="Ignoruj" name="ignore_btn"/> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/pl/panel_people.xml b/indra/newview/skins/default/xui/pl/panel_people.xml index fcb6b19635..1bd5b4a912 100644 --- a/indra/newview/skins/default/xui/pl/panel_people.xml +++ b/indra/newview/skins/default/xui/pl/panel_people.xml @@ -22,7 +22,7 @@ Chcesz spotkać ludzi? Spróbuj [secondlife:///app/worldmap Mapa Świata]. <tab_container name="tabs"> <panel label="W POBLIŻU" name="nearby_panel"> <panel label="bottom_panel" name="bottom_panel"> - <button name="nearby_view_sort_btn" tool_tip="Opcje"/> + <menu_button name="nearby_view_sort_btn" tool_tip="Opcje"/> <button name="add_friend_btn" tool_tip="Dodaj wybranego Rezydenta do znajomych"/> </panel> </panel> @@ -34,27 +34,27 @@ Chcesz spotkać ludzi? Spróbuj [secondlife:///app/worldmap Mapa Świata]. <panel label="bottom_panel" name="bottom_panel"> <layout_stack name="bottom_panel"> <layout_panel name="options_gear_btn_panel"> - <button name="friends_viewsort_btn" tool_tip="Pokaż opcje dodatkowe"/> + <menu_button name="friends_viewsort_btn" tool_tip="Pokaż opcje dodatkowe"/> </layout_panel> <layout_panel name="add_btn_panel"> <button name="add_btn" tool_tip="Dodaj wybranego Rezydenta do znajomych"/> </layout_panel> <layout_panel name="trash_btn_panel"> - <dnd_button name="trash_btn" tool_tip="Usuń wybraną osobę ze swojej listy znajomych"/> + <dnd_button name="del_btn" tool_tip="Usuń zaznaczoną osobę ze swojej listy znajomych"/> </layout_panel> </layout_stack> </panel> </panel> <panel label="GRUPY" name="groups_panel"> <panel label="bottom_panel" name="bottom_panel"> - <button name="groups_viewsort_btn" tool_tip="Opcje"/> + <menu_button name="groups_viewsort_btn" tool_tip="Opcje"/> <button name="plus_btn" tool_tip="Dołącz do grupy/Stwórz nową grupę"/> <button name="activate_btn" tool_tip="Aktywuj wybraną grupę"/> </panel> </panel> <panel label="OSTATNIE" name="recent_panel"> <panel label="bottom_panel" name="bottom_panel"> - <button name="recent_viewsort_btn" tool_tip="Opcje"/> + <menu_button name="recent_viewsort_btn" tool_tip="Opcje"/> <button name="add_friend_btn" tool_tip="Dodaj wybranego Rezydenta do znajomych"/> </panel> </panel> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/pl/panel_preferences_advanced.xml index b267610d33..5e61f62691 100644 --- a/indra/newview/skins/default/xui/pl/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/pl/panel_preferences_advanced.xml @@ -3,35 +3,16 @@ <panel.string name="aspect_ratio_text"> [NUM]:[DEN] </panel.string> - <panel.string name="middle_mouse"> - Środkowy klawisz myszki - </panel.string> - <slider label="Kąt widoku" name="camera_fov"/> - <slider label="Odległość" name="camera_offset_scale"/> - <text name="heading2"> - Automatyczna pozycja dla: - </text> - <check_box label="Buduj/Edytuj" name="edit_camera_movement" tool_tip="Używaj automatycznego pozycjonowania kamery aktywując i deaktywując tryb edycji"/> - <check_box label="Wygląd" name="appearance_camera_movement" tool_tip="Używaj automatycznego pozycjonowania kamery podczas trybu edycji"/> - <check_box initial_value="prawda" label="Schowek" name="appearance_sidebar_positioning" tool_tip="Użyj automatycznego pozycjonowania kamery dla schowka"/> - <check_box label="Pokaż w trybie widoku panoramicznego" name="first_person_avatar_visible"/> - <check_box label="Aktywacja klawiszy strzałek do poruszania awatarem" name="arrow_keys_move_avatar_check"/> - <check_box label="Kliknij-kliknij-przytrzymaj, aby uruchomić" name="tap_tap_hold_to_run"/> - <check_box label="Poruszaj ustami awatara kiedy używana jest komunikacja głosowa" name="enable_lip_sync"/> - <check_box label="Czat chmurkowy" name="bubble_text_chat"/> - <slider label="Intensywność" name="bubble_chat_opacity"/> - <color_swatch name="background" tool_tip="Wybierz kolor czatu w chmurce"/> <text name="UI Size:"> - Rozmiar UI + rozmiar UI: </text> <check_box label="Pokaż błędy skryptu w:" name="show_script_errors"/> <radio_group name="show_location"> <radio_item label="Czat Lokalny" name="0"/> <radio_item label="Osobne okno:" name="1"/> </radio_group> - <check_box label="Włącz/Wyłącz głos:" name="push_to_talk_toggle_check" tool_tip="Jeżeli jesteś w trybie mówienia, w celu aktywacji lub deaktywacji swojego mikrofonu wybierz i wyłącz przycisk Mów tylko raz. Jeżeli nie jesteś w trybie mówienia, mikrofon przesyła Twój głos tylko w momencie aktywacji pełnej przycisku Mów."/> - <line_editor label="Naciśnij Mów by rozpocząć komunikację głosową" name="modifier_combo"/> - <button label="Wybierz klawisz" name="set_voice_hotkey_button"/> - <button label="Środkowy przycisk myszki" name="set_voice_middlemouse_button" tool_tip="Zresetuj do środkowego przycisku myszy"/> - <button label="Inne urządzenia" name="joystick_setup_button"/> + <check_box label="Pozwól na wiele przeglądarek" name="allow_multiple_viewer_check"/> + <check_box label="Pokaż selekcję siatki przy logowaniu" name="show_grid_selection_check"/> + <check_box label="Pokaz menu Zaawansowane" name="show_advanced_menu_check"/> + <check_box label="Pokaz menu Rozwinięcie" name="show_develop_menu_check"/> </panel> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml b/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml index 87894bb358..c7142c8419 100644 --- a/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml @@ -8,44 +8,10 @@ <radio_item label="Średnia" name="radio2" value="1"/> <radio_item label="Duża" name="radio3" value="2"/> </radio_group> - <text name="font_colors"> - Kolor czcionki: - </text> - <color_swatch label="Ty" name="user"/> - <text name="text_box1"> - Ja - </text> - <color_swatch label="Inni" name="agent"/> - <text name="text_box2"> - Inni - </text> - <color_swatch label="IM" name="im"/> - <text name="text_box3"> - IM - </text> - <color_swatch label="System" name="system"/> - <text name="text_box4"> - System - </text> - <color_swatch label="Błędy" name="script_error"/> - <text name="text_box5"> - Błędy - </text> - <color_swatch label="Obiekty" name="objects"/> - <text name="text_box6"> - Obiekty - </text> - <color_swatch label="Właściciel" name="owner"/> - <text name="text_box7"> - Właściciel - </text> - <color_swatch label="Linki" name="links"/> - <text name="text_box9"> - Linki - </text> <check_box initial_value="true" label="Używaj animacji podczas pisania" name="play_typing_animation"/> <check_box label="Wysyłaj wszystkie wiadomości (IM) na moją skrzynkę pocztową kiedy jestem niedostępny" name="send_im_to_email"/> <check_box label="Zwykły tekst IM i historia czatu" name="plain_text_chat_history"/> + <check_box label="Czat chmurkowy" name="bubble_text_chat"/> <text name="show_ims_in_label"> Pokaż wiadomości (IM) w: </text> @@ -56,6 +22,13 @@ <radio_item label="Osobne okna" name="radio" value="0"/> <radio_item label="Etykiety" name="radio2" value="1"/> </radio_group> + <text name="disable_toast_label"> + Uaktywnij wyskakujące okienka rozpoczynających się rozmów: + </text> + <check_box label="Czat grupy" name="EnableGroupChatPopups" tool_tip="Zaznacz aby widzieć wyskakuące okienka kiedy czat grupy się pojawia"/> + <check_box label="Czat IM" name="EnableIMChatPopups" tool_tip="Zaznacz aby widzieć wyskakujące okienka kiedy IM się pojawia"/> + <spinner label="Czas widoczności czatu w pobliżu:" name="nearby_toasts_lifetime"/> + <spinner label="Czas znikania czatu w pobliżu:" name="nearby_toasts_fadingtime"/> <check_box label="Używaj translatora podczas rozmowy (wspierany przez Google)" name="translate_chat_checkbox"/> <text name="translate_language_text"> Przetłumacz czat na: diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_colors.xml b/indra/newview/skins/default/xui/pl/panel_preferences_colors.xml new file mode 100644 index 0000000000..3d1160882b --- /dev/null +++ b/indra/newview/skins/default/xui/pl/panel_preferences_colors.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Kolory" name="colors_panel"> + <text name="effects_color_textbox"> + Moje efekty (selection beam): + </text> + <color_swatch name="effect_color_swatch" tool_tip="Kliknij aby wybrać kolor"/> + <text name="font_colors"> + Kolor czcionki czatu: + </text> + <text name="text_box1"> + Ja + </text> + <text name="text_box2"> + Inni + </text> + <text name="text_box3"> + Obiekty + </text> + <text name="text_box4"> + System + </text> + <text name="text_box5"> + Błędy + </text> + <text name="text_box7"> + Właściciel + </text> + <text name="text_box9"> + URL + </text> + <text name="bubble_chat"> + Kolor tła taga (dotyczy również czatu chmurkowego): + </text> + <color_swatch name="background" tool_tip="Wybierz kolor taga"/> + <slider label="Przeźroczystość:" name="bubble_chat_opacity" tool_tip="Wybierz przeźroczystość taga"/> + <text name="floater_opacity"> + Przeźroczystość: + </text> + <slider label="Aktywny:" name="active"/> + <slider label="Niekatywny:" name="inactive"/> +</panel> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_general.xml b/indra/newview/skins/default/xui/pl/panel_preferences_general.xml index 00dc84dd7a..44dcb2112c 100644 --- a/indra/newview/skins/default/xui/pl/panel_preferences_general.xml +++ b/indra/newview/skins/default/xui/pl/panel_preferences_general.xml @@ -48,13 +48,18 @@ <check_box label="Nazwy użytkowników" name="show_slids" tool_tip="Pokaż nazwy użytkowników, np. bobsmith123"/> <check_box label="Wyświetl tytuł grupowy" name="show_all_title_checkbox1" tool_tip="Wyświetl tytuł grupowy np. oficer"/> <check_box label="Zaznacz znajomych" name="show_friends" tool_tip="Zaznacz imiona swoich znajomych"/> - <text name="effects_color_textbox"> - Kolor moich efektów: + <check_box label="Pokaż wyświetlane nazwy" name="display_names_check" tool_tip="Pokaż wyświetlane nazwy w czacie, IM, imionach, etc."/> + <check_box label="Uaktywnij wskazówki UI" name="viewer_hints_check"/> + <text name="inworld_typing_rg_label"> + Wciśnięcie klawiszy liter: </text> + <radio_group name="inworld_typing_preference"> + <radio_item label="Włącza czat lokalny" name="radio_start_chat" value="1"/> + <radio_item label="Wpływ na ruch (WASD)" name="radio_move" value="0"/> + </radio_group> <text name="title_afk_text"> Zasypiaj w czasie: </text> - <color_swatch label="" name="effect_color_swatch" tool_tip="Selekcja koloru"/> <combo_box label="Czas Trybu Oddalenia:" name="afk"> <combo_box.item label="2 minuty" name="item0"/> <combo_box.item label="5 minut" name="item1"/> @@ -62,7 +67,6 @@ <combo_box.item label="30 minut" name="item3"/> <combo_box.item label="nigdy" name="item4"/> </combo_box> - <check_box label="Pokaż wyświetlane nazwy" name="display_names_check" tool_tip="Pokaż wyświetlane nazwy w czacie, IM, imionach, etc."/> <text name="text_box3"> Odpowiedź w trybie pracy: </text> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml index 1a9f59bbff..0f21aa9dd1 100644 --- a/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml @@ -26,6 +26,7 @@ <text name="ShadersText"> Cieniowanie pixeli (shadery): </text> + <check_box initial_value="prawda" label="Przeźroczystość wody" name="TransparentWater"/> <check_box initial_value="true" label="Mapowanie wypukłości i połysk" name="BumpShiny"/> <check_box initial_value="true" label="Podstawowe shadery" name="BasicShaders" tool_tip="Wyłączenie tej opcji może naprawić błędy niektórych sterowników graficznych."/> <check_box initial_value="true" label="Shadery atmosfery" name="WindLightUseAtmosShaders"/> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_move.xml b/indra/newview/skins/default/xui/pl/panel_preferences_move.xml new file mode 100644 index 0000000000..4c2df2c1f3 --- /dev/null +++ b/indra/newview/skins/default/xui/pl/panel_preferences_move.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel label="Ruch" name="move_panel"> + <slider label="Kąt widoku kamery" name="camera_fov"/> + <slider label="Dystans kamery" name="camera_offset_scale"/> + <text name="heading2"> + Automatyczna pozycja dla: + </text> + <check_box label="Budowanie/Edycja" name="edit_camera_movement" tool_tip="Używaj automatycznego pozycjonowania kamery podczas włączania i wyłączania trybu edycji."/> + <check_box label="Wygląd" name="appearance_camera_movement" tool_tip="Używaj automatycznego pozycjonowania kamery podczas trybu edycji"/> + <check_box initial_value="prawda" label="Schowek" name="appearance_sidebar_positioning" tool_tip="Używaj automatycznego pozycjonowania kamery dla panelu bocznego"/> + <check_box label="Awatar widoczny w trybie panoramicznym" name="first_person_avatar_visible"/> + <text name=" Mouse Sensitivity"> + Czułość myszki w widoku panoramicznym: + </text> + <check_box label="Zmień klawisze myszki" name="invert_mouse"/> + <check_box label="Przyciski ze strzałkami zawsze poruszają awatarem" name="arrow_keys_move_avatar_check"/> + <check_box label="Wciśnij-wciśnij-przytrzymaj aby biec" name="tap_tap_hold_to_run"/> + <check_box label="Podwójnie kliknij aby:" name="double_click_chkbox"/> + <radio_group name="double_click_action"> + <radio_item label="teleportować się" name="radio_teleport"/> + <radio_item label="włączyć auto-pilota" name="radio_autopilot"/> + </radio_group> + <button label="Inne urządzenia" name="joystick_setup_button"/> +</panel> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/pl/panel_preferences_privacy.xml index fd9cdd6ff0..a2f9b4176e 100644 --- a/indra/newview/skins/default/xui/pl/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/pl/panel_preferences_privacy.xml @@ -7,19 +7,24 @@ <text name="cache_size_label_l"> (Miejsca, obrazy, przeglądarka internetowa, wyszukiwarka historii) </text> + <check_box label="Pokaż mój profil w wynikach wyszukiwarki" name="online_searchresults"/> <check_box label="Mój status online jest dostępny tylko dla znajomych i grup do których należę" name="online_visibility"/> <check_box label="Możliwość wysyłania wiadomości prywatnej (IM) oraz rozmowy głosowej tylko dla znajomych i grup do których należę" name="voice_call_friends_only_check"/> <check_box label="Wyłącz mikrofon po zakończeniu rozmowy głosowej" name="auto_disengage_mic_check"/> - <check_box label="Akceptuj ciasteczka" name="cookies_enabled"/> + <check_box label="Pokaż moje ulubione landmarki przy logowaniu (w rozwijanym menu 'Rozpocznij w')" name="favorites_on_login_check"/> <text name="Logs:"> - Logi: + Logi rozmów: </text> <check_box label="Zapisz logi rozmów ogólnych na moim komputerze" name="log_nearby_chat"/> <check_box label="Zapisuj logi wiadomości prywatnych (IM) na moim komputerze" name="log_instant_messages"/> - <check_box label="Pokazuj czas" name="show_timestamps_check_im"/> + <check_box label="Dodaj znacznik czasu do każdej linii w logu rozmów." name="show_timestamps_check_im"/> + <check_box label="Dodaj znacznik czasu do nazwy pliku z zapisem rozmów." name="logfile_name_datestamp"/> <text name="log_path_desc"> Lokalizacja zapisu: </text> <button label="Przeglądaj" label_selected="Przeglądaj" name="log_path_button"/> <button label="Lista zablokowanych" name="block_list"/> + <text name="block_list_label"> + (Ludzie i/lub obiekty zablokowane) + </text> </panel> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml b/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml index 24e5c2b824..fa0a5981a8 100644 --- a/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml @@ -1,13 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Ustawienia" name="Input panel"> - <text name="Mouselook:"> - Widok panoramiczny: - </text> - <text name=" Mouse Sensitivity"> - Czułość myszki - </text> - <slider name="mouse_sensitivity"/> - <check_box label="Zmień klawisze myszki" name="invert_mouse"/> <text name="Network:"> Sieć: </text> @@ -47,4 +39,11 @@ </text> <line_editor name="web_proxy_editor" tool_tip="Nazwa lub IP proxy, którego chcesz użyć"/> <spinner label="Numer portu:" name="web_proxy_port"/> + <text name="Software updates:"> + Aktualizaje oprogramowania: + </text> + <combo_box name="updater_service_combobox"> + <combo_box.item label="Zainstauj automatycznie" name="Install_automatically"/> + <combo_box.item label="Pobierz i zainstaluj aktualizacje ręcznie" name="Install_manual"/> + </combo_box> </panel> diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml index eaf9ae809b..c708cc0b99 100644 --- a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml @@ -1,5 +1,8 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel label="Dźwięki" name="Preference Media panel"> + <panel.string name="middle_mouse"> + Środkowy przycisk myszy + </panel.string> <slider label="Główny" name="System Volume"/> <check_box initial_value="true" label="Wycisz podczas minimalizacji" name="mute_when_minimized"/> <slider label="Interfejs" name="UI Volume"/> @@ -23,6 +26,11 @@ <radio_item label="pozycji kamery" name="0"/> <radio_item label="pozycji awatara" name="1"/> </radio_group> + <check_box label="Poruszaj ustami awatara podczas mówienia" name="enable_lip_sync"/> + <check_box label="Włącz/wyłącz mikrofon kiedy naciskam:" name="push_to_talk_toggle_check" tool_tip="Kiedy aktywny jest tryb przełączania wciśnij i zwolnij przełącznik RAZ aby włączyć lub wyłączyć mikrofon. Kiedy tryb przełączania nie jest aktywny mikrofon nadaje głos tylko kiedy przełącznik jest wciśnięty."/> + <line_editor label="Przełącznik kliknij-aby-mówić" name="modifier_combo"/> + <button label="Ustaw klawisz" name="set_voice_hotkey_button"/> + <button name="set_voice_middlemouse_button" tool_tip="Zresetuj do środkowego przycisku myszy"/> <button label="Wejściowe/Wyjściowe urządzenia" name="device_settings_btn"/> <panel label="Ustawienia sprzętowe" name="device_settings_panel"> <panel.string name="default_text"> diff --git a/indra/newview/skins/default/xui/pl/panel_script_ed.xml b/indra/newview/skins/default/xui/pl/panel_script_ed.xml index fa89a3f727..e18900af68 100644 --- a/indra/newview/skins/default/xui/pl/panel_script_ed.xml +++ b/indra/newview/skins/default/xui/pl/panel_script_ed.xml @@ -15,11 +15,6 @@ <panel.string name="Title"> Skrypt: [NAME] </panel.string> - <text_editor name="Script Editor"> - Ładowanie... - </text_editor> - <button label="Zapisz" label_selected="Zapisz" name="Save_btn"/> - <combo_box label="Wklej..." name="Insert..."/> <menu_bar name="script_menu"> <menu label="Plik" name="File"> <menu_item_call label="Zapisz" name="Save"/> @@ -40,4 +35,10 @@ <menu_item_call label="Pomoc..." name="Keyword Help..."/> </menu> </menu_bar> + <text_editor name="Script Editor"> + Ładowanie... + </text_editor> + <combo_box label="Wklej..." name="Insert..."/> + <button label="Zapisz" label_selected="Zapisz" name="Save_btn"/> + <button label="Edytuj..." name="Edit_btn"/> </panel> diff --git a/indra/newview/skins/default/xui/pl/panel_status_bar.xml b/indra/newview/skins/default/xui/pl/panel_status_bar.xml index 5e97dd8961..6aa0d27bb8 100644 --- a/indra/newview/skins/default/xui/pl/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/pl/panel_status_bar.xml @@ -22,7 +22,7 @@ L$ [AMT] </panel.string> <panel name="balance_bg"> - <text name="balance" tool_tip="Mój bilans" value="L$20"/> + <text name="balance" tool_tip="Kliknij aby odświeżyć bilans L$" value="L$20"/> <button label="Kup L$" name="buyL" tool_tip="Kliknij aby kupić więcej L$"/> </panel> <text name="TimeText" tool_tip="Obecny czas (Pacyficzny)"> diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index ea8bdd75b9..d1fb382a2d 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -1737,11 +1737,8 @@ <string name="InvOfferGaveYou"> oddany Tobie </string> - <string name="InvOfferYouDecline"> - Odrzucony przez Ciebie - </string> - <string name="InvOfferFrom"> - od + <string name="InvOfferDecline"> + Odrzucono [DESC] od <nolink>[NAME]</nolink>. </string> <string name="GroupMoneyTotal"> Suma diff --git a/indra/newview/skins/default/xui/pt/floater_web_content.xml b/indra/newview/skins/default/xui/pt/floater_web_content.xml new file mode 100644 index 0000000000..5101579c6f --- /dev/null +++ b/indra/newview/skins/default/xui/pt/floater_web_content.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater name="floater_web_content" title=""> + <layout_stack name="stack1"> + <layout_panel name="nav_controls"> + <button name="back" tool_tip="Navegar para trás"/> + <button name="forward" tool_tip="Navegar para frente"/> + <button name="stop" tool_tip="Parar a navegação"/> + <button name="reload" tool_tip="Recarregar página"/> + <combo_box name="address" tool_tip="Digite a URL aqui"/> + <icon name="media_secure_lock_flag" tool_tip="Navegação segura"/> + <button name="popexternal" tool_tip="Abrir a URL atual no navegador do seu computador"/> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/pt/menu_login.xml b/indra/newview/skins/default/xui/pt/menu_login.xml index a43ac271a9..3dff3d7c8a 100644 --- a/indra/newview/skins/default/xui/pt/menu_login.xml +++ b/indra/newview/skins/default/xui/pt/menu_login.xml @@ -16,7 +16,8 @@ <menu_item_call label="Definir tamanho da janela:" name="Set Window Size..."/> <menu_item_call label="Mostrar TOS" name="TOS"/> <menu_item_call label="Mostrar mensagem crítica" name="Critical"/> - <menu_item_call label="Teste de navegador web" name="Web Browser Test"/> + <menu_item_call label="Teste de mídia do navegador" name="Web Browser Test"/> + <menu_item_call label="Teste de conteúdo web" name="Web Content Floater Test"/> <menu_item_check label="Exibir seletor da grade" name="Show Grid Picker"/> <menu_item_call label="Exibir painel de notificações" name="Show Notifications Console"/> </menu> diff --git a/indra/newview/skins/default/xui/pt/menu_mini_map.xml b/indra/newview/skins/default/xui/pt/menu_mini_map.xml index d742038e15..6a3fe55de5 100644 --- a/indra/newview/skins/default/xui/pt/menu_mini_map.xml +++ b/indra/newview/skins/default/xui/pt/menu_mini_map.xml @@ -3,6 +3,7 @@ <menu_item_call label="Zoom Perto" name="Zoom Close"/> <menu_item_call label="Zoom Médio" name="Zoom Medium"/> <menu_item_call label="Zoom Longe" name="Zoom Far"/> + <menu_item_call label="Zoom padrão" name="Zoom Default"/> <menu_item_check label="Girar mapa" name="Rotate Map"/> <menu_item_check label="Auto Center" name="Auto Center"/> <menu_item_call label="Parar Acompanhamento" name="Stop Tracking"/> diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml index 95c37c53ca..3bbf2b66f2 100644 --- a/indra/newview/skins/default/xui/pt/menu_viewer.xml +++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml @@ -121,13 +121,15 @@ <menu_item_call label="Animação (L$[COST])..." name="Upload Animation"/> <menu_item_call label="Volume (L$[COST] por arquivo)..." name="Bulk Upload"/> </menu> + <menu_item_call label="Desfazer" name="Undo"/> + <menu_item_call label="Repetir" name="Redo"/> </menu> <menu label="Ajuda" name="Help"> <menu_item_call label="[SECOND_LIFE] Ajuda" name="Second Life Help"/> + <menu_item_check label="Ativar dicas" name="Enable Hints"/> <menu_item_call label="Denunciar abuso" name="Report Abuse"/> <menu_item_call label="Relatar bug" name="Report Bug"/> <menu_item_call label="Sobre [APP_NAME]" name="About Second Life"/> - <menu_item_check label="Ativar dicas" name="Enable Hints"/> </menu> <menu label="Avançado" name="Advanced"> <menu_item_call label="Recarregar texturas" name="Rebake Texture"/> @@ -268,7 +270,8 @@ <menu_item_call label="Dump Region Object Cache" name="Dump Region Object Cache"/> </menu> <menu label="Interface" name="UI"> - <menu_item_call label="Teste de navegador web" name="Web Browser Test"/> + <menu_item_call label="Teste de mídia do navegador" name="Web Browser Test"/> + <menu_item_call label="Navegador de conteúdo web" name="Web Content Browser"/> <menu_item_call label="Print Selected Object Info" name="Print Selected Object Info"/> <menu_item_call label="Dados de memória" name="Memory Stats"/> <menu_item_check label="Console de depuração de região" name="Region Debug Console"/> diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml index a1855f2e89..4b2e4bc5e0 100644 --- a/indra/newview/skins/default/xui/pt/notifications.xml +++ b/indra/newview/skins/default/xui/pt/notifications.xml @@ -108,6 +108,10 @@ Por favor, selecione apenas um objeto e tente novamente. Residentes que não são amigos não veem que você decidiu ignorar ligações e MIs deles. <usetemplate name="okbutton" yestext="OK"/> </notification> + <notification name="FavoritesOnLogin"> + Nota: Ao ativar esta opção, qualquer pessoa que utilizar este computador poderá ver a sua lista de lugares preferidos. + <usetemplate name="okbutton" yestext="OK"/> + </notification> <notification name="GrantModifyRights"> Conceder direitos de modificação a outros residentes vai autorizá-los a mudar, apagar ou pegar TODOS os seus objetos. Seja MUITO cuidadoso ao conceder esta autorização. Deseja dar direitos de modificação a [NAME]? @@ -938,7 +942,7 @@ Oferecer amizade para [NAME]? <input name="message"> [DESC] (novo) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Cancelar"/> </form> </notification> @@ -948,7 +952,7 @@ Oferecer amizade para [NAME]? <input name="message"> [DESC] (novo) </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Cancelar"/> </form> </notification> @@ -958,7 +962,7 @@ Oferecer amizade para [NAME]? <input name="new_name"> [NAME] </input> - <button name="Offer" text="OK"/> + <button name="OK" text="OK"/> <button name="Cancel" text="Cancelar"/> </form> </notification> @@ -1329,9 +1333,41 @@ Baixe e instale a versão mais recente do visualizador em http://secondlife.com/download. <usetemplate name="okbutton" yestext="OK"/> </notification> - <notification name="DownloadBackground"> - Foi baixada uma nova versão do [APP_NAME] -A nova versão será exibida quando o [APP_NAME] for reiniciado. + <notification name="FailedRequiredUpdateInstall"> + Não foi possível instalar uma atualização necessária. +Não será possível acessar a sua conta até que você atualize o [APP_NAME]. + +Baixe e instale a versão mais recente do visualizador em +http://secondlife.com/download. + <usetemplate name="okbutton" yestext="Sair"/> + </notification> + <notification name="UpdaterServiceNotRunning"> + A instalação do Second Life requer uma atualização. + +Baixe a atualização em http://www.secondlife.com/downloads +ou você pode instalar a instalação agora. + <usetemplate name="okcancelbuttons" notext="Sair do Second Life" yestext="Baixar e instalar agora"/> + </notification> + <notification name="DownloadBackgroundTip"> + Baixamos uma atualização para a instalação do [APP_NAME]. +Versão [VERSION] [[RELEASE_NOTES_FULL_URL] sobre esta atualização] + <usetemplate name="okcancelbuttons" notext="Depois..." yestext="Instalar agora e reiniciar o [APP_NAME]"/> + </notification> + <notification name="DownloadBackgroundDialog"> + Baixamos uma atualização para a instalação do [APP_NAME]. +Versão [VERSION] [[RELEASE_NOTES_FULL_URL] sobre esta atualização] + <usetemplate name="okcancelbuttons" notext="Depois..." yestext="Instalar agora e reiniciar o [APP_NAME]"/> + </notification> + <notification name="RequiredUpdateDownloadedVerboseDialog"> + O software requer uma atualização que já foi baixada. +Versão [VERSION] + +Para instalar a atualização, será preciso reiniciar o [APP_NAME]. + <usetemplate name="okbutton" yestext="OK"/> + </notification> + <notification name="RequiredUpdateDownloadedDialog"> + Para instalar a atualização, será preciso reiniciar o [APP_NAME]. + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="DeedObjectToGroup"> Delegar este objeto causará ao grupo: @@ -2198,14 +2234,6 @@ Selecione o residente da lista e clique em 'MI' na parte de baixo do p <notification name="NoContentToSearch"> Por favor, selecione ao menos um tipo de conteúdo para a busca (PG, Mature ou Adult). </notification> - <notification name="GroupVote"> - [NAME] propõe que você vote: -[MESSAGE] - <form name="form"> - <button name="VoteNow" text="Vote agora"/> - <button name="Later" text="Depois"/> - </form> - </notification> <notification name="SystemMessage"> [MESSAGE] </notification> @@ -2658,9 +2686,6 @@ Clique em Aceitar para atender ou em Recusar para recusar este convite. Clique <notification name="VoiceCallGenericError"> Ocorreu um erro enquanto você tentava se conectar à conversa de voz de [VOICE_CHANNEL_NAME]. Favor tentar novamente mais tarde. </notification> - <notification name="ServerVersionChanged"> - Você chegou a uma região com uma versão diferente de servidor, que pode afetar o desempenho. [[URL] Consultar notas da versão.] - </notification> <notification name="UnsupportedCommandSLURL"> O SLurl no qual você clicou não é suportado. </notification> @@ -2763,9 +2788,7 @@ Avatar '[NAME]' sair do modo aparecer. <notification name="NoConnect"> Detectamos um problema de conexão com [PROTOCOL] [HOSTID]. Verifique a configuração da sua rede e firewall. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="NoVoiceConnect"> Estamos tendo problemas de conexão com o seu servidor de voz: @@ -2774,9 +2797,7 @@ Verifique a configuração da sua rede e firewall. Talvez não seja possível se comunicar via voz. Verifique a configuração da sua rede e firewall. - <form name="form"> - <button name="OK" text="OK"/> - </form> + <usetemplate name="okbutton" yestext="OK"/> </notification> <notification name="AvatarRezLeftNotification"> ( [EXISTENCE] segundos de vida ) @@ -2811,6 +2832,9 @@ Silenciar todos? <notification label="Explore o mundo" name="HintDestinationGuide"> O Guia de Destinos traz milhares de lugares novos para você explorar e conhecer. Selecione um lugar, clique em Teletransportar e comece suas descobertas. </notification> + <notification label="Troque o visual" name="HintAvatarPicker"> + Que tal mudar o visual? Clique o botão abaixo para ver Avatares diferentes. + </notification> <notification label="Painel lateral" name="HintSidePanel"> Acesse rapidamente seu inventário, roupas, looks, perfis e mais no painel lateral. </notification> @@ -2820,6 +2844,12 @@ Silenciar todos? <notification label="Nome de tela" name="HintDisplayName"> Defina seu nome de tela personalizável. O nome de tele é separado do seu nome de usuário, que não pode ser modificado. Você pode mudar a visualização dos nomes de outras pessoas nas suas preferências. </notification> + <notification label="Movimentar" name="HintMoveArrows"> + Para andar, use as setas do teclado. Para correr, pressione a seta para cima duas vezes. + </notification> + <notification label="Exibir" name="HintView"> + Para mudar o ângulo de visualização, use os controles Órbita e Pan. Volte à visualização normal pressionando a tecla Escape ou começando a andar. + </notification> <notification label="Inventário" name="HintInventory"> Você encontrará seus pertences no inventário. Os itens mais novos também ficam na guia Itens recentes. </notification> @@ -2833,6 +2863,15 @@ Silenciar todos? <button name="open" text="Abrir pop-up"/> </form> </notification> + <notification name="AuthRequest"> + O site em '<nolink>[HOST_NAME]</nolink>' em '[REALM]' requer nome e senha. + <form name="form"> + <input name="username" text="Nome de usuário"/> + <input name="password" text="Senha:"/> + <button name="ok" text="Enviar"/> + <button name="cancel" text="Cancelar"/> + </form> + </notification> <global name="UnsupportedCPU"> - A velocidade da sua CPU não suporta os requisitos mínimos exigidos. </global> diff --git a/indra/newview/skins/default/xui/pt/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/pt/panel_avatar_list_item.xml index ca67125c65..b444593af8 100644 --- a/indra/newview/skins/default/xui/pt/panel_avatar_list_item.xml +++ b/indra/newview/skins/default/xui/pt/panel_avatar_list_item.xml @@ -21,7 +21,7 @@ <string name="FormatYears"> [COUNT]anos </string> - <text name="avatar_name" value="Desconhecido"/> + <text name="avatar_name" value="(carregando)"/> <icon name="permission_edit_theirs_icon" tool_tip="Você pode editar os pertences deste amigo"/> <icon name="permission_edit_mine_icon" tool_tip="Este amigo pode editar, excluir ou pegar seus pertences"/> <icon name="permission_map_icon" tool_tip="Este amigo pode localizar você no mapa"/> diff --git a/indra/newview/skins/default/xui/pt/panel_edit_alpha.xml b/indra/newview/skins/default/xui/pt/panel_edit_alpha.xml index f8be9daf1b..b274945dbd 100644 --- a/indra/newview/skins/default/xui/pt/panel_edit_alpha.xml +++ b/indra/newview/skins/default/xui/pt/panel_edit_alpha.xml @@ -1,10 +1,12 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <panel name="edit_alpha_panel"> - <panel name="avatar_alpha_color_panel"> - <texture_picker label="Alpha inferior" name="Lower Alpha" tool_tip="Selecionar imagem"/> - <texture_picker label="Alpha de cima" name="Upper Alpha" tool_tip="Selecionar imagem"/> - <texture_picker label="Cabeça Alpha" name="Head Alpha" tool_tip="Selecionar imagem"/> - <texture_picker label="Olhos Alpha" name="Eye Alpha" tool_tip="Selecionar imagem"/> - <texture_picker label="Cabelo alpha" name="Hair Alpha" tool_tip="Selecionar imagem"/> - </panel> + <scroll_container name="avatar_alpha_color_panel_scroll"> + <panel name="avatar_alpha_color_panel"> + <texture_picker label="Alpha inferior" name="Lower Alpha" tool_tip="Selecionar imagem"/> + <texture_picker label="Alpha de cima" name="Upper Alpha" tool_tip="Selecionar imagem"/> + <texture_picker label="Cabeça Alpha" name="Head Alpha" tool_tip="Selecionar imagem"/> + <texture_picker label="Olhos Alpha" name="Eye Alpha" tool_tip="Selecionar imagem"/> + <texture_picker label="Cabelo alpha" name="Hair Alpha" tool_tip="Selecionar imagem"/> + </panel> + </scroll_container> </panel> diff --git a/indra/newview/skins/default/xui/pt/panel_login.xml b/indra/newview/skins/default/xui/pt/panel_login.xml index 9c8650e75e..42df93fd86 100644 --- a/indra/newview/skins/default/xui/pt/panel_login.xml +++ b/indra/newview/skins/default/xui/pt/panel_login.xml @@ -11,7 +11,7 @@ <text name="username_text"> Nome de usuário: </text> - <line_editor label="zecazc12 or Magia Solar" name="username_edit" tool_tip="O nome de usuário que você escolheu ao fazer seu cadastro, como zecazc12 or Magia Solar"/> + <combo_box name="username_combo" tool_tip="O nome de usuário que você escolheu ao fazer seu cadastro, como zecazc12 or Magia Solar"/> <text name="password_text"> Senha: </text> diff --git a/indra/newview/skins/default/xui/pt/panel_my_profile.xml b/indra/newview/skins/default/xui/pt/panel_my_profile.xml index 1a28f61c2d..aa15a2445d 100644 --- a/indra/newview/skins/default/xui/pt/panel_my_profile.xml +++ b/indra/newview/skins/default/xui/pt/panel_my_profile.xml @@ -5,30 +5,27 @@ <string name="RegisterDateFormat"> [REG_DATE] ([AGE]) </string> + <string name="name_text_args"> + [NAME] + </string> + <string name="display_name_text_args"> + [DISPLAY_NAME] + </string> <layout_stack name="layout"> <layout_panel name="profile_stack"> <scroll_container name="profile_scroll"> <panel name="scroll_content_panel"> <panel name="second_life_image_panel"> - <icon label="" name="2nd_life_edit_icon" tool_tip="Clique no botão Editar para trocar a imagem"/> - <text name="title_sl_descr_text" value="[SECOND_LIFE]:"/> - </panel> - <panel name="first_life_image_panel"> - <icon label="" name="real_world_edit_icon" tool_tip="Clique no botão Editar para trocar a imagem"/> - <text name="title_rw_descr_text" value="Mundo real:"/> - </panel> - <text name="title_member_text" value="Residente desde:"/> - <text name="title_acc_status_text" value="Conta:"/> - <text name="title_partner_text" value="Parceiro(a):"/> - <panel name="partner_data_panel"> - <name_box initial_value="(pesquisando)" name="partner_text"/> + <text name="display_name_descr_text"> + Nome de usuário + </text> + <text name="name_descr_text"> + Nome de tela + </text> + <button label="Perfil" name="see_profile_btn" tool_tip="Ver o perfil deste avatar"/> </panel> - <text name="title_groups_text" value="Grupos:"/> </panel> </scroll_container> </layout_panel> </layout_stack> - <panel name="profile_me_buttons_panel"> - <button label="Editar perfil" name="edit_profile_btn" tool_tip="Editar dados pessoais"/> - </panel> </panel> diff --git a/indra/newview/skins/default/xui/pt/panel_notify_textbox.xml b/indra/newview/skins/default/xui/pt/panel_notify_textbox.xml index d9614fe76b..dcd9ba1815 100644 --- a/indra/newview/skins/default/xui/pt/panel_notify_textbox.xml +++ b/indra/newview/skins/default/xui/pt/panel_notify_textbox.xml @@ -3,8 +3,9 @@ <string name="message_max_lines_count" value="7"/> <panel label="info_panel" name="info_panel"> <text_editor name="message" value="mensagem"/> - parse_urls="false" + </panel> + <panel label="control_panel" name="control_panel"> <button label="Enviar" name="btn_submit"/> + <button label="Ignorar" name="ignore_btn"/> </panel> - <panel label="control_panel" name="control_panel"/> </panel> diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_colors.xml b/indra/newview/skins/default/xui/pt/panel_preferences_colors.xml index 3ca9da06c9..5f2f341e3f 100644 --- a/indra/newview/skins/default/xui/pt/panel_preferences_colors.xml +++ b/indra/newview/skins/default/xui/pt/panel_preferences_colors.xml @@ -29,10 +29,10 @@ URLs </text> <text name="bubble_chat"> - Fundo do balão: + Cor de fundo do nome (e do balão do bate-papo): </text> - <color_swatch name="background" tool_tip="Escolha a cor do balão de bate-papo"/> - <slider label="Opacidade:" name="bubble_chat_opacity"/> + <color_swatch name="background" tool_tip="Selecionar cor do nome"/> + <slider label="Opacidade:" name="bubble_chat_opacity" tool_tip="Selecionar cor do nome"/> <text name="floater_opacity"> Opacidade: </text> diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/pt/panel_preferences_privacy.xml index 5545dcda38..d7fb585e35 100644 --- a/indra/newview/skins/default/xui/pt/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/pt/panel_preferences_privacy.xml @@ -7,9 +7,11 @@ <text name="cache_size_label_l"> (Locações, imagens, web, histórico de busca) </text> + <check_box label="Mostrar nos resultados de busca" name="online_searchresults"/> <check_box label="Apenas amigos e grupos sabem que estou online" name="online_visibility"/> <check_box label="Apenas amigos e grupos podem me chamar ou enviar MI" name="voice_call_friends_only_check"/> <check_box label="Desligar o microfone quando terminar chamadas" name="auto_disengage_mic_check"/> + <check_box label="Mostrar meus marcos preferidos na página de login (menu 'Começar em':)" name="favorites_on_login_check"/> <text name="Logs:"> Registro de bate-papos: </text> diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml b/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml index 0c6fb68140..d8d4a8fc1c 100644 --- a/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml @@ -39,5 +39,11 @@ </text> <line_editor name="web_proxy_editor" tool_tip="O nome ou endereço IP do proxy da sua preferência"/> <spinner label="Porta:" name="web_proxy_port"/> - <check_box initial_value="verdadeiro" label="Baixar e instalar atualizações [APP_NAME] automaticamente" name="updater_service_active"/> + <text name="Software updates:"> + Atualizações de software: + </text> + <combo_box name="updater_service_combobox"> + <combo_box.item label="Instalar automaticamente" name="Install_automatically"/> + <combo_box.item label="Baixar e instalar atualizações manualmente" name="Install_manual"/> + </combo_box> </panel> diff --git a/indra/newview/skins/default/xui/pt/panel_status_bar.xml b/indra/newview/skins/default/xui/pt/panel_status_bar.xml index fbbcf0d1be..f7890ae57d 100644 --- a/indra/newview/skins/default/xui/pt/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/pt/panel_status_bar.xml @@ -22,7 +22,7 @@ L$ [AMT] </panel.string> <panel name="balance_bg"> - <text name="balance" tool_tip="Meu saldo" value="L$20"/> + <text name="balance" tool_tip="Atualizar saldo de L$" value="L$20"/> <button label="Comprar L$" name="buyL" tool_tip="Comprar mais L$"/> </panel> <text name="TimeText" tool_tip="Hora atual (Pacífico)"> diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp index 9da851ffc4..d691bb6c44 100644 --- a/indra/newview/tests/llcapabilitylistener_test.cpp +++ b/indra/newview/tests/llcapabilitylistener_test.cpp @@ -72,7 +72,7 @@ struct TestCapabilityProvider: public LLCapabilityProvider { mCaps[cap] = url; } - LLHost getHost() const { return mHost; } + const LLHost& getHost() const { return mHost; } std::string getDescription() const { return "TestCapabilityProvider"; } LLHost mHost; diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index aa4983a3b6..1888f191e2 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -361,6 +361,7 @@ void LLUpdaterServiceImpl::error(std::string const & message) { if(mIsChecking) { + setState(LLUpdaterService::TEMPORARY_ERROR); restartTimer(mCheckPeriod); } } @@ -372,9 +373,8 @@ void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion, stopTimer(); mNewVersion = newVersion; mIsDownloading = true; - mUpdateDownloader.download(uri, hash, newVersion, false); - setState(LLUpdaterService::DOWNLOADING); + mUpdateDownloader.download(uri, hash, newVersion, false); } void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, @@ -384,9 +384,8 @@ void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, stopTimer(); mNewVersion = newVersion; mIsDownloading = true; - mUpdateDownloader.download(uri, hash, newVersion, true); - setState(LLUpdaterService::DOWNLOADING); + mUpdateDownloader.download(uri, hash, newVersion, true); } void LLUpdaterServiceImpl::upToDate(void) diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 421481bc43..450f19c1c6 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -59,6 +59,7 @@ public: enum eUpdaterState { INITIAL, CHECKING_FOR_UPDATE, + TEMPORARY_ERROR, DOWNLOADING, INSTALLING, UP_TO_DATE, |