diff --git a/.hgtags b/.hgtags index 423b89132f5f158f9034c7f650f23b276489b01d..a89e7a5795199a1ada2b71810d5e7e4464650b27 100644 --- a/.hgtags +++ b/.hgtags @@ -53,3 +53,17 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start 345b17e7cf630db77e840b4fe3451bd476d750a3 2.5.0-beta1 345b17e7cf630db77e840b4fe3451bd476d750a3 76f586a8e22b 0000000000000000000000000000000000000000 76f586a8e22b +54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f 2.5.0-beta2 +7076e22f9f43f479a4ea75eac447a36364bead5a DRTVWR-5_2.2.0-beta1 +9822eb3e25f7fe0c28ffd8aba45c507caa383cbc DRTVWR-3_2.2.0-beta2 +b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3 +1415e6538d54fd5d568ee88343424d57c6803c2c DRTVWR-8_2.2.0-release +a3c12342b1af0951b8aa3b828aacef17fcea8178 DRTVWR-14_2.3.0-beta1 +db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2 +6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-20_2.3.0-beta3 +6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-13_2.3.0-release +3bc1f50a72e117f4d4ad8d555f0c785ea8cc201e DRTVWR-26_2.4.0-beta1 +25bd6007e3d2fc15db9326ed4b18a24a5969a46a DRTVWR-27_2.4.0-beta2 +1ed382c6a08ba3850b6ce9061bc551ddece0ea07 DRTVWR-25_2.4.0-release +345b17e7cf630db77e840b4fe3451bd476d750a3 DRTVWR-32_2.5.0-beta1 +54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f DRTVWR-33_2.5.0-beta2 diff --git a/BuildParams b/BuildParams index 57237afc1e035a69fa4fe51f57c834a235a35b31..f816c7b368ba6d771f8619290255961ce32f74b9 100755 --- a/BuildParams +++ b/BuildParams @@ -26,6 +26,7 @@ viewer-development.show_changes_since = last_sprint # Build Settings viewer-development_coverity.coverity_product = viewer +viewer-development_coverity.run_tests = false viewer-development.build_debug_release_separately = true # Notifications - to configure email notices, add a setting like this: diff --git a/build.sh b/build.sh index 852875f755307b53b17adfbe6d992c961b148c55..c7c8d134657312202c3effce53f9cfbc8e78c143 100644 --- a/build.sh +++ b/build.sh @@ -66,7 +66,8 @@ pre_build() -DRELEASE_CRASH_REPORTING:BOOL=ON \ -DLOCALIZESETUP:BOOL=ON \ -DPACKAGE:BOOL=ON - -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE + -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE \ + -DLL_TESTS:BOOL="$run_tests" end_section "Pre$variant" } diff --git a/doc/contributions.txt b/doc/contributions.txt index 18fed00ff8a5c8ce69a9695e7b7bcffee162d21f..519df22b934717e615957144be7d4b4cd8258c72 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -83,6 +83,7 @@ Aleric Inglewood VWR-24315 VWR-24317 VWR-24320 + VWR-24321 VWR-24354 VWR-24519 SNOW-84 @@ -385,9 +386,11 @@ Jonathan Yap STORM-869 STORM-785 STORM-812 + STORM-829 VWR-17801 VWR-24347 STORM-844 + STORM-643 Kage Pixel VWR-11 Ken March @@ -770,6 +773,7 @@ Twisted Laws STORM-466 STORM-467 STORM-844 + STORM-643 Vadim Bigbear VWR-2681 Vector Hastings diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 06ad7736d392255f7368d3db7cae7b3c6bcb90fc..21d1c84d695d4a5868e21fc1825f05db63db58d9 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 @@ U64 LLMemory::getCurrentRSS() 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 8d114f744b4b83769faf78e67b0971d4235041f7..0adb78236ea24ca8fbe5b8fccecbe2723f1b57f5 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 @@ class LL_COMMON_API LLMemory // 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 fe83f87d4b3dd04bb245d46986489fd402c6a399..6290a7158fac475b1932373d750aedec2b52d6c3 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 b46a99e03034160b3598e24427f3072f1f8fc692..39211bf7fa5158f1ccce04111f67a3d3159fd1c6 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 bca7e915fac8d9f469f6566b46540ba0fbf1f351..825b9aab1a49cefd54b092e05d869d00b15a32b7 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -164,7 +164,7 @@ class LLImageRaw : public LLImageBase 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 @@ class LLImageRaw : public LLImageBase 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 d6dfb5c7a95c655eda255ee9df4ee0abb8e0e5c4..316eed679db743d8c5698f4e31e9f08666503d7b 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,7269 +1,5548 @@ -/** - - * @file llvolume.cpp - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llmemory.h" -#include "llmath.h" - -#include <set> -#if !LL_WINDOWS -#include <stdint.h> -#endif - -#include "llerror.h" -#include "llmemtype.h" - -#include "llvolumemgr.h" -#include "v2math.h" -#include "v3math.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llmatrix3a.h" -#include "lloctree.h" -#include "lldarray.h" -#include "llvolume.h" -#include "llvolumeoctree.h" -#include "llstl.h" -#include "llsdserialize.h" -#include "llvector4a.h" -#include "llmatrix4a.h" - -#define DEBUG_SILHOUETTE_BINORMALS 0 -#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette -#define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette - -const F32 CUT_MIN = 0.f; -const F32 CUT_MAX = 1.f; -const F32 MIN_CUT_DELTA = 0.02f; - -const F32 HOLLOW_MIN = 0.f; -const F32 HOLLOW_MAX = 0.95f; -const F32 HOLLOW_MAX_SQUARE = 0.7f; - -const F32 TWIST_MIN = -1.f; -const F32 TWIST_MAX = 1.f; - -const F32 RATIO_MIN = 0.f; -const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper - -const F32 HOLE_X_MIN= 0.05f; -const F32 HOLE_X_MAX= 1.0f; - -const F32 HOLE_Y_MIN= 0.05f; -const F32 HOLE_Y_MAX= 0.5f; - -const F32 SHEAR_MIN = -0.5f; -const F32 SHEAR_MAX = 0.5f; - -const F32 REV_MIN = 1.f; -const F32 REV_MAX = 4.f; - -const F32 TAPER_MIN = -1.f; -const F32 TAPER_MAX = 1.f; - -const F32 SKEW_MIN = -0.95f; -const F32 SKEW_MAX = 0.95f; - -const F32 SCULPT_MIN_AREA = 0.002f; -const S32 SCULPT_MIN_AREA_DETAIL = 1; - -extern BOOL gDebugGL; - -void assert_aligned(void* ptr, uintptr_t alignment) -{ -#if 0 - uintptr_t t = (uintptr_t) ptr; - if (t%alignment != 0) - { - llerrs << "WTF?" << llendl; - } -#endif -} - -BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) -{ - LLVector3 test = (pt2-pt1)%(pt3-pt2); - - //answer - if(test * norm < 0) - { - return FALSE; - } - else - { - return TRUE; - } -} - -BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) -{ - return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV); -} - -BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size) -{ - F32 fAWdU[3]; - F32 dir[3]; - F32 diff[3]; - - for (U32 i = 0; i < 3; i++) - { - dir[i] = 0.5f * (end[i] - start[i]); - diff[i] = (0.5f * (end[i] + start[i])) - center[i]; - fAWdU[i] = fabsf(dir[i]); - if(fabsf(diff[i])>size[i] + fAWdU[i]) return false; - } - - float f; - f = dir[1] * diff[2] - dir[2] * diff[1]; if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1]) return false; - f = dir[2] * diff[0] - dir[0] * diff[2]; if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0]) return false; - f = dir[0] * diff[1] - dir[1] * diff[0]; if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0]) return false; - - return true; -} - - - -// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir. -// returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b, -// and returns the intersection point along dir in intersection_t. - -// Moller-Trumbore algorithm -BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t) -{ - - /* find vectors for two edges sharing vert0 */ - LLVector4a edge1; - edge1.setSub(vert1, vert0); - - LLVector4a edge2; - edge2.setSub(vert2, vert0); - - /* begin calculating determinant - also used to calculate U parameter */ - LLVector4a pvec; - pvec.setCross3(dir, edge2); - - /* if determinant is near zero, ray lies in plane of triangle */ - LLVector4a det; - det.setAllDot3(edge1, pvec); - - if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7) - { - /* calculate distance from vert0 to ray origin */ - LLVector4a tvec; - tvec.setSub(orig, vert0); - - /* calculate U parameter and test bounds */ - LLVector4a u; - u.setAllDot3(tvec,pvec); - - if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) && - (u.lessEqual(det).getGatheredBits() & 0x7)) - { - /* prepare to test V parameter */ - LLVector4a qvec; - qvec.setCross3(tvec, edge1); - - /* calculate V parameter and test bounds */ - LLVector4a v; - v.setAllDot3(dir, qvec); - - - //if (!(v < 0.f || u + v > det)) - - LLVector4a sum_uv; - sum_uv.setAdd(u, v); - - S32 v_gequal = v.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7; - S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 0x7; - - if (v_gequal && sum_lequal) - { - /* calculate t, scale parameters, ray intersects triangle */ - LLVector4a t; - t.setAllDot3(edge2,qvec); - - t.div(det); - u.div(det); - v.div(det); - - intersection_a = u[0]; - intersection_b = v[0]; - intersection_t = t[0]; - return TRUE; - } - } - } - - return FALSE; -} - -BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t) -{ - F32 u, v, t; - - /* find vectors for two edges sharing vert0 */ - LLVector4a edge1; - edge1.setSub(vert1, vert0); - - - LLVector4a edge2; - edge2.setSub(vert2, vert0); - - /* begin calculating determinant - also used to calculate U parameter */ - LLVector4a pvec; - pvec.setCross3(dir, edge2); - - /* if determinant is near zero, ray lies in plane of triangle */ - F32 det = edge1.dot3(pvec).getF32(); - - - if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) - { - return FALSE; - } - - F32 inv_det = 1.f / det; - - /* calculate distance from vert0 to ray origin */ - LLVector4a tvec; - tvec.setSub(orig, vert0); - - /* calculate U parameter and test bounds */ - u = (tvec.dot3(pvec).getF32()) * inv_det; - if (u < 0.f || u > 1.f) - { - return FALSE; - } - - /* prepare to test V parameter */ - tvec.sub(edge1); - - /* calculate V parameter and test bounds */ - v = (dir.dot3(tvec).getF32()) * inv_det; - - if (v < 0.f || u + v > 1.f) - { - return FALSE; - } - - /* calculate t, ray intersects triangle */ - t = (edge2.dot3(tvec).getF32()) * inv_det; - - intersection_a = u; - intersection_b = v; - intersection_t = t; - - - return TRUE; -} - -//helper for non-aligned vectors -BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided) -{ - LLVector4a vert0a, vert1a, vert2a, origa, dira; - vert0a.load3(vert0.mV); - vert1a.load3(vert1.mV); - vert2a.load3(vert2.mV); - origa.load3(orig.mV); - dira.load3(dir.mV); - - if (two_sided) - { - return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira, - intersection_a, intersection_b, intersection_t); - } - else - { - return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira, - intersection_a, intersection_b, intersection_t); - } -} - -class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle> -{ -public: - const LLVolumeFace* mFace; - - LLVolumeOctreeRebound(const LLVolumeFace* face) - { - mFace = face; - } - - virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch) - { //this is a depth first traversal, so it's safe to assum all children have complete - //bounding data - - LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); - - LLVector4a& min = node->mExtents[0]; - LLVector4a& max = node->mExtents[1]; - - if (!branch->getData().empty()) - { //node has data, find AABB that binds data set - const LLVolumeTriangle* tri = *(branch->getData().begin()); - - //initialize min/max to first available vertex - min = *(tri->mV[0]); - max = *(tri->mV[0]); - - for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = - branch->getData().begin(); iter != branch->getData().end(); ++iter) - { //for each triangle in node - - //stretch by triangles in node - tri = *iter; - - min.setMin(min, *tri->mV[0]); - min.setMin(min, *tri->mV[1]); - min.setMin(min, *tri->mV[2]); - - max.setMax(max, *tri->mV[0]); - max.setMax(max, *tri->mV[1]); - max.setMax(max, *tri->mV[2]); - } - } - else if (!branch->getChildren().empty()) - { //no data, but child nodes exist - LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0); - - //initialize min/max to extents of first child - min = child->mExtents[0]; - max = child->mExtents[1]; - } - else - { - llerrs << "WTF? Empty leaf" << llendl; - } - - for (S32 i = 0; i < branch->getChildCount(); ++i) - { //stretch by child extents - LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); - min.setMin(min, child->mExtents[0]); - max.setMax(max, child->mExtents[1]); - } - - node->mBounds[0].setAdd(min, max); - node->mBounds[0].mul(0.5f); - - node->mBounds[1].setSub(max,min); - node->mBounds[1].mul(0.5f); - } -}; - -//------------------------------------------------------------------- -// statics -//------------------------------------------------------------------- - - -//---------------------------------------------------- - -LLProfile::Face* LLProfile::addCap(S16 faceID) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - Face *face = vector_append(mFaces, 1); - - face->mIndex = 0; - face->mCount = mTotal; - face->mScaleU= 1.0f; - face->mCap = TRUE; - face->mFaceID = faceID; - return face; -} - -LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - Face *face = vector_append(mFaces, 1); - - face->mIndex = i; - face->mCount = count; - face->mScaleU= scaleU; - - face->mFlat = flat; - face->mCap = FALSE; - face->mFaceID = faceID; - return face; -} - -// What is the bevel parameter used for? - DJS 04/05/02 -// Bevel parameter is currently unused but presumedly would support -// filleted and chamfered corners -void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - // Generate an n-sided "circular" path. - // 0 is (1,0), and we go counter-clockwise along a circular path from there. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; - F32 scale = 0.5f; - F32 t, t_step, t_first, t_fraction, ang, ang_step; - LLVector3 pt1,pt2; - - F32 begin = params.getBegin(); - F32 end = params.getEnd(); - - t_step = 1.0f / sides; - ang_step = 2.0f*F_PI*t_step*ang_scale; - - // Scale to have size "match" scale. Compensates to get object to generally fill bounding box. - - S32 total_sides = llround(sides / ang_scale); // Total number of sides all around - - if (total_sides < 8) - { - scale = tableScale[total_sides]; - } - - t_first = floor(begin * sides) / (F32)sides; - - // pt1 is the first point on the fractional face. - // Starting t and ang values for the first face - t = t_first; - ang = 2.0f*F_PI*(t*ang_scale + offset); - pt1.setVec(cos(ang)*scale,sin(ang)*scale, t); - - // Increment to the next point. - // pt2 is the end point on the fractional face - t += t_step; - ang += ang_step; - pt2.setVec(cos(ang)*scale,sin(ang)*scale,t); - - t_fraction = (begin - t_first)*sides; - - // Only use if it's not almost exactly on an edge. - if (t_fraction < 0.9999f) - { - LLVector3 new_pt = lerp(pt1, pt2, t_fraction); - mProfile.push_back(new_pt); - } - - // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02 - while (t < end) - { - // Iterate through all the integer steps of t. - pt1.setVec(cos(ang)*scale,sin(ang)*scale,t); - - if (mProfile.size() > 0) { - LLVector3 p = mProfile[mProfile.size()-1]; - for (S32 i = 0; i < split && mProfile.size() > 0; i++) { - mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1)); - } - } - mProfile.push_back(pt1); - - t += t_step; - ang += ang_step; - } - - t_fraction = (end - (t - t_step))*sides; - - // pt1 is the first point on the fractional face - // pt2 is the end point on the fractional face - pt2.setVec(cos(ang)*scale,sin(ang)*scale,t); - - // Find the fraction that we need to add to the end point. - t_fraction = (end - (t - t_step))*sides; - if (t_fraction > 0.0001f) - { - LLVector3 new_pt = lerp(pt1, pt2, t_fraction); - - if (mProfile.size() > 0) { - LLVector3 p = mProfile[mProfile.size()-1]; - for (S32 i = 0; i < split && mProfile.size() > 0; i++) { - mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1)); - } - } - mProfile.push_back(new_pt); - } - - // If we're sliced, the profile is open. - if ((end - begin)*ang_scale < 0.99f) - { - if ((end - begin)*ang_scale > 0.5f) - { - mConcave = TRUE; - } - else - { - mConcave = FALSE; - } - mOpen = TRUE; - if (params.getHollow() <= 0) - { - // put center point if not hollow. - mProfile.push_back(LLVector3(0,0,0)); - } - } - else - { - // The profile isn't open. - mOpen = FALSE; - mConcave = FALSE; - } - - mTotal = mProfile.size(); -} - -void LLProfile::genNormals(const LLProfileParams& params) -{ - S32 count = mProfile.size(); - - S32 outer_count; - if (mTotalOut) - { - outer_count = mTotalOut; - } - else - { - outer_count = mTotal / 2; - } - - mEdgeNormals.resize(count * 2); - mEdgeCenters.resize(count * 2); - mNormals.resize(count); - - LLVector2 pt0,pt1; - - BOOL hollow = (params.getHollow() > 0); - - S32 i0, i1, i2, i3, i4; - - // Parametrically generate normal - for (i2 = 0; i2 < count; i2++) - { - mNormals[i2].mV[0] = mProfile[i2].mV[0]; - mNormals[i2].mV[1] = mProfile[i2].mV[1]; - if (hollow && (i2 >= outer_count)) - { - mNormals[i2] *= -1.f; - } - if (mNormals[i2].magVec() < 0.001) - { - // Special case for point at center, get adjacent points. - i1 = (i2 - 1) >= 0 ? i2 - 1 : count - 1; - i0 = (i1 - 1) >= 0 ? i1 - 1 : count - 1; - i3 = (i2 + 1) < count ? i2 + 1 : 0; - i4 = (i3 + 1) < count ? i3 + 1 : 0; - - pt0.setVec(mProfile[i1].mV[VX] + mProfile[i1].mV[VX] - mProfile[i0].mV[VX], - mProfile[i1].mV[VY] + mProfile[i1].mV[VY] - mProfile[i0].mV[VY]); - pt1.setVec(mProfile[i3].mV[VX] + mProfile[i3].mV[VX] - mProfile[i4].mV[VX], - mProfile[i3].mV[VY] + mProfile[i3].mV[VY] - mProfile[i4].mV[VY]); - - mNormals[i2] = pt0 + pt1; - mNormals[i2] *= 0.5f; - } - mNormals[i2].normVec(); - } - - S32 num_normal_sets = isConcave() ? 2 : 1; - for (S32 normal_set = 0; normal_set < num_normal_sets; normal_set++) - { - S32 point_num; - for (point_num = 0; point_num < mTotal; point_num++) - { - LLVector3 point_1 = mProfile[point_num]; - point_1.mV[VZ] = 0.f; - - LLVector3 point_2; - - if (isConcave() && normal_set == 0 && point_num == (mTotal - 1) / 2) - { - point_2 = mProfile[mTotal - 1]; - } - else if (isConcave() && normal_set == 1 && point_num == mTotal - 1) - { - point_2 = mProfile[(mTotal - 1) / 2]; - } - else - { - LLVector3 delta_pos; - S32 neighbor_point = (point_num + 1) % mTotal; - while(delta_pos.magVecSquared() < 0.01f * 0.01f) - { - point_2 = mProfile[neighbor_point]; - delta_pos = point_2 - point_1; - neighbor_point = (neighbor_point + 1) % mTotal; - if (neighbor_point == point_num) - { - break; - } - } - } - - point_2.mV[VZ] = 0.f; - LLVector3 face_normal = (point_2 - point_1) % LLVector3::z_axis; - face_normal.normVec(); - mEdgeNormals[normal_set * count + point_num] = face_normal; - mEdgeCenters[normal_set * count + point_num] = lerp(point_1, point_2, 0.5f); - } - } -} - - -// Hollow is percent of the original bounding box, not of this particular -// profile's geometry. Thus, a swept triangle needs lower hollow values than -// a swept square. -LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) -{ - // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them. - - // Total add has number of vertices on outside. - mTotalOut = mTotal; - - // Why is the "bevel" parameter -1? DJS 04/05/02 - genNGon(params, llfloor(sides),offset,-1, ang_scale, split); - - Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat); - - std::vector<LLVector3> pt; - pt.resize(mTotal) ; - - for (S32 i=mTotalOut;i<mTotal;i++) - { - pt[i] = mProfile[i] * box_hollow; - } - - S32 j=mTotal-1; - for (S32 i=mTotalOut;i<mTotal;i++) - { - mProfile[i] = pt[j--]; - } - - for (S32 i=0;i<(S32)mFaces.size();i++) - { - if (mFaces[i].mCap) - { - mFaces[i].mCount *= 2; - } - } - - return face; -} - - - -BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if ((!mDirty) && (!is_sculpted)) - { - return FALSE; - } - mDirty = FALSE; - - if (detail < MIN_LOD) - { - llinfos << "Generating profile with LOD < MIN_LOD. CLAMPING" << llendl; - detail = MIN_LOD; - } - - mProfile.clear(); - mFaces.clear(); - - // Generate the face data - S32 i; - F32 begin = params.getBegin(); - F32 end = params.getEnd(); - F32 hollow = params.getHollow(); - - // Quick validation to eliminate some server crashes. - if (begin > end - 0.01f) - { - llwarns << "LLProfile::generate() assertion failed (begin >= end)" << llendl; - return FALSE; - } - - S32 face_num = 0; - - switch (params.getCurveType() & LL_PCODE_PROFILE_MASK) - { - case LL_PCODE_PROFILE_SQUARE: - { - genNGon(params, 4,-0.375, 0, 1, split); - if (path_open) - { - addCap (LL_FACE_PATH_BEGIN); - } - - for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++) - { - addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); - } - - for (i = 0; i <(S32) mProfile.size(); i++) - { - // Scale by 4 to generate proper tex coords. - mProfile[i].mV[2] *= 4.f; - } - - if (hollow) - { - switch (params.getCurveType() & LL_PCODE_HOLE_MASK) - { - case LL_PCODE_HOLE_TRIANGLE: - // This offset is not correct, but we can't change it now... DK 11/17/04 - addHole(params, TRUE, 3, -0.375f, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - // TODO: Compute actual detail levels for cubes - addHole(params, FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); - break; - case LL_PCODE_HOLE_SAME: - case LL_PCODE_HOLE_SQUARE: - default: - addHole(params, TRUE, 4, -0.375f, hollow, 1.f, split); - break; - } - } - - if (path_open) { - mFaces[0].mCount = mTotal; - } - } - break; - case LL_PCODE_PROFILE_ISOTRI: - case LL_PCODE_PROFILE_RIGHTTRI: - case LL_PCODE_PROFILE_EQUALTRI: - { - genNGon(params, 3,0, 0, 1, split); - for (i = 0; i <(S32) mProfile.size(); i++) - { - // Scale by 3 to generate proper tex coords. - mProfile[i].mV[2] *= 3.f; - } - - if (path_open) - { - addCap(LL_FACE_PATH_BEGIN); - } - - for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++) - { - addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); - } - if (hollow) - { - // Swept triangles need smaller hollowness values, - // because the triangle doesn't fill the bounding box. - F32 triangle_hollow = hollow / 2.f; - - switch (params.getCurveType() & LL_PCODE_HOLE_MASK) - { - case LL_PCODE_HOLE_CIRCLE: - // TODO: Actually generate level of detail for triangles - addHole(params, FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); - break; - case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 4, 0, triangle_hollow, 1.f, split); - break; - case LL_PCODE_HOLE_SAME: - case LL_PCODE_HOLE_TRIANGLE: - default: - addHole(params, TRUE, 3, 0, triangle_hollow, 1.f, split); - break; - } - } - } - break; - case LL_PCODE_PROFILE_CIRCLE: - { - // If this has a square hollow, we should adjust the - // number of faces a bit so that the geometry lines up. - U8 hole_type=0; - F32 circle_detail = MIN_DETAIL_FACES * detail; - if (hollow) - { - hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; - if (hole_type == LL_PCODE_HOLE_SQUARE) - { - // Snap to the next multiple of four sides, - // so that corners line up. - circle_detail = llceil(circle_detail / 4.0f) * 4.0f; - } - } - - S32 sides = (S32)circle_detail; - - if (is_sculpted) - sides = sculpt_size; - - genNGon(params, sides); - - if (path_open) - { - addCap (LL_FACE_PATH_BEGIN); - } - - if (mOpen && !hollow) - { - addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); - } - else - { - addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE); - } - - if (hollow) - { - switch (hole_type) - { - case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 4, 0, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_TRIANGLE: - addHole(params, TRUE, 3, 0, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - case LL_PCODE_HOLE_SAME: - default: - addHole(params, FALSE, circle_detail, 0, hollow, 1.f); - break; - } - } - } - break; - case LL_PCODE_PROFILE_CIRCLE_HALF: - { - // If this has a square hollow, we should adjust the - // number of faces a bit so that the geometry lines up. - U8 hole_type=0; - // Number of faces is cut in half because it's only a half-circle. - F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f; - if (hollow) - { - hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; - if (hole_type == LL_PCODE_HOLE_SQUARE) - { - // Snap to the next multiple of four sides (div 2), - // so that corners line up. - circle_detail = llceil(circle_detail / 2.0f) * 2.0f; - } - } - genNGon(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f); - if (path_open) - { - addCap(LL_FACE_PATH_BEGIN); - } - if (mOpen && !params.getHollow()) - { - addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); - } - else - { - addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE); - } - - if (hollow) - { - switch (hole_type) - { - case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 2, 0.5f, hollow, 0.5f, split); - break; - case LL_PCODE_HOLE_TRIANGLE: - addHole(params, TRUE, 3, 0.5f, hollow, 0.5f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - case LL_PCODE_HOLE_SAME: - default: - addHole(params, FALSE, circle_detail, 0.5f, hollow, 0.5f); - break; - } - } - - // Special case for openness of sphere - if ((params.getEnd() - params.getBegin()) < 1.f) - { - mOpen = TRUE; - } - else if (!hollow) - { - mOpen = FALSE; - mProfile.push_back(mProfile[0]); - mTotal++; - } - } - break; - default: - llerrs << "Unknown profile: getCurveType()=" << params.getCurveType() << llendl; - break; - }; - - if (path_open) - { - addCap(LL_FACE_PATH_END); // bottom - } - - if ( mOpen) // interior edge caps - { - addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, TRUE); - - if (hollow) - { - addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, TRUE); - } - else - { - addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE); - } - } - - //genNormals(params); - - return TRUE; -} - - - -BOOL LLProfileParams::importFile(LLFILE *fp) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - F32 tempF32; - U32 tempU32; - - while (!feof(fp)) - { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("hollow",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setHollow(tempF32); - } - else - { - llwarns << "unknown keyword " << keyword << " in profile import" << llendl; - } - } - - return TRUE; -} - - -BOOL LLProfileParams::exportFile(LLFILE *fp) const -{ - fprintf(fp,"\t\tprofile 0\n"); - fprintf(fp,"\t\t{\n"); - fprintf(fp,"\t\t\tcurve\t%d\n", getCurveType()); - fprintf(fp,"\t\t\tbegin\t%g\n", getBegin()); - fprintf(fp,"\t\t\tend\t%g\n", getEnd()); - fprintf(fp,"\t\t\thollow\t%g\n", getHollow()); - fprintf(fp, "\t\t}\n"); - return TRUE; -} - - -BOOL LLProfileParams::importLegacyStream(std::istream& input_stream) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - F32 tempF32; - U32 tempU32; - - while (input_stream.good()) - { - input_stream.getline(buffer, BUFSIZE); - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, - valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("hollow",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setHollow(tempF32); - } - else - { - llwarns << "unknown keyword " << keyword << " in profile import" << llendl; - } - } - - return TRUE; -} - - -BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const -{ - output_stream <<"\t\tprofile 0\n"; - output_stream <<"\t\t{\n"; - output_stream <<"\t\t\tcurve\t" << (S32) getCurveType() << "\n"; - output_stream <<"\t\t\tbegin\t" << getBegin() << "\n"; - output_stream <<"\t\t\tend\t" << getEnd() << "\n"; - output_stream <<"\t\t\thollow\t" << getHollow() << "\n"; - output_stream << "\t\t}\n"; - return TRUE; -} - -LLSD LLProfileParams::asLLSD() const -{ - LLSD sd; - - sd["curve"] = getCurveType(); - sd["begin"] = getBegin(); - sd["end"] = getEnd(); - sd["hollow"] = getHollow(); - return sd; -} - -bool LLProfileParams::fromLLSD(LLSD& sd) -{ - setCurveType(sd["curve"].asInteger()); - setBegin((F32)sd["begin"].asReal()); - setEnd((F32)sd["end"].asReal()); - setHollow((F32)sd["hollow"].asReal()); - return true; -} - -void LLProfileParams::copyParams(const LLProfileParams ¶ms) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - setCurveType(params.getCurveType()); - setBegin(params.getBegin()); - setEnd(params.getEnd()); - setHollow(params.getHollow()); -} - - -LLPath::~LLPath() -{ -} - -void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) -{ - // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; - - F32 revolutions = params.getRevolutions(); - F32 skew = params.getSkew(); - F32 skew_mag = fabs(skew); - F32 hole_x = params.getScaleX() * (1.0f - skew_mag); - F32 hole_y = params.getScaleY(); - - // Calculate taper begin/end for x,y (Negative means taper the beginning) - F32 taper_x_begin = 1.0f; - F32 taper_x_end = 1.0f - params.getTaperX(); - F32 taper_y_begin = 1.0f; - F32 taper_y_end = 1.0f - params.getTaperY(); - - if ( taper_x_end > 1.0f ) - { - // Flip tapering. - taper_x_begin = 2.0f - taper_x_end; - taper_x_end = 1.0f; - } - if ( taper_y_end > 1.0f ) - { - // Flip tapering. - taper_y_begin = 2.0f - taper_y_end; - taper_y_end = 1.0f; - } - - // For spheres, the radius is usually zero. - F32 radius_start = 0.5f; - if (sides < 8) - { - radius_start = tableScale[sides]; - } - - // Scale the radius to take the hole size into account. - radius_start *= 1.0f - hole_y; - - // Now check the radius offset to calculate the start,end radius. (Negative means - // decrease the start radius instead). - F32 radius_end = radius_start; - F32 radius_offset = params.getRadiusOffset(); - if (radius_offset < 0.f) - { - radius_start *= 1.f + radius_offset; - } - else - { - radius_end *= 1.f - radius_offset; - } - - // Is the path NOT a closed loop? - mOpen = ( (params.getEnd()*end_scale - params.getBegin() < 1.0f) || - (skew_mag > 0.001f) || - (fabs(taper_x_end - taper_x_begin) > 0.001f) || - (fabs(taper_y_end - taper_y_begin) > 0.001f) || - (fabs(radius_end - radius_start) > 0.001f) ); - - F32 ang, c, s; - LLQuaternion twist, qang; - PathPt *pt; - LLVector3 path_axis (1.f, 0.f, 0.f); - //LLVector3 twist_axis(0.f, 0.f, 1.f); - F32 twist_begin = params.getTwistBegin() * twist_scale; - F32 twist_end = params.getTwist() * twist_scale; - - // We run through this once before the main loop, to make sure - // the path begins at the correct cut. - F32 step= 1.0f / sides; - F32 t = params.getBegin(); - pt = vector_append(mPath, 1); - ang = 2.0f*F_PI*revolutions * t; - s = sin(ang)*lerp(radius_start, radius_end, t); - c = cos(ang)*lerp(radius_start, radius_end, t); - - - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; - - t+=step; - - // Snap to a quantized parameter, so that cut does not - // affect most sample points. - t = ((S32)(t * sides)) / (F32)sides; - - // Run through the non-cut dependent points. - while (t < params.getEnd()) - { - pt = vector_append(mPath, 1); - - ang = 2.0f*F_PI*revolutions * t; - c = cos(ang)*lerp(radius_start, radius_end, t); - s = sin(ang)*lerp(radius_start, radius_end, t); - - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; - - t+=step; - } - - // Make one final pass for the end cut. - t = params.getEnd(); - pt = vector_append(mPath, 1); - ang = 2.0f*F_PI*revolutions * t; - c = cos(ang)*lerp(radius_start, radius_end, t); - s = sin(ang)*lerp(radius_start, radius_end, t); - - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; - - mTotal = mPath.size(); -} - -const LLVector2 LLPathParams::getBeginScale() const -{ - LLVector2 begin_scale(1.f, 1.f); - if (getScaleX() > 1) - { - begin_scale.mV[0] = 2-getScaleX(); - } - if (getScaleY() > 1) - { - begin_scale.mV[1] = 2-getScaleY(); - } - return begin_scale; -} - -const LLVector2 LLPathParams::getEndScale() const -{ - LLVector2 end_scale(1.f, 1.f); - if (getScaleX() < 1) - { - end_scale.mV[0] = getScaleX(); - } - if (getScaleY() < 1) - { - end_scale.mV[1] = getScaleY(); - } - return end_scale; -} - -BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if ((!mDirty) && (!is_sculpted)) - { - return FALSE; - } - - if (detail < MIN_LOD) - { - llinfos << "Generating path with LOD < MIN! Clamping to 1" << llendl; - detail = MIN_LOD; - } - - mDirty = FALSE; - S32 np = 2; // hardcode for line - - mPath.clear(); - mOpen = TRUE; - - // Is this 0xf0 mask really necessary? DK 03/02/05 - switch (params.getCurveType() & 0xf0) - { - default: - case LL_PCODE_PATH_LINE: - { - // Take the begin/end twist into account for detail. - np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2; - if (np < split+2) - { - np = split+2; - } - - mStep = 1.0f / (np-1); - - mPath.resize(np); - - LLVector2 start_scale = params.getBeginScale(); - LLVector2 end_scale = params.getEndScale(); - - for (S32 i=0;i<np;i++) - { - F32 t = lerp(params.getBegin(),params.getEnd(),(F32)i * mStep); - mPath[i].mPos.setVec(lerp(0,params.getShear().mV[0],t), - lerp(0,params.getShear().mV[1],t), - t - 0.5f); - mPath[i].mRot.setQuat(lerp(F_PI * params.getTwistBegin(),F_PI * params.getTwist(),t),0,0,1); - mPath[i].mScale.mV[0] = lerp(start_scale.mV[0],end_scale.mV[0],t); - mPath[i].mScale.mV[1] = lerp(start_scale.mV[1],end_scale.mV[1],t); - mPath[i].mTexT = t; - } - } - break; - - case LL_PCODE_PATH_CIRCLE: - { - // Increase the detail as the revolutions and twist increase. - F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist()); - - S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions()); - - if (is_sculpted) - sides = sculpt_size; - - genNGon(params, sides); - } - break; - - case LL_PCODE_PATH_CIRCLE2: - { - if (params.getEnd() - params.getBegin() >= 0.99f && - params.getScaleX() >= .99f) - { - mOpen = FALSE; - } - - //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); - genNGon(params, llfloor(MIN_DETAIL_FACES * detail)); - - F32 t = 0.f; - F32 tStep = 1.0f / mPath.size(); - - F32 toggle = 0.5f; - for (S32 i=0;i<(S32)mPath.size();i++) - { - mPath[i].mPos.mV[0] = toggle; - if (toggle == 0.5f) - toggle = -0.5f; - else - toggle = 0.5f; - t += tStep; - } - } - - break; - - case LL_PCODE_PATH_TEST: - - np = 5; - mStep = 1.0f / (np-1); - - mPath.resize(np); - - for (S32 i=0;i<np;i++) - { - F32 t = (F32)i * mStep; - mPath[i].mPos.setVec(0, - lerp(0, -sin(F_PI*params.getTwist()*t)*0.5f,t), - lerp(-0.5, cos(F_PI*params.getTwist()*t)*0.5f,t)); - mPath[i].mScale.mV[0] = lerp(1,params.getScale().mV[0],t); - mPath[i].mScale.mV[1] = lerp(1,params.getScale().mV[1],t); - mPath[i].mTexT = t; - mPath[i].mRot.setQuat(F_PI * params.getTwist() * t,1,0,0); - } - - break; - }; - - if (params.getTwist() != params.getTwistBegin()) mOpen = TRUE; - - //if ((int(fabsf(params.getTwist() - params.getTwistBegin())*100))%100 != 0) { - // mOpen = TRUE; - //} - - return TRUE; -} - -BOOL LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - mOpen = TRUE; // Draw end caps - if (getPathLength() == 0) - { - // Path hasn't been generated yet. - // Some algorithms later assume at least TWO path points. - resizePath(2); - for (U32 i = 0; i < 2; i++) - { - mPath[i].mPos.setVec(0, 0, 0); - mPath[i].mRot.setQuat(0, 0, 0); - mPath[i].mScale.setVec(1, 1); - mPath[i].mTexT = 0; - } - } - - return TRUE; -} - - -BOOL LLPathParams::importFile(LLFILE *fp) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - - F32 tempF32; - F32 x, y; - U32 tempU32; - - while (!feof(fp)) - { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("scale",keyword)) - { - // Legacy for one dimensional scale per path - sscanf(valuestr,"%g",&tempF32); - setScale(tempF32, tempF32); - } - else if (!strcmp("scale_x", keyword)) - { - sscanf(valuestr, "%g", &x); - setScaleX(x); - } - else if (!strcmp("scale_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setScaleY(y); - } - else if (!strcmp("shear_x", keyword)) - { - sscanf(valuestr, "%g", &x); - setShearX(x); - } - else if (!strcmp("shear_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setShearY(y); - } - else if (!strcmp("twist",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setTwist(tempF32); - } - else if (!strcmp("twist_begin", keyword)) - { - sscanf(valuestr, "%g", &y); - setTwistBegin(y); - } - else if (!strcmp("radius_offset", keyword)) - { - sscanf(valuestr, "%g", &y); - setRadiusOffset(y); - } - else if (!strcmp("taper_x", keyword)) - { - sscanf(valuestr, "%g", &y); - setTaperX(y); - } - else if (!strcmp("taper_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setTaperY(y); - } - else if (!strcmp("revolutions", keyword)) - { - sscanf(valuestr, "%g", &y); - setRevolutions(y); - } - else if (!strcmp("skew", keyword)) - { - sscanf(valuestr, "%g", &y); - setSkew(y); - } - else - { - llwarns << "unknown keyword " << " in path import" << llendl; - } - } - return TRUE; -} - - -BOOL LLPathParams::exportFile(LLFILE *fp) const -{ - fprintf(fp, "\t\tpath 0\n"); - fprintf(fp, "\t\t{\n"); - fprintf(fp, "\t\t\tcurve\t%d\n", getCurveType()); - fprintf(fp, "\t\t\tbegin\t%g\n", getBegin()); - fprintf(fp, "\t\t\tend\t%g\n", getEnd()); - fprintf(fp, "\t\t\tscale_x\t%g\n", getScaleX() ); - fprintf(fp, "\t\t\tscale_y\t%g\n", getScaleY() ); - fprintf(fp, "\t\t\tshear_x\t%g\n", getShearX() ); - fprintf(fp, "\t\t\tshear_y\t%g\n", getShearY() ); - fprintf(fp,"\t\t\ttwist\t%g\n", getTwist()); - - fprintf(fp,"\t\t\ttwist_begin\t%g\n", getTwistBegin()); - fprintf(fp,"\t\t\tradius_offset\t%g\n", getRadiusOffset()); - fprintf(fp,"\t\t\ttaper_x\t%g\n", getTaperX()); - fprintf(fp,"\t\t\ttaper_y\t%g\n", getTaperY()); - fprintf(fp,"\t\t\trevolutions\t%g\n", getRevolutions()); - fprintf(fp,"\t\t\tskew\t%g\n", getSkew()); - - fprintf(fp, "\t\t}\n"); - return TRUE; -} - - -BOOL LLPathParams::importLegacyStream(std::istream& input_stream) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - - F32 tempF32; - F32 x, y; - U32 tempU32; - - while (input_stream.good()) - { - input_stream.getline(buffer, BUFSIZE); - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("scale",keyword)) - { - // Legacy for one dimensional scale per path - sscanf(valuestr,"%g",&tempF32); - setScale(tempF32, tempF32); - } - else if (!strcmp("scale_x", keyword)) - { - sscanf(valuestr, "%g", &x); - setScaleX(x); - } - else if (!strcmp("scale_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setScaleY(y); - } - else if (!strcmp("shear_x", keyword)) - { - sscanf(valuestr, "%g", &x); - setShearX(x); - } - else if (!strcmp("shear_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setShearY(y); - } - else if (!strcmp("twist",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setTwist(tempF32); - } - else if (!strcmp("twist_begin", keyword)) - { - sscanf(valuestr, "%g", &y); - setTwistBegin(y); - } - else if (!strcmp("radius_offset", keyword)) - { - sscanf(valuestr, "%g", &y); - setRadiusOffset(y); - } - else if (!strcmp("taper_x", keyword)) - { - sscanf(valuestr, "%g", &y); - setTaperX(y); - } - else if (!strcmp("taper_y", keyword)) - { - sscanf(valuestr, "%g", &y); - setTaperY(y); - } - else if (!strcmp("revolutions", keyword)) - { - sscanf(valuestr, "%g", &y); - setRevolutions(y); - } - else if (!strcmp("skew", keyword)) - { - sscanf(valuestr, "%g", &y); - setSkew(y); - } - else - { - llwarns << "unknown keyword " << " in path import" << llendl; - } - } - return TRUE; -} - - -BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const -{ - output_stream << "\t\tpath 0\n"; - output_stream << "\t\t{\n"; - output_stream << "\t\t\tcurve\t" << (S32) getCurveType() << "\n"; - output_stream << "\t\t\tbegin\t" << getBegin() << "\n"; - output_stream << "\t\t\tend\t" << getEnd() << "\n"; - output_stream << "\t\t\tscale_x\t" << getScaleX() << "\n"; - output_stream << "\t\t\tscale_y\t" << getScaleY() << "\n"; - output_stream << "\t\t\tshear_x\t" << getShearX() << "\n"; - output_stream << "\t\t\tshear_y\t" << getShearY() << "\n"; - output_stream <<"\t\t\ttwist\t" << getTwist() << "\n"; - - output_stream <<"\t\t\ttwist_begin\t" << getTwistBegin() << "\n"; - output_stream <<"\t\t\tradius_offset\t" << getRadiusOffset() << "\n"; - output_stream <<"\t\t\ttaper_x\t" << getTaperX() << "\n"; - output_stream <<"\t\t\ttaper_y\t" << getTaperY() << "\n"; - output_stream <<"\t\t\trevolutions\t" << getRevolutions() << "\n"; - output_stream <<"\t\t\tskew\t" << getSkew() << "\n"; - - output_stream << "\t\t}\n"; - return TRUE; -} - -LLSD LLPathParams::asLLSD() const -{ - LLSD sd = LLSD(); - sd["curve"] = getCurveType(); - sd["begin"] = getBegin(); - sd["end"] = getEnd(); - sd["scale_x"] = getScaleX(); - sd["scale_y"] = getScaleY(); - sd["shear_x"] = getShearX(); - sd["shear_y"] = getShearY(); - sd["twist"] = getTwist(); - sd["twist_begin"] = getTwistBegin(); - sd["radius_offset"] = getRadiusOffset(); - sd["taper_x"] = getTaperX(); - sd["taper_y"] = getTaperY(); - sd["revolutions"] = getRevolutions(); - sd["skew"] = getSkew(); - - return sd; -} - -bool LLPathParams::fromLLSD(LLSD& sd) -{ - setCurveType(sd["curve"].asInteger()); - setBegin((F32)sd["begin"].asReal()); - setEnd((F32)sd["end"].asReal()); - setScaleX((F32)sd["scale_x"].asReal()); - setScaleY((F32)sd["scale_y"].asReal()); - setShearX((F32)sd["shear_x"].asReal()); - setShearY((F32)sd["shear_y"].asReal()); - setTwist((F32)sd["twist"].asReal()); - setTwistBegin((F32)sd["twist_begin"].asReal()); - setRadiusOffset((F32)sd["radius_offset"].asReal()); - setTaperX((F32)sd["taper_x"].asReal()); - setTaperY((F32)sd["taper_y"].asReal()); - setRevolutions((F32)sd["revolutions"].asReal()); - setSkew((F32)sd["skew"].asReal()); - return true; -} - -void LLPathParams::copyParams(const LLPathParams ¶ms) -{ - setCurveType(params.getCurveType()); - setBegin(params.getBegin()); - setEnd(params.getEnd()); - setScale(params.getScaleX(), params.getScaleY() ); - setShear(params.getShearX(), params.getShearY() ); - setTwist(params.getTwist()); - setTwistBegin(params.getTwistBegin()); - setRadiusOffset(params.getRadiusOffset()); - setTaper( params.getTaperX(), params.getTaperY() ); - setRevolutions(params.getRevolutions()); - setSkew(params.getSkew()); -} - -S32 profile_delete_lock = 1 ; -LLProfile::~LLProfile() -{ - if(profile_delete_lock) - { - llerrs << "LLProfile should not be deleted here!" << llendl ; - } -} - - -S32 LLVolume::sNumMeshPoints = 0; - -LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) - : mParams(params) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - mUnique = is_unique; - mFaceMask = 0x0; - mDetail = detail; - mSculptLevel = -2; - mIsTetrahedron = FALSE; - mLODScaleBias.setVec(1,1,1); - mHullPoints = NULL; - mHullIndices = NULL; - mNumHullPoints = 0; - mNumHullIndices = 0; - - // set defaults - if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) - { - mPathp = new LLDynamicPath(); - } - else - { - mPathp = new LLPath(); - } - mProfilep = new LLProfile(); - - mGenerateSingleFace = generate_single_face; - - generate(); - - if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE) - { - createVolumeFaces(); - } -} - -void LLVolume::resizePath(S32 length) -{ - mPathp->resizePath(length); - mVolumeFaces.clear(); -} - -void LLVolume::regen() -{ - generate(); - createVolumeFaces(); -} - -void LLVolume::genBinormals(S32 face) -{ - mVolumeFaces[face].createBinormals(); -} - -LLVolume::~LLVolume() -{ - sNumMeshPoints -= mMesh.size(); - delete mPathp; - - profile_delete_lock = 0 ; - delete mProfilep; - profile_delete_lock = 1 ; - - mPathp = NULL; - mProfilep = NULL; - mVolumeFaces.clear(); - - free(mHullPoints); - mHullPoints = NULL; - free(mHullIndices); - mHullIndices = NULL; -} - -BOOL LLVolume::generate() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - llassert_always(mProfilep); - - //Added 10.03.05 Dave Parks - // Split is a parameter to LLProfile::generate that tesselates edges on the profile - // to prevent lighting and texture interpolation errors on triangles that are - // stretched due to twisting or scaling on the path. - S32 split = (S32) ((mDetail)*0.66f); - - if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE && - (mParams.getPathParams().getScale().mV[0] != 1.0f || - mParams.getPathParams().getScale().mV[1] != 1.0f) && - (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI)) - { - split = 0; - } - - mLODScaleBias.setVec(0.5f, 0.5f, 0.5f); - - F32 profile_detail = mDetail; - F32 path_detail = mDetail; - - U8 path_type = mParams.getPathParams().getCurveType(); - U8 profile_type = mParams.getProfileParams().getCurveType(); - - if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) - { //cylinders don't care about Z-Axis - mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); - } - else if (path_type == LL_PCODE_PATH_CIRCLE) - { - mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); - } - - //******************************************************************** - //debug info, to be removed - if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20)) - { - llinfos << "sizeS: " << mPathp->mPath.size() << " sizeT: " << mProfilep->mProfile.size() << llendl ; - llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; - llinfos << mParams << llendl ; - llinfos << "more info to check if mProfilep is deleted or not." << llendl ; - llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; - - llerrs << "LLVolume corrupted!" << llendl ; - } - //******************************************************************** - - BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); - BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); - - if (regenPath || regenProf ) - { - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - //******************************************************************** - //debug info, to be removed - if((U32)(sizeS * sizeT) > (1u << 20)) - { - llinfos << "regenPath: " << (S32)regenPath << " regenProf: " << (S32)regenProf << llendl ; - llinfos << "sizeS: " << sizeS << " sizeT: " << sizeT << llendl ; - llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; - llinfos << mParams << llendl ; - llinfos << "more info to check if mProfilep is deleted or not." << llendl ; - llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; - - llerrs << "LLVolume corrupted!" << llendl ; - } - //******************************************************************** - - sNumMeshPoints -= mMesh.size(); - mMesh.resize(sizeT * sizeS); - sNumMeshPoints += mMesh.size(); - - //generate vertex positions - - // Run along the path. - for (S32 s = 0; s < sizeS; ++s) - { - LLVector2 scale = mPathp->mPath[s].mScale; - LLQuaternion rot = mPathp->mPath[s].mRot; - - // Run along the profile. - for (S32 t = 0; t < sizeT; ++t) - { - S32 m = s*sizeT + t; - Point& pt = mMesh[m]; - - pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0]; - pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1]; - pt.mPos.mV[2] = 0.0f; - pt.mPos = pt.mPos * rot; - pt.mPos += mPathp->mPath[s].mPos; - } - } - - for (std::vector<LLProfile::Face>::iterator iter = mProfilep->mFaces.begin(); - iter != mProfilep->mFaces.end(); ++iter) - { - LLFaceID id = iter->mFaceID; - mFaceMask |= id; - } - - return TRUE; - } - return FALSE; -} - -void LLVolumeFace::VertexData::init() +/** + * @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 "llmath.h" + +#include <set> + +#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 "lldarray.h" +#include "llvolume.h" +#include "llstl.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; + +#define GEN_TRI_STRIP 0 + +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) +{ + float fAWdU[3]; + LLVector3 dir; + LLVector3 diff; + + for (U32 i = 0; i < 3; i++) + { + dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]); + diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i]; + fAWdU[i] = fabsf(dir.mV[i]); + if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false; + } + + float f; + f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1]; if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1]) return false; + f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2]; if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0]) return false; + f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0]; if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[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 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) +{ + F32 u, v, t; + + /* find vectors for two edges sharing vert0 */ + LLVector3 edge1 = vert1 - vert0; + + LLVector3 edge2 = vert2 - vert0;; + + /* begin calculating determinant - also used to calculate U parameter */ + LLVector3 pvec = dir % edge2; + + /* if determinant is near zero, ray lies in plane of triangle */ + F32 det = edge1 * pvec; + + if (!two_sided) + { + if (det < F_APPROXIMATELY_ZERO) + { + return FALSE; + } + + /* calculate distance from vert0 to ray origin */ + LLVector3 tvec = orig - vert0; + + /* calculate U parameter and test bounds */ + u = tvec * pvec; + + if (u < 0.f || u > det) + { + return FALSE; + } + + /* prepare to test V parameter */ + LLVector3 qvec = tvec % edge1; + + /* calculate V parameter and test bounds */ + v = dir * qvec; + if (v < 0.f || u + v > det) + { + return FALSE; + } + + /* calculate t, scale parameters, ray intersects triangle */ + t = edge2 * qvec; + F32 inv_det = 1.0 / det; + t *= inv_det; + u *= inv_det; + v *= inv_det; + } + + else // two sided + { + if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) + { + return FALSE; + } + F32 inv_det = 1.0 / det; + + /* calculate distance from vert0 to ray origin */ + LLVector3 tvec = orig - vert0; + + /* calculate U parameter and test bounds */ + u = (tvec * pvec) * inv_det; + if (u < 0.f || u > 1.f) + { + return FALSE; + } + + /* prepare to test V parameter */ + LLVector3 qvec = tvec - edge1; + + /* calculate V parameter and test bounds */ + v = (dir * qvec) * inv_det; + + if (v < 0.f || u + v > 1.f) + { + return FALSE; + } + + /* calculate t, ray intersects triangle */ + t = (edge2 * qvec) * inv_det; + } + + if (intersection_a != NULL) + *intersection_a = u; + if (intersection_b != NULL) + *intersection_b = v; + if (intersection_t != NULL) + *intersection_t = t; + + + return TRUE; +} + + +//------------------------------------------------------------------- +// 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; + + // 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() && params.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(); +} + +BOOL LLVolume::generate() +{ + LLMemType m1(LLMemType::MTYPE_VOLUME); + llassert_always(mProfilep); + + //Added 10.03.05 Dave Parks + // Split is a parameter to LLProfile::generate that tesselates edges on the profile + // to prevent lighting and texture interpolation errors on triangles that are + // stretched due to twisting or scaling on the path. + S32 split = (S32) ((mDetail)*0.66f); + + if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE && + (mParams.getPathParams().getScale().mV[0] != 1.0f || + mParams.getPathParams().getScale().mV[1] != 1.0f) && + (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI)) + { + split = 0; + } + + mLODScaleBias.setVec(0.5f, 0.5f, 0.5f); + + F32 profile_detail = mDetail; + F32 path_detail = mDetail; + + U8 path_type = mParams.getPathParams().getCurveType(); + U8 profile_type = mParams.getProfileParams().getCurveType(); + + if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) + { //cylinders don't care about Z-Axis + mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); + } + else if (path_type == LL_PCODE_PATH_CIRCLE) + { + mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); + } + + //******************************************************************** + //debug info, to be removed + if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20)) + { + llinfos << "sizeS: " << mPathp->mPath.size() << " sizeT: " << mProfilep->mProfile.size() << llendl ; + llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; + llinfos << mParams << llendl ; + llinfos << "more info to check if mProfilep is deleted or not." << llendl ; + llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; + + llerrs << "LLVolume corrupted!" << llendl ; + } + //******************************************************************** + + BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); + BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); + + if (regenPath || regenProf ) + { + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + //******************************************************************** + //debug info, to be removed + if((U32)(sizeS * sizeT) > (1u << 20)) + { + llinfos << "regenPath: " << (S32)regenPath << " regenProf: " << (S32)regenProf << llendl ; + llinfos << "sizeS: " << sizeS << " sizeT: " << sizeT << llendl ; + llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; + llinfos << mParams << llendl ; + llinfos << "more info to check if mProfilep is deleted or not." << llendl ; + llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; + + llerrs << "LLVolume corrupted!" << llendl ; + } + //******************************************************************** + + sNumMeshPoints -= mMesh.size(); + mMesh.resize(sizeT * sizeS); + sNumMeshPoints += mMesh.size(); + + //generate vertex positions + + // Run along the path. + for (S32 s = 0; s < sizeS; ++s) + { + LLVector2 scale = mPathp->mPath[s].mScale; + LLQuaternion rot = mPathp->mPath[s].mRot; + + // Run along the profile. + for (S32 t = 0; t < sizeT; ++t) + { + S32 m = s*sizeT + t; + Point& pt = mMesh[m]; + + pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0]; + pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1]; + pt.mPos.mV[2] = 0.0f; + pt.mPos = pt.mPos * rot; + pt.mPos += mPathp->mPath[s].mPos; + } + } + + for (std::vector<LLProfile::Face>::iterator iter = mProfilep->mFaces.begin(); + iter != mProfilep->mFaces.end(); ++iter) + { + LLFaceID id = iter->mFaceID; + mFaceMask |= id; + } + + return TRUE; + } + return FALSE; +} + + +void 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)fsqrtf(((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::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; +} + +//----------------------------------------------------------------------------- +// generateSilhouetteVertices() +//----------------------------------------------------------------------------- +void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, + std::vector<LLVector3> &normals, + std::vector<S32> &segments, + const LLVector3& obj_cam_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat, + S32 face_mask) +{ + LLMemType m1(LLMemType::MTYPE_VOLUME); + + vertices.clear(); + normals.clear(); + segments.clear(); + + S32 cur_index = 0; + //for each face + for (face_list_t::iterator iter = mVolumeFaces.begin(); + iter != mVolumeFaces.end(); ++iter) + { + const LLVolumeFace& face = *iter; + + if (!(face_mask & (0x1 << cur_index++))) + { + 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.mIndices.size(); + 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].mPosition + + face.mVertices[v2].mPosition + + face.mVertices[v3].mPosition) / 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].mPosition + + face.mVertices[v2].mPosition + + face.mVertices[v3].mPosition) / 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.mVertices.size(); j++) { + vertices.push_back(face.mVertices[j].mPosition); + vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*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].mPosition); + vertices.push_back(face.mVertices[j].mPosition + 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.mIndices.size()/3); + for (U32 j = 0; j < face.mIndices.size()/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]; + + LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) % + (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition); + + if (norm.magVecSquared() < 0.00000001f) + { + fFacing[j] = AWAY | TOWARDS; + } + else + { + //get view vector + LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition); + bool away = view * norm > 0.0f; + if (away) + { + fFacing[j] = AWAY; + } + else + { + fFacing[j] = TOWARDS; + } + } + } + + //for each triangle + for (U32 j = 0; j < face.mIndices.size()/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)]; + + vertices.push_back(face.mVertices[v1].mPosition*mat); + LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat; + norm1.normVec(); + normals.push_back(norm1); + + vertices.push_back(face.mVertices[v2].mPosition*mat); + LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat; + norm2.normVec(); + normals.push_back(norm2); + + 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) +{ + 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; + } + + LLVector3 dir = end - start; + + F32 closest_t = 2.f; // must be larger than 1 + + for (S32 i = start_face; i <= end_face; i++) + { + const LLVolumeFace &face = getVolumeFace((U32)i); + + LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f; + LLVector3 box_size = 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); + } + + for (U32 tri = 0; tri < face.mIndices.size()/3; tri++) + { + S32 index1 = face.mIndices[tri*3+0]; + S32 index2 = face.mIndices[tri*3+1]; + S32 index3 = face.mIndices[tri*3+2]; + + F32 a, b, t; + + if (LLTriangleRayIntersect(face.mVertices[index1].mPosition, + face.mVertices[index2].mPosition, + face.mVertices[index3].mPosition, + start, dir, &a, &b, &t, FALSE)) + { + if ((t >= 0.f) && // if hit is after start + (t <= 1.f) && // and before end + (t < closest_t)) // and this hit is closer + { + closest_t = t; + hit_face = i; + + if (intersection != NULL) + { + *intersection = start + dir * closest_t; + } + + if (tex_coord != NULL) + { + *tex_coord = ((1.f - a - b) * face.mVertices[index1].mTexCoord + + a * face.mVertices[index2].mTexCoord + + b * face.mVertices[index3].mTexCoord); + + } + + if (normal != NULL) + { + *normal = ((1.f - a - b) * face.mVertices[index1].mNormal + + a * face.mVertices[index2].mNormal + + b * face.mVertices[index3].mNormal); + } + + if (bi_normal != NULL) + { + *bi_normal = ((1.f - a - b) * face.mVertices[index1].mBinormal + + a * face.mVertices[index2].mBinormal + + b * face.mVertices[index3].mBinormal); + } + + } + } + } + } + } + + + 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::asLLSD() const +{ + LLSD sd = LLSD(); + sd["path"] = mPathParams; + sd["profile"] = mProfileParams; + return sd; +} + +bool LLVolumeParams::fromLLSD(LLSD& sd) +{ + mPathParams.fromLLSD(sd["path"]); + mProfileParams.fromLLSD(sd["profile"]); + 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 +{ + 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) { - if (!mData) + LLFaceID test_mask = 0; + for(S32 i = 0; i < getNumFaces(); i++) { - mData = (LLVector4a*) malloc(sizeof(LLVector4a)*2); + test_mask |= mProfilep->mFaces[i].mFaceID; } + + return test_mask == face_mask; } -LLVolumeFace::VertexData::VertexData() +BOOL LLVolume::isConvex() const { - mData = NULL; - init(); + // 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(); } - -LLVolumeFace::VertexData::VertexData(const VertexData& rhs) + + +std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params) { - mData = NULL; - *this = rhs; + s << "{type=" << (U32) profile_params.mCurveType; + s << ", begin=" << profile_params.mBegin; + s << ", end=" << profile_params.mEnd; + s << ", hollow=" << profile_params.mHollow; + s << "}"; + return s; } -const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs) + +std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params) { - if (this != &rhs) - { - init(); - LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 2*sizeof(LLVector4a)); - mTexCoord = rhs.mTexCoord; - } - return *this; + 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; } -LLVolumeFace::VertexData::~VertexData() + +std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params) { - free(mData); - mData = NULL; + s << "{profileparams = " << volume_params.mProfileParams; + s << ", pathparams = " << volume_params.mPathParams; + s << "}"; + return s; } -LLVector4a& LLVolumeFace::VertexData::getPosition() + +std::ostream& operator<<(std::ostream &s, const LLProfile &profile) { - return mData[POSITION]; + s << " {open=" << (U32) profile.mOpen; + s << ", dirty=" << profile.mDirty; + s << ", totalout=" << profile.mTotalOut; + s << ", total=" << profile.mTotal; + s << "}"; + return s; } -LLVector4a& LLVolumeFace::VertexData::getNormal() + +std::ostream& operator<<(std::ostream &s, const LLPath &path) { - return mData[NORMAL]; + s << "{open=" << (U32) path.mOpen; + s << ", dirty=" << path.mDirty; + s << ", step=" << path.mStep; + s << ", total=" << path.mTotal; + s << "}"; + return s; } -const LLVector4a& LLVolumeFace::VertexData::getPosition() const +std::ostream& operator<<(std::ostream &s, const LLVolume &volume) { - return mData[POSITION]; + s << "{params = " << volume.getParams(); + s << ", path = " << *volume.mPathp; + s << ", profile = " << *volume.mProfilep; + s << "}"; + return s; } -const LLVector4a& LLVolumeFace::VertexData::getNormal() const + +std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) { - return mData[NORMAL]; + s << "{params = " << volumep->getParams(); + s << ", path = " << *(volumep->mPathp); + s << ", profile = " << *(volumep->mProfilep); + s << "}"; + return s; } -void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos) +BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) +{ + BOOL ret = FALSE ; + if (mTypeMask & CAP_MASK) + { + ret = createCap(volume, partial_build); + } + else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) + { + ret = createSide(volume, partial_build); + } + else + { + llerrs << "Unknown/uninitialized face type!" << llendl; + } + + //update the range of the texture coordinates + if(ret) + { + mTexCoordExtents[0].setVec(1.f, 1.f) ; + mTexCoordExtents[1].setVec(0.f, 0.f) ; + + U32 end = mVertices.size() ; + for(U32 i = 0 ; i < end ; i++) + { + if(mTexCoordExtents[0].mV[0] > mVertices[i].mTexCoord.mV[0]) + { + mTexCoordExtents[0].mV[0] = mVertices[i].mTexCoord.mV[0] ; + } + if(mTexCoordExtents[1].mV[0] < mVertices[i].mTexCoord.mV[0]) + { + mTexCoordExtents[1].mV[0] = mVertices[i].mTexCoord.mV[0] ; + } + + if(mTexCoordExtents[0].mV[1] > mVertices[i].mTexCoord.mV[1]) + { + mTexCoordExtents[0].mV[1] = mVertices[i].mTexCoord.mV[1] ; + } + if(mTexCoordExtents[1].mV[1] < mVertices[i].mTexCoord.mV[1]) + { + mTexCoordExtents[1].mV[1] = mVertices[i].mTexCoord.mV[1] ; + } + } + mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ; + mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ; + mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ; + mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ; + } + + return ret ; +} + +void LerpPlanarVertex(LLVolumeFace::VertexData& v0, + LLVolumeFace::VertexData& v1, + LLVolumeFace::VertexData& v2, + LLVolumeFace::VertexData& vout, + F32 coef01, + F32 coef02) { - mData[POSITION] = pos; + vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02); + vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02); + vout.mNormal = v0.mNormal; + vout.mBinormal = v0.mBinormal; } -void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm) +BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) { - mData[NORMAL] = norm; + 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; + + LLVector3& min = mExtents[0]; + LLVector3& 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(int t = 0; t < 4; t++){ + corners[t].mPosition = mesh[offset + (grid_size*t)].mPos; + 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]; + } + baseVert.mNormal = + ((corners[1].mPosition-corners[0].mPosition) % + (corners[2].mPosition-corners[1].mPosition)); + baseVert.mNormal.normVec(); + if(!(mTypeMask & TOP_MASK)){ + baseVert.mNormal *= -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; + } + baseVert.mBinormal = calc_binormal_from_triangle( + corners[0].mPosition, corners[0].mTexCoord, + corners[1].mPosition, corners[1].mTexCoord, + corners[2].mPosition, corners[2].mTexCoord); + for(int t = 0; t < 4; t++){ + corners[t].mBinormal = baseVert.mBinormal; + corners[t].mNormal = baseVert.mNormal; + } + mHasBinormals = TRUE; + + if (partial_build) + { + mVertices.clear(); + } + + S32 vtop = mVertices.size(); + 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); + mVertices.push_back(newVert); + + if (gx == 0 && gy == 0) + { + min = max = newVert.mPosition; + } + else + { + update_min_max(min,max,newVert.mPosition); + } + } + } + + mCenter = (min + max) * 0.5f; + + if (!partial_build) + { +#if GEN_TRI_STRIP + mTriStrip.clear(); +#endif + 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--) + { + mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); + } + +#if GEN_TRI_STRIP + if (gy == 0) + { + mTriStrip.push_back((gx+1)*(grid_size+1)); + mTriStrip.push_back((gx+1)*(grid_size+1)); + mTriStrip.push_back(gx*(grid_size+1)); + } + + mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); + mTriStrip.push_back(gy+1+gx*(grid_size+1)); + + + if (gy == grid_size-1) + { + mTriStrip.push_back(gy+1+gx*(grid_size+1)); + } +#endif + } + else + { + for(S32 i=0;i<6;i++) + { + mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); + } + +#if GEN_TRI_STRIP + if (gy == 0) + { + mTriStrip.push_back(gx*(grid_size+1)); + mTriStrip.push_back(gx*(grid_size+1)); + mTriStrip.push_back((gx+1)*(grid_size+1)); + } + + mTriStrip.push_back(gy+1+gx*(grid_size+1)); + mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); + + if (gy == grid_size-1) + { + mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1)); + } +#endif + } + } + + } + +#if GEN_TRI_STRIP + if (mTriStrip.size()%2 == 1) + { + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } +#endif + } + + return TRUE; } -bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const + +BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) { - const F32* lp = this->getPosition().getF32ptr(); - const F32* rp = rhs.getPosition().getF32ptr(); + 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; - if (lp[0] != rp[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; + + mVertices.resize(num_vertices); + + if (!partial_build) { - return lp[0] < rp[0]; + mIndices.resize(num_indices); } - if (rp[1] != lp[1]) + S32 max_s = volume->getProfile().getTotal(); + S32 max_t = volume->getPath().mPath.size(); + + mCenter.clearVec(); + + S32 offset = 0; + if (mTypeMask & TOP_MASK) + { + offset = (max_t-1) * max_s; + } + else { - return lp[1] < rp[1]; + offset = mBeginS; } - if (rp[2] != lp[2]) + // Figure out the normal, assume all caps are flat faces. + // Cross product to get normals. + + LLVector2 cuv; + LLVector2 min_uv, max_uv; + + LLVector3& min = mExtents[0]; + LLVector3& max = mExtents[1]; + + // Copy the vertices into the array + for (S32 i = 0; i < num_vertices; i++) { - return lp[2] < rp[2]; + if (mTypeMask & TOP_MASK) + { + mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; + mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f; + } + else + { + // Mirror for underside. + mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; + mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1]; + } + + mVertices[i].mPosition = mesh[i + offset].mPos; + + if (i == 0) + { + min = max = mVertices[i].mPosition; + min_uv = max_uv = mVertices[i].mTexCoord; + } + else + { + update_min_max(min,max, mVertices[i].mPosition); + update_min_max(min_uv, max_uv, mVertices[i].mTexCoord); + } } - lp = getNormal().getF32ptr(); - rp = rhs.getNormal().getF32ptr(); + mCenter = (min+max)*0.5f; + cuv = (min_uv + max_uv)*0.5f; + + LLVector3 binormal = calc_binormal_from_triangle( + mCenter, cuv, + mVertices[0].mPosition, mVertices[0].mTexCoord, + mVertices[1].mPosition, mVertices[1].mTexCoord); + binormal.normVec(); + + LLVector3 d0; + LLVector3 d1; + LLVector3 normal; + + d0 = mCenter-mVertices[0].mPosition; + d1 = mCenter-mVertices[1].mPosition; - if (lp[0] != rp[0]) + normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0); + normal.normVec(); + + VertexData vd; + vd.mPosition = mCenter; + vd.mNormal = normal; + vd.mBinormal = binormal; + vd.mTexCoord = cuv; + + if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) + { + mVertices.push_back(vd); + num_vertices++; + if (!partial_build) + { + vector_append(mIndices, 3); + } + } + + + for (S32 i = 0; i < num_vertices; i++) { - return lp[0] < rp[0]; + mVertices[i].mBinormal = binormal; + mVertices[i].mNormal = normal; } - if (rp[1] != lp[1]) + mHasBinormals = TRUE; + + if (partial_build) { - return lp[1] < rp[1]; + return TRUE; } - if (rp[2] != lp[2]) + 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--; + } + } + + makeTriStrip(); + } + 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--; + } + } + + makeTriStrip(); + } + } + else { - return lp[2] < rp[2]; + // 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; + } + +#if GEN_TRI_STRIP + //make tri strip + if (mTypeMask & OPEN_MASK) + { + makeTriStrip(); + } + else + { + S32 j = num_vertices-2; + if (mTypeMask & TOP_MASK) + { + mTriStrip.push_back(0); + for (S32 i = 0; i <= j; ++i) + { + mTriStrip.push_back(i); + if (i != j) + { + mTriStrip.push_back(j); + } + --j; + } + } + else + { + mTriStrip.push_back(j); + for (S32 i = 0; i <= j; ++i) + { + if (i != j) + { + mTriStrip.push_back(j); + } + mTriStrip.push_back(i); + --j; + } + } + + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + + if (mTriStrip.size()%2 == 1) + { + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } + } +#endif } + + return TRUE; +} - if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0]) +void LLVolumeFace::makeTriStrip() +{ +#if GEN_TRI_STRIP + for (U32 i = 0; i < mIndices.size(); i+=3) { - return mTexCoord.mV[0] < rhs.mTexCoord.mV[0]; + U16 i0 = mIndices[i]; + U16 i1 = mIndices[i+1]; + U16 i2 = mIndices[i+2]; + + if ((i/3)%2 == 1) + { + mTriStrip.push_back(i0); + mTriStrip.push_back(i0); + mTriStrip.push_back(i1); + mTriStrip.push_back(i2); + mTriStrip.push_back(i2); + } + else + { + mTriStrip.push_back(i2); + mTriStrip.push_back(i2); + mTriStrip.push_back(i1); + mTriStrip.push_back(i0); + mTriStrip.push_back(i0); + } } - return mTexCoord.mV[1] < rhs.mTexCoord.mV[1]; + if (mTriStrip.size()%2 == 1) + { + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } +#endif } -bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const +void LLVolumeFace::createBinormals() { - return mData[POSITION].equals3(rhs.getPosition()) && - mData[NORMAL].equals3(rhs.getNormal()) && - mTexCoord == rhs.mTexCoord; + LLMemType m1(LLMemType::MTYPE_VOLUME); + + if (!mHasBinormals) + { + //generate binormals + for (U32 i = 0; i < mIndices.size()/3; i++) + { //for each triangle + const VertexData& v0 = mVertices[mIndices[i*3+0]]; + const VertexData& v1 = mVertices[mIndices[i*3+1]]; + const VertexData& v2 = mVertices[mIndices[i*3+2]]; + + //calculate binormal + LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord, + v1.mPosition, v1.mTexCoord, + v2.mPosition, v2.mTexCoord); + + for (U32 j = 0; j < 3; j++) + { //add triangle normal to vertices + mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum; + } + + //even out quad contributions + if (i % 2 == 0) + { + mVertices[mIndices[i*3+2]].mBinormal += binorm; + } + else + { + mVertices[mIndices[i*3+1]].mBinormal += binorm; + } + } + + //normalize binormals + for (U32 i = 0; i < mVertices.size(); i++) + { + mVertices[i].mBinormal.normVec(); + mVertices[i].mNormal.normVec(); + } + + mHasBinormals = TRUE; + } } -bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const +BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { - bool retval = false; - if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord) + 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; + + mVertices.resize(num_vertices); + + if (!partial_build) + { + mIndices.resize(num_indices); + mEdge.resize(num_indices); + } + else + { + mHasBinormals = FALSE; + } + + 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++) { - if (angle_cutoff > 1.f) + tt = path_data[t].mTexT; + for (s = 0; s < num_s; s++) { - retval = (mData[NORMAL].equals3(rhs.mData[NORMAL])); + 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; + } + + mVertices[cur_vertex].mPosition = mesh[i].mPos; + mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); + + mVertices[cur_vertex].mNormal = LLVector3(0,0,0); + mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); + + cur_vertex++; + + if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0) + { + mVertices[cur_vertex].mPosition = mesh[i].mPos; + mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); + + mVertices[cur_vertex].mNormal = LLVector3(0,0,0); + mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); + cur_vertex++; + } } - else + + 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; + mVertices[cur_vertex].mPosition = mesh[i].mPos; + mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); + + mVertices[cur_vertex].mNormal = LLVector3(0,0,0); + mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); + + cur_vertex++; + } + } + + + //get bounding box for this side + LLVector3& face_min = mExtents[0]; + LLVector3& face_max = mExtents[1]; + mCenter.clearVec(); + + face_min = face_max = mVertices[0].mPosition; + for (U32 i = 1; i < mVertices.size(); ++i) + { + update_min_max(face_min, face_max, mVertices[i].mPosition); + } + + mCenter = (face_min + face_max) * 0.5f; + + S32 cur_index = 0; + S32 cur_edge = 0; + BOOL flat_face = mTypeMask & FLAT_MASK; + + if (!partial_build) + { +#if GEN_TRI_STRIP + mTriStrip.clear(); +#endif + + // Now we generate the indices. + for (t = 0; t < (mNumT-1); t++) + { +#if GEN_TRI_STRIP + //prepend terminating index to strip + mTriStrip.push_back(mNumS*t); +#endif + + 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 + +#if GEN_TRI_STRIP + if (s == 0) + { + mTriStrip.push_back(s+mNumS*t); + mTriStrip.push_back(s+mNumS*(t+1)); + } + mTriStrip.push_back(s+1+mNumS*t); + mTriStrip.push_back(s+1+mNumS*(t+1)); +#endif + + 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 + } +#if GEN_TRI_STRIP + //append terminating vertex to strip + mTriStrip.push_back(mNumS-1+mNumS*(t+1)); +#endif + } + +#if GEN_TRI_STRIP + if (mTriStrip.size()%2 == 1) + { + mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } +#endif + } + + //generate normals + for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle + { + const U16* idx = &(mIndices[i*3]); + + VertexData* v[] = + { &mVertices[idx[0]], &mVertices[idx[1]], &mVertices[idx[2]] }; + + //calculate triangle normal + LLVector3 norm = (v[0]->mPosition-v[1]->mPosition) % (v[0]->mPosition-v[2]->mPosition); + + v[0]->mNormal += norm; + v[1]->mNormal += norm; + v[2]->mNormal += norm; + + //even out quad contributions + v[i%2+1]->mNormal += norm; + } + + // adjust normals based on wrapping and stitching + + BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f); + BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 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++) + { + LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; + mVertices[i].mNormal = norm; + mVertices[mNumS*(mNumT-1)+i].mNormal = norm; + } + } + + if ((volume->getProfile().isOpen() == FALSE) && !(s_bottom_converges)) + { //wrap normals on S + for (S32 i = 0; i < mNumT; i++) + { + LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal; + mVertices[mNumS * i].mNormal = norm; + mVertices[mNumS * i+mNumS-1].mNormal = norm; + } + } + + if (volume->getPathType() == LL_PCODE_PATH_CIRCLE && + ((volume->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) { - F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32(); - retval = cur_angle > angle_cutoff; + if (s_bottom_converges) + { //all lower S have same normal + for (S32 i = 0; i < mNumT; i++) + { + mVertices[mNumS*i].mNormal = LLVector3(1,0,0); + } + } + + if (s_top_converges) + { //all upper S have same normal + for (S32 i = 0; i < mNumT; i++) + { + mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-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 + + LLVector3 average(0.0, 0.0, 0.0); + for (S32 i = 0; i < mNumS; i++) + { + average += mVertices[i].mNormal; + } + + // set average + for (S32 i = 0; i < mNumS; i++) + { + mVertices[i].mNormal = average; + } + + // average normals for south pole + + average = LLVector3(0.0, 0.0, 0.0); + for (S32 i = 0; i < mNumS; i++) + { + average += mVertices[i + mNumS * (mNumT - 1)].mNormal; + } + + // set average + for (S32 i = 0; i < mNumS; i++) + { + mVertices[i + mNumS * (mNumT - 1)].mNormal = average; + } + + } + + + if (wrap_s) + { + for (S32 i = 0; i < mNumT; i++) + { + LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal; + mVertices[mNumS * i].mNormal = norm; + mVertices[mNumS * i+mNumS-1].mNormal = norm; + } } + + + + if (wrap_t) + { + for (S32 i = 0; i < mNumS; i++) + { + LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; + mVertices[i].mNormal = norm; + mVertices[mNumS*(mNumT-1)+i].mNormal = norm; + } + + } + } - return retval; + return TRUE; +} + +// Finds binormal based on three vertices with texture coordinates. +// Fills in dummy values if the triangle has degenerate texture coordinates. +LLVector3 calc_binormal_from_triangle( + const LLVector3& pos0, + const LLVector2& tex0, + const LLVector3& pos1, + const LLVector2& tex1, + const LLVector3& pos2, + const LLVector2& tex2) +{ + LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] ); + LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] ); + LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] ); + + LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] ); + LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] ); + LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] ); + + LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] ); + LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] ); + LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] ); + + LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2); + LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2); + LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2); + + if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] ) + { + LLVector3 binormal( + -r0.mV[VZ] / r0.mV[VX], + -r1.mV[VZ] / r1.mV[VX], + -r2.mV[VZ] / r2.mV[VX]); + // binormal.normVec(); + return binormal; + } + else + { + return LLVector3( 0, 1 , 0 ); + } } - -BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name) -{ - std::ifstream is; - - is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary); - - BOOL success = createVolumeFacesFromStream(is); - - is.close(); - - return success; -} - -BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) -{ - mSculptLevel = -1; // default is an error occured - - LLSD header; - { - if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024)) - { - llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; - return FALSE; - } - } - - std::string nm[] = - { - "lowest_lod", - "low_lod", - "medium_lod", - "high_lod" - }; - - S32 lod = llclamp((S32) mDetail, 0, 3); - - while (lod < 4 && - (header[nm[lod]]["offset"].asInteger() == -1 || - header[nm[lod]]["size"].asInteger() == 0 )) - { - ++lod; - } - - if (lod >= 4) - { - lod = llclamp((S32) mDetail, 0, 3); - - while (lod >= 0 && - (header[nm[lod]]["offset"].asInteger() == -1 || - header[nm[lod]]["size"].asInteger() == 0) ) - { - --lod; - } - - if (lod < 0) - { - llwarns << "Mesh header missing LOD offsets. Not a valid mesh asset!" << llendl; - return FALSE; - } - } - - is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); - - return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()); -} - -bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) -{ - //input stream is now pointing at a zlib compressed block of LLSD - //decompress block - LLSD mdl; - if (!unzip_llsd(mdl, is, size)) - { - llwarns << "not a valid mesh asset!" << llendl; - return false; - } - - { - U32 face_count = mdl.size(); - - if (face_count == 0) - { - llerrs << "WTF?" << llendl; - } - - mVolumeFaces.resize(face_count); - - for (U32 i = 0; i < face_count; ++i) - { - LLSD::Binary pos = mdl[i]["Position"]; - LLSD::Binary norm = mdl[i]["Normal"]; - LLSD::Binary tc = mdl[i]["TexCoord0"]; - LLSD::Binary idx = mdl[i]["TriangleList"]; - - LLVolumeFace& face = mVolumeFaces[i]; - - //copy out indices - face.resizeIndices(idx.size()/2); - - if (idx.empty() || face.mNumIndices < 3) - { //why is there an empty index list? - llerrs <<"WTF?" << llendl; - continue; - } - - U16* indices = (U16*) &(idx[0]); - for (U32 j = 0; j < idx.size()/2; ++j) - { - face.mIndices[j] = indices[j]; - } - - //copy out vertices - U32 num_verts = pos.size()/(3*2); - face.resizeVertices(num_verts); - - if (mdl[i].has("Weights")) - { - face.allocateWeights(num_verts); - - LLSD::Binary weights = mdl[i]["Weights"]; - - U32 idx = 0; - - U32 cur_vertex = 0; - while (idx < weights.size() && cur_vertex < num_verts) - { - const U8 END_INFLUENCES = 0xFF; - U8 joint = weights[idx++]; - - U32 cur_influence = 0; - LLVector4 wght(0,0,0,0); - - while (joint != END_INFLUENCES && idx < weights.size()) - { - U16 influence = weights[idx++]; - influence |= ((U16) weights[idx++] << 8); - - F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f); - wght.mV[cur_influence++] = (F32) joint + w; - - if (cur_influence >= 4) - { - joint = END_INFLUENCES; - } - else - { - joint = weights[idx++]; - } - } - - face.mWeights[cur_vertex].loadua(wght.mV); - - cur_vertex++; - } - - if (cur_vertex != num_verts || idx != weights.size()) - { - llwarns << "Vertex weight count does not match vertex count!" << llendl; - } - - } - - LLVector3 minp; - LLVector3 maxp; - LLVector2 min_tc; - LLVector2 max_tc; - - minp.setValue(mdl[i]["PositionDomain"]["Min"]); - maxp.setValue(mdl[i]["PositionDomain"]["Max"]); - LLVector4a min_pos, max_pos; - min_pos.load3(minp.mV); - max_pos.load3(maxp.mV); - - min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]); - max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]); - - LLVector4a pos_range; - pos_range.setSub(max_pos, min_pos); - LLVector2 tc_range = max_tc - min_tc; - - LLVector4a* pos_out = face.mPositions; - LLVector4a* norm_out = face.mNormals; - LLVector2* tc_out = face.mTexCoords; - - for (U32 j = 0; j < num_verts; ++j) - { - U16* v = (U16*) &(pos[j*3*2]); - - pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]); - pos_out->div(65535.f); - pos_out->mul(pos_range); - pos_out->add(min_pos); - - pos_out++; - - U16* n = (U16*) &(norm[j*3*2]); - - norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]); - norm_out->div(65535.f); - norm_out->mul(2.f); - norm_out->sub(1.f); - norm_out++; - - U16* t = (U16*) &(tc[j*2*2]); - - tc_out->mV[0] = (F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0]; - tc_out->mV[1] = (F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1]; - - tc_out++; - } - - - // modifier flags? - bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR); - bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT); - - - // translate to actions: - bool do_reflect_x = false; - bool do_reverse_triangles = false; - bool do_invert_normals = false; - - if (do_mirror) - { - do_reflect_x = true; - do_reverse_triangles = !do_reverse_triangles; - } - - if (do_invert) - { - do_invert_normals = true; - do_reverse_triangles = !do_reverse_triangles; - } - - // now do the work - - if (do_reflect_x) - { - LLVector4a* p = (LLVector4a*) face.mPositions; - LLVector4a* n = (LLVector4a*) face.mNormals; - - for (S32 i = 0; i < face.mNumVertices; i++) - { - p[i].mul(-1.0f); - n[i].mul(-1.0f); - } - } - - if (do_invert_normals) - { - LLVector4a* n = (LLVector4a*) face.mNormals; - - for (S32 i = 0; i < face.mNumVertices; i++) - { - n[i].mul(-1.0f); - } - } - - if (do_reverse_triangles) - { - for (U32 j = 0; j < face.mNumIndices; j += 3) - { - // swap the 2nd and 3rd index - S32 swap = face.mIndices[j+1]; - face.mIndices[j+1] = face.mIndices[j+2]; - face.mIndices[j+2] = swap; - } - } - - //calculate bounding box - LLVector4a& min = face.mExtents[0]; - LLVector4a& max = face.mExtents[1]; - - min.clear(); - max.clear(); - min = max = face.mPositions[0]; - - for (S32 i = 1; i < face.mNumVertices; ++i) - { - min.setMin(min, face.mPositions[i]); - max.setMax(max, face.mPositions[i]); - } - } - } - - mSculptLevel = 0; // success! - - cacheOptimize(); - - return true; -} - -void tetrahedron_set_normal(LLVolumeFace::VertexData* cv) -{ - LLVector4a v0; - v0.setSub(cv[1].getPosition(), cv[0].getNormal()); - LLVector4a v1; - v1.setSub(cv[2].getNormal(), cv[0].getPosition()); - - cv[0].getNormal().setCross3(v0,v1); - cv[0].getNormal().normalize3fast(); - cv[1].setNormal(cv[0].getNormal()); - cv[2].setNormal(cv[1].getNormal()); -} - -BOOL LLVolume::isTetrahedron() -{ - return mIsTetrahedron; -} - -void LLVolume::makeTetrahedron() -{ - mVolumeFaces.clear(); - - LLVolumeFace face; - - F32 x = 0.25f; - LLVector4a p[] = - { //unit tetrahedron corners - LLVector4a(x,x,x), - LLVector4a(-x,-x,x), - LLVector4a(-x,x,-x), - LLVector4a(x,-x,-x) - }; - - face.mExtents[0].splat(-x); - face.mExtents[1].splat(x); - - LLVolumeFace::VertexData cv[3]; - - //set texture coordinates - cv[0].mTexCoord = LLVector2(0,0); - cv[1].mTexCoord = LLVector2(1,0); - cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3); - - - //side 1 - cv[0].setPosition(p[1]); - cv[1].setPosition(p[0]); - cv[2].setPosition(p[2]); - - tetrahedron_set_normal(cv); - - face.resizeVertices(12); - face.resizeIndices(12); - - LLVector4a* v = (LLVector4a*) face.mPositions; - LLVector4a* n = (LLVector4a*) face.mNormals; - LLVector2* tc = (LLVector2*) face.mTexCoords; - - v[0] = cv[0].getPosition(); - v[1] = cv[1].getPosition(); - v[2] = cv[2].getPosition(); - v += 3; - - n[0] = cv[0].getNormal(); - n[1] = cv[1].getNormal(); - n[2] = cv[2].getNormal(); - n += 3; - - tc[0] = cv[0].mTexCoord; - tc[1] = cv[1].mTexCoord; - tc[2] = cv[2].mTexCoord; - tc += 3; - - - //side 2 - cv[0].setPosition(p[3]); - cv[1].setPosition(p[0]); - cv[2].setPosition(p[1]); - - tetrahedron_set_normal(cv); - - v[0] = cv[0].getPosition(); - v[1] = cv[1].getPosition(); - v[2] = cv[2].getPosition(); - v += 3; - - n[0] = cv[0].getNormal(); - n[1] = cv[1].getNormal(); - n[2] = cv[2].getNormal(); - n += 3; - - tc[0] = cv[0].mTexCoord; - tc[1] = cv[1].mTexCoord; - tc[2] = cv[2].mTexCoord; - tc += 3; - - //side 3 - cv[0].setPosition(p[3]); - cv[1].setPosition(p[1]); - cv[2].setPosition(p[2]); - - tetrahedron_set_normal(cv); - - v[0] = cv[0].getPosition(); - v[1] = cv[1].getPosition(); - v[2] = cv[2].getPosition(); - v += 3; - - n[0] = cv[0].getNormal(); - n[1] = cv[1].getNormal(); - n[2] = cv[2].getNormal(); - n += 3; - - tc[0] = cv[0].mTexCoord; - tc[1] = cv[1].mTexCoord; - tc[2] = cv[2].mTexCoord; - tc += 3; - - //side 4 - cv[0].setPosition(p[2]); - cv[1].setPosition(p[0]); - cv[2].setPosition(p[3]); - - tetrahedron_set_normal(cv); - - v[0] = cv[0].getPosition(); - v[1] = cv[1].getPosition(); - v[2] = cv[2].getPosition(); - v += 3; - - n[0] = cv[0].getNormal(); - n[1] = cv[1].getNormal(); - n[2] = cv[2].getNormal(); - n += 3; - - tc[0] = cv[0].mTexCoord; - tc[1] = cv[1].mTexCoord; - tc[2] = cv[2].mTexCoord; - tc += 3; - - //set index buffer - for (U16 i = 0; i < 12; i++) - { - face.mIndices[i] = i; - } - - mVolumeFaces.push_back(face); - mSculptLevel = 0; - mIsTetrahedron = TRUE; -} - -void LLVolume::copyVolumeFaces(const LLVolume* volume) -{ - mVolumeFaces = volume->mVolumeFaces; - mSculptLevel = 0; - mIsTetrahedron = FALSE; -} - -void LLVolume::cacheOptimize() -{ - for (S32 i = 0; i < mVolumeFaces.size(); ++i) - { - mVolumeFaces[i].cacheOptimize(); - } -} - - -S32 LLVolume::getNumFaces() const -{ - U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK); - - if (sculpt_type == LL_SCULPT_TYPE_MESH) - { - return LL_SCULPT_MESH_MAX_FACES; - } - - return (S32)mProfilep->mFaces.size(); -} - - -void LLVolume::createVolumeFaces() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if (mGenerateSingleFace) - { - // do nothing - } - else - { - S32 num_faces = getNumFaces(); - BOOL partial_build = TRUE; - if (num_faces != mVolumeFaces.size()) - { - partial_build = FALSE; - mVolumeFaces.resize(num_faces); - } - // Initialize volume faces with parameter data - for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++) - { - LLVolumeFace& vf = mVolumeFaces[i]; - LLProfile::Face& face = mProfilep->mFaces[i]; - vf.mBeginS = face.mIndex; - vf.mNumS = face.mCount; - if (vf.mNumS < 0) - { - llerrs << "Volume face corruption detected." << llendl; - } - - vf.mBeginT = 0; - vf.mNumT= getPath().mPath.size(); - vf.mID = i; - - // Set the type mask bits correctly - if (mParams.getProfileParams().getHollow() > 0) - { - vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK; - } - if (mProfilep->isOpen()) - { - vf.mTypeMask |= LLVolumeFace::OPEN_MASK; - } - if (face.mCap) - { - vf.mTypeMask |= LLVolumeFace::CAP_MASK; - if (face.mFaceID == LL_FACE_PATH_BEGIN) - { - vf.mTypeMask |= LLVolumeFace::TOP_MASK; - } - else - { - llassert(face.mFaceID == LL_FACE_PATH_END); - vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK; - } - } - else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) - { - vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK; - } - else - { - vf.mTypeMask |= LLVolumeFace::SIDE_MASK; - if (face.mFlat) - { - vf.mTypeMask |= LLVolumeFace::FLAT_MASK; - } - if (face.mFaceID & LL_FACE_INNER_SIDE) - { - vf.mTypeMask |= LLVolumeFace::INNER_MASK; - if (face.mFlat && vf.mNumS > 2) - { //flat inner faces have to copy vert normals - vf.mNumS = vf.mNumS*2; - if (vf.mNumS < 0) - { - llerrs << "Volume face corruption detected." << llendl; - } - } - } - else - { - vf.mTypeMask |= LLVolumeFace::OUTER_MASK; - } - } - } - - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) - { - (*iter).create(this, partial_build); - } - } -} - - -inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b) -{ - // maps RGB values to vector values [0..255] -> [-0.5..0.5] - LLVector3 value; - value.mV[VX] = r / 255.f - 0.5f; - value.mV[VY] = g / 255.f - 0.5f; - value.mV[VZ] = b / 255.f - 0.5f; - - return value; -} - -inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) -{ - U32 index = (x + y * sculpt_width) * sculpt_components; - return index; -} - - -inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) -{ - U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width); - U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height); - - return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); -} - - -inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data) -{ - LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]); - - return v; -} - -inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) -{ - U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components); - - return sculpt_index_to_vector(index, sculpt_data); -} - -inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) -{ - U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); - - return sculpt_index_to_vector(index, sculpt_data); -} - - -F32 LLVolume::sculptGetSurfaceArea() -{ - // test to see if image has enough variation to create non-degenerate geometry - - F32 area = 0; - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - for (S32 s = 0; s < sizeS-1; s++) - { - for (S32 t = 0; t < sizeT-1; t++) - { - // get four corners of quad - LLVector3 p1 = mMesh[(s )*sizeT + (t )].mPos; - LLVector3 p2 = mMesh[(s+1)*sizeT + (t )].mPos; - LLVector3 p3 = mMesh[(s )*sizeT + (t+1)].mPos; - LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos; - - // compute the area of the quad by taking the length of the cross product of the two triangles - LLVector3 cross1 = (p1 - p2) % (p1 - p3); - LLVector3 cross2 = (p4 - p2) % (p4 - p3); - area += (cross1.magVec() + cross2.magVec()) / 2.0; - } - } - - return area; -} - -// create placeholder shape -void LLVolume::sculptGeneratePlaceholder() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - S32 line = 0; - - // for now, this is a sphere. - for (S32 s = 0; s < sizeS; s++) - { - for (S32 t = 0; t < sizeT; t++) - { - S32 i = t + line; - Point& pt = mMesh[i]; - - - F32 u = (F32)s/(sizeS-1); - F32 v = (F32)t/(sizeT-1); - - const F32 RADIUS = (F32) 0.3; - - pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS); - pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS); - pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS); - - } - line += sizeT; - } -} - -// create the vertices from the map -void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type) -{ - U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR - - - LLMemType m1(LLMemType::MTYPE_VOLUME); - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - S32 line = 0; - for (S32 s = 0; s < sizeS; s++) - { - // Run along the profile. - for (S32 t = 0; t < sizeT; t++) - { - S32 i = t + line; - Point& pt = mMesh[i]; - - S32 reversed_t = t; - - if (reverse_horizontal) - { - reversed_t = sizeT - t - 1; - } - - U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width); - U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height); - - - if (y == 0) // top row stitching - { - // pinch? - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - { - x = sculpt_width / 2; - } - } - - if (y == sculpt_height) // bottom row stitching - { - // wrap? - if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) - { - y = 0; - } - else - { - y = sculpt_height - 1; - } - - // pinch? - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - { - x = sculpt_width / 2; - } - } - - if (x == sculpt_width) // side stitching - { - // wrap? - if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || - (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || - (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) - { - x = 0; - } - - else - { - x = sculpt_width - 1; - } - } - - pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); - - if (sculpt_mirror) - { - pt.mPos.mV[VX] *= -1.f; - } - } - - line += sizeT; - } -} - - -const S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square -const S32 SCULPT_REZ_2 = 8; -const S32 SCULPT_REZ_3 = 16; -const S32 SCULPT_REZ_4 = 32; - -S32 sculpt_sides(F32 detail) -{ - - // detail is usually one of: 1, 1.5, 2.5, 4.0. - - if (detail <= 1.0) - { - return SCULPT_REZ_1; - } - if (detail <= 2.0) - { - return SCULPT_REZ_2; - } - if (detail <= 3.0) - { - return SCULPT_REZ_3; - } - else - { - return SCULPT_REZ_4; - } -} - - - -// determine the number of vertices in both s and t direction for this sculpt -void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) -{ - // this code has the following properties: - // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map - // while still using all available verts - // 2) the mesh cannot have more verts than is allowed by LOD - // 3) the mesh cannot have more verts than is allowed by the map - - S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0); - S32 max_vertices_map = width * height / 4; - - S32 vertices; - if (max_vertices_map > 0) - vertices = llmin(max_vertices_lod, max_vertices_map); - else - vertices = max_vertices_lod; - - - F32 ratio; - if ((width == 0) || (height == 0)) - ratio = 1.f; - else - ratio = (F32) width / (F32) height; - - - s = (S32)(F32) sqrt(((F32)vertices / ratio)); - - s = llmax(s, 4); // no degenerate sizes, please - t = vertices / s; - - t = llmax(t, 4); // no degenerate sizes, please - s = vertices / t; -} - -// sculpt replaces generate() for sculpted surfaces -void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - U8 sculpt_type = mParams.getSculptType(); - - BOOL data_is_empty = FALSE; - - if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) - { - sculpt_level = -1; - data_is_empty = TRUE; - } - - S32 requested_sizeS = 0; - S32 requested_sizeT = 0; - - sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT); - - mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS); - mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT); - - S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got - S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got - - // weird crash bug - DEV-11158 - trying to collect more data: - if ((sizeS == 0) || (sizeT == 0)) - { - llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl; - } - - sNumMeshPoints -= mMesh.size(); - mMesh.resize(sizeS * sizeT); - sNumMeshPoints += mMesh.size(); - - //generate vertex positions - if (!data_is_empty) - { - sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type); - - // don't test lowest LOD to support legacy content DEV-33670 - if (mDetail > SCULPT_MIN_AREA_DETAIL) - { - if (sculptGetSurfaceArea() < SCULPT_MIN_AREA) - { - data_is_empty = TRUE; - } - } - } - - if (data_is_empty) - { - sculptGeneratePlaceholder(); - } - - - - for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) - { - mFaceMask |= mProfilep->mFaces[i].mFaceID; - } - - mSculptLevel = sculpt_level; - - // Delete any existing faces so that they get regenerated - mVolumeFaces.clear(); - - createVolumeFaces(); -} - - - - -BOOL LLVolume::isCap(S32 face) -{ - return mProfilep->mFaces[face].mCap; -} - -BOOL LLVolume::isFlat(S32 face) -{ - return mProfilep->mFaces[face].mFlat; -} - - -bool LLVolumeParams::isSculpt() const -{ - return mSculptID.notNull(); -} - -bool LLVolumeParams::isMeshSculpt() const -{ - return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH); -} - -bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const -{ - return ( (getPathParams() == params.getPathParams()) && - (getProfileParams() == params.getProfileParams()) && - (mSculptID == params.mSculptID) && - (mSculptType == params.mSculptType) ); -} - -bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const -{ - return ( (getPathParams() != params.getPathParams()) || - (getProfileParams() != params.getProfileParams()) || - (mSculptID != params.mSculptID) || - (mSculptType != params.mSculptType) ); -} - -bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const -{ - if( getPathParams() != params.getPathParams() ) - { - return getPathParams() < params.getPathParams(); - } - - if (getProfileParams() != params.getProfileParams()) - { - return getProfileParams() < params.getProfileParams(); - } - - if (mSculptID != params.mSculptID) - { - return mSculptID < params.mSculptID; - } - - return mSculptType < params.mSculptType; - - -} - -void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - mProfileParams.copyParams(params.mProfileParams); - mPathParams.copyParams(params.mPathParams); - mSculptID = params.getSculptID(); - mSculptType = params.getSculptType(); -} - -// Less restricitve approx 0 for volumes -const F32 APPROXIMATELY_ZERO = 0.001f; -bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO) -{ - return (f >= -tolerance) && (f <= tolerance); -} - -// return true if in range (or nearly so) -static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO) -{ - F32 min_delta = v - min; - if (min_delta < 0.f) - { - v = min; - if (!approx_zero(min_delta, tolerance)) - return false; - } - F32 max_delta = max - v; - if (max_delta < 0.f) - { - v = max; - if (!approx_zero(max_delta, tolerance)) - return false; - } - return true; -} - -bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e) -{ - bool valid = true; - - // First, clamp to valid ranges. - F32 begin = b; - valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); - - F32 end = e; - if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error - valid &= limit_range(end, MIN_CUT_DELTA, 1.f); - - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); - - // Now set them. - mProfileParams.setBegin(begin); - mProfileParams.setEnd(end); - - return valid; -} - -bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e) -{ - bool valid = true; - - // First, clamp to valid ranges. - F32 begin = b; - valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); - - F32 end = e; - valid &= limit_range(end, MIN_CUT_DELTA, 1.f); - - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); - - // Now set them. - mPathParams.setBegin(begin); - mPathParams.setEnd(end); - - return valid; -} - -bool LLVolumeParams::setHollow(const F32 h) -{ - // Validate the hollow based on path and profile. - U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK; - - F32 max_hollow = HOLLOW_MAX; - - // Only square holes have trouble. - if (LL_PCODE_HOLE_SQUARE == hole_type) - { - switch(profile) - { - case LL_PCODE_PROFILE_CIRCLE: - case LL_PCODE_PROFILE_CIRCLE_HALF: - case LL_PCODE_PROFILE_EQUALTRI: - max_hollow = HOLLOW_MAX_SQUARE; - } - } - - F32 hollow = h; - bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow); - mProfileParams.setHollow(hollow); - - return valid; -} - -bool LLVolumeParams::setTwistBegin(const F32 b) -{ - F32 twist_begin = b; - bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX); - mPathParams.setTwistBegin(twist_begin); - return valid; -} - -bool LLVolumeParams::setTwistEnd(const F32 e) -{ - F32 twist_end = e; - bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX); - mPathParams.setTwistEnd(twist_end); - return valid; -} - -bool LLVolumeParams::setRatio(const F32 x, const F32 y) -{ - F32 min_x = RATIO_MIN; - F32 max_x = RATIO_MAX; - F32 min_y = RATIO_MIN; - F32 max_y = RATIO_MAX; - // If this is a circular path (and not a sphere) then 'ratio' is actually hole size. - U8 path_type = mPathParams.getCurveType(); - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PATH_CIRCLE == path_type && - LL_PCODE_PROFILE_CIRCLE_HALF != profile_type) - { - // Holes are more restricted... - min_x = HOLE_X_MIN; - max_x = HOLE_X_MAX; - min_y = HOLE_Y_MIN; - max_y = HOLE_Y_MAX; - } - - F32 ratio_x = x; - bool valid = limit_range(ratio_x, min_x, max_x); - F32 ratio_y = y; - valid &= limit_range(ratio_y, min_y, max_y); - - mPathParams.setScale(ratio_x, ratio_y); - - return valid; -} - -bool LLVolumeParams::setShear(const F32 x, const F32 y) -{ - F32 shear_x = x; - bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX); - F32 shear_y = y; - valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX); - mPathParams.setShear(shear_x, shear_y); - return valid; -} - -bool LLVolumeParams::setTaperX(const F32 v) -{ - F32 taper = v; - bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); - mPathParams.setTaperX(taper); - return valid; -} - -bool LLVolumeParams::setTaperY(const F32 v) -{ - F32 taper = v; - bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); - mPathParams.setTaperY(taper); - return valid; -} - -bool LLVolumeParams::setRevolutions(const F32 r) -{ - F32 revolutions = r; - bool valid = limit_range(revolutions, REV_MIN, REV_MAX); - mPathParams.setRevolutions(revolutions); - return valid; -} - -bool LLVolumeParams::setRadiusOffset(const F32 offset) -{ - bool valid = true; - - // If this is a sphere, just set it to 0 and get out. - U8 path_type = mPathParams.getCurveType(); - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type || - LL_PCODE_PATH_CIRCLE != path_type ) - { - mPathParams.setRadiusOffset(0.f); - return true; - } - - // Limit radius offset, based on taper and hole size y. - F32 radius_offset = offset; - F32 taper_y = getTaperY(); - F32 radius_mag = fabs(radius_offset); - F32 hole_y_mag = fabs(getRatioY()); - F32 taper_y_mag = fabs(taper_y); - // Check to see if the taper effects us. - if ( (radius_offset > 0.f && taper_y < 0.f) || - (radius_offset < 0.f && taper_y > 0.f) ) - { - // The taper does not help increase the radius offset range. - taper_y_mag = 0.f; - } - F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); - - // Enforce the maximum magnitude. - F32 delta = max_radius_mag - radius_mag; - if (delta < 0.f) - { - // Check radius offset sign. - if (radius_offset < 0.f) - { - radius_offset = -max_radius_mag; - } - else - { - radius_offset = max_radius_mag; - } - valid = approx_zero(delta, .1f); - } - - mPathParams.setRadiusOffset(radius_offset); - return valid; -} - -bool LLVolumeParams::setSkew(const F32 skew_value) -{ - bool valid = true; - - // Check the skew value against the revolutions. - F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX); - F32 skew_mag = fabs(skew); - F32 revolutions = getRevolutions(); - F32 scale_x = getRatioX(); - F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); - // Discontinuity; A revolution of 1 allows skews below 0.5. - if ( fabs(revolutions - 1.0f) < 0.001) - min_skew_mag = 0.0f; - - // Clip skew. - F32 delta = skew_mag - min_skew_mag; - if (delta < 0.f) - { - // Check skew sign. - if (skew < 0.0f) - { - skew = -min_skew_mag; - } - else - { - skew = min_skew_mag; - } - valid = approx_zero(delta, .01f); - } - - mPathParams.setSkew(skew); - return valid; -} - -bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type) -{ - mSculptID = sculpt_id; - mSculptType = sculpt_type; - return true; -} - -bool LLVolumeParams::setType(U8 profile, U8 path) -{ - bool result = true; - // First, check profile and path for validity. - U8 profile_type = profile & LL_PCODE_PROFILE_MASK; - U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4; - U8 path_type = path >> 4; - - if (profile_type > LL_PCODE_PROFILE_MAX) - { - // Bad profile. Make it square. - profile = LL_PCODE_PROFILE_SQUARE; - result = false; - llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type - << ") to be LL_PCODE_PROFILE_SQUARE" << llendl; - } - else if (hole_type > LL_PCODE_HOLE_MAX) - { - // Bad hole. Make it the same. - profile = profile_type; - result = false; - llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type - << ") to be LL_PCODE_HOLE_SAME" << llendl; - } - - if (path_type < LL_PCODE_PATH_MIN || - path_type > LL_PCODE_PATH_MAX) - { - // Bad path. Make it linear. - result = false; - llwarns << "LLVolumeParams::setType changing bad path (" << path - << ") to be LL_PCODE_PATH_LINE" << llendl; - path = LL_PCODE_PATH_LINE; - } - - mProfileParams.setCurveType(profile); - mPathParams.setCurveType(path); - return result; -} - -// static -bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, - U8 path_curve, F32 path_begin, F32 path_end, - F32 scx, F32 scy, F32 shx, F32 shy, - F32 twistend, F32 twistbegin, F32 radiusoffset, - F32 tx, F32 ty, F32 revolutions, F32 skew) -{ - LLVolumeParams test_params; - if (!test_params.setType (prof_curve, path_curve)) - { - return false; - } - if (!test_params.setBeginAndEndS (prof_begin, prof_end)) - { - return false; - } - if (!test_params.setBeginAndEndT (path_begin, path_end)) - { - return false; - } - if (!test_params.setHollow (hollow)) - { - return false; - } - if (!test_params.setTwistBegin (twistbegin)) - { - return false; - } - if (!test_params.setTwistEnd (twistend)) - { - return false; - } - if (!test_params.setRatio (scx, scy)) - { - return false; - } - if (!test_params.setShear (shx, shy)) - { - return false; - } - if (!test_params.setTaper (tx, ty)) - { - return false; - } - if (!test_params.setRevolutions (revolutions)) - { - return false; - } - if (!test_params.setRadiusOffset (radiusoffset)) - { - return false; - } - if (!test_params.setSkew (skew)) - { - return false; - } - return true; -} - -S32 *LLVolume::getTriangleIndices(U32 &num_indices) const -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - S32 expected_num_triangle_indices = getNumTriangleIndices(); - if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES) - { - // we don't allow LLVolumes with this many vertices - llwarns << "Couldn't allocate triangle indices" << llendl; - num_indices = 0; - return NULL; - } - - S32* index = new S32[expected_num_triangle_indices]; - S32 count = 0; - - // Let's do this totally diffently, as we don't care about faces... - // Counter-clockwise triangles are forward facing... - - BOOL open = getProfile().isOpen(); - BOOL hollow = (mParams.getProfileParams().getHollow() > 0); - BOOL path_open = getPath().isOpen(); - S32 size_s, size_s_out, size_t; - S32 s, t, i; - size_s = getProfile().getTotal(); - size_s_out = getProfile().getTotalOut(); - size_t = getPath().mPath.size(); - - // NOTE -- if the construction of the triangles below ever changes - // then getNumTriangleIndices() method may also have to be updated. - - if (open) /* Flawfinder: ignore */ - { - if (hollow) - { - // Open hollow -- much like the closed solid, except we - // we need to stitch up the gap between s=0 and s=size_s-1 - - for (t = 0; t < size_t - 1; t++) - { - // The outer face, first cut, and inner face - for (s = 0; s < size_s - 1; s++) - { - i = s + t*size_s; - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - - // The other cut face - index[count++] = s + t*size_s; // x,y - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = s + (t+1)*size_s; // x,y+1 - - index[count++] = s + (t+1)*size_s; // x,y+1 - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = 0 + (t+1)*size_s; // x+1,y+1 - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - // Top cap - S32 pt1 = 0; - S32 pt2 = size_s-1; - S32 i = (size_t - 1)*size_s; - - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1 + i; - index[count++] = pt1 + 1 + i; - index[count++] = pt2 + i; - pt1++; - } - else - { - index[count++] = pt1 + i; - index[count++] = pt2 - 1 + i; - index[count++] = pt2 + i; - pt2--; - } - } - - // Bottom cap - pt1 = 0; - pt2 = size_s-1; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt1 + 1; - pt1++; - } - else - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt2 - 1; - pt2--; - } - } - } - } - else - { - // Open solid - - for (t = 0; t < size_t - 1; t++) - { - // Outer face + 1 cut face - for (s = 0; s < size_s - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - - // The other cut face - index[count++] = (size_s - 1) + (t*size_s); // x,y - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 - - index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 - index[count++] = 0 + (t*size_s); // x+1,y - index[count++] = 0 + (t+1)*size_s; // x+1,y+1 - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - for (s = 0; s < size_s - 2; s++) - { - index[count++] = s+1; - index[count++] = s; - index[count++] = size_s - 1; - } - - // We've got a top cap - S32 offset = (size_t - 1)*size_s; - for (s = 0; s < size_s - 2; s++) - { - // Inverted ordering from bottom cap. - index[count++] = offset + size_s - 1; - index[count++] = offset + s; - index[count++] = offset + s + 1; - } - } - } - } - else if (hollow) - { - // Closed hollow - // Outer face - - for (t = 0; t < size_t - 1; t++) - { - for (s = 0; s < size_s_out - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + 1 + size_s; // x+1,y+1 - } - } - - // Inner face - // Invert facing from outer face - for (t = 0; t < size_t - 1; t++) - { - for (s = size_s_out; s < size_s - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + 1 + size_s; // x+1,y+1 - } - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - // Top cap - S32 pt1 = 0; - S32 pt2 = size_s-1; - S32 i = (size_t - 1)*size_s; - - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1 + i; - index[count++] = pt1 + 1 + i; - index[count++] = pt2 + i; - pt1++; - } - else - { - index[count++] = pt1 + i; - index[count++] = pt2 - 1 + i; - index[count++] = pt2 + i; - pt2--; - } - } - - // Bottom cap - pt1 = 0; - pt2 = size_s-1; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt1 + 1; - pt1++; - } - else - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt2 - 1; - pt2--; - } - } - } - } - else - { - // Closed solid. Easy case. - for (t = 0; t < size_t - 1; t++) - { - for (s = 0; s < size_s - 1; s++) - { - // Should wrap properly, but for now... - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - // bottom cap - for (s = 1; s < size_s - 2; s++) - { - index[count++] = s+1; - index[count++] = s; - index[count++] = 0; - } - - // top cap - S32 offset = (size_t - 1)*size_s; - for (s = 1; s < size_s - 2; s++) - { - // Inverted ordering from bottom cap. - index[count++] = offset; - index[count++] = offset + s; - index[count++] = offset + s + 1; - } - } - } - -#ifdef LL_DEBUG - // assert that we computed the correct number of indices - if (count != expected_num_triangle_indices ) - { - llerrs << "bad index count prediciton:" - << " expected=" << expected_num_triangle_indices - << " actual=" << count << llendl; - } -#endif - -#if 0 - // verify that each index does not point beyond the size of the mesh - S32 num_vertices = mMesh.size(); - for (i = 0; i < count; i+=3) - { - llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl; - llassert(index[i] < num_vertices); - llassert(index[i+1] < num_vertices); - llassert(index[i+2] < num_vertices); - } -#endif - - num_indices = count; - return index; -} - -S32 LLVolume::getNumTriangleIndices() const -{ - BOOL profile_open = getProfile().isOpen(); - BOOL hollow = (mParams.getProfileParams().getHollow() > 0); - BOOL path_open = getPath().isOpen(); - - S32 size_s, size_s_out, size_t; - size_s = getProfile().getTotal(); - size_s_out = getProfile().getTotalOut(); - size_t = getPath().mPath.size(); - - S32 count = 0; - if (profile_open) /* Flawfinder: ignore */ - { - if (hollow) - { - // Open hollow -- much like the closed solid, except we - // we need to stitch up the gap between s=0 and s=size_s-1 - count = (size_t - 1) * (((size_s -1) * 6) + 6); - } - else - { - count = (size_t - 1) * (((size_s -1) * 6) + 6); - } - } - else if (hollow) - { - // Closed hollow - // Outer face - count = (size_t - 1) * (size_s_out - 1) * 6; - - // Inner face - count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6; - } - else - { - // Closed solid. Easy case. - count = (size_t - 1) * (size_s - 1) * 6; - } - - if (path_open) - { - S32 cap_triangle_count = size_s - 3; - if ( profile_open - || hollow ) - { - cap_triangle_count = size_s - 2; - } - if ( cap_triangle_count > 0 ) - { - // top and bottom caps - count += cap_triangle_count * 2 * 3; - } - } - return count; -} - - -S32 LLVolume::getNumTriangles() const -{ - U32 triangle_count = 0; - - for (S32 i = 0; i < getNumVolumeFaces(); ++i) - { - triangle_count += getVolumeFace(i).mNumIndices/3; - } - - return triangle_count; -} - - -//----------------------------------------------------------------------------- -// generateSilhouetteVertices() -//----------------------------------------------------------------------------- -void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, - std::vector<LLVector3> &normals, - std::vector<S32> &segments, - const LLVector3& obj_cam_vec_in, - const LLMatrix4& mat_in, - const LLMatrix3& norm_mat_in, - S32 face_mask) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - LLMatrix4a mat; - mat.loadu(mat_in); - - LLMatrix4a norm_mat; - norm_mat.loadu(norm_mat_in); - - LLVector4a obj_cam_vec; - obj_cam_vec.load3(obj_cam_vec_in.mV); - - vertices.clear(); - normals.clear(); - segments.clear(); - - if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - { - return; - } - - S32 cur_index = 0; - //for each face - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) - { - LLVolumeFace& face = *iter; - - if (!(face_mask & (0x1 << cur_index++)) || - face.mNumIndices == 0 || face.mEdge.empty()) - { - continue; - } - - if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { - - } - else { - - //============================================== - //DEBUG draw edge map instead of silhouette edge - //============================================== - -#if DEBUG_SILHOUETTE_EDGE_MAP - - //for each triangle - U32 count = face.mNumIndices; - for (U32 j = 0; j < count/3; j++) { - //get vertices - S32 v1 = face.mIndices[j*3+0]; - S32 v2 = face.mIndices[j*3+1]; - S32 v3 = face.mIndices[j*3+2]; - - //get current face center - LLVector3 cCenter = (face.mVertices[v1].getPosition() + - face.mVertices[v2].getPosition() + - face.mVertices[v3].getPosition()) / 3.0f; - - //for each edge - for (S32 k = 0; k < 3; k++) { - S32 nIndex = face.mEdge[j*3+k]; - if (nIndex <= -1) { - continue; - } - - if (nIndex >= (S32) count/3) { - continue; - } - //get neighbor vertices - v1 = face.mIndices[nIndex*3+0]; - v2 = face.mIndices[nIndex*3+1]; - v3 = face.mIndices[nIndex*3+2]; - - //get neighbor face center - LLVector3 nCenter = (face.mVertices[v1].getPosition() + - face.mVertices[v2].getPosition() + - face.mVertices[v3].getPosition()) / 3.0f; - - //draw line - vertices.push_back(cCenter); - vertices.push_back(nCenter); - normals.push_back(LLVector3(1,1,1)); - normals.push_back(LLVector3(1,1,1)); - segments.push_back(vertices.size()); - } - } - - continue; - - //============================================== - //DEBUG - //============================================== - - //============================================== - //DEBUG draw normals instead of silhouette edge - //============================================== -#elif DEBUG_SILHOUETTE_NORMALS - - //for each vertex - for (U32 j = 0; j < face.mNumVertices; j++) { - vertices.push_back(face.mVertices[j].getPosition()); - vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f); - normals.push_back(LLVector3(0,0,1)); - normals.push_back(LLVector3(0,0,1)); - segments.push_back(vertices.size()); -#if DEBUG_SILHOUETTE_BINORMALS - vertices.push_back(face.mVertices[j].getPosition()); - vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f); - normals.push_back(LLVector3(0,0,1)); - normals.push_back(LLVector3(0,0,1)); - segments.push_back(vertices.size()); -#endif - } - - continue; -#else - //============================================== - //DEBUG - //============================================== - - static const U8 AWAY = 0x01, - TOWARDS = 0x02; - - //for each triangle - std::vector<U8> fFacing; - vector_append(fFacing, face.mNumIndices/3); - - LLVector4a* v = (LLVector4a*) face.mPositions; - LLVector4a* n = (LLVector4a*) face.mNormals; - - for (U32 j = 0; j < face.mNumIndices/3; j++) - { - //approximate normal - S32 v1 = face.mIndices[j*3+0]; - S32 v2 = face.mIndices[j*3+1]; - S32 v3 = face.mIndices[j*3+2]; - - LLVector4a c1,c2; - c1.setSub(v[v1], v[v2]); - c2.setSub(v[v2], v[v3]); - - LLVector4a norm; - - norm.setCross3(c1, c2); - - if (norm.dot3(norm) < 0.00000001f) - { - fFacing[j] = AWAY | TOWARDS; - } - else - { - //get view vector - LLVector4a view; - view.setSub(obj_cam_vec, v[v1]); - bool away = view.dot3(norm) > 0.0f; - if (away) - { - fFacing[j] = AWAY; - } - else - { - fFacing[j] = TOWARDS; - } - } - } - - //for each triangle - for (U32 j = 0; j < face.mNumIndices/3; j++) - { - if (fFacing[j] == (AWAY | TOWARDS)) - { //this is a degenerate triangle - //take neighbor facing (degenerate faces get facing of one of their neighbors) - // *FIX IF NEEDED: this does not deal with neighboring degenerate faces - for (S32 k = 0; k < 3; k++) - { - S32 index = face.mEdge[j*3+k]; - if (index != -1) - { - fFacing[j] = fFacing[index]; - break; - } - } - continue; //skip degenerate face - } - - //for each edge - for (S32 k = 0; k < 3; k++) { - S32 index = face.mEdge[j*3+k]; - if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) { - //our neighbor is degenerate, make him face our direction - fFacing[face.mEdge[j*3+k]] = fFacing[j]; - continue; - } - - if (index == -1 || //edge has no neighbor, MUST be a silhouette edge - (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge - - S32 v1 = face.mIndices[j*3+k]; - S32 v2 = face.mIndices[j*3+((k+1)%3)]; - - LLVector4a t; - mat.affineTransform(v[v1], t); - vertices.push_back(LLVector3(t[0], t[1], t[2])); - - norm_mat.rotate(n[v1], t); - - t.normalize3fast(); - normals.push_back(LLVector3(t[0], t[1], t[2])); - - mat.affineTransform(v[v2], t); - vertices.push_back(LLVector3(t[0], t[1], t[2])); - - norm_mat.rotate(n[v2], t); - t.normalize3fast(); - normals.push_back(LLVector3(t[0], t[1], t[2])); - - segments.push_back(vertices.size()); - } - } - } -#endif - } - } -} - -S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) -{ - LLVector4a starta, enda; - starta.load3(start.mV); - enda.load3(end.mV); - - return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal); - -} - - -S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - S32 face, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) -{ - S32 hit_face = -1; - - S32 start_face; - S32 end_face; - - if (face == -1) // ALL_SIDES - { - start_face = 0; - end_face = getNumVolumeFaces() - 1; - } - else - { - start_face = face; - end_face = face; - } - - LLVector4a dir; - dir.setSub(end, start); - - F32 closest_t = 2.f; // must be larger than 1 - - end_face = llmin(end_face, getNumVolumeFaces()-1); - - for (S32 i = start_face; i <= end_face; i++) - { - LLVolumeFace &face = mVolumeFaces[i]; - - LLVector4a box_center; - box_center.setAdd(face.mExtents[0], face.mExtents[1]); - box_center.mul(0.5f); - - LLVector4a box_size; - box_size.setSub(face.mExtents[1], face.mExtents[0]); - - if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) - { - if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them - { - genBinormals(i); - } - - if (!face.mOctree) - { - face.createOctree(); - } - - //LLVector4a* p = (LLVector4a*) face.mPositions; - - LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal); - intersect.traverse(face.mOctree); - if (intersect.mHitFace) - { - hit_face = i; - } - } - } - - - return hit_face; -} - -class LLVertexIndexPair -{ -public: - LLVertexIndexPair(const LLVector3 &vertex, const S32 index); - - LLVector3 mVertex; - S32 mIndex; -}; - -LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) -{ - mVertex = vertex; - mIndex = index; -} - -const F32 VERTEX_SLOP = 0.00001f; -const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP; - -struct lessVertex -{ - bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b) - { - const F32 slop = VERTEX_SLOP; - - if (a->mVertex.mV[0] + slop < b->mVertex.mV[0]) - { - return TRUE; - } - else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0]) - { - return FALSE; - } - - if (a->mVertex.mV[1] + slop < b->mVertex.mV[1]) - { - return TRUE; - } - else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1]) - { - return FALSE; - } - - if (a->mVertex.mV[2] + slop < b->mVertex.mV[2]) - { - return TRUE; - } - else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2]) - { - return FALSE; - } - - return FALSE; - } -}; - -struct lessTriangle -{ - bool operator()(const S32 *a, const S32 *b) - { - if (*a < *b) - { - return TRUE; - } - else if (*a > *b) - { - return FALSE; - } - - if (*(a+1) < *(b+1)) - { - return TRUE; - } - else if (*(a+1) > *(b+1)) - { - return FALSE; - } - - if (*(a+2) < *(b+2)) - { - return TRUE; - } - else if (*(a+2) > *(b+2)) - { - return FALSE; - } - - return FALSE; - } -}; - -BOOL equalTriangle(const S32 *a, const S32 *b) -{ - if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2))) - { - return TRUE; - } - return FALSE; -} - -BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, - const std::vector<Point>& input_vertices, - const S32 num_input_triangles, - S32 *input_triangles, - S32 &num_output_vertices, - LLVector3 **output_vertices, - S32 &num_output_triangles, - S32 **output_triangles) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - /* Testing: avoid any cleanup - static BOOL skip_cleanup = TRUE; - if ( skip_cleanup ) - { - num_output_vertices = num_input_vertices; - num_output_triangles = num_input_triangles; - - *output_vertices = new LLVector3[num_input_vertices]; - for (S32 index = 0; index < num_input_vertices; index++) - { - (*output_vertices)[index] = input_vertices[index].mPos; - } - - *output_triangles = new S32[num_input_triangles*3]; - memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32)); // Flawfinder: ignore - return TRUE; - } - */ - - // Here's how we do this: - // Create a structure which contains the original vertex index and the - // LLVector3 data. - // "Sort" the data by the vectors - // Create an array the size of the old vertex list, with a mapping of - // old indices to new indices. - // Go through triangles, shift so the lowest index is first - // Sort triangles by first index - // Remove duplicate triangles - // Allocate and pack new triangle data. - - //LLTimer cleanupTimer; - //llinfos << "In vertices: " << num_input_vertices << llendl; - //llinfos << "In triangles: " << num_input_triangles << llendl; - - S32 i; - typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t; - vertex_set_t vertex_list; - - LLVertexIndexPair *pairp = NULL; - for (i = 0; i < num_input_vertices; i++) - { - LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i); - vertex_list.insert(new_pairp); - } - - // Generate the vertex mapping and the list of vertices without - // duplicates. This will crash if there are no vertices. - llassert(num_input_vertices > 0); // check for no vertices! - S32 *vertex_mapping = new S32[num_input_vertices]; - LLVector3 *new_vertices = new LLVector3[num_input_vertices]; - LLVertexIndexPair *prev_pairp = NULL; - - S32 new_num_vertices; - - new_num_vertices = 0; - for (vertex_set_t::iterator iter = vertex_list.begin(), - end = vertex_list.end(); - iter != end; iter++) - { - pairp = *iter; - if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD)) - { - new_vertices[new_num_vertices] = pairp->mVertex; - //llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl; - new_num_vertices++; - // Update the previous - prev_pairp = pairp; - } - else - { - //llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl; - } - vertex_mapping[pairp->mIndex] = new_num_vertices - 1; - } - - // Iterate through triangles and remove degenerates, re-ordering vertices - // along the way. - S32 *new_triangles = new S32[num_input_triangles * 3]; - S32 new_num_triangles = 0; - - for (i = 0; i < num_input_triangles; i++) - { - S32 v1 = i*3; - S32 v2 = v1 + 1; - S32 v3 = v1 + 2; - - //llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; - input_triangles[v1] = vertex_mapping[input_triangles[v1]]; - input_triangles[v2] = vertex_mapping[input_triangles[v2]]; - input_triangles[v3] = vertex_mapping[input_triangles[v3]]; - - if ((input_triangles[v1] == input_triangles[v2]) - || (input_triangles[v1] == input_triangles[v3]) - || (input_triangles[v2] == input_triangles[v3])) - { - //llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; - // Degenerate triangle, skip - continue; - } - - if (input_triangles[v1] < input_triangles[v2]) - { - if (input_triangles[v1] < input_triangles[v3]) - { - // (0 < 1) && (0 < 2) - new_triangles[new_num_triangles*3] = input_triangles[v1]; - new_triangles[new_num_triangles*3+1] = input_triangles[v2]; - new_triangles[new_num_triangles*3+2] = input_triangles[v3]; - } - else - { - // (0 < 1) && (2 < 0) - new_triangles[new_num_triangles*3] = input_triangles[v3]; - new_triangles[new_num_triangles*3+1] = input_triangles[v1]; - new_triangles[new_num_triangles*3+2] = input_triangles[v2]; - } - } - else if (input_triangles[v2] < input_triangles[v3]) - { - // (1 < 0) && (1 < 2) - new_triangles[new_num_triangles*3] = input_triangles[v2]; - new_triangles[new_num_triangles*3+1] = input_triangles[v3]; - new_triangles[new_num_triangles*3+2] = input_triangles[v1]; - } - else - { - // (1 < 0) && (2 < 1) - new_triangles[new_num_triangles*3] = input_triangles[v3]; - new_triangles[new_num_triangles*3+1] = input_triangles[v1]; - new_triangles[new_num_triangles*3+2] = input_triangles[v2]; - } - new_num_triangles++; - } - - if (new_num_triangles == 0) - { - llwarns << "Created volume object with 0 faces." << llendl; - delete[] new_triangles; - delete[] vertex_mapping; - delete[] new_vertices; - return FALSE; - } - - typedef std::set<S32*, lessTriangle> triangle_set_t; - triangle_set_t triangle_list; - - for (i = 0; i < new_num_triangles; i++) - { - triangle_list.insert(&new_triangles[i*3]); - } - - // Sort through the triangle list, and delete duplicates - - S32 *prevp = NULL; - S32 *curp = NULL; - - S32 *sorted_tris = new S32[new_num_triangles*3]; - S32 cur_tri = 0; - for (triangle_set_t::iterator iter = triangle_list.begin(), - end = triangle_list.end(); - iter != end; iter++) - { - curp = *iter; - if (!prevp || !equalTriangle(prevp, curp)) - { - //llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; - sorted_tris[cur_tri*3] = *curp; - sorted_tris[cur_tri*3+1] = *(curp+1); - sorted_tris[cur_tri*3+2] = *(curp+2); - cur_tri++; - prevp = curp; - } - else - { - //llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl; - } - } - - *output_vertices = new LLVector3[new_num_vertices]; - num_output_vertices = new_num_vertices; - for (i = 0; i < new_num_vertices; i++) - { - (*output_vertices)[i] = new_vertices[i]; - } - - *output_triangles = new S32[cur_tri*3]; - num_output_triangles = cur_tri; - memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32)); /* Flawfinder: ignore */ - - /* - llinfos << "Out vertices: " << num_output_vertices << llendl; - llinfos << "Out triangles: " << num_output_triangles << llendl; - for (i = 0; i < num_output_vertices; i++) - { - llinfos << i << ":" << (*output_vertices)[i] << llendl; - } - for (i = 0; i < num_output_triangles; i++) - { - llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl; - } - */ - - //llinfos << "Out vertices: " << num_output_vertices << llendl; - //llinfos << "Out triangles: " << num_output_triangles << llendl; - delete[] vertex_mapping; - vertex_mapping = NULL; - delete[] new_vertices; - new_vertices = NULL; - delete[] new_triangles; - new_triangles = NULL; - delete[] sorted_tris; - sorted_tris = NULL; - triangle_list.clear(); - std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer()); - vertex_list.clear(); - - return TRUE; -} - - -BOOL LLVolumeParams::importFile(LLFILE *fp) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - //llinfos << "importing volume" << llendl; - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of this buffer will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - - while (!feof(fp)) - { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf(buffer, " %255s", keyword); /* Flawfinder: ignore */ - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("profile", keyword)) - { - mProfileParams.importFile(fp); - } - else if (!strcmp("path",keyword)) - { - mPathParams.importFile(fp); - } - else - { - llwarns << "unknown keyword " << keyword << " in volume import" << llendl; - } - } - - return TRUE; -} - -BOOL LLVolumeParams::exportFile(LLFILE *fp) const -{ - fprintf(fp,"\tshape 0\n"); - fprintf(fp,"\t{\n"); - mPathParams.exportFile(fp); - mProfileParams.exportFile(fp); - fprintf(fp, "\t}\n"); - return TRUE; -} - - -BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - //llinfos << "importing volume" << llendl; - const S32 BUFSIZE = 16384; - // *NOTE: changing the size or type of this buffer will require - // changing the sscanf below. - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - char keyword[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - - while (input_stream.good()) - { - input_stream.getline(buffer, BUFSIZE); - sscanf(buffer, " %255s", keyword); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("profile", keyword)) - { - mProfileParams.importLegacyStream(input_stream); - } - else if (!strcmp("path",keyword)) - { - mPathParams.importLegacyStream(input_stream); - } - else - { - llwarns << "unknown keyword " << keyword << " in volume import" << llendl; - } - } - - return TRUE; -} - -BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - output_stream <<"\tshape 0\n"; - output_stream <<"\t{\n"; - mPathParams.exportLegacyStream(output_stream); - mProfileParams.exportLegacyStream(output_stream); - output_stream << "\t}\n"; - return TRUE; -} - -LLSD LLVolumeParams::sculptAsLLSD() const -{ - LLSD sd = LLSD(); - sd["id"] = getSculptID(); - sd["type"] = getSculptType(); - - return sd; -} - -bool LLVolumeParams::sculptFromLLSD(LLSD& sd) -{ - setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger()); - return true; -} - -LLSD LLVolumeParams::asLLSD() const -{ - LLSD sd = LLSD(); - sd["path"] = mPathParams; - sd["profile"] = mProfileParams; - sd["sculpt"] = sculptAsLLSD(); - - return sd; -} - -bool LLVolumeParams::fromLLSD(LLSD& sd) -{ - mPathParams.fromLLSD(sd["path"]); - mProfileParams.fromLLSD(sd["profile"]); - sculptFromLLSD(sd["sculpt"]); - - return true; -} - -void LLVolumeParams::reduceS(F32 begin, F32 end) -{ - begin = llclampf(begin); - end = llclampf(end); - if (begin > end) - { - F32 temp = begin; - begin = end; - end = temp; - } - F32 a = mProfileParams.getBegin(); - F32 b = mProfileParams.getEnd(); - mProfileParams.setBegin(a + begin * (b - a)); - mProfileParams.setEnd(a + end * (b - a)); -} - -void LLVolumeParams::reduceT(F32 begin, F32 end) -{ - begin = llclampf(begin); - end = llclampf(end); - if (begin > end) - { - F32 temp = begin; - begin = end; - end = temp; - } - F32 a = mPathParams.getBegin(); - F32 b = mPathParams.getEnd(); - mPathParams.setBegin(a + begin * (b - a)); - mPathParams.setEnd(a + end * (b - a)); -} - -const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity -const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity - -// returns TRUE if the shape can be approximated with a convex shape -// for collison purposes -BOOL LLVolumeParams::isConvex() const -{ - if (!getSculptID().isNull()) - { - // can't determine, be safe and say no: - return FALSE; - } - - F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); - F32 hollow = mProfileParams.getHollow(); - - U8 path_type = mPathParams.getCurveType(); - if ( path_length > MIN_CONCAVE_PATH_WEDGE - && ( mPathParams.getTwist() != mPathParams.getTwistBegin() - || (hollow > 0.f - && LL_PCODE_PATH_LINE != path_type) ) ) - { - // twist along a "not too short" path is concave - return FALSE; - } - - F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); - BOOL same_hole = hollow == 0.f - || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; - - F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) - { - // it is a sphere and spheres get twice the minimum profile wedge - min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; - } - - BOOL convex_profile = ( ( profile_length == 1.f - || profile_length <= 0.5f ) - && hollow == 0.f ) // trivially convex - || ( profile_length <= min_profile_wedge - && same_hole ); // effectvely convex (even when hollow) - - if (!convex_profile) - { - // profile is concave - return FALSE; - } - - if ( LL_PCODE_PATH_LINE == path_type ) - { - // straight paths with convex profile - return TRUE; - } - - BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f); - if (concave_path) - { - return FALSE; - } - - // we're left with spheres, toroids and tubes - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) - { - // at this stage all spheres must be convex - return TRUE; - } - - // it's a toroid or tube - if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) - { - // effectively convex - return TRUE; - } - - return FALSE; -} - -// debug -void LLVolumeParams::setCube() -{ - mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE); - mProfileParams.setBegin(0.f); - mProfileParams.setEnd(1.f); - mProfileParams.setHollow(0.f); - - mPathParams.setBegin(0.f); - mPathParams.setEnd(1.f); - mPathParams.setScale(1.f, 1.f); - mPathParams.setShear(0.f, 0.f); - mPathParams.setCurveType(LL_PCODE_PATH_LINE); - mPathParams.setTwistBegin(0.f); - mPathParams.setTwistEnd(0.f); - mPathParams.setRadiusOffset(0.f); - mPathParams.setTaper(0.f, 0.f); - mPathParams.setRevolutions(0.f); - mPathParams.setSkew(0.f); -} - -LLFaceID LLVolume::generateFaceMask() -{ - LLFaceID new_mask = 0x0000; - - switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK) - { - case LL_PCODE_PROFILE_CIRCLE: - case LL_PCODE_PROFILE_CIRCLE_HALF: - new_mask |= LL_FACE_OUTER_SIDE_0; - break; - case LL_PCODE_PROFILE_SQUARE: - { - for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++) - { - new_mask |= LL_FACE_OUTER_SIDE_0 << side; - } - } - break; - case LL_PCODE_PROFILE_ISOTRI: - case LL_PCODE_PROFILE_EQUALTRI: - case LL_PCODE_PROFILE_RIGHTTRI: - { - for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++) - { - new_mask |= LL_FACE_OUTER_SIDE_0 << side; - } - } - break; - default: - llerrs << "Unknown profile!" << llendl; - break; - } - - // handle hollow objects - if (mParams.getProfileParams().getHollow() > 0) - { - new_mask |= LL_FACE_INNER_SIDE; - } - - // handle open profile curves - if (mProfilep->isOpen()) - { - new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END; - } - - // handle open path curves - if (mPathp->isOpen()) - { - new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END; - } - - return new_mask; -} - -BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask) -{ - LLFaceID test_mask = 0; - for(S32 i = 0; i < getNumFaces(); i++) - { - test_mask |= mProfilep->mFaces[i].mFaceID; - } - - return test_mask == face_mask; -} - -BOOL LLVolume::isConvex() const -{ - // mParams.isConvex() may return FALSE even though the final - // geometry is actually convex due to LOD approximations. - // TODO -- provide LLPath and LLProfile with isConvex() methods - // that correctly determine convexity. -- Leviathan - return mParams.isConvex(); -} - - -std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params) -{ - s << "{type=" << (U32) profile_params.mCurveType; - s << ", begin=" << profile_params.mBegin; - s << ", end=" << profile_params.mEnd; - s << ", hollow=" << profile_params.mHollow; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params) -{ - s << "{type=" << (U32) path_params.mCurveType; - s << ", begin=" << path_params.mBegin; - s << ", end=" << path_params.mEnd; - s << ", twist=" << path_params.mTwistEnd; - s << ", scale=" << path_params.mScale; - s << ", shear=" << path_params.mShear; - s << ", twist_begin=" << path_params.mTwistBegin; - s << ", radius_offset=" << path_params.mRadiusOffset; - s << ", taper=" << path_params.mTaper; - s << ", revolutions=" << path_params.mRevolutions; - s << ", skew=" << path_params.mSkew; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params) -{ - s << "{profileparams = " << volume_params.mProfileParams; - s << ", pathparams = " << volume_params.mPathParams; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLProfile &profile) -{ - s << " {open=" << (U32) profile.mOpen; - s << ", dirty=" << profile.mDirty; - s << ", totalout=" << profile.mTotalOut; - s << ", total=" << profile.mTotal; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLPath &path) -{ - s << "{open=" << (U32) path.mOpen; - s << ", dirty=" << path.mDirty; - s << ", step=" << path.mStep; - s << ", total=" << path.mTotal; - s << "}"; - return s; -} - -std::ostream& operator<<(std::ostream &s, const LLVolume &volume) -{ - s << "{params = " << volume.getParams(); - s << ", path = " << *volume.mPathp; - s << ", profile = " << *volume.mProfilep; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) -{ - s << "{params = " << volumep->getParams(); - s << ", path = " << *(volumep->mPathp); - s << ", profile = " << *(volumep->mProfilep); - s << "}"; - return s; -} - -LLVolumeFace::LLVolumeFace() : - mID(0), - mTypeMask(0), - mBeginS(0), - mBeginT(0), - mNumS(0), - mNumT(0), - mNumVertices(0), - mNumIndices(0), - mPositions(NULL), - mNormals(NULL), - mBinormals(NULL), - mTexCoords(NULL), - mIndices(NULL), - mWeights(NULL), - mOctree(NULL) -{ - mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3); - mCenter = mExtents+2; -} - -LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) -: mID(0), - mTypeMask(0), - mBeginS(0), - mBeginT(0), - mNumS(0), - mNumT(0), - mNumVertices(0), - mNumIndices(0), - mPositions(NULL), - mNormals(NULL), - mBinormals(NULL), - mTexCoords(NULL), - mIndices(NULL), - mWeights(NULL), - mOctree(NULL) -{ - mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3); - mCenter = mExtents+2; - *this = src; -} - -LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) -{ - if (&src == this) - { //self assignment, do nothing - return *this; - } - - mID = src.mID; - mTypeMask = src.mTypeMask; - mBeginS = src.mBeginS; - mBeginT = src.mBeginT; - mNumS = src.mNumS; - mNumT = src.mNumT; - - mExtents[0] = src.mExtents[0]; - mExtents[1] = src.mExtents[1]; - *mCenter = *src.mCenter; - - mNumVertices = 0; - mNumIndices = 0; - - freeData(); - - LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a)); - - resizeVertices(src.mNumVertices); - resizeIndices(src.mNumIndices); - - if (mNumVertices) - { - S32 vert_size = mNumVertices*sizeof(LLVector4a); - S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF; - - LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size); - LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size); - LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size); - - - if (src.mBinormals) - { - allocateBinormals(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size); - } - else - { - free(mBinormals); - mBinormals = NULL; - } - - if (src.mWeights) - { - allocateWeights(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); - } - else - { - free(mWeights); - mWeights = NULL; - } - } - - if (mNumIndices) - { - S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF; - - LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); - } - - //delete - return *this; -} - -LLVolumeFace::~LLVolumeFace() -{ - free(mExtents); - mExtents = NULL; - - freeData(); -} - -void LLVolumeFace::freeData() -{ - free(mPositions); - mPositions = NULL; - free( mNormals); - mNormals = NULL; - free(mTexCoords); - mTexCoords = NULL; - free(mIndices); - mIndices = NULL; - free(mBinormals); - mBinormals = NULL; - free(mWeights); - mWeights = NULL; - - delete mOctree; - mOctree = NULL; -} - -BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) -{ - //tree for this face is no longer valid - delete mOctree; - mOctree = NULL; - - if (mTypeMask & CAP_MASK) - { - return createCap(volume, partial_build); - } - else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) - { - return createSide(volume, partial_build); - } - else - { - llerrs << "Unknown/uninitialized face type!" << llendl; - return FALSE; - } -} - -void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv) -{ - cv.setPosition(mPositions[index]); - cv.setNormal(mNormals[index]); - cv.mTexCoord = mTexCoords[index]; -} - -bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const -{ - return getPosition().equals3(rhs.getPosition()) && - mTexCoord == rhs.mTexCoord && - getNormal().equals3(rhs.getNormal()); -} - -bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a, const LLVector3& b) const -{ - if (a.mV[0] != b.mV[0]) - { - return a.mV[0] < b.mV[0]; - } - - if (a.mV[1] != b.mV[1]) - { - return a.mV[1] < b.mV[1]; - } - - return a.mV[2] < b.mV[2]; -} - -void LLVolumeFace::optimize(F32 angle_cutoff) -{ - LLVolumeFace new_face; - - //map of points to vector of vertices at that point - VertexMapData::PointMap point_map; - - //remove redundant vertices - for (U32 i = 0; i < mNumIndices; ++i) - { - U16 index = mIndices[i]; - - LLVolumeFace::VertexData cv; - getVertexData(index, cv); - - BOOL found = FALSE; - VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr())); - if (point_iter != point_map.end()) - { //duplicate point might exist - for (U32 j = 0; j < point_iter->second.size(); ++j) - { - LLVolumeFace::VertexData& tv = (point_iter->second)[j]; - if (tv.compareNormal(cv, angle_cutoff)) - { - found = TRUE; - new_face.pushIndex((point_iter->second)[j].mIndex); - break; - } - } - } - - if (!found) - { - new_face.pushVertex(cv); - U16 index = (U16) new_face.mNumVertices-1; - new_face.pushIndex(index); - - VertexMapData d; - d.setPosition(cv.getPosition()); - d.mTexCoord = cv.mTexCoord; - d.setNormal(cv.getNormal()); - d.mIndex = index; - if (point_iter != point_map.end()) - { - point_iter->second.push_back(d); - } - else - { - point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d); - } - } - } - - swapData(new_face); -} - -class LLVCacheTriangleData; - -class LLVCacheVertexData -{ -public: - S32 mIdx; - S32 mCacheTag; - F32 mScore; - U32 mActiveTriangles; - std::vector<LLVCacheTriangleData*> mTriangles; - - LLVCacheVertexData() - { - mCacheTag = -1; - mScore = 0.f; - mActiveTriangles = 0; - mIdx = -1; - } -}; - -class LLVCacheTriangleData -{ -public: - bool mActive; - F32 mScore; - LLVCacheVertexData* mVertex[3]; - - LLVCacheTriangleData() - { - mActive = true; - mScore = 0.f; - mVertex[0] = mVertex[1] = mVertex[2] = NULL; - } - - void complete() - { - mActive = false; - for (S32 i = 0; i < 3; ++i) - { - if (mVertex[i]) - { - llassert_always(mVertex[i]->mActiveTriangles > 0); - mVertex[i]->mActiveTriangles--; - } - } - } - - bool operator<(const LLVCacheTriangleData& rhs) const - { //highest score first - return rhs.mScore < mScore; - } -}; - -const F32 FindVertexScore_CacheDecayPower = 1.5f; -const F32 FindVertexScore_LastTriScore = 0.75f; -const F32 FindVertexScore_ValenceBoostScale = 2.0f; -const F32 FindVertexScore_ValenceBoostPower = 0.5f; -const U32 MaxSizeVertexCache = 32; - -F32 find_vertex_score(LLVCacheVertexData& data) -{ - if (data.mActiveTriangles == 0) - { //no triangle references this vertex - return -1.f; - } - - F32 score = 0.f; - - S32 cache_idx = data.mCacheTag; - - if (cache_idx < 0) - { - //not in cache - } - else - { - if (cache_idx < 3) - { //vertex was in the last triangle - score = FindVertexScore_LastTriScore; - } - else - { //more points for being higher in the cache - F32 scaler = 1.f/(MaxSizeVertexCache-3); - score = 1.f-((cache_idx-3)*scaler); - score = powf(score, FindVertexScore_CacheDecayPower); - } - } - - //bonus points for having low valence - F32 valence_boost = powf(data.mActiveTriangles, -FindVertexScore_ValenceBoostPower); - score += FindVertexScore_ValenceBoostScale * valence_boost; - - return score; -} - -class LLVCacheFIFO -{ -public: - LLVCacheVertexData* mCache[MaxSizeVertexCache]; - U32 mMisses; - - LLVCacheFIFO() - { - mMisses = 0; - for (U32 i = 0; i < MaxSizeVertexCache; ++i) - { - mCache[i] = NULL; - } - } - - void addVertex(LLVCacheVertexData* data) - { - if (data->mCacheTag == -1) - { - mMisses++; - - S32 end = MaxSizeVertexCache-1; - - if (mCache[end]) - { - mCache[end]->mCacheTag = -1; - } - - for (S32 i = end; i > 0; --i) - { - mCache[i] = mCache[i-1]; - if (mCache[i]) - { - mCache[i]->mCacheTag = i; - } - } - - mCache[0] = data; - data->mCacheTag = 0; - } - } -}; - -class LLVCacheLRU -{ -public: - LLVCacheVertexData* mCache[MaxSizeVertexCache+3]; - - LLVCacheTriangleData* mBestTriangle; - - U32 mMisses; - - LLVCacheLRU() - { - for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) - { - mCache[i] = NULL; - } - - mBestTriangle = NULL; - mMisses = 0; - } - - void addVertex(LLVCacheVertexData* data) - { - S32 end = MaxSizeVertexCache+2; - if (data->mCacheTag != -1) - { //just moving a vertex to the front of the cache - end = data->mCacheTag; - } - else - { - mMisses++; - if (mCache[end]) - { //adding a new vertex, vertex at end of cache falls off - mCache[end]->mCacheTag = -1; - } - } - - for (S32 i = end; i > 0; --i) - { //adjust cache pointers and tags - mCache[i] = mCache[i-1]; - - if (mCache[i]) - { - mCache[i]->mCacheTag = i; - } - } - - mCache[0] = data; - mCache[0]->mCacheTag = 0; - } - - void addTriangle(LLVCacheTriangleData* data) - { - addVertex(data->mVertex[0]); - addVertex(data->mVertex[1]); - addVertex(data->mVertex[2]); - } - - void updateScores() - { - for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) - { //trailing 3 vertices aren't actually in the cache for scoring purposes - if (mCache[i]) - { - mCache[i]->mCacheTag = -1; - } - } - - for (U32 i = 0; i < MaxSizeVertexCache; ++i) - { //update scores of vertices in cache - if (mCache[i]) - { - mCache[i]->mScore = find_vertex_score(*(mCache[i])); - llassert_always(mCache[i]->mCacheTag == i); - } - } - - mBestTriangle = NULL; - //update triangle scores - for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) - { - if (mCache[i]) - { - for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j) - { - LLVCacheTriangleData* tri = mCache[i]->mTriangles[j]; - if (tri->mActive) - { - tri->mScore = tri->mVertex[0]->mScore; - tri->mScore += tri->mVertex[1]->mScore; - tri->mScore += tri->mVertex[2]->mScore; - - if (!mBestTriangle || mBestTriangle->mScore < tri->mScore) - { - mBestTriangle = tri; - } - } - } - } - } - - //knock trailing 3 vertices off the cache - for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) - { - if (mCache[i]) - { - llassert_always(mCache[i]->mCacheTag == -1); - mCache[i] = NULL; - } - } - } -}; - - -void LLVolumeFace::cacheOptimize() -{ //optimize for vertex cache according to Forsyth method: - // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html - - LLVCacheLRU cache; - - //mapping of vertices to triangles and indices - std::vector<LLVCacheVertexData> vertex_data; - - //mapping of triangles do vertices - std::vector<LLVCacheTriangleData> triangle_data; - - triangle_data.resize(mNumIndices/3); - vertex_data.resize(mNumVertices); - - for (U32 i = 0; i < mNumIndices; i++) - { //populate vertex data and triangle data arrays - U16 idx = mIndices[i]; - U32 tri_idx = i/3; - - vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx])); - vertex_data[idx].mIdx = idx; - triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]); - } - - /*F32 pre_acmr = 1.f; - //measure cache misses from before rebuild - { - LLVCacheFIFO test_cache; - for (U32 i = 0; i < mNumIndices; ++i) - { - test_cache.addVertex(&vertex_data[mIndices[i]]); - } - - for (U32 i = 0; i < mNumVertices; i++) - { - vertex_data[i].mCacheTag = -1; - } - - pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3); - }*/ - - for (U32 i = 0; i < mNumVertices; i++) - { //initialize score values (no cache -- might try a fifo cache here) - vertex_data[i].mScore = find_vertex_score(vertex_data[i]); - vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size(); - - for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j) - { - vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore; - } - } - - //sort triangle data by score - std::sort(triangle_data.begin(), triangle_data.end()); - - std::vector<U16> new_indices; - - LLVCacheTriangleData* tri; - - //prime pump by adding first triangle to cache; - tri = &(triangle_data[0]); - cache.addTriangle(tri); - new_indices.push_back(tri->mVertex[0]->mIdx); - new_indices.push_back(tri->mVertex[1]->mIdx); - new_indices.push_back(tri->mVertex[2]->mIdx); - tri->complete(); - - U32 breaks = 0; - for (U32 i = 1; i < mNumIndices/3; ++i) - { - cache.updateScores(); - tri = cache.mBestTriangle; - if (!tri) - { - breaks++; - for (U32 j = 0; j < triangle_data.size(); ++j) - { - if (triangle_data[j].mActive) - { - tri = &(triangle_data[j]); - break; - } - } - } - - cache.addTriangle(tri); - new_indices.push_back(tri->mVertex[0]->mIdx); - new_indices.push_back(tri->mVertex[1]->mIdx); - new_indices.push_back(tri->mVertex[2]->mIdx); - tri->complete(); - } - - for (U32 i = 0; i < mNumIndices; ++i) - { - mIndices[i] = new_indices[i]; - } - - /*F32 post_acmr = 1.f; - //measure cache misses from after rebuild - { - LLVCacheFIFO test_cache; - for (U32 i = 0; i < mNumVertices; i++) - { - vertex_data[i].mCacheTag = -1; - } - - for (U32 i = 0; i < mNumIndices; ++i) - { - test_cache.addVertex(&vertex_data[mIndices[i]]); - } - - post_acmr = (F32) test_cache.mMisses/(mNumIndices/3); - }*/ - - //optimize for pre-TnL cache - - //allocate space for new buffer - S32 num_verts = mNumVertices; - LLVector4a* pos = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - LLVector4a* norm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; - LLVector2* tc = (LLVector2*) malloc(size); - - LLVector4a* wght = NULL; - if (mWeights) - { - wght = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - } - - LLVector4a* binorm = NULL; - if (mBinormals) - { - binorm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - } - - //allocate mapping of old indices to new indices - std::vector<S32> new_idx; - new_idx.resize(mNumVertices, -1); - - S32 cur_idx = 0; - for (U32 i = 0; i < mNumIndices; ++i) - { - U16 idx = mIndices[i]; - if (new_idx[idx] == -1) - { //this vertex hasn't been added yet - new_idx[idx] = cur_idx; - - //copy vertex data - pos[cur_idx] = mPositions[idx]; - norm[cur_idx] = mNormals[idx]; - tc[cur_idx] = mTexCoords[idx]; - if (mWeights) - { - wght[cur_idx] = mWeights[idx]; - } - if (mBinormals) - { - binorm[cur_idx] = mBinormals[idx]; - } - - cur_idx++; - } - } - - for (U32 i = 0; i < mNumIndices; ++i) - { - mIndices[i] = new_idx[mIndices[i]]; - } - - free(mPositions); - free(mNormals); - free(mTexCoords); - free(mWeights); - free(mBinormals); - - mPositions = pos; - mNormals = norm; - mTexCoords = tc; - mWeights = wght; - mBinormals = binorm; - - //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks); - //llinfos << result << llendl; - -} - -void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size) -{ - if (mOctree) - { - return; - } - - mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL); - new LLVolumeOctreeListener(mOctree); - - for (U32 i = 0; i < mNumIndices; i+= 3) - { //for each triangle - LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle(); - - const LLVector4a& v0 = mPositions[mIndices[i]]; - const LLVector4a& v1 = mPositions[mIndices[i+1]]; - const LLVector4a& v2 = mPositions[mIndices[i+2]]; - - //store pointers to vertex data - tri->mV[0] = &v0; - tri->mV[1] = &v1; - tri->mV[2] = &v2; - - //store indices - tri->mIndex[0] = mIndices[i]; - tri->mIndex[1] = mIndices[i+1]; - tri->mIndex[2] = mIndices[i+2]; - - //get minimum point - LLVector4a min = v0; - min.setMin(min, v1); - min.setMin(min, v2); - - //get maximum point - LLVector4a max = v0; - max.setMax(max, v1); - max.setMax(max, v2); - - //compute center - LLVector4a center; - center.setAdd(min, max); - center.mul(0.5f); - - tri->mPositionGroup = center; - - //compute "radius" - LLVector4a size; - size.setSub(max,min); - - tri->mRadius = size.getLength3().getF32() * scaler; - - //insert - mOctree->insert(tri); - } - - //remove unneeded octree layers - while (!mOctree->balance()) { } - - //calculate AABB for each node - LLVolumeOctreeRebound rebound(this); - rebound.traverse(mOctree); - - if (gDebugGL) - { - LLVolumeOctreeValidate validate; - validate.traverse(mOctree); - } -} - - -void LLVolumeFace::swapData(LLVolumeFace& rhs) -{ - llswap(rhs.mPositions, mPositions); - llswap(rhs.mNormals, mNormals); - llswap(rhs.mBinormals, mBinormals); - llswap(rhs.mTexCoords, mTexCoords); - llswap(rhs.mIndices,mIndices); - llswap(rhs.mNumVertices, mNumVertices); - llswap(rhs.mNumIndices, mNumIndices); -} - -void LerpPlanarVertex(LLVolumeFace::VertexData& v0, - LLVolumeFace::VertexData& v1, - LLVolumeFace::VertexData& v2, - LLVolumeFace::VertexData& vout, - F32 coef01, - F32 coef02) -{ - - LLVector4a lhs; - lhs.setSub(v1.getPosition(), v0.getPosition()); - lhs.mul(coef01); - LLVector4a rhs; - rhs.setSub(v2.getPosition(), v0.getPosition()); - rhs.mul(coef02); - - rhs.add(lhs); - rhs.add(v0.getPosition()); - - vout.setPosition(rhs); - - vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02); - vout.setNormal(v0.getNormal()); -} - -BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - const std::vector<LLVolume::Point>& mesh = volume->getMesh(); - const std::vector<LLVector3>& profile = volume->getProfile().mProfile; - S32 max_s = volume->getProfile().getTotal(); - S32 max_t = volume->getPath().mPath.size(); - - // S32 i; - S32 num_vertices = 0, num_indices = 0; - S32 grid_size = (profile.size()-1)/4; - S32 quad_count = (grid_size * grid_size); - - num_vertices = (grid_size+1)*(grid_size+1); - num_indices = quad_count * 4; - - LLVector4a& min = mExtents[0]; - LLVector4a& max = mExtents[1]; - - S32 offset = 0; - if (mTypeMask & TOP_MASK) - { - offset = (max_t-1) * max_s; - } - else - { - offset = mBeginS; - } - - { - VertexData corners[4]; - VertexData baseVert; - for(S32 t = 0; t < 4; t++) - { - corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV); - corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f; - corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1]; - } - - { - LLVector4a lhs; - lhs.setSub(corners[1].getPosition(), corners[0].getPosition()); - LLVector4a rhs; - rhs.setSub(corners[2].getPosition(), corners[1].getPosition()); - baseVert.getNormal().setCross3(lhs, rhs); - baseVert.getNormal().normalize3fast(); - } - - if(!(mTypeMask & TOP_MASK)) - { - baseVert.getNormal().mul(-1.0f); - } - else - { - //Swap the UVs on the U(X) axis for top face - LLVector2 swap; - swap = corners[0].mTexCoord; - corners[0].mTexCoord=corners[3].mTexCoord; - corners[3].mTexCoord=swap; - swap = corners[1].mTexCoord; - corners[1].mTexCoord=corners[2].mTexCoord; - corners[2].mTexCoord=swap; - } - - LLVector4a binormal; - - calc_binormal_from_triangle( binormal, - corners[0].getPosition(), corners[0].mTexCoord, - corners[1].getPosition(), corners[1].mTexCoord, - corners[2].getPosition(), corners[2].mTexCoord); - - binormal.normalize3fast(); - - S32 size = (grid_size+1)*(grid_size+1); - resizeVertices(size); - allocateBinormals(size); - - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; - LLVector4a* binorm = (LLVector4a*) mBinormals; - LLVector2* tc = (LLVector2*) mTexCoords; - - for(int gx = 0;gx<grid_size+1;gx++) - { - for(int gy = 0;gy<grid_size+1;gy++) - { - VertexData newVert; - LerpPlanarVertex( - corners[0], - corners[1], - corners[3], - newVert, - (F32)gx/(F32)grid_size, - (F32)gy/(F32)grid_size); - - *pos++ = newVert.getPosition(); - *norm++ = baseVert.getNormal(); - *tc++ = newVert.mTexCoord; - *binorm++ = binormal; - - if (gx == 0 && gy == 0) - { - min = newVert.getPosition(); - max = min; - } - else - { - min.setMin(min, newVert.getPosition()); - max.setMax(max, newVert.getPosition()); - } - } - } - - mCenter->setAdd(min, max); - mCenter->mul(0.5f); - } - - if (!partial_build) - { - resizeIndices(grid_size*grid_size*6); - - U16* out = mIndices; - - S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; - for(S32 gx = 0;gx<grid_size;gx++) - { - - for(S32 gy = 0;gy<grid_size;gy++) - { - if (mTypeMask & TOP_MASK) - { - for(S32 i=5;i>=0;i--) - { - *out++ = ((gy*(grid_size+1))+gx+idxs[i]); - } - } - else - { - for(S32 i=0;i<6;i++) - { - *out++ = ((gy*(grid_size+1))+gx+idxs[i]); - } - } - } - } - } - - return TRUE; -} - - -BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if (!(mTypeMask & HOLLOW_MASK) && - !(mTypeMask & OPEN_MASK) && - ((volume->getParams().getPathParams().getBegin()==0.0f)&& - (volume->getParams().getPathParams().getEnd()==1.0f))&& - (volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE && - volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE) - ){ - return createUnCutCubeCap(volume, partial_build); - } - - S32 num_vertices = 0, num_indices = 0; - - const std::vector<LLVolume::Point>& mesh = volume->getMesh(); - const std::vector<LLVector3>& profile = volume->getProfile().mProfile; - - // All types of caps have the same number of vertices and indices - num_vertices = profile.size(); - num_indices = (profile.size() - 2)*3; - - if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) - { - resizeVertices(num_vertices+1); - allocateBinormals(num_vertices+1); - - if (!partial_build) - { - resizeIndices(num_indices+3); - } - } - else - { - resizeVertices(num_vertices); - allocateBinormals(num_vertices); - - if (!partial_build) - { - resizeIndices(num_indices); - } - } - - S32 max_s = volume->getProfile().getTotal(); - S32 max_t = volume->getPath().mPath.size(); - - mCenter->clear(); - - S32 offset = 0; - if (mTypeMask & TOP_MASK) - { - offset = (max_t-1) * max_s; - } - else - { - offset = mBeginS; - } - - // Figure out the normal, assume all caps are flat faces. - // Cross product to get normals. - - LLVector2 cuv; - LLVector2 min_uv, max_uv; - - LLVector4a& min = mExtents[0]; - LLVector4a& max = mExtents[1]; - - LLVector2* tc = (LLVector2*) mTexCoords; - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; - LLVector4a* binorm = (LLVector4a*) mBinormals; - - // Copy the vertices into the array - for (S32 i = 0; i < num_vertices; i++) - { - if (mTypeMask & TOP_MASK) - { - tc[i].mV[0] = profile[i].mV[0]+0.5f; - tc[i].mV[1] = profile[i].mV[1]+0.5f; - } - else - { - // Mirror for underside. - tc[i].mV[0] = profile[i].mV[0]+0.5f; - tc[i].mV[1] = 0.5f - profile[i].mV[1]; - } - - pos[i].load3(mesh[i + offset].mPos.mV); - - if (i == 0) - { - max = pos[i]; - min = max; - min_uv = max_uv = tc[i]; - } - else - { - update_min_max(min,max,pos[i]); - update_min_max(min_uv, max_uv, tc[i]); - } - } - - mCenter->setAdd(min, max); - mCenter->mul(0.5f); - - cuv = (min_uv + max_uv)*0.5f; - - LLVector4a binormal; - calc_binormal_from_triangle(binormal, - *mCenter, cuv, - pos[0], tc[0], - pos[1], tc[1]); - binormal.normalize3fast(); - - LLVector4a normal; - LLVector4a d0, d1; - - - d0.setSub(*mCenter, pos[0]); - d1.setSub(*mCenter, pos[1]); - - if (mTypeMask & TOP_MASK) - { - normal.setCross3(d0, d1); - } - else - { - normal.setCross3(d1, d0); - } - - normal.normalize3fast(); - - VertexData vd; - vd.setPosition(*mCenter); - vd.mTexCoord = cuv; - - if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) - { - pos[num_vertices] = *mCenter; - tc[num_vertices] = cuv; - num_vertices++; - } - - for (S32 i = 0; i < num_vertices; i++) - { - binorm[i].load4a(binormal.getF32ptr()); - norm[i].load4a(normal.getF32ptr()); - } - - if (partial_build) - { - return TRUE; - } - - if (mTypeMask & HOLLOW_MASK) - { - if (mTypeMask & TOP_MASK) - { - // HOLLOW TOP - // Does it matter if it's open or closed? - djs - - S32 pt1 = 0, pt2 = num_vertices - 1; - S32 i = 0; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = profile[pt1]; - LLVector3 p2 = profile[pt2]; - LLVector3 pa = profile[pt1+1]; - LLVector3 pb = profile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - mIndices[i++] = pt1; - mIndices[i++] = pt1 + 1; - mIndices[i++] = pt2; - pt1++; - } - else - { - mIndices[i++] = pt1; - mIndices[i++] = pt2 - 1; - mIndices[i++] = pt2; - pt2--; - } - } - } - else - { - // HOLLOW BOTTOM - // Does it matter if it's open or closed? - djs - - llassert(mTypeMask & BOTTOM_MASK); - S32 pt1 = 0, pt2 = num_vertices - 1; - - S32 i = 0; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = profile[pt1]; - LLVector3 p2 = profile[pt2]; - LLVector3 pa = profile[pt1+1]; - LLVector3 pb = profile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - // Flipped backfacing from top - if (use_tri1a2) - { - mIndices[i++] = pt1; - mIndices[i++] = pt2; - mIndices[i++] = pt1 + 1; - pt1++; - } - else - { - mIndices[i++] = pt1; - mIndices[i++] = pt2; - mIndices[i++] = pt2 - 1; - pt2--; - } - } - } - } - else - { - // Not hollow, generate the triangle fan. - U16 v1 = 2; - U16 v2 = 1; - - if (mTypeMask & TOP_MASK) - { - v1 = 1; - v2 = 2; - } - - for (S32 i = 0; i < (num_vertices - 2); i++) - { - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+v1] = i; - mIndices[3*i+v2] = i + 1; - } - - - } - - return TRUE; -} - -void LLVolumeFace::createBinormals() -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - if (!mBinormals) - { - allocateBinormals(mNumVertices); - - //generate binormals - LLVector4a* pos = mPositions; - LLVector2* tc = (LLVector2*) mTexCoords; - LLVector4a* binorm = (LLVector4a*) mBinormals; - - LLVector4a* end = mBinormals+mNumVertices; - while (binorm < end) - { - (*binorm++).clear(); - } - - binorm = mBinormals; - - for (U32 i = 0; i < mNumIndices/3; i++) - { //for each triangle - const U16& i0 = mIndices[i*3+0]; - const U16& i1 = mIndices[i*3+1]; - const U16& i2 = mIndices[i*3+2]; - - //calculate binormal - LLVector4a binormal; - calc_binormal_from_triangle(binormal, - pos[i0], tc[i0], - pos[i1], tc[i1], - pos[i2], tc[i2]); - - - //add triangle normal to vertices - binorm[i0].add(binormal); - binorm[i1].add(binormal); - binorm[i2].add(binormal); - - //even out quad contributions - if (i % 2 == 0) - { - binorm[i2].add(binormal); - } - else - { - binorm[i1].add(binormal); - } - } - - //normalize binormals - for (U32 i = 0; i < mNumVertices; i++) - { - binorm[i].normalize3fast(); - //bump map/planar projection code requires normals to be normalized - mNormals[i].normalize3fast(); - } - } -} - -void LLVolumeFace::resizeVertices(S32 num_verts) -{ - free(mPositions); - free(mNormals); - free(mBinormals); - free(mTexCoords); - - mBinormals = NULL; - - if (num_verts) - { - mPositions = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - assert_aligned(mPositions, 16); - mNormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); - assert_aligned(mNormals, 16); - - //pad texture coordinate block end to allow for QWORD reads - S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; - mTexCoords = (LLVector2*) malloc(size); - assert_aligned(mTexCoords, 16); - } - else - { - mPositions = NULL; - mNormals = NULL; - mTexCoords = NULL; - } - - mNumVertices = num_verts; -} - -void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv) -{ - pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord); -} - -void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc) -{ - S32 new_verts = mNumVertices+1; - S32 new_size = new_verts*16; -// S32 old_size = mNumVertices*16; - - //positions - mPositions = (LLVector4a*) realloc(mPositions, new_size); - - //normals - mNormals = (LLVector4a*) realloc(mNormals, new_size); - - //tex coords - new_size = ((new_verts*8)+0xF) & ~0xF; - mTexCoords = (LLVector2*) realloc(mTexCoords, new_size); - - - //just clear binormals - free(mBinormals); - mBinormals = NULL; - - mPositions[mNumVertices] = pos; - mNormals[mNumVertices] = norm; - mTexCoords[mNumVertices] = tc; - - mNumVertices++; -} - -void LLVolumeFace::allocateBinormals(S32 num_verts) -{ - free(mBinormals); - mBinormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); -} - -void LLVolumeFace::allocateWeights(S32 num_verts) -{ - free(mWeights); - mWeights = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts); -} - -void LLVolumeFace::resizeIndices(S32 num_indices) -{ - free(mIndices); - - if (num_indices) - { - //pad index block end to allow for QWORD reads - S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF; - - mIndices = (U16*) malloc(size); - } - else - { - mIndices = NULL; - } - - mNumIndices = num_indices; -} - -void LLVolumeFace::pushIndex(const U16& idx) -{ - S32 new_count = mNumIndices + 1; - S32 new_size = ((new_count*2)+0xF) & ~0xF; - - S32 old_size = ((mNumIndices*2)+0xF) & ~0xF; - if (new_size != old_size) - { - mIndices = (U16*) realloc(mIndices, new_size); - } - - mIndices[mNumIndices++] = idx; -} - -void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx) -{ - resizeVertices(v.size()); - resizeIndices(idx.size()); - - for (U32 i = 0; i < v.size(); ++i) - { - mPositions[i] = v[i].getPosition(); - mNormals[i] = v[i].getNormal(); - mTexCoords[i] = v[i].mTexCoord; - } - - for (U32 i = 0; i < idx.size(); ++i) - { - mIndices[i] = idx[i]; - } -} - -void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in) -{ - U16 offset = mNumVertices; - - S32 new_count = face.mNumVertices + mNumVertices; - - if (new_count > 65536) - { - llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl; - } - - if (face.mNumVertices == 0) - { - llerrs << "Cannot append empty face." << llendl; - } - - //allocate new buffer space - mPositions = (LLVector4a*) realloc(mPositions, new_count*sizeof(LLVector4a)); - assert_aligned(mPositions, 16); - mNormals = (LLVector4a*) realloc(mNormals, new_count*sizeof(LLVector4a)); - assert_aligned(mNormals, 16); - mTexCoords = (LLVector2*) realloc(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF); - assert_aligned(mTexCoords, 16); - - mNumVertices = new_count; - - //get destination address of appended face - LLVector4a* dst_pos = mPositions+offset; - LLVector2* dst_tc = mTexCoords+offset; - LLVector4a* dst_norm = mNormals+offset; - - //get source addresses of appended face - const LLVector4a* src_pos = face.mPositions; - const LLVector2* src_tc = face.mTexCoords; - const LLVector4a* src_norm = face.mNormals; - - //load aligned matrices - LLMatrix4a mat, norm_mat; - mat.loadu(mat_in); - norm_mat.loadu(norm_mat_in); - - for (U32 i = 0; i < face.mNumVertices; ++i) - { - //transform appended face position and store - mat.affineTransform(src_pos[i], dst_pos[i]); - - //transform appended face normal and store - norm_mat.rotate(src_norm[i], dst_norm[i]); - dst_norm[i].normalize3fast(); - - //copy appended face texture coordinate - dst_tc[i] = src_tc[i]; - - if (offset == 0 && i == 0) - { //initialize bounding box - mExtents[0] = mExtents[1] = dst_pos[i]; - } - else - { - //stretch bounding box - update_min_max(mExtents[0], mExtents[1], dst_pos[i]); - } - } - - - new_count = mNumIndices + face.mNumIndices; - - //allocate new index buffer - mIndices = (U16*) realloc(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF); - - //get destination address into new index buffer - U16* dst_idx = mIndices+mNumIndices; - mNumIndices = new_count; - - for (U32 i = 0; i < face.mNumIndices; ++i) - { //copy indices, offsetting by old vertex count - dst_idx[i] = face.mIndices[i]+offset; - } -} - -BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) -{ - LLMemType m1(LLMemType::MTYPE_VOLUME); - - BOOL flat = mTypeMask & FLAT_MASK; - - U8 sculpt_type = volume->getParams().getSculptType(); - U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - BOOL sculpt_reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR - - S32 num_vertices, num_indices; - - const std::vector<LLVolume::Point>& mesh = volume->getMesh(); - const std::vector<LLVector3>& profile = volume->getProfile().mProfile; - const std::vector<LLPath::PathPt>& path_data = volume->getPath().mPath; - - S32 max_s = volume->getProfile().getTotal(); - - S32 s, t, i; - F32 ss, tt; - - num_vertices = mNumS*mNumT; - num_indices = (mNumS-1)*(mNumT-1)*6; - - if (!partial_build) - { - resizeVertices(num_vertices); - resizeIndices(num_indices); - - if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) - { - mEdge.resize(num_indices); - } - } - - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; - LLVector2* tc = (LLVector2*) mTexCoords; - S32 begin_stex = llfloor( profile[mBeginS].mV[2] ); - S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; - - S32 cur_vertex = 0; - // Copy the vertices into the array - for (t = mBeginT; t < mBeginT + mNumT; t++) - { - tt = path_data[t].mTexT; - for (s = 0; s < num_s; s++) - { - if (mTypeMask & END_MASK) - { - if (s) - { - ss = 1.f; - } - else - { - ss = 0.f; - } - } - else - { - // Get s value for tex-coord. - if (!flat) - { - ss = profile[mBeginS + s].mV[2]; - } - else - { - ss = profile[mBeginS + s].mV[2] - begin_stex; - } - } - - if (sculpt_reverse_horizontal) - { - ss = 1.f - ss; - } - - // Check to see if this triangle wraps around the array. - if (mBeginS + s >= max_s) - { - // We're wrapping - i = mBeginS + s + max_s*(t-1); - } - else - { - i = mBeginS + s + max_s*t; - } - - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); - - norm[cur_vertex].clear(); - cur_vertex++; - - if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0) - { - - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); - - norm[cur_vertex].clear(); - - cur_vertex++; - } - } - - if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) - { - if (mTypeMask & OPEN_MASK) - { - s = num_s-1; - } - else - { - s = 0; - } - - i = mBeginS + s + max_s*t; - ss = profile[mBeginS + s].mV[2] - begin_stex; - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); - norm[cur_vertex].clear(); - - cur_vertex++; - } - } - - - //get bounding box for this side - LLVector4a& face_min = mExtents[0]; - LLVector4a& face_max = mExtents[1]; - mCenter->clear(); - - face_min = face_max = pos[0]; - - for (U32 i = 1; i < mNumVertices; ++i) - { - update_min_max(face_min, face_max, pos[i]); - } - - mCenter->setAdd(face_min, face_max); - mCenter->mul(0.5f); - - S32 cur_index = 0; - S32 cur_edge = 0; - BOOL flat_face = mTypeMask & FLAT_MASK; - - if (!partial_build) - { - // Now we generate the indices. - for (t = 0; t < (mNumT-1); t++) - { - for (s = 0; s < (mNumS-1); s++) - { - mIndices[cur_index++] = s + mNumS*t; //bottom left - mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right - mIndices[cur_index++] = s + mNumS*(t+1); //top left - mIndices[cur_index++] = s + mNumS*t; //bottom left - mIndices[cur_index++] = s+1 + mNumS*t; //bottom right - mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right - - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face - if (t < mNumT-2) { //top right/top left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; - } - else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor - mEdge[cur_edge++] = -1; - } - else { //wrap on T - mEdge[cur_edge++] = s*2+1; - } - if (s > 0) { //top left/bottom left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; - } - else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor - mEdge[cur_edge++] = -1; - } - else { //wrap on S - mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1; - } - - if (t > 0) { //bottom left/bottom right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; - } - else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor - mEdge[cur_edge++] = -1; - } - else { //wrap on T - mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2; - } - if (s < mNumS-2) { //bottom right/top right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; - } - else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor - mEdge[cur_edge++] = -1; - } - else { //wrap on S - mEdge[cur_edge++] = (mNumS-1)*2*t; - } - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face - } - } - } - - //clear normals - for (U32 i = 0; i < mNumVertices; i++) - { - mNormals[i].clear(); - } - - //generate normals - for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle - { - const U16* idx = &(mIndices[i*3]); - - - LLVector4a* v[] = - { pos+idx[0], pos+idx[1], pos+idx[2] }; - - LLVector4a* n[] = - { norm+idx[0], norm+idx[1], norm+idx[2] }; - - //calculate triangle normal - LLVector4a a, b, c; - - a.setSub(*v[0], *v[1]); - b.setSub(*v[0], *v[2]); - c.setCross3(a,b); - - n[0]->add(c); - n[1]->add(c); - n[2]->add(c); - - //even out quad contributions - n[i%2+1]->add(c); - } - - // adjust normals based on wrapping and stitching - - LLVector4a top; - top.setSub(pos[0], pos[mNumS*(mNumT-2)]); - BOOL s_bottom_converges = (top.dot3(top) < 0.000001f); - - top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]); - BOOL s_top_converges = (top.dot3(top) < 0.000001f); - - if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes - { - if (volume->getPath().isOpen() == FALSE) - { //wrap normals on T - for (S32 i = 0; i < mNumS; i++) - { - LLVector4a n; - n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); - norm[i] = n; - norm[mNumS*(mNumT-1)+i] = n; - } - } - - if ((volume->getProfile().isOpen() == FALSE) && !(s_bottom_converges)) - { //wrap normals on S - for (S32 i = 0; i < mNumT; i++) - { - LLVector4a n; - n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); - norm[mNumS * i] = n; - norm[mNumS * i+mNumS-1] = n; - } - } - - if (volume->getPathType() == LL_PCODE_PATH_CIRCLE && - ((volume->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) - { - if (s_bottom_converges) - { //all lower S have same normal - for (S32 i = 0; i < mNumT; i++) - { - norm[mNumS*i].set(1,0,0); - } - } - - if (s_top_converges) - { //all upper S have same normal - for (S32 i = 0; i < mNumT; i++) - { - norm[mNumS*i+mNumS-1].set(-1,0,0); - } - } - } - } - else // logic for sculpt volumes - { - BOOL average_poles = FALSE; - BOOL wrap_s = FALSE; - BOOL wrap_t = FALSE; - - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - average_poles = TRUE; - - if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || - (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || - (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) - wrap_s = TRUE; - - if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) - wrap_t = TRUE; - - - if (average_poles) - { - // average normals for north pole - - LLVector4a average; - average.clear(); - - for (S32 i = 0; i < mNumS; i++) - { - average.add(norm[i]); - } - - // set average - for (S32 i = 0; i < mNumS; i++) - { - norm[i] = average; - } - - // average normals for south pole - - average.clear(); - - for (S32 i = 0; i < mNumS; i++) - { - average.add(norm[i + mNumS * (mNumT - 1)]); - } - - // set average - for (S32 i = 0; i < mNumS; i++) - { - norm[i + mNumS * (mNumT - 1)] = average; - } - - } - - - if (wrap_s) - { - for (S32 i = 0; i < mNumT; i++) - { - LLVector4a n; - n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); - norm[mNumS * i] = n; - norm[mNumS * i+mNumS-1] = n; - } - } - - if (wrap_t) - { - for (S32 i = 0; i < mNumS; i++) - { - LLVector4a n; - n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); - norm[i] = n; - norm[mNumS*(mNumT-1)+i] = n; - } - } - - } - - return TRUE; -} - -// Finds binormal based on three vertices with texture coordinates. -// Fills in dummy values if the triangle has degenerate texture coordinates. -void calc_binormal_from_triangle(LLVector4a& binormal, - - const LLVector4a& pos0, - const LLVector2& tex0, - const LLVector4a& pos1, - const LLVector2& tex1, - const LLVector4a& pos2, - const LLVector2& tex2) -{ - LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a lhs, rhs; - - LLVector4a r0; - lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2); - r0.setCross3(lhs, rhs); - - LLVector4a r1; - lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2); - r1.setCross3(lhs, rhs); - - LLVector4a r2; - lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2); - r2.setCross3(lhs, rhs); - - if( r0[VX] && r1[VX] && r2[VX] ) - { - binormal.set( - -r0[VZ] / r0[VX], - -r1[VZ] / r1[VX], - -r2[VZ] / r2[VX]); - // binormal.normVec(); - } - else - { - binormal.set( 0, 1 , 0 ); - } -} diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 32ac5313067c07a85e2665e19619b639d1baa504..4a25f586da81cc2fd0d9d8643bb1f561acef25fb 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1,797 +1,797 @@ -/** - * @file llvolume.h - * @brief LLVolume base class. - * - * $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$ - */ - -#ifndef LL_LLVOLUME_H -#define LL_LLVOLUME_H - -#include <iostream> - -class LLProfileParams; -class LLPathParams; -class LLVolumeParams; -class LLProfile; -class LLPath; - -template <class T> class LLOctreeNode; - -class LLVector4a; -class LLVolumeFace; -class LLVolume; -class LLVolumeTriangle; - -#include "lldarray.h" -#include "lluuid.h" -#include "v4color.h" -//#include "vmath.h" -#include "v2math.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4math.h" -#include "llquaternion.h" -#include "llstrider.h" -#include "v4coloru.h" -#include "llrefcount.h" -#include "llfile.h" - -//============================================================================ - -const S32 MIN_DETAIL_FACES = 6; -const S32 MIN_LOD = 0; -const S32 MAX_LOD = 3; - -// These are defined here but are not enforced at this level, -// rather they are here for the convenience of code that uses -// the LLVolume class. -const F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; -const F32 MIN_VOLUME_PATH_WIDTH = 0.05f; - -const F32 CUT_QUANTA = 0.00002f; -const F32 SCALE_QUANTA = 0.01f; -const F32 SHEAR_QUANTA = 0.01f; -const F32 TAPER_QUANTA = 0.01f; -const F32 REV_QUANTA = 0.015f; -const F32 HOLLOW_QUANTA = 0.00002f; - -const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; - -//============================================================================ - -// useful masks -const LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness -const LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) -const LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) -const LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum -const LLPCode LL_PCODE_BASE_MASK = 0x0F; - - // primitive shapes -const LLPCode LL_PCODE_CUBE = 1; -const LLPCode LL_PCODE_PRISM = 2; -const LLPCode LL_PCODE_TETRAHEDRON = 3; -const LLPCode LL_PCODE_PYRAMID = 4; -const LLPCode LL_PCODE_CYLINDER = 5; -const LLPCode LL_PCODE_CONE = 6; -const LLPCode LL_PCODE_SPHERE = 7; -const LLPCode LL_PCODE_TORUS = 8; -const LLPCode LL_PCODE_VOLUME = 9; - - // surfaces -//const LLPCode LL_PCODE_SURFACE_TRIANGLE = 10; -//const LLPCode LL_PCODE_SURFACE_SQUARE = 11; -//const LLPCode LL_PCODE_SURFACE_DISC = 12; - -const LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) -const LLPCode LL_PCODE_LEGACY = 15; - -// Pcodes for legacy objects -//const LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR -const LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER -//const LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD -//const LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON -const LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS -const LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees -//const LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE -const LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS -const LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK -//const LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT -//const LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY; -//const LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE -//const LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK -const LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE -const LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE - - // hemis -const LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK; - - -// Volumes consist of a profile at the base that is swept around -// a path to make a volume. -// The profile code -const U8 LL_PCODE_PROFILE_MASK = 0x0f; -const U8 LL_PCODE_PROFILE_MIN = 0x00; -const U8 LL_PCODE_PROFILE_CIRCLE = 0x00; -const U8 LL_PCODE_PROFILE_SQUARE = 0x01; -const U8 LL_PCODE_PROFILE_ISOTRI = 0x02; -const U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; -const U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; -const U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; -const U8 LL_PCODE_PROFILE_MAX = 0x05; - -// Stored in the profile byte -const U8 LL_PCODE_HOLE_MASK = 0xf0; -const U8 LL_PCODE_HOLE_MIN = 0x00; -const U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile -const U8 LL_PCODE_HOLE_CIRCLE = 0x10; -const U8 LL_PCODE_HOLE_SQUARE = 0x20; -const U8 LL_PCODE_HOLE_TRIANGLE = 0x30; -const U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max - -const U8 LL_PCODE_PATH_IGNORE = 0x00; -const U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max -const U8 LL_PCODE_PATH_LINE = 0x10; -const U8 LL_PCODE_PATH_CIRCLE = 0x20; -const U8 LL_PCODE_PATH_CIRCLE2 = 0x30; -const U8 LL_PCODE_PATH_TEST = 0x40; -const U8 LL_PCODE_PATH_FLEXIBLE = 0x80; -const U8 LL_PCODE_PATH_MAX = 0x08; - -//============================================================================ - -// face identifiers -typedef U16 LLFaceID; - -const LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; -const LLFaceID LL_FACE_PATH_END = 0x1 << 1; -const LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; -const LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; -const LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; -const LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; -const LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; -const LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; -const LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; - -//============================================================================ - -// sculpt types + flags - -const U8 LL_SCULPT_TYPE_NONE = 0; -const U8 LL_SCULPT_TYPE_SPHERE = 1; -const U8 LL_SCULPT_TYPE_TORUS = 2; -const U8 LL_SCULPT_TYPE_PLANE = 3; -const U8 LL_SCULPT_TYPE_CYLINDER = 4; -const U8 LL_SCULPT_TYPE_MESH = 5; -const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | - LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; - -const U8 LL_SCULPT_FLAG_INVERT = 64; -const U8 LL_SCULPT_FLAG_MIRROR = 128; - -const S32 LL_SCULPT_MESH_MAX_FACES = 8; - -class LLProfileParams -{ -public: - LLProfileParams() - : mCurveType(LL_PCODE_PROFILE_SQUARE), - mBegin(0.f), - mEnd(1.f), - mHollow(0.f), - mCRC(0) - { - } - - LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow) - : mCurveType(curve), - mBegin(begin), - mEnd(end), - mHollow(hollow), - mCRC(0) - { - } - - LLProfileParams(U8 curve, U16 begin, U16 end, U16 hollow) - { - mCurveType = curve; - F32 temp_f32 = begin * CUT_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mBegin = temp_f32; - temp_f32 = end * CUT_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mEnd = 1.f - temp_f32; - temp_f32 = hollow * HOLLOW_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mHollow = temp_f32; - mCRC = 0; - } - - bool operator==(const LLProfileParams ¶ms) const; - bool operator!=(const LLProfileParams ¶ms) const; - bool operator<(const LLProfileParams ¶ms) const; - - void copyParams(const LLProfileParams ¶ms); - - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; - - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; - - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - - const F32& getBegin () const { return mBegin; } - const F32& getEnd () const { return mEnd; } - const F32& getHollow() const { return mHollow; } - const U8& getCurveType () const { return mCurveType; } - - void setCurveType(const U32 type) { mCurveType = type;} - void setBegin(const F32 begin) { mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 100000))/100000.0f;} - void setEnd(const F32 end) { mEnd = (end <= 0.0f) ? 1.0f : ((int) (end * 100000))/100000.0f;} - void setHollow(const F32 hollow) { mHollow = ((int) (hollow * 100000))/100000.0f;} - - friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params); - -protected: - // Profile params - U8 mCurveType; - F32 mBegin; - F32 mEnd; - F32 mHollow; - - U32 mCRC; -}; - -inline bool LLProfileParams::operator==(const LLProfileParams ¶ms) const -{ - return - (getCurveType() == params.getCurveType()) && - (getBegin() == params.getBegin()) && - (getEnd() == params.getEnd()) && - (getHollow() == params.getHollow()); -} - -inline bool LLProfileParams::operator!=(const LLProfileParams ¶ms) const -{ - return - (getCurveType() != params.getCurveType()) || - (getBegin() != params.getBegin()) || - (getEnd() != params.getEnd()) || - (getHollow() != params.getHollow()); -} - - -inline bool LLProfileParams::operator<(const LLProfileParams ¶ms) const -{ - if (getCurveType() != params.getCurveType()) - { - return getCurveType() < params.getCurveType(); - } - else - if (getBegin() != params.getBegin()) - { - return getBegin() < params.getBegin(); - } - else - if (getEnd() != params.getEnd()) - { - return getEnd() < params.getEnd(); - } - else - { - return getHollow() < params.getHollow(); - } -} - -#define U8_TO_F32(x) (F32)(*((S8 *)&x)) - -class LLPathParams -{ -public: - LLPathParams() - : - mCurveType(LL_PCODE_PATH_LINE), - mBegin(0.f), - mEnd(1.f), - mScale(1.f,1.f), - mShear(0.f,0.f), - mTwistBegin(0.f), - mTwistEnd(0.f), - mRadiusOffset(0.f), - mTaper(0.f,0.f), - mRevolutions(1.f), - mSkew(0.f), - mCRC(0) - { - } - - LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew) - : mCurveType(curve), - mBegin(begin), - mEnd(end), - mScale(scx,scy), - mShear(shx,shy), - mTwistBegin(twistbegin), - mTwistEnd(twistend), - mRadiusOffset(radiusoffset), - mTaper(tx,ty), - mRevolutions(revolutions), - mSkew(skew), - mCRC(0) - { - } - - LLPathParams(U8 curve, U16 begin, U16 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew) - { - mCurveType = curve; - mBegin = (F32)(begin * CUT_QUANTA); - mEnd = (F32)(100.f - end) * CUT_QUANTA; - if (mEnd > 1.f) - mEnd = 1.f; - mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA); - mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA); - mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA; - mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA; - mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA; - mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA); - mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f; - mSkew = U8_TO_F32(skew) * SCALE_QUANTA; - - mCRC = 0; - } - - bool operator==(const LLPathParams ¶ms) const; - bool operator!=(const LLPathParams ¶ms) const; - bool operator<(const LLPathParams ¶ms) const; - - void copyParams(const LLPathParams ¶ms); - - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; - - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; - - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - - const F32& getBegin() const { return mBegin; } - const F32& getEnd() const { return mEnd; } - const LLVector2 &getScale() const { return mScale; } - const F32& getScaleX() const { return mScale.mV[0]; } - const F32& getScaleY() const { return mScale.mV[1]; } - const LLVector2 getBeginScale() const; - const LLVector2 getEndScale() const; - const LLVector2 &getShear() const { return mShear; } - const F32& getShearX() const { return mShear.mV[0]; } - const F32& getShearY() const { return mShear.mV[1]; } - const U8& getCurveType () const { return mCurveType; } - - const F32& getTwistBegin() const { return mTwistBegin; } - const F32& getTwistEnd() const { return mTwistEnd; } - const F32& getTwist() const { return mTwistEnd; } // deprecated - const F32& getRadiusOffset() const { return mRadiusOffset; } - const LLVector2 &getTaper() const { return mTaper; } - const F32& getTaperX() const { return mTaper.mV[0]; } - const F32& getTaperY() const { return mTaper.mV[1]; } - const F32& getRevolutions() const { return mRevolutions; } - const F32& getSkew() const { return mSkew; } - - void setCurveType(const U8 type) { mCurveType = type; } - void setBegin(const F32 begin) { mBegin = begin; } - void setEnd(const F32 end) { mEnd = end; } - - void setScale(const F32 x, const F32 y) { mScale.setVec(x,y); } - void setScaleX(const F32 v) { mScale.mV[VX] = v; } - void setScaleY(const F32 v) { mScale.mV[VY] = v; } - void setShear(const F32 x, const F32 y) { mShear.setVec(x,y); } - void setShearX(const F32 v) { mShear.mV[VX] = v; } - void setShearY(const F32 v) { mShear.mV[VY] = v; } - - void setTwistBegin(const F32 twist_begin) { mTwistBegin = twist_begin; } - void setTwistEnd(const F32 twist_end) { mTwistEnd = twist_end; } - void setTwist(const F32 twist) { setTwistEnd(twist); } // deprecated - void setRadiusOffset(const F32 radius_offset){ mRadiusOffset = radius_offset; } - void setTaper(const F32 x, const F32 y) { mTaper.setVec(x,y); } - void setTaperX(const F32 v) { mTaper.mV[VX] = v; } - void setTaperY(const F32 v) { mTaper.mV[VY] = v; } - void setRevolutions(const F32 revolutions) { mRevolutions = revolutions; } - void setSkew(const F32 skew) { mSkew = skew; } - - friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params); - -protected: - // Path params - U8 mCurveType; - F32 mBegin; - F32 mEnd; - LLVector2 mScale; - LLVector2 mShear; - - F32 mTwistBegin; - F32 mTwistEnd; - F32 mRadiusOffset; - LLVector2 mTaper; - F32 mRevolutions; - F32 mSkew; - - U32 mCRC; -}; - -inline bool LLPathParams::operator==(const LLPathParams ¶ms) const -{ - return - (getCurveType() == params.getCurveType()) && - (getScale() == params.getScale()) && - (getBegin() == params.getBegin()) && - (getEnd() == params.getEnd()) && - (getShear() == params.getShear()) && - (getTwist() == params.getTwist()) && - (getTwistBegin() == params.getTwistBegin()) && - (getRadiusOffset() == params.getRadiusOffset()) && - (getTaper() == params.getTaper()) && - (getRevolutions() == params.getRevolutions()) && - (getSkew() == params.getSkew()); -} - -inline bool LLPathParams::operator!=(const LLPathParams ¶ms) const -{ - return - (getCurveType() != params.getCurveType()) || - (getScale() != params.getScale()) || - (getBegin() != params.getBegin()) || - (getEnd() != params.getEnd()) || - (getShear() != params.getShear()) || - (getTwist() != params.getTwist()) || - (getTwistBegin() !=params.getTwistBegin()) || - (getRadiusOffset() != params.getRadiusOffset()) || - (getTaper() != params.getTaper()) || - (getRevolutions() != params.getRevolutions()) || - (getSkew() != params.getSkew()); -} - - -inline bool LLPathParams::operator<(const LLPathParams ¶ms) const -{ - if( getCurveType() != params.getCurveType()) - { - return getCurveType() < params.getCurveType(); - } - else - if( getScale() != params.getScale()) - { - return getScale() < params.getScale(); - } - else - if( getBegin() != params.getBegin()) - { - return getBegin() < params.getBegin(); - } - else - if( getEnd() != params.getEnd()) - { - return getEnd() < params.getEnd(); - } - else - if( getShear() != params.getShear()) - { - return getShear() < params.getShear(); - } - else - if( getTwist() != params.getTwist()) - { - return getTwist() < params.getTwist(); - } - else - if( getTwistBegin() != params.getTwistBegin()) - { - return getTwistBegin() < params.getTwistBegin(); - } - else - if( getRadiusOffset() != params.getRadiusOffset()) - { - return getRadiusOffset() < params.getRadiusOffset(); - } - else - if( getTaper() != params.getTaper()) - { - return getTaper() < params.getTaper(); - } - else - if( getRevolutions() != params.getRevolutions()) - { - return getRevolutions() < params.getRevolutions(); - } - else - { - return getSkew() < params.getSkew(); - } -} - -typedef LLVolumeParams* LLVolumeParamsPtr; -typedef const LLVolumeParams* const_LLVolumeParamsPtr; - -class LLVolumeParams -{ -public: - LLVolumeParams() - : mSculptType(LL_SCULPT_TYPE_NONE) - { - } - - LLVolumeParams(LLProfileParams &profile, LLPathParams &path, - LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE) - : mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type) - { - } - - bool operator==(const LLVolumeParams ¶ms) const; - bool operator!=(const LLVolumeParams ¶ms) const; - bool operator<(const LLVolumeParams ¶ms) const; - - - void copyParams(const LLVolumeParams ¶ms); - - const LLProfileParams &getProfileParams() const {return mProfileParams;} - LLProfileParams &getProfileParams() {return mProfileParams;} - const LLPathParams &getPathParams() const {return mPathParams;} - LLPathParams &getPathParams() {return mPathParams;} - - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; - - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; - - LLSD sculptAsLLSD() const; - bool sculptFromLLSD(LLSD& sd); - - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - - bool setType(U8 profile, U8 path); - - //void setBeginS(const F32 beginS) { mProfileParams.setBegin(beginS); } // range 0 to 1 - //void setBeginT(const F32 beginT) { mPathParams.setBegin(beginT); } // range 0 to 1 - //void setEndS(const F32 endS) { mProfileParams.setEnd(endS); } // range 0 to 1, must be greater than begin - //void setEndT(const F32 endT) { mPathParams.setEnd(endT); } // range 0 to 1, must be greater than begin - - bool setBeginAndEndS(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end - bool setBeginAndEndT(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end - - bool setHollow(const F32 hollow); // range 0 to 1 - bool setRatio(const F32 x) { return setRatio(x,x); } // 0 = point, 1 = same as base - bool setShear(const F32 x) { return setShear(x,x); } // 0 = no movement, - bool setRatio(const F32 x, const F32 y); // 0 = point, 1 = same as base - bool setShear(const F32 x, const F32 y); // 0 = no movement - - bool setTwistBegin(const F32 twist_begin); // range -1 to 1 - bool setTwistEnd(const F32 twist_end); // range -1 to 1 - bool setTwist(const F32 twist) { return setTwistEnd(twist); } // deprecated - bool setTaper(const F32 x, const F32 y) { bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; } - bool setTaperX(const F32 v); // -1 to 1 - bool setTaperY(const F32 v); // -1 to 1 - bool setRevolutions(const F32 revolutions); // 1 to 4 - bool setRadiusOffset(const F32 radius_offset); - bool setSkew(const F32 skew); - bool setSculptID(const LLUUID sculpt_id, U8 sculpt_type); - - static bool 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); - - const F32& getBeginS() const { return mProfileParams.getBegin(); } - const F32& getBeginT() const { return mPathParams.getBegin(); } - const F32& getEndS() const { return mProfileParams.getEnd(); } - const F32& getEndT() const { return mPathParams.getEnd(); } - - const F32& getHollow() const { return mProfileParams.getHollow(); } - const F32& getTwist() const { return mPathParams.getTwist(); } - const F32& getRatio() const { return mPathParams.getScaleX(); } - const F32& getRatioX() const { return mPathParams.getScaleX(); } - const F32& getRatioY() const { return mPathParams.getScaleY(); } - const F32& getShearX() const { return mPathParams.getShearX(); } - const F32& getShearY() const { return mPathParams.getShearY(); } - - const F32& getTwistBegin()const { return mPathParams.getTwistBegin(); } - const F32& getRadiusOffset() const { return mPathParams.getRadiusOffset(); } - const F32& getTaper() const { return mPathParams.getTaperX(); } - const F32& getTaperX() const { return mPathParams.getTaperX(); } - const F32& getTaperY() const { return mPathParams.getTaperY(); } - const F32& getRevolutions() const { return mPathParams.getRevolutions(); } - const F32& getSkew() const { return mPathParams.getSkew(); } - const LLUUID& getSculptID() const { return mSculptID; } - const U8& getSculptType() const { return mSculptType; } - bool isSculpt() const; - bool isMeshSculpt() const; - BOOL isConvex() const; - - // 'begin' and 'end' should be in range [0, 1] (they will be clamped) - // (begin, end) = (0, 1) will not change the volume - // (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T) - void reduceS(F32 begin, F32 end); - void reduceT(F32 begin, F32 end); - - struct compare - { - bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const - { - return (*first < *second); - } - }; - - friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); - - // debug helper functions - void setCube(); - -protected: - LLProfileParams mProfileParams; - LLPathParams mPathParams; - LLUUID mSculptID; - U8 mSculptType; -}; - - -class LLProfile -{ -public: - LLProfile() - : mOpen(FALSE), - mConcave(FALSE), - mDirty(TRUE), - mTotalOut(0), - mTotal(2) - { - } - - ~LLProfile(); - - S32 getTotal() const { return mTotal; } - S32 getTotalOut() const { return mTotalOut; } // Total number of outside points - BOOL isFlat(S32 face) const { return (mFaces[face].mCount == 2); } - BOOL isOpen() const { return mOpen; } - void setDirty() { mDirty = TRUE; } - BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); - BOOL isConcave() const { return mConcave; } -public: - struct Face - { - S32 mIndex; - S32 mCount; - F32 mScaleU; - BOOL mCap; - BOOL mFlat; - LLFaceID mFaceID; - }; - - std::vector<LLVector3> mProfile; - std::vector<LLVector2> mNormals; - std::vector<Face> mFaces; - std::vector<LLVector3> mEdgeNormals; - std::vector<LLVector3> mEdgeCenters; - - friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile); - -protected: - void genNormals(const LLProfileParams& params); - void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); - - Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); - Face* addCap (S16 faceID); - Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, BOOL flat); - -protected: - BOOL mOpen; - BOOL mConcave; - BOOL mDirty; - - S32 mTotalOut; - S32 mTotal; -}; - -//------------------------------------------------------------------- -// SWEEP/EXTRUDE PATHS -//------------------------------------------------------------------- - -class LLPath -{ -public: - struct PathPt - { - LLVector3 mPos; - LLVector2 mScale; - LLQuaternion mRot; - F32 mTexT; - PathPt() { mPos.setVec(0,0,0); mTexT = 0; mScale.setVec(0,0); mRot.loadIdentity(); } - }; - -public: - LLPath() - : mOpen(FALSE), - mTotal(0), - mDirty(TRUE), - mStep(1) - { - } - - virtual ~LLPath(); - - void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); - virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); - - BOOL isOpen() const { return mOpen; } - F32 getStep() const { return mStep; } - void setDirty() { mDirty = TRUE; } - - S32 getPathLength() const { return (S32)mPath.size(); } - - void resizePath(S32 length) { mPath.resize(length); } - - friend std::ostream& operator<<(std::ostream &s, const LLPath &path); - -public: - std::vector<PathPt> mPath; - -protected: - BOOL mOpen; - S32 mTotal; - BOOL mDirty; - F32 mStep; -}; - -class LLDynamicPath : public LLPath -{ -public: - LLDynamicPath() : LLPath() { } - /*virtual*/ BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); -}; - -// Yet another "face" class - caches volume-specific, but not instance-specific data for faces) -class LLVolumeFace -{ -public: +/** + * @file llvolume.h + * @brief LLVolume base class. + * + * $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$ + */ + +#ifndef LL_LLVOLUME_H +#define LL_LLVOLUME_H + +#include <iostream> + +class LLProfileParams; +class LLPathParams; +class LLVolumeParams; +class LLProfile; +class LLPath; + +template <class T> class LLOctreeNode; + +class LLVector4a; +class LLVolumeFace; +class LLVolume; +class LLVolumeTriangle; + +#include "lldarray.h" +#include "lluuid.h" +#include "v4color.h" +//#include "vmath.h" +#include "v2math.h" +#include "v3math.h" +#include "v3dmath.h" +#include "v4math.h" +#include "llquaternion.h" +#include "llstrider.h" +#include "v4coloru.h" +#include "llrefcount.h" +#include "llfile.h" + +//============================================================================ + +const S32 MIN_DETAIL_FACES = 6; +const S32 MIN_LOD = 0; +const S32 MAX_LOD = 3; + +// These are defined here but are not enforced at this level, +// rather they are here for the convenience of code that uses +// the LLVolume class. +const F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; +const F32 MIN_VOLUME_PATH_WIDTH = 0.05f; + +const F32 CUT_QUANTA = 0.00002f; +const F32 SCALE_QUANTA = 0.01f; +const F32 SHEAR_QUANTA = 0.01f; +const F32 TAPER_QUANTA = 0.01f; +const F32 REV_QUANTA = 0.015f; +const F32 HOLLOW_QUANTA = 0.00002f; + +const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; + +//============================================================================ + +// useful masks +const LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness +const LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) +const LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) +const LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum +const LLPCode LL_PCODE_BASE_MASK = 0x0F; + + // primitive shapes +const LLPCode LL_PCODE_CUBE = 1; +const LLPCode LL_PCODE_PRISM = 2; +const LLPCode LL_PCODE_TETRAHEDRON = 3; +const LLPCode LL_PCODE_PYRAMID = 4; +const LLPCode LL_PCODE_CYLINDER = 5; +const LLPCode LL_PCODE_CONE = 6; +const LLPCode LL_PCODE_SPHERE = 7; +const LLPCode LL_PCODE_TORUS = 8; +const LLPCode LL_PCODE_VOLUME = 9; + + // surfaces +//const LLPCode LL_PCODE_SURFACE_TRIANGLE = 10; +//const LLPCode LL_PCODE_SURFACE_SQUARE = 11; +//const LLPCode LL_PCODE_SURFACE_DISC = 12; + +const LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) +const LLPCode LL_PCODE_LEGACY = 15; + +// Pcodes for legacy objects +//const LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR +const LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER +//const LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD +//const LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON +const LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS +const LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees +//const LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE +const LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS +const LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK +//const LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT +//const LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY; +//const LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE +//const LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK +const LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE +const LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE + + // hemis +const LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; +const LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; +const LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; +const LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK; + + +// Volumes consist of a profile at the base that is swept around +// a path to make a volume. +// The profile code +const U8 LL_PCODE_PROFILE_MASK = 0x0f; +const U8 LL_PCODE_PROFILE_MIN = 0x00; +const U8 LL_PCODE_PROFILE_CIRCLE = 0x00; +const U8 LL_PCODE_PROFILE_SQUARE = 0x01; +const U8 LL_PCODE_PROFILE_ISOTRI = 0x02; +const U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; +const U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; +const U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; +const U8 LL_PCODE_PROFILE_MAX = 0x05; + +// Stored in the profile byte +const U8 LL_PCODE_HOLE_MASK = 0xf0; +const U8 LL_PCODE_HOLE_MIN = 0x00; +const U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile +const U8 LL_PCODE_HOLE_CIRCLE = 0x10; +const U8 LL_PCODE_HOLE_SQUARE = 0x20; +const U8 LL_PCODE_HOLE_TRIANGLE = 0x30; +const U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max + +const U8 LL_PCODE_PATH_IGNORE = 0x00; +const U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max +const U8 LL_PCODE_PATH_LINE = 0x10; +const U8 LL_PCODE_PATH_CIRCLE = 0x20; +const U8 LL_PCODE_PATH_CIRCLE2 = 0x30; +const U8 LL_PCODE_PATH_TEST = 0x40; +const U8 LL_PCODE_PATH_FLEXIBLE = 0x80; +const U8 LL_PCODE_PATH_MAX = 0x08; + +//============================================================================ + +// face identifiers +typedef U16 LLFaceID; + +const LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; +const LLFaceID LL_FACE_PATH_END = 0x1 << 1; +const LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; +const LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; +const LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; +const LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; +const LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; +const LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; +const LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; + +//============================================================================ + +// sculpt types + flags + +const U8 LL_SCULPT_TYPE_NONE = 0; +const U8 LL_SCULPT_TYPE_SPHERE = 1; +const U8 LL_SCULPT_TYPE_TORUS = 2; +const U8 LL_SCULPT_TYPE_PLANE = 3; +const U8 LL_SCULPT_TYPE_CYLINDER = 4; +const U8 LL_SCULPT_TYPE_MESH = 5; +const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | + LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; + +const U8 LL_SCULPT_FLAG_INVERT = 64; +const U8 LL_SCULPT_FLAG_MIRROR = 128; + +const S32 LL_SCULPT_MESH_MAX_FACES = 8; + +class LLProfileParams +{ +public: + LLProfileParams() + : mCurveType(LL_PCODE_PROFILE_SQUARE), + mBegin(0.f), + mEnd(1.f), + mHollow(0.f), + mCRC(0) + { + } + + LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow) + : mCurveType(curve), + mBegin(begin), + mEnd(end), + mHollow(hollow), + mCRC(0) + { + } + + LLProfileParams(U8 curve, U16 begin, U16 end, U16 hollow) + { + mCurveType = curve; + F32 temp_f32 = begin * CUT_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mBegin = temp_f32; + temp_f32 = end * CUT_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mEnd = 1.f - temp_f32; + temp_f32 = hollow * HOLLOW_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mHollow = temp_f32; + mCRC = 0; + } + + bool operator==(const LLProfileParams ¶ms) const; + bool operator!=(const LLProfileParams ¶ms) const; + bool operator<(const LLProfileParams ¶ms) const; + + void copyParams(const LLProfileParams ¶ms); + + BOOL importFile(LLFILE *fp); + BOOL exportFile(LLFILE *fp) const; + + BOOL importLegacyStream(std::istream& input_stream); + BOOL exportLegacyStream(std::ostream& output_stream) const; + + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + const F32& getBegin () const { return mBegin; } + const F32& getEnd () const { return mEnd; } + const F32& getHollow() const { return mHollow; } + const U8& getCurveType () const { return mCurveType; } + + void setCurveType(const U32 type) { mCurveType = type;} + void setBegin(const F32 begin) { mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 100000))/100000.0f;} + void setEnd(const F32 end) { mEnd = (end <= 0.0f) ? 1.0f : ((int) (end * 100000))/100000.0f;} + void setHollow(const F32 hollow) { mHollow = ((int) (hollow * 100000))/100000.0f;} + + friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params); + +protected: + // Profile params + U8 mCurveType; + F32 mBegin; + F32 mEnd; + F32 mHollow; + + U32 mCRC; +}; + +inline bool LLProfileParams::operator==(const LLProfileParams ¶ms) const +{ + return + (getCurveType() == params.getCurveType()) && + (getBegin() == params.getBegin()) && + (getEnd() == params.getEnd()) && + (getHollow() == params.getHollow()); +} + +inline bool LLProfileParams::operator!=(const LLProfileParams ¶ms) const +{ + return + (getCurveType() != params.getCurveType()) || + (getBegin() != params.getBegin()) || + (getEnd() != params.getEnd()) || + (getHollow() != params.getHollow()); +} + + +inline bool LLProfileParams::operator<(const LLProfileParams ¶ms) const +{ + if (getCurveType() != params.getCurveType()) + { + return getCurveType() < params.getCurveType(); + } + else + if (getBegin() != params.getBegin()) + { + return getBegin() < params.getBegin(); + } + else + if (getEnd() != params.getEnd()) + { + return getEnd() < params.getEnd(); + } + else + { + return getHollow() < params.getHollow(); + } +} + +#define U8_TO_F32(x) (F32)(*((S8 *)&x)) + +class LLPathParams +{ +public: + LLPathParams() + : + mCurveType(LL_PCODE_PATH_LINE), + mBegin(0.f), + mEnd(1.f), + mScale(1.f,1.f), + mShear(0.f,0.f), + mTwistBegin(0.f), + mTwistEnd(0.f), + mRadiusOffset(0.f), + mTaper(0.f,0.f), + mRevolutions(1.f), + mSkew(0.f), + mCRC(0) + { + } + + LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew) + : mCurveType(curve), + mBegin(begin), + mEnd(end), + mScale(scx,scy), + mShear(shx,shy), + mTwistBegin(twistbegin), + mTwistEnd(twistend), + mRadiusOffset(radiusoffset), + mTaper(tx,ty), + mRevolutions(revolutions), + mSkew(skew), + mCRC(0) + { + } + + LLPathParams(U8 curve, U16 begin, U16 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew) + { + mCurveType = curve; + mBegin = (F32)(begin * CUT_QUANTA); + mEnd = (F32)(100.f - end) * CUT_QUANTA; + if (mEnd > 1.f) + mEnd = 1.f; + mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA); + mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA); + mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA; + mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA; + mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA; + mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA); + mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f; + mSkew = U8_TO_F32(skew) * SCALE_QUANTA; + + mCRC = 0; + } + + bool operator==(const LLPathParams ¶ms) const; + bool operator!=(const LLPathParams ¶ms) const; + bool operator<(const LLPathParams ¶ms) const; + + void copyParams(const LLPathParams ¶ms); + + BOOL importFile(LLFILE *fp); + BOOL exportFile(LLFILE *fp) const; + + BOOL importLegacyStream(std::istream& input_stream); + BOOL exportLegacyStream(std::ostream& output_stream) const; + + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + const F32& getBegin() const { return mBegin; } + const F32& getEnd() const { return mEnd; } + const LLVector2 &getScale() const { return mScale; } + const F32& getScaleX() const { return mScale.mV[0]; } + const F32& getScaleY() const { return mScale.mV[1]; } + const LLVector2 getBeginScale() const; + const LLVector2 getEndScale() const; + const LLVector2 &getShear() const { return mShear; } + const F32& getShearX() const { return mShear.mV[0]; } + const F32& getShearY() const { return mShear.mV[1]; } + const U8& getCurveType () const { return mCurveType; } + + const F32& getTwistBegin() const { return mTwistBegin; } + const F32& getTwistEnd() const { return mTwistEnd; } + const F32& getTwist() const { return mTwistEnd; } // deprecated + const F32& getRadiusOffset() const { return mRadiusOffset; } + const LLVector2 &getTaper() const { return mTaper; } + const F32& getTaperX() const { return mTaper.mV[0]; } + const F32& getTaperY() const { return mTaper.mV[1]; } + const F32& getRevolutions() const { return mRevolutions; } + const F32& getSkew() const { return mSkew; } + + void setCurveType(const U8 type) { mCurveType = type; } + void setBegin(const F32 begin) { mBegin = begin; } + void setEnd(const F32 end) { mEnd = end; } + + void setScale(const F32 x, const F32 y) { mScale.setVec(x,y); } + void setScaleX(const F32 v) { mScale.mV[VX] = v; } + void setScaleY(const F32 v) { mScale.mV[VY] = v; } + void setShear(const F32 x, const F32 y) { mShear.setVec(x,y); } + void setShearX(const F32 v) { mShear.mV[VX] = v; } + void setShearY(const F32 v) { mShear.mV[VY] = v; } + + void setTwistBegin(const F32 twist_begin) { mTwistBegin = twist_begin; } + void setTwistEnd(const F32 twist_end) { mTwistEnd = twist_end; } + void setTwist(const F32 twist) { setTwistEnd(twist); } // deprecated + void setRadiusOffset(const F32 radius_offset){ mRadiusOffset = radius_offset; } + void setTaper(const F32 x, const F32 y) { mTaper.setVec(x,y); } + void setTaperX(const F32 v) { mTaper.mV[VX] = v; } + void setTaperY(const F32 v) { mTaper.mV[VY] = v; } + void setRevolutions(const F32 revolutions) { mRevolutions = revolutions; } + void setSkew(const F32 skew) { mSkew = skew; } + + friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params); + +protected: + // Path params + U8 mCurveType; + F32 mBegin; + F32 mEnd; + LLVector2 mScale; + LLVector2 mShear; + + F32 mTwistBegin; + F32 mTwistEnd; + F32 mRadiusOffset; + LLVector2 mTaper; + F32 mRevolutions; + F32 mSkew; + + U32 mCRC; +}; + +inline bool LLPathParams::operator==(const LLPathParams ¶ms) const +{ + return + (getCurveType() == params.getCurveType()) && + (getScale() == params.getScale()) && + (getBegin() == params.getBegin()) && + (getEnd() == params.getEnd()) && + (getShear() == params.getShear()) && + (getTwist() == params.getTwist()) && + (getTwistBegin() == params.getTwistBegin()) && + (getRadiusOffset() == params.getRadiusOffset()) && + (getTaper() == params.getTaper()) && + (getRevolutions() == params.getRevolutions()) && + (getSkew() == params.getSkew()); +} + +inline bool LLPathParams::operator!=(const LLPathParams ¶ms) const +{ + return + (getCurveType() != params.getCurveType()) || + (getScale() != params.getScale()) || + (getBegin() != params.getBegin()) || + (getEnd() != params.getEnd()) || + (getShear() != params.getShear()) || + (getTwist() != params.getTwist()) || + (getTwistBegin() !=params.getTwistBegin()) || + (getRadiusOffset() != params.getRadiusOffset()) || + (getTaper() != params.getTaper()) || + (getRevolutions() != params.getRevolutions()) || + (getSkew() != params.getSkew()); +} + + +inline bool LLPathParams::operator<(const LLPathParams ¶ms) const +{ + if( getCurveType() != params.getCurveType()) + { + return getCurveType() < params.getCurveType(); + } + else + if( getScale() != params.getScale()) + { + return getScale() < params.getScale(); + } + else + if( getBegin() != params.getBegin()) + { + return getBegin() < params.getBegin(); + } + else + if( getEnd() != params.getEnd()) + { + return getEnd() < params.getEnd(); + } + else + if( getShear() != params.getShear()) + { + return getShear() < params.getShear(); + } + else + if( getTwist() != params.getTwist()) + { + return getTwist() < params.getTwist(); + } + else + if( getTwistBegin() != params.getTwistBegin()) + { + return getTwistBegin() < params.getTwistBegin(); + } + else + if( getRadiusOffset() != params.getRadiusOffset()) + { + return getRadiusOffset() < params.getRadiusOffset(); + } + else + if( getTaper() != params.getTaper()) + { + return getTaper() < params.getTaper(); + } + else + if( getRevolutions() != params.getRevolutions()) + { + return getRevolutions() < params.getRevolutions(); + } + else + { + return getSkew() < params.getSkew(); + } +} + +typedef LLVolumeParams* LLVolumeParamsPtr; +typedef const LLVolumeParams* const_LLVolumeParamsPtr; + +class LLVolumeParams +{ +public: + LLVolumeParams() + : mSculptType(LL_SCULPT_TYPE_NONE) + { + } + + LLVolumeParams(LLProfileParams &profile, LLPathParams &path, + LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE) + : mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type) + { + } + + bool operator==(const LLVolumeParams ¶ms) const; + bool operator!=(const LLVolumeParams ¶ms) const; + bool operator<(const LLVolumeParams ¶ms) const; + + + void copyParams(const LLVolumeParams ¶ms); + + const LLProfileParams &getProfileParams() const {return mProfileParams;} + LLProfileParams &getProfileParams() {return mProfileParams;} + const LLPathParams &getPathParams() const {return mPathParams;} + LLPathParams &getPathParams() {return mPathParams;} + + BOOL importFile(LLFILE *fp); + BOOL exportFile(LLFILE *fp) const; + + BOOL importLegacyStream(std::istream& input_stream); + BOOL exportLegacyStream(std::ostream& output_stream) const; + + LLSD sculptAsLLSD() const; + bool sculptFromLLSD(LLSD& sd); + + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + bool setType(U8 profile, U8 path); + + //void setBeginS(const F32 beginS) { mProfileParams.setBegin(beginS); } // range 0 to 1 + //void setBeginT(const F32 beginT) { mPathParams.setBegin(beginT); } // range 0 to 1 + //void setEndS(const F32 endS) { mProfileParams.setEnd(endS); } // range 0 to 1, must be greater than begin + //void setEndT(const F32 endT) { mPathParams.setEnd(endT); } // range 0 to 1, must be greater than begin + + bool setBeginAndEndS(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end + bool setBeginAndEndT(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end + + bool setHollow(const F32 hollow); // range 0 to 1 + bool setRatio(const F32 x) { return setRatio(x,x); } // 0 = point, 1 = same as base + bool setShear(const F32 x) { return setShear(x,x); } // 0 = no movement, + bool setRatio(const F32 x, const F32 y); // 0 = point, 1 = same as base + bool setShear(const F32 x, const F32 y); // 0 = no movement + + bool setTwistBegin(const F32 twist_begin); // range -1 to 1 + bool setTwistEnd(const F32 twist_end); // range -1 to 1 + bool setTwist(const F32 twist) { return setTwistEnd(twist); } // deprecated + bool setTaper(const F32 x, const F32 y) { bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; } + bool setTaperX(const F32 v); // -1 to 1 + bool setTaperY(const F32 v); // -1 to 1 + bool setRevolutions(const F32 revolutions); // 1 to 4 + bool setRadiusOffset(const F32 radius_offset); + bool setSkew(const F32 skew); + bool setSculptID(const LLUUID sculpt_id, U8 sculpt_type); + + static bool 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); + + const F32& getBeginS() const { return mProfileParams.getBegin(); } + const F32& getBeginT() const { return mPathParams.getBegin(); } + const F32& getEndS() const { return mProfileParams.getEnd(); } + const F32& getEndT() const { return mPathParams.getEnd(); } + + const F32& getHollow() const { return mProfileParams.getHollow(); } + const F32& getTwist() const { return mPathParams.getTwist(); } + const F32& getRatio() const { return mPathParams.getScaleX(); } + const F32& getRatioX() const { return mPathParams.getScaleX(); } + const F32& getRatioY() const { return mPathParams.getScaleY(); } + const F32& getShearX() const { return mPathParams.getShearX(); } + const F32& getShearY() const { return mPathParams.getShearY(); } + + const F32& getTwistBegin()const { return mPathParams.getTwistBegin(); } + const F32& getRadiusOffset() const { return mPathParams.getRadiusOffset(); } + const F32& getTaper() const { return mPathParams.getTaperX(); } + const F32& getTaperX() const { return mPathParams.getTaperX(); } + const F32& getTaperY() const { return mPathParams.getTaperY(); } + const F32& getRevolutions() const { return mPathParams.getRevolutions(); } + const F32& getSkew() const { return mPathParams.getSkew(); } + const LLUUID& getSculptID() const { return mSculptID; } + const U8& getSculptType() const { return mSculptType; } + bool isSculpt() const; + bool isMeshSculpt() const; + BOOL isConvex() const; + + // 'begin' and 'end' should be in range [0, 1] (they will be clamped) + // (begin, end) = (0, 1) will not change the volume + // (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T) + void reduceS(F32 begin, F32 end); + void reduceT(F32 begin, F32 end); + + struct compare + { + bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const + { + return (*first < *second); + } + }; + + friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); + + // debug helper functions + void setCube(); + +protected: + LLProfileParams mProfileParams; + LLPathParams mPathParams; + LLUUID mSculptID; + U8 mSculptType; +}; + + +class LLProfile +{ +public: + LLProfile() + : mOpen(FALSE), + mConcave(FALSE), + mDirty(TRUE), + mTotalOut(0), + mTotal(2) + { + } + + ~LLProfile(); + + S32 getTotal() const { return mTotal; } + S32 getTotalOut() const { return mTotalOut; } // Total number of outside points + BOOL isFlat(S32 face) const { return (mFaces[face].mCount == 2); } + BOOL isOpen() const { return mOpen; } + void setDirty() { mDirty = TRUE; } + BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0, + BOOL is_sculpted = FALSE, S32 sculpt_size = 0); + BOOL isConcave() const { return mConcave; } +public: + struct Face + { + S32 mIndex; + S32 mCount; + F32 mScaleU; + BOOL mCap; + BOOL mFlat; + LLFaceID mFaceID; + }; + + std::vector<LLVector3> mProfile; + std::vector<LLVector2> mNormals; + std::vector<Face> mFaces; + std::vector<LLVector3> mEdgeNormals; + std::vector<LLVector3> mEdgeCenters; + + friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile); + +protected: + void genNormals(const LLProfileParams& params); + void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); + + Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); + Face* addCap (S16 faceID); + Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, BOOL flat); + +protected: + BOOL mOpen; + BOOL mConcave; + BOOL mDirty; + + S32 mTotalOut; + S32 mTotal; +}; + +//------------------------------------------------------------------- +// SWEEP/EXTRUDE PATHS +//------------------------------------------------------------------- + +class LLPath +{ +public: + struct PathPt + { + LLVector3 mPos; + LLVector2 mScale; + LLQuaternion mRot; + F32 mTexT; + PathPt() { mPos.setVec(0,0,0); mTexT = 0; mScale.setVec(0,0); mRot.loadIdentity(); } + }; + +public: + LLPath() + : mOpen(FALSE), + mTotal(0), + mDirty(TRUE), + mStep(1) + { + } + + virtual ~LLPath(); + + void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); + virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, + BOOL is_sculpted = FALSE, S32 sculpt_size = 0); + + BOOL isOpen() const { return mOpen; } + F32 getStep() const { return mStep; } + void setDirty() { mDirty = TRUE; } + + S32 getPathLength() const { return (S32)mPath.size(); } + + void resizePath(S32 length) { mPath.resize(length); } + + friend std::ostream& operator<<(std::ostream &s, const LLPath &path); + +public: + std::vector<PathPt> mPath; + +protected: + BOOL mOpen; + S32 mTotal; + BOOL mDirty; + F32 mStep; +}; + +class LLDynamicPath : public LLPath +{ +public: + LLDynamicPath() : LLPath() { } + /*virtual*/ BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, + BOOL is_sculpted = FALSE, S32 sculpt_size = 0); +}; + +// Yet another "face" class - caches volume-specific, but not instance-specific data for faces) +class LLVolumeFace +{ +public: class VertexData { enum @@ -825,281 +825,282 @@ class LLVolumeFace private: LLVector4a* mData; }; - - LLVolumeFace(); - LLVolumeFace(const LLVolumeFace& src); - LLVolumeFace& operator=(const LLVolumeFace& rhs); - - ~LLVolumeFace(); -private: - void freeData(); -public: - - BOOL create(LLVolume* volume, BOOL partial_build = FALSE); - void createBinormals(); - - void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform); - - void resizeVertices(S32 num_verts); - void allocateBinormals(S32 num_verts); - void allocateWeights(S32 num_verts); - void resizeIndices(S32 num_indices); - void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx); - - void pushVertex(const VertexData& cv); - void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc); - void pushIndex(const U16& idx); - - void swapData(LLVolumeFace& rhs); - - void getVertexData(U16 indx, LLVolumeFace::VertexData& cv); - - class VertexMapData : public LLVolumeFace::VertexData - { - public: - U16 mIndex; - - bool operator==(const LLVolumeFace::VertexData& rhs) const; - - struct ComparePosition - { - bool operator()(const LLVector3& a, const LLVector3& b) const; - }; - - typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap; - }; - - void optimize(F32 angle_cutoff = 2.f); - void cacheOptimize(); - - void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); - - enum - { - SINGLE_MASK = 0x0001, - CAP_MASK = 0x0002, - END_MASK = 0x0004, - SIDE_MASK = 0x0008, - INNER_MASK = 0x0010, - OUTER_MASK = 0x0020, - HOLLOW_MASK = 0x0040, - OPEN_MASK = 0x0080, - FLAT_MASK = 0x0100, - TOP_MASK = 0x0200, - BOTTOM_MASK = 0x0400 - }; - -public: - S32 mID; - U32 mTypeMask; - - // Only used for INNER/OUTER faces - S32 mBeginS; - S32 mBeginT; - S32 mNumS; - S32 mNumT; - - LLVector4a* mExtents; //minimum and maximum point of face - LLVector4a* mCenter; - - S32 mNumVertices; - S32 mNumIndices; - - LLVector4a* mPositions; - LLVector4a* mNormals; - LLVector4a* mBinormals; - LLVector2* mTexCoords; - U16* mIndices; - - std::vector<S32> mEdge; - - //list of skin weights for rigged volumes - // format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight> - // mWeights.size() should be empty or match mVertices.size() - LLVector4a* mWeights; - - LLOctreeNode<LLVolumeTriangle>* mOctree; - -private: - BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE); - BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE); - BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE); -}; - -class LLVolume : public LLRefCount -{ - friend class LLVolumeLODGroup; - -protected: - ~LLVolume(); // use unref - -public: - struct Point - { - LLVector3 mPos; - }; - - struct FaceParams - { - LLFaceID mFaceID; - S32 mBeginS; - S32 mCountS; - S32 mBeginT; - S32 mCountT; - }; - - LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face = FALSE, const BOOL is_unique = FALSE); - - U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } - U8 getPathType() const { return mParams.getPathParams().getCurveType(); } - S32 getNumFaces() const; - S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } - F32 getDetail() const { return mDetail; } - const LLVolumeParams& getParams() const { return mParams; } - LLVolumeParams getCopyOfParams() const { return mParams; } - const LLProfile& getProfile() const { return *mProfilep; } - LLPath& getPath() const { return *mPathp; } - void resizePath(S32 length); - const std::vector<Point>& getMesh() const { return mMesh; } - const LLVector3& getMeshPt(const U32 i) const { return mMesh[i].mPos; } - - void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } - - void regen(); - void genBinormals(S32 face); - - BOOL isConvex() const; - BOOL isCap(S32 face); - BOOL isFlat(S32 face); - BOOL isUnique() const { return mUnique; } - - S32 getSculptLevel() const { return mSculptLevel; } - void setSculptLevel(S32 level) { mSculptLevel = level; } - - S32 *getTriangleIndices(U32 &num_indices) const; - - // returns number of triangle indeces required for path/profile mesh - S32 getNumTriangleIndices() const; - - S32 getNumTriangles() const; - - void generateSilhouetteVertices(std::vector<LLVector3> &vertices, - std::vector<LLVector3> &normals, - std::vector<S32> &segments, - const LLVector3& view_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat, - S32 face_index); - - //get the face index of the face that intersects with the given line segment at the point - //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. - //Line segment must be in volume space. - S32 lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face = -1, // which face to check, -1 = ALL_SIDES - LLVector3* intersection = NULL, // return the intersection point - LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point - ); - - S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - S32 face = 1, - LLVector3* intersection = NULL, - LLVector2* tex_coord = NULL, - LLVector3* normal = NULL, - LLVector3* bi_normal = NULL); - - // The following cleans up vertices and triangles, - // getting rid of degenerate triangles and duplicate vertices, - // and allocates new arrays with the clean data. - static BOOL 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); - LLFaceID generateFaceMask(); - - BOOL isFaceMaskValid(LLFaceID face_mask); - static S32 sNumMeshPoints; - - friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume); - friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep); // HACK to bypass Windoze confusion over - // conversion if *(LLVolume*) to LLVolume& - const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE - - U32 mFaceMask; // bit array of which faces exist in this volume - LLVector3 mLODScaleBias; // vector for biasing LOD based on scale - - void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level); - void copyVolumeFaces(const LLVolume* volume); - void cacheOptimize(); - -private: - void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); - F32 sculptGetSurfaceArea(); - void sculptGeneratePlaceholder(); - void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t); - - -protected: - BOOL generate(); - void createVolumeFaces(); -public: - virtual BOOL createVolumeFacesFromFile(const std::string& file_name); - virtual BOOL createVolumeFacesFromStream(std::istream& is); - virtual bool unpackVolumeFaces(std::istream& is, S32 size); - - virtual void makeTetrahedron(); - virtual BOOL isTetrahedron(); - - protected: - BOOL mUnique; - F32 mDetail; - S32 mSculptLevel; - BOOL mIsTetrahedron; - - LLVolumeParams mParams; - LLPath *mPathp; - LLProfile *mProfilep; - std::vector<Point> mMesh; - - BOOL mGenerateSingleFace; - typedef std::vector<LLVolumeFace> face_list_t; - face_list_t mVolumeFaces; - -public: - LLVector4a* mHullPoints; - U16* mHullIndices; - S32 mNumHullPoints; - S32 mNumHullIndices; -}; - -std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); - -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); - -BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size); -BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size); -BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size); - -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); - -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); -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); - - - -#endif + + LLVolumeFace(); + LLVolumeFace(const LLVolumeFace& src); + LLVolumeFace& operator=(const LLVolumeFace& rhs); + + ~LLVolumeFace(); +private: + void freeData(); +public: + + BOOL create(LLVolume* volume, BOOL partial_build = FALSE); + void createBinormals(); + + void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform); + + void resizeVertices(S32 num_verts); + void allocateBinormals(S32 num_verts); + void allocateWeights(S32 num_verts); + void resizeIndices(S32 num_indices); + void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx); + + void pushVertex(const VertexData& cv); + void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc); + void pushIndex(const U16& idx); + + void swapData(LLVolumeFace& rhs); + + void getVertexData(U16 indx, LLVolumeFace::VertexData& cv); + + class VertexMapData : public LLVolumeFace::VertexData + { + public: + U16 mIndex; + + bool operator==(const LLVolumeFace::VertexData& rhs) const; + + struct ComparePosition + { + bool operator()(const LLVector3& a, const LLVector3& b) const; + }; + + typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap; + }; + + void optimize(F32 angle_cutoff = 2.f); + void cacheOptimize(); + + void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); + + enum + { + SINGLE_MASK = 0x0001, + CAP_MASK = 0x0002, + END_MASK = 0x0004, + SIDE_MASK = 0x0008, + INNER_MASK = 0x0010, + OUTER_MASK = 0x0020, + HOLLOW_MASK = 0x0040, + OPEN_MASK = 0x0080, + FLAT_MASK = 0x0100, + TOP_MASK = 0x0200, + BOTTOM_MASK = 0x0400 + }; + +public: + S32 mID; + U32 mTypeMask; + + // Only used for INNER/OUTER faces + S32 mBeginS; + S32 mBeginT; + S32 mNumS; + S32 mNumT; + + 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; + + LLVector4a* mPositions; + LLVector4a* mNormals; + LLVector4a* mBinormals; + LLVector2* mTexCoords; + U16* mIndices; + + std::vector<S32> mEdge; + + //list of skin weights for rigged volumes + // format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight> + // mWeights.size() should be empty or match mVertices.size() + LLVector4a* mWeights; + + LLOctreeNode<LLVolumeTriangle>* mOctree; + +private: + BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE); + BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE); + BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE); +}; + +class LLVolume : public LLRefCount +{ + friend class LLVolumeLODGroup; + +protected: + ~LLVolume(); // use unref + +public: + struct Point + { + LLVector3 mPos; + }; + + struct FaceParams + { + LLFaceID mFaceID; + S32 mBeginS; + S32 mCountS; + S32 mBeginT; + S32 mCountT; + }; + + LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face = FALSE, const BOOL is_unique = FALSE); + + U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } + U8 getPathType() const { return mParams.getPathParams().getCurveType(); } + S32 getNumFaces() const; + S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } + F32 getDetail() const { return mDetail; } + const LLVolumeParams& getParams() const { return mParams; } + LLVolumeParams getCopyOfParams() const { return mParams; } + const LLProfile& getProfile() const { return *mProfilep; } + LLPath& getPath() const { return *mPathp; } + void resizePath(S32 length); + const std::vector<Point>& getMesh() const { return mMesh; } + const LLVector3& getMeshPt(const U32 i) const { return mMesh[i].mPos; } + + void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } + + void regen(); + void genBinormals(S32 face); + + BOOL isConvex() const; + BOOL isCap(S32 face); + BOOL isFlat(S32 face); + BOOL isUnique() const { return mUnique; } + + S32 getSculptLevel() const { return mSculptLevel; } + void setSculptLevel(S32 level) { mSculptLevel = level; } + + S32 *getTriangleIndices(U32 &num_indices) const; + + // returns number of triangle indeces required for path/profile mesh + S32 getNumTriangleIndices() const; + + S32 getNumTriangles() const; + + void generateSilhouetteVertices(std::vector<LLVector3> &vertices, + std::vector<LLVector3> &normals, + std::vector<S32> &segments, + const LLVector3& view_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat, + S32 face_index); + + //get the face index of the face that intersects with the given line segment at the point + //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. + //Line segment must be in volume space. + S32 lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face = -1, // which face to check, -1 = ALL_SIDES + LLVector3* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector3* normal = NULL, // return the surface normal at the intersection point + LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + ); + + S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face = 1, + LLVector3* intersection = NULL, + LLVector2* tex_coord = NULL, + LLVector3* normal = NULL, + LLVector3* bi_normal = NULL); + + // The following cleans up vertices and triangles, + // getting rid of degenerate triangles and duplicate vertices, + // and allocates new arrays with the clean data. + static BOOL 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); + LLFaceID generateFaceMask(); + + BOOL isFaceMaskValid(LLFaceID face_mask); + static S32 sNumMeshPoints; + + friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume); + friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep); // HACK to bypass Windoze confusion over + // conversion if *(LLVolume*) to LLVolume& + const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE + + U32 mFaceMask; // bit array of which faces exist in this volume + LLVector3 mLODScaleBias; // vector for biasing LOD based on scale + + void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level); + void copyVolumeFaces(const LLVolume* volume); + void cacheOptimize(); + +private: + void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); + F32 sculptGetSurfaceArea(); + void sculptGeneratePlaceholder(); + void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t); + + +protected: + BOOL generate(); + void createVolumeFaces(); +public: + virtual BOOL createVolumeFacesFromFile(const std::string& file_name); + virtual BOOL createVolumeFacesFromStream(std::istream& is); + virtual bool unpackVolumeFaces(std::istream& is, S32 size); + + virtual void makeTetrahedron(); + virtual BOOL isTetrahedron(); + + protected: + BOOL mUnique; + F32 mDetail; + S32 mSculptLevel; + BOOL mIsTetrahedron; + + LLVolumeParams mParams; + LLPath *mPathp; + LLProfile *mProfilep; + std::vector<Point> mMesh; + + BOOL mGenerateSingleFace; + typedef std::vector<LLVolumeFace> face_list_t; + face_list_t mVolumeFaces; + +public: + LLVector4a* mHullPoints; + U16* mHullIndices; + S32 mNumHullPoints; + S32 mNumHullIndices; +}; + +std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); + +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); + +BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size); +BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size); +BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size); + +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); + +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); +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); + + + +#endif diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 3c1d031ff5d8b72d46d1233c63446b9c88a7cc23..861bde5c89285bceae0bb9e730a233ab353ae812 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 ac43b53eccae5e09322bb2e6a8f181e109565775..dfd72d13b04ebc4060dbfdd06dcac9bec26797ea 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 64556bcb4c34dcacd2b48f391dbfebf0eb528421..cb898e385f91b84a9d027eebce9923240526d92e 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/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 66dd11547f355af059def39fcefe5f1ad8736e7b..6f47d9c01993784661062aa9f7cf8a43bf292c6d 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> @@ -1179,7 +1157,7 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>20000</integer> + <integer>128</integer> </map> <key>CacheSize</key> <map> @@ -1901,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> @@ -1934,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> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e74a7a84c383562fa726f858c2aa272113d3eecc..c1a311b170cf88d4e4f5a181dd6e0536d7067f5f 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 a6e743f625db2ca3e58b66c006247eb41deacfd0..9d912455977289d779a4a2ba27cbe26a478a2e02 100644 --- a/indra/newview/llcapabilityprovider.h +++ b/indra/newview/llcapabilityprovider.h @@ -46,7 +46,7 @@ class LLCapabilityProvider /** * 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 a3d2941114f39d4124e0cc9b550202676debb977..f781d5f3ff96274388f40bc2a12bfcebc53ba944 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 15f59e84a658a8a7130b7bdd8a19470e6505ce1c..1576ef0769ba2a6dbd0612c4d8eaf4772053820d 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 1b94d8cbcd2e7ccfe1bac70a41412eb07cc0f5f0..80920c80d650b9d13d71a71eb2c0c60b0a1b6900 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 62ba746a02a84ab3b9e9a8294c3ea697cc93ab45..b3b1ce5743ceb3e5a583038d4f269c8c24488c99 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 afaac86b04664056e5fffd4e035c7ee759474dd5..210ba9eb3ccf22ca0e048d984f932644e0057347 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -269,7 +269,10 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler 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 91ede6d2213aebbd4b7c91723b566666ecf09de0..17d0b0ffbb4901e3649dbad7ff3345a3c6fb325f 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 @@ class LLInspectAvatar : public LLInspect, LLTransientFloater 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 ef4774a06d684985cca6e5083105e4b581215668..e22363c2f63bdd0e95da0ca4bbc8bf97044cbfa4 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 5a9d1524f3491963882a8444dceb98b1d3da0c6d..1dcb91ad4d28893ac1bf1e15bc24965a01d9ae1a 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 @@ class LLInventoryPanelObserver : public LLInventoryObserver 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 6545fc0d5e5508661190254bf4dfef33a3a9c4a9..9da9f7d8ba93bdcc4bf0ae4894d870fcbfcc4e0c 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 @@ class LLInventoryPanel : public LLPanel 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 9a244e25626d86a2607fce4486d25bb33ca6835d..7e9c3c84a742147582dbf636ecce9f7c821f9f8a 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 24ea05827967fb23757ad695b76274b76352b419..9bdc59ab100049d4f21c79acd7e231be4dce55e8 100644 --- a/indra/newview/llmemoryview.h +++ b/indra/newview/llmemoryview.h @@ -55,6 +55,7 @@ class LLMemoryView : public LLView private: std::vector<LLWString> mLines; LLAllocator* mAlloc; + BOOL mPaused ; }; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 1a8ec4991d7dedef4b1f47cf0440dfce89b213e4..93039d935d6ee939595ae1f72521f30dd30d3b6f 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 e053b1c177006a02d33443c69dbf51a93703aa89..20fcee0814bf2ff1db301dddf3e4028b06e4c47e 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 @@ class LLNetMap : public LLUICtrl /*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 @@ class LLNetMap : public LLUICtrl 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 94b2340c937a2a8f7e75e32658b14f366d2f67d7..73c4722b828f15d512a36a3fc7b1251aa1cd7be6 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 070fe4579ac14499ab0d63d8c6bf7f36a0216f67..e95441cd581e2bbc071061904187ee18a55e0a94 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/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 54198d6aa486fd208d73567682d7f5efcd0595e2..b07a46a222170565f15a243cfc67b95a72650155 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 b496bb3779ec132c8da2235cf80d5dbbd9950fad..46c58cd139ab3fb660a1d78cd2f0903eaa0e7e55 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -142,6 +142,7 @@ class LLPanelPeople 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 7657cccd4ea3b5f6602d15d6e98f6fd9e8d28ed3..6cfb708112ab10ab270e7eaa90ac6672e8af4427 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 19d1bdee862b5bafd624cae04bb367724fd0eb2d..eb537c7d7b987a8b6e5efa8ad9eab04adf2d0a0b 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -141,6 +141,8 @@ class LLSideTrayTab: public LLPanel 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 92080d1fd75757d37706711dd6153628aabc8951..f54214b95cbc6e173270fe7d39cc544299171c9e 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 4f63abb152dc59faaca838d5938d28e056034f81..18c3a3b87ddf6ef917c86fc2107d112e46bbf026 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 ad00a7ea36fdb6aec9d13e549e1f26b8bcb25f47..d101da1f4be1697e6221825a3c6cd72d8a7ca150 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -79,6 +79,7 @@ class LLTextureFetch : public LLWorkerThread void dump(); S32 getNumRequests() ; S32 getNumHTTPRequests() ; + U32 getTotalNumHTTPRequests() ; // Public for access by callbacks S32 getPending(); @@ -183,6 +184,9 @@ class LLTextureFetch : public LLWorkerThread 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 b9a15fd1f4dd836c757b739118563ef81efb9e22..0115115a230fde1d5a2c5030a8649dd37af0fa02 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 b2156df999400f29e1c1e808dfd6c96e3a34de89..b36b5aa9ee5bd47d05adeb54c3bb322838570162 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1832,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 ae8bd3f29a5739ee30abc9d8dde530e1b11af1a4..f3cbb8cce3bc24661c98461a5e24032c8a84b03e 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/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index ca32ee4202a08b8d4e0d89cea7677a9ed899a0d8..8c3bf5bf1233fddb5e5a174c0db18a6bc378b88f 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 2c5f789eb10d0bbfd6644ef133b6e8226ac0b246..7d0653b3b4e203326950bd2173943ed85b80c896 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -176,7 +176,7 @@ class LLViewerObjectList 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 7fd6979702c1fa544ddf24ef056d30530e6c5d0a..1d18858750ff36d70d71aab2c66e688a4cf6b989 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 7c6559203e5fa7606685f67a5cc8b328e1ffdf4a..dd40b876cd4c24173ab0104d8f9374946ff50981 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -245,7 +245,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface 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 092edafdbba650fd30cea55dd81a49146adb7ecc..34b0ae9f023ca322979e099b2a67e2802355d68f 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 db48b769e49c02d942e348615633a149028082eb..42d4878cac1ef65754f6f85d22706218aa95a5f6 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -298,13 +298,15 @@ class LLDebugText 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 @@ class LLDebugText U32 ypos = 64; const U32 y_inc = 20; + clearText(); + if (gSavedSettings.getBOOL("DebugShowTime")) { const U32 y_inc2 = 15; @@ -349,6 +353,14 @@ class LLDebugText 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 @@ class LLDebugText 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 10d6b009ae646e006d94e72b5ae92cb7a8b63705..d0738a789f7a9c7452ef156775bacf6ed94fb9e1 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 e1030079793a01a91e36c9c9cee9f670ae69dc57..14e3b4c79355a94b23827c9b29be224c13a085e7 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -95,13 +95,15 @@ class LLVOCache { 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 @@ class LLVOCache 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 @@ class LLVOCache 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 @@ class LLVOCache 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 b296d21b2bf8d63d9830dc02013fe03f2d10d298..fe48bf5493532d40f4a200370fe04481267af041 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 9e1d0328a9951c68e62302f8e6ad06f0430c1e89..5af88c6cbdb39676e7dac2dc5079d1e766d16870 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -116,6 +116,7 @@ class LLVOVolume : public LLViewerObject 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 a49dc1b59da6907bd8d9e8a2c2f72afd2a1f4658..66a6ab5e94242a30cb0387196e1999856c46b550 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 510d22136be0f9efb64a387f948e26a1f47bddaa..ec3d0c10ab3bcf8f1975f9924dc5370be145657e 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 d351c442d3d06069a97f3854b512fcf939da666a..10aeef7c8a06d54aa05c1d1be7bed8707fefa72f 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 599686d36007a2e1dc0bdea8d932b8e7c168f0fc..b85a33279aa39a5da001981eb19798a567b01fc1 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 0000000000000000000000000000000000000000..6ab119eeab2b9a54049181e2b9af2a198e87019d --- /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 70d31f93ded08edf0cd94ae9e5b779f1eca699bf..a373e15338cfbf48542d28af416d46d167ffc902 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 bec79be34da21a192f33187c335f0aa7900164e1..2e0d72c40c0d0420e0ba43cd9f81c02408b8c862 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 9eeeaccdea417d298dca89217e56c728bab57d82..4a043e1233ff30b15cc47b1fd333c009217b488b 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 c26b02ec8fbe396f83c2d1e34aa10701e1fc5a16..b0ad989a59bc801675bec7cf355bacaa16c0e042 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 2db8cf7c0910796a7313742b7ddbd577fdd274b2..dcfcffa6e2f076730d3d7ddc030b68771d26a9ad 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 4b48950341771110c8840ce498248cfb9d475757..4c6facf5e33d8ca2eaffd1496c608c432fed8a28 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 0fc4fa71175c8b333d432dd15342e56a2cab3020..1bee6b1ead257819e50dd818d3249d460d1ce014 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 aea87cc2c4c5596f9238afc169bb188b0612be7f..89a4dfdabae25de398e5d4582486055035acf2d2 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 7187be570ce0e2cc3b503be99a56d28bda08b433..da672a03092b2d18b230336253b5967ae08cb47a 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 d9e5c7f2b56d1cad67231cd496d2e2ca782c8fb1..22681ffdf230b7dc6d87a7f61e88a6e4e24ba53b 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 d78064833b7a207b3de7715f74ed01fb2a54279a..b56f150394b25eb9a9d862d6f4b46f80fb5a756e 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 c4d095dde5f683ef4271106c80f00a085f6db1d2..490cead17dd0fccef2ba867ff51f4ef58975f7d8 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 005290c1ff70e914dc1d5c1c1e72b429f31ae801..04ed58f9445e736154ceab74cf5c4c8be08c2e11 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 6370ff92438cf701c45dc4bcd88d2a704098dbaf..ae99fa8dd5b094b74bd8dfb6045a2a190db7b586 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 6ec063cd26df9a1238fd6f4b7b26edec551af0c3..e04a72cbc001c54aaf539e42eb7fb32af9957d48 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 58d58a6ca9bd30acd7254a954402e235df14eee1..76b188220ddca219e3e24d5e3efa7f52bf8c8fac 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 3e006d7b31076ac1281b662c07439136488e3a08..0a6be2899ba83919476081e608e284bfe38d1953 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1994,6 +1994,16 @@ <menu_item_check.on_click 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" @@ -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 5871eb06540206df6e97c633b4ae6d26c1bef293..21c627cdfb82407f50b9c27be99559f1d9cf74fc 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_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 6a8bf87bc56ad85a31cce7bdf72327d35b04f9cf..43431ea7c1c255a3151a3faf27a9e14f86b4de7c 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 61e3bb354f492c8af9e0abcb99c9b86fbfa8a169..d36220385ddf68ec1c73d3b743952addd07c1148 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 a7e271a1ff50a6a12b6bbb04ebef8d040cc6f6e2..d792e9f29c46bc3be7e19c80936f99397bec1970 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 0000000000000000000000000000000000000000..5e02fad2dd9ef84fd13a42f9fbaae6ac98252604 --- /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 5386f82ee5e8302d79cad0e193c9c39f14faab7f..c27d6247324206eca98b8f563d0203df1213653f 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 41dc817551e8671f4316bfc1223a9c786c3774bd..07d1b08572936f0409098abbf2c2c9646c8648b6 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 3dd940c331f78359af4048cdb43398bc2f2ef4c0..2fe7db10418ca00d0eb3c0ab5f0ab8b514239f34 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 1c310669625c089f06f782dfc6f3d26ccd7183d3..2bf36bb763fc00afdab6a8cc890bd4cc1d6a5142 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 09221c5599b211fcd9a80cccc419f55b1b3d9372..5220df5d21bed9b0c57510db2ba74ab7fe329eca 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 3f238da9d007fec1227d9369974ce117764fe834..829c206ae121fd4ed9f910cc3ea2528764caab03 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 49d4881737bbd78ba52ccd47278c089570ed0e35..ada964f33efc2f1432957824f9ba82b48180ac04 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 14c94acf5b4db093fc1122b627e0a9ebe3df6e11..29e5e6f652ed19642c33946b2bb725a4c03e86bb 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 10aaa288d7db99e3e767b5e017d2f18096e94b25..dc7c873303c5a9db7e71c395f755a5999720448b 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 4fa5c4ce635d8f89327a7187e050ee32f97afd13..edd417d564463ddcd4e2b967c3a75b3e42d0e883 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 abff72c346c1c516bda3aa2e63f7dfe635da7f2f..5eaa345c988e2e1df63878b5895486f8ae3803ad 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 f968f489100c38a954d48ac6755257a0bf68db0b..68484645b7ed917043b7f9e09bde7dde8f2042b8 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 13ed1acf0b4dda5d861d461475e2f70cd15d9d57..ab76d3f994a4e0bdbb9e57769699d13d85c809f7 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 0000000000000000000000000000000000000000..65dfafe760340f0ab2f71dc9df544bdcd1192168 --- /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 b712c008cdd05d1e3e82a96ba8adb1755a36b459..400c77e51a5746e102d3cd07295a9bfae67e1be4 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 7530f31d4ebed9e179f71879142807c122021a4a..b9d0a70383efa6577d6ff7a53b62561d804f9a59 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 fb4ab314afed3a025b01fb7dbe076b02d75e84f3..65a00c2e6c61d56e38ccc0176562d88dd8aabed1 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 2ccac5c19ae465040a943640cfcd318dce852688..603b8f0edcd3ba16d839480d95b114626abb609c 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 607665ddd80305a69d54f2b3a02c42932cdc91d7..54b8f53e59ba49b08242310e835d0810743a6f11 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 3b81ef2a5f97445a9d69060cc91a00ad5a45e4e5..a8b95c66fb111ac703ceb08e960cf75b3b4f44f1 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 b6677801802dd2c7233b6245f3f05a924e1c5662..ef55ba7991da384d73fd7ed1cc010dc755fcbadd 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 8dbc22d3c7434caa01c4c8b857fb11201bb49747..5207c5a28e7967fa8d961c1323a4430decdf0635 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 a37770e184e4977da4d3da24c428b689b8554dcb..6ce09cde4b18334c4146494585e6e15b33ec0b7f 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 e94bb08c9c9ed3009a5994c7fcf73cfffdad5623..4e7d75e1b9d00b598dd48505e17905e8c2749226 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 6a4c77a10e6c21bd8fdae1182ce381d4293f377d..202ec779f58cc7032c8b8f9cb270affadf900cdd 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 8fa499d14aab04315a9f6fb9e1c1294a03af8e5a..bfe0defd56f5b469242adaefefb3b2d4f1812ed5 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 85429a18c736ca9b2c86645b36f5c2eed39572aa..69aec99e1d80d0e27136d85617a3a02a508c5eca 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 bd5dd7e7d2ed418a2dda65f024e1641d420eb069..471d2c39baf2571cd487108b858625a008520771 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 3f62d764c61b703782e455f325f270ecdb30a62c..930a5c76b005e8882ecad6eb2986c11fda402176 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 0000000000000000000000000000000000000000..ce1f3c0ac73491c2c0834fcb833f91c605c15dea --- /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 0000000000000000000000000000000000000000..4cc8d0b27b3272ea0f66db049595663230655432 --- /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 d110a2f02e1e2de645aab3f3674034eb5ffac49d..491b4deeaaff5b7766f6647aa8f93e4a2a11d2c3 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 0dd6117b8541cbb7937e64cd63695f0265feacde..e50b69464119b2f3b2b020f5af4b6422adbdfbdf 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 148adfba0d12883d1f24b24e31debfd8ba9a509d..8f869654165d268d4c23e4ed73383f0473b47979 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 a359180ffb0f8a05429260c1f6d70165680fb4b6..e6a9d360c4c2c74eeaa0fee511b981519051d259 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 138125ff0b7e65664df7176dc028cd45fed75eb8..25fa5da3ab0c28b5059a2627a92ee577c58007d3 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"/> @@ -578,6 +585,10 @@ Oczekiwana - [VALIDS] </notification> <notification name="SoundFileInvalidHeader"> 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"> @@ -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 1ab95eec0023f815ddbc3bf17f200ee8d9752cd5..c43a9bed811a09ba51110abfb79cd349297a2beb 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 a22d4b048273b634f8241b7d448d3c31f7d2b4cd..51ee3af00d830402797ff0f707f7ec7db9e2c917 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 166e3c4551f48ec0e1383527bb90dfc034360fd2..d32646d1a3db242c84d980388061d617f63a03d2 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 ba0b908394bdb649874d48008b1adf267e8e3f4d..7653e84cc09ed74993e1e15969ba80f090305318 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 4adac604f4600ece614358b80ff1cc17f703b223..7975e5574672a5691ef65bbe1f8e659b29922b9a 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 3bcf992d4d98648ba4f379a58749f1662fb68327..9530c781ab839091ada6722205eb00ef749397e8 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 e2c00c05069d0bbf2d5c9231eae085f1794001a1..d90a6d8726658e02066f47f96f8abb475709d330 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 3fa9cefeb67fe97602a5fdb1ee796a4bd02b2c22..f74ad916cd47b3fbdcd67c992d0ebcb4593bd344 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 bb2cd637b5fcd1de3711f3b7437400b1c0a712ac..b41069e8d75f53ca803ba3b6065f743ba3b5b74d 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 010d9b53d9ceaaf074b38d32e990426fda334bdb..f2a9b10f17371cdace338a68ce33269bd3e8a7c9 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 63ae1215e09ed70aae932993042e83749d2a40d3..7da1341e96be4dad20e028ef97cda0b8ae00fb7b 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 30432c509d5703a1b4f793bc09429aa59ff20b68..81da94a65952e37aec3130f46b2b95ee9b191f80 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 6b0ba44bb49b583eb9349a4c4668ab00c2e6b946..cdc833241d650d51815debdb80f2d59b37a65bce 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 0000000000000000000000000000000000000000..e1668e1ef15cfab25aae5600001baf6ea66e66c6 --- /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 fcb6b196350588dcc8f2ba4d6b4da9315d058624..1bd5b4a9123f15f536a6f461c7366f3c537601e3 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 b267610d333f0903a53b556232638c24424e62df..5e61f6269131a78ebc784b9a89025757bd3c831b 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 87894bb35808bdbddc3c4b1f01f99c77d8ab29c5..c7142c8419969df8242705a6699ed435466e41ba 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 0000000000000000000000000000000000000000..3d1160882b6af1587c4bb4e71137391740b9f2d4 --- /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 00dc84dd7a7604ed2afe60adadc1a53834d030b0..44dcb2112c845b292f336e05a3bc3fae5f5c283b 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 1a9f59bbffb65699b052522064eca815a7cd37e3..0f21aa9dd1f467e674ed1dc3e634e6d722f7c1c6 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 0000000000000000000000000000000000000000..4c2df2c1f3f022769f7bc3faf9fa04b6206fe581 --- /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 fd9cdd6ff0af18a934e9b82ba1ef0f241b6e7b06..a2f9b4176e1fe1b0f7a39cc5291a0d924d9ee7f9 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 24e5c2b8243004ce1842cda95d83fa7e370d9b63..fa0a5981a8711f62b775bf2f231710522d54790b 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 eaf9ae809b3dda458ba3a852f6c1bb8f2fc44327..c708cc0b99f6e61441502d2aa6be3f8577041ed0 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 fa89a3f72767ad4824ff26b7ff522b1621248e2c..e18900af68541b410e6b4ed5896b08c8cfa18be0 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 5e97dd89611417c86518f7ff7feed0cdac136cea..6aa0d27bb80881b6f0b102f7b8c8847251da9846 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 ea8bdd75b9fa53b0fd733949e301894f8bf60977..d1fb382a2dafb3cbb713743f7f84f274205c7bda 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 0000000000000000000000000000000000000000..5101579c6f21e8fde127f7e08487b5f6c50a29b4 --- /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 a43ac271a9dc786c0455e2722251c52149f9139d..3dff3d7c8a96d76881d90f76718e9526c9572710 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 d742038e1521a40089d8f21871f02e42ecd30378..6a3fe55de52df5be09679231de600e69391e76ba 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 95c37c53ca48eb6c358b596e0a9ff1d41b5b22e7..3bbf2b66f223dc8b67bb756e90a9f34e520808aa 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 9c3b9386e02bb665bff4e0af6068d72693bddf93..4b2e4bc5e0e342b072116b7858170a1efb9e21ad 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 ca67125c65fc618f31e7badc056f8fe4b80c0487..b444593af82dc5f62c382682e86a096d7eeb21c3 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 f8be9daf1bc62341543ffbc34037b14edddfbb10..b274945dbdb0dd61e3f2b6eee6a21aeab9766c47 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 9c8650e75e16a3446f32b99186c4e0a9bc8b1050..42df93fd867d324870f02c13db968411884d6c96 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 1a28f61c2da5e1cf717d5db13416f1a20554cda0..aa15a2445d236e491446f8b7aacfb7a0e6831510 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 d9614fe76bdf076787ea9c1f3ae8441ae65ed656..dcd9ba18154a4f03bb410d35bba64d139fee45cd 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 3ca9da06c9cd0ef3169ca215bef57a36e6f35beb..5f2f341e3fdacfdbdddac7591e4bc86b8cd4f6c6 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 5545dcda388bbd18cdd04091d531c2ec8f5a7220..d7fb585e352e739e356a97fa04110546ad583e15 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 0c6fb68140b0e6a81a196ff58d4513d437f553e5..d8d4a8fc1c64b63320eee14e28016d214b49db3a 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 fbbcf0d1be0020c1d9c755d14d3c5abd5a954686..f7890ae57d6b62e6b1b2289757730f69cb2fb2ff 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 9da851ffc4e0906cd3f7510a81698756f442a702..d691bb6c44f6aec08bdb7480729edda9a6234ff0 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 ea242f45cdad09799eabea2614371cc0e6acffd4..1888f191e2f4ed40c98bfe8439350ed59181dab6 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)