diff options
Diffstat (limited to 'indra')
164 files changed, 9587 insertions, 8441 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/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/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 2d3d1adaa5..6fa57604d8 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,2008 +1,2008 @@ -/** - - * @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 = 0;//(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; -} - +/**
+
+ * @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 = 0;//(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)
@@ -2142,5128 +2142,5128 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs 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; - } -}; - +
+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 ); - } -} +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/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/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/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/settings.xml b/indra/newview/app_settings/settings.xml index e679a04320..051f981e8d 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> diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index afeba6bdf0..afeba6bdf0 100755..100644 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e74a7a84c3..c1a311b170 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1314,7 +1314,7 @@ bool LLAppViewer::mainLoop() resumeMainloopTimeout(); pingMainloopTimeout("Main:End"); - } + } } catch(std::bad_alloc) { @@ -1817,6 +1817,8 @@ bool LLAppViewer::cleanup() ll_close_fail_log(); + MEM_TRACK_RELEASE + llinfos << "Goodbye!" << llendflush; // return 0; @@ -2515,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 { 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/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/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/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/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/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/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/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/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/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/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 92080d1fd7..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; } 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/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/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ae8bd3f29a..f3cbb8cce3 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2721,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); } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 244de7fed3..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) 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 db48b769e4..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; @@ -676,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/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 b296d21b2b..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 ;
}
@@ -2882,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 510d22136b..ec3d0c10ab 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2295,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 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/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 c26b02ec8f..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> @@ -2793,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: @@ -2804,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 ) @@ -2841,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> @@ -2850,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> @@ -2863,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_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml index 6ec063cd26..e04a72cbc0 100644 --- a/indra/newview/skins/default/xui/en/floater_web_content.xml +++ b/indra/newview/skins/default/xui/en/floater_web_content.xml @@ -12,7 +12,7 @@ auto_tile="true" title="" initial_mime_type="text/html" - width="735"> + width="780"> <layout_stack bottom="775" follows="left|right|top|bottom" @@ -21,7 +21,7 @@ name="stack1" orientation="vertical" top="20" - width="725"> + width="770"> <layout_panel auto_resize="false" default_tab_group="1" @@ -32,7 +32,7 @@ name="nav_controls" top="400" user_resize="false" - width="725"> + width="770"> <button image_overlay="Arrow_Left_Off" image_disabled="PushButton_Disabled" @@ -115,7 +115,7 @@ combo_editor.select_on_focus="true" tool_tip="Enter URL here" top_delta="0" - width="627"> + width="672"> <combo_box.commit_callback function="WebContent.EnterAddress" /> </combo_box> @@ -125,7 +125,7 @@ follows="top|right" image_name="Lock2" layout="topleft" - left_delta="575" + left_delta="620" top_delta="2" visible="false" tool_tip="Secured Browsing" @@ -142,7 +142,7 @@ height="22" layout="topleft" name="popexternal" - right="725" + 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" @@ -175,7 +175,7 @@ parse_urls="false" text_color="0.4 0.4 0.4 1" top_pad="5" - width="520"/> + 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_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 3e006d7b31..0a6be2899b 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -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/> 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 1c31066962..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> @@ -2780,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: @@ -2791,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) @@ -2827,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> @@ -2836,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> @@ -2849,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 2ccac5c19a..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> @@ -2776,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 : @@ -2787,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) @@ -2824,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> @@ -2833,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> @@ -2846,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/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 138125ff0b..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"/> @@ -2737,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: @@ -2748,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) @@ -2784,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> @@ -2793,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> @@ -2806,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 9c3b9386e0..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> @@ -2760,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: @@ -2771,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 ) @@ -2808,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> @@ -2817,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> @@ -2830,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 ea242f45cd..1888f191e2 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -373,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, @@ -385,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) |