diff options
Diffstat (limited to 'indra')
164 files changed, 10199 insertions, 2727 deletions
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index a114d6e778..2c7bb77758 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -35,10 +35,10 @@ if (WINDOWS) # Don't build DLLs. set(BUILD_SHARED_LIBS OFF) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP" + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /ZI /MDd /MP" CACHE STRING "C++ compiler debug options" FORCE) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP" + "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /ZI /MD /MP" CACHE STRING "C++ compiler release-with-debug options" FORCE) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP" @@ -49,11 +49,12 @@ if (WINDOWS) add_definitions( /DLL_WINDOWS=1 + /DDOM_DYNAMIC /DUNICODE /D_UNICODE /GS /TP - /W3 + /W2 /c /Zc:forScope /nologo @@ -172,6 +173,8 @@ if (LINUX) add_definitions(-fvisibility=hidden) # don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway. add_definitions(-DLL_IGNORE_SIGCHLD) + add_definitions(-march=pentium4 -mfpmath=sse) + #add_definitions(-ftree-vectorize) # THIS CRASHES GCC 3.1-3.2 if (NOT STANDALONE) # this stops us requiring a really recent glibc at runtime add_definitions(-fno-stack-protector) @@ -211,7 +214,7 @@ if (LINUX OR DARWIN) set(GCC_WARNINGS "${GCC_WARNINGS} -Werror") endif (NOT GCC_DISABLE_FATAL_WARNINGS) - set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual") + set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor") set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}") diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 4fc25dcc24..cadd2608e2 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -34,6 +34,7 @@ set(cmake_SOURCE_FILES FindXmlRpcEpi.cmake FMOD.cmake FreeType.cmake + GLOD.cmake GStreamer010Plugin.cmake GooglePerfTools.cmake JPEG.cmake @@ -41,6 +42,7 @@ set(cmake_SOURCE_FILES LLAudio.cmake LLCharacter.cmake LLCommon.cmake + LLConvexDecomposition.cmake LLCrashLogger.cmake LLDatabase.cmake LLImage.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 89422fbdb2..9900a8fb45 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -38,6 +38,8 @@ if(WINDOWS) libapr-1.dll libaprutil-1.dll libapriconv-1.dll + libcollada14dom21.dll + glod.dll ) # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables @@ -48,6 +50,8 @@ if(WINDOWS) libapr-1.dll libaprutil-1.dll libapriconv-1.dll + libcollada14dom21.dll + glod.dll ) if(USE_GOOGLE_PERFTOOLS) diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake index d397b78f1c..9f8d99a0bf 100644 --- a/indra/cmake/LLPrimitive.cmake +++ b/indra/cmake/LLPrimitive.cmake @@ -1,7 +1,27 @@ # -*- cmake -*- +# these should be moved to their own cmake file +include(Prebuilt) +use_prebuilt_binary(colladadom) +use_prebuilt_binary(pcre) +use_prebuilt_binary(libxml) + set(LLPRIMITIVE_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llprimitive ) -set(LLPRIMITIVE_LIBRARIES llprimitive) +if (WINDOWS) + set(LLPRIMITIVE_LIBRARIES + llprimitive + libcollada14dom21 + ) +else (WINDOWS) + set(LLPRIMITIVE_LIBRARIES + llprimitive + collada14dom + xml2 + pcrecpp + pcre + ) +endif (WINDOWS) + diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index bfaf3f4f26..28feb523ea 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -81,7 +81,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # otherwise CMAKE_OSX_SYSROOT will be overridden here. We can't just check # for it being unset, as it gets set to the system default :( - # Default to building against the 10.4 SDK if no deployment target is + # Default to building against the 10.4u SDK if no deployment target is # specified. if (NOT CMAKE_OSX_DEPLOYMENT_TARGET) # NOTE: setting -isysroot is NOT adequate: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00696.html diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 2cd29448ae..bdd115364e 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -99,8 +99,9 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true)); addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true)); + addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); + addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); - addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false)); }; // static diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 2c2dc27aaa..27d35e95ff 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -114,8 +114,10 @@ public: AT_LINK_FOLDER = 25, // Inventory folder link - - AT_COUNT = 26, + AT_MESH = 49, + // Mesh data in our proprietary SLM format + + AT_COUNT = 50, // +*********************************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h index f3b5ca361f..10e6cb34bf 100644 --- a/indra/llcommon/lldefs.h +++ b/indra/llcommon/lldefs.h @@ -242,5 +242,13 @@ inline LLDATATYPE llclampb(const LLDATATYPE& a) return llmin(llmax(a, (LLDATATYPE)0), (LLDATATYPE)255); } +template <class LLDATATYPE> +inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs) +{ + LLDATATYPE tmp = lhs; + lhs = rhs; + rhs = tmp; +} + #endif // LL_LLDEFS_H diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp index 2610fe9e6a..16ae4cddde 100644 --- a/indra/llcommon/llfoldertype.cpp +++ b/indra/llcommon/llfoldertype.cpp @@ -95,6 +95,9 @@ LLFolderDictionary::LLFolderDictionary() addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE)); addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE)); addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE)); + + addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE)); + addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE)); addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE)); diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h index 7aa77f7f7e..409112a04e 100644 --- a/indra/llcommon/llfoldertype.h +++ b/indra/llcommon/llfoldertype.h @@ -86,9 +86,11 @@ public: FT_OUTFIT = 47, FT_MY_OUTFITS = 48, - FT_INBOX = 49, + FT_MESH = 49, - FT_COUNT = 50, + FT_INBOX = 50, + + FT_COUNT = 51, FT_NONE = -1 }; diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 2a8015e26d..5c6ca30cdd 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -73,25 +73,6 @@ void LLMemory::freeReserve() reserveMem = NULL; } -void* ll_allocate (size_t size) -{ - if (size == 0) - { - llwarns << "Null allocation" << llendl; - } - void *p = malloc(size); - if (p == NULL) - { - LLMemory::freeReserve(); - llerrs << "Out of memory Error" << llendl; - } - return p; -} - -void ll_release (void *p) -{ - free(p); -} //---------------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 1c6f64dd8b..35935efa88 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -32,14 +32,75 @@ #ifndef LLMEMORY_H #define LLMEMORY_H +#include <stdlib.h> +// A not necessarily efficient, but general, aligned malloc http://stackoverflow.com/questions/196329/osx-lacks-memalign +inline void* ll_aligned_malloc( size_t size, int align ) +{ + void* mem = malloc( size + (align - 1) + sizeof(void*) ); + char* aligned = ((char*)mem) + sizeof(void*); + aligned += align - ((uintptr_t)aligned & (align - 1)); + + ((void**)aligned)[-1] = mem; + return aligned; +} -extern S32 gTotalDAlloc; -extern S32 gTotalDAUse; -extern S32 gDACount; +inline void ll_aligned_free( void* ptr ) +{ + free( ((void**)ptr)[-1] ); +} -extern void* ll_allocate (size_t size); -extern void ll_release (void *p); +inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16(). +{ +#if defined(LL_WINDOWS) + return _mm_malloc(size, 16); +#elif defined(LL_DARWIN) + return malloc(size); // default osx malloc is 16 byte aligned. +#else + void *rtn; + if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size))) + return rtn; + else // bad alignment requested, or out of memory + return NULL; +#endif +} + +inline void ll_aligned_free_16(void *p) +{ +#if defined(LL_WINDOWS) + _mm_free(p); +#elif defined(LL_DARWIN) + return free(p); +#else + free(p); // posix_memalign() is compatible with heap deallocator +#endif +} + +inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32(). +{ +#if defined(LL_WINDOWS) + return _mm_malloc(size, 32); +#elif defined(LL_DARWIN) + return ll_aligned_malloc( size, 32 ); +#else + void *rtn; + if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size))) + return rtn; + else // bad alignment requested, or out of memory + return NULL; +#endif +} + +inline void ll_aligned_free_32(void *p) +{ +#if defined(LL_WINDOWS) + _mm_free(p); +#elif defined(LL_DARWIN) + ll_aligned_free( p ); +#else + free(p); // posix_memalign() is compatible with heap deallocator +#endif +} class LL_COMMON_API LLMemory { diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index cf337be161..fdeb93e27f 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -39,6 +39,7 @@ #include <iostream> #include "apr_base64.h" +#include "zlib/zlib.h" // for davep's dirty little zip functions #if !LL_WINDOWS #include <netinet/in.h> // htonl & ntohl @@ -1989,3 +1990,141 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd) return s; } + +//dirty little zippers -- yell at davep if these are horrid + +//return a string containing gzipped bytes of binary serialized LLSD +// VERY inefficient -- creates several copies of LLSD block in memory +std::string zip_llsd(LLSD& data) +{ + std::stringstream llsd_strm; + + LLSDSerialize::serialize(data, llsd_strm, LLSDSerialize::LLSD_BINARY); + + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION); + if (ret != Z_OK) + { + llwarns << "Failed to compress LLSD block." << llendl; + return std::string(); + } + + std::string source = llsd_strm.str(); + + strm.avail_in = source.size(); + strm.next_in = (U8*) source.data(); + U8* output = new U8[strm.avail_in]; + strm.avail_out = strm.avail_in; + strm.next_out = output; + ret = deflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END) + { + delete [] output; + llwarns << "Failed to compress LLSD block." << llendl; + return std::string(); + } + + std::string::size_type size = source.size()-strm.avail_out; + + std::string result((char*) output, size); + deflateEnd(&strm); + delete [] output; + + return result; +} + +//decompress a block of LLSD from provided istream +// not very efficient -- creats a copy of decompressed LLSD block in memory +// and deserializes from that copy using LLSDSerialize +bool unzip_llsd(LLSD& data, std::istream& is, S32 size) +{ + U8* result = NULL; + U32 cur_size = 0; + z_stream strm; + + const U32 CHUNK = 65536; + + U8 *in = new U8[size]; + is.read((char*) in, size); + + U8 out[CHUNK]; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = size; + strm.next_in = in; + + S32 ret = inflateInit(&strm); + + if (ret != Z_OK) + { + llerrs << "WTF?" << llendl; + } + + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR) + { + inflateEnd(&strm); + free(result); + delete [] in; + return false; + } + + switch (ret) + { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&strm); + free(result); + delete [] in; + return false; + break; + } + + U32 have = CHUNK-strm.avail_out; + + result = (U8*) realloc(result, cur_size + have); + memcpy(result+cur_size, out, have); + cur_size += have; + + } while (strm.avail_out == 0); + + inflateEnd(&strm); + delete [] in; + + if (ret != Z_STREAM_END) + { + free(result); + return false; + } + + //result now points to the decompressed LLSD block + { + std::string res_str((char*) result, cur_size); + std::istringstream istr(res_str); + + if (!LLSDSerialize::deserialize(data, istr, cur_size)) + { + llwarns << "Failed to unzip LLSD block" << llendl; + free(result); + return false; + } + } + + free(result); + return true; +} + + + diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 2f2b292189..390eaca783 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -796,4 +796,8 @@ public: } }; +//dirty little zip functions -- yell at davep +LL_COMMON_API std::string zip_llsd(LLSD& data); +LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size); + #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 37370e44e7..0385569a02 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -62,6 +62,12 @@ // //---------------------------------------------------------------------------- +#if !LL_DARWIN +U32 ll_thread_local sThreadID = 0; +#endif + +U32 LLThread::sIDIter = 0; + // // Handed to the APR thread creation function // @@ -72,10 +78,14 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // Set thread state to running threadp->mStatus = RUNNING; +#if !LL_DARWIN + sThreadID = threadp->mID; +#endif + // Run the user supplied function threadp->run(); - llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl; + //llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl; // We're done with the run function, this thread is done executing now. threadp->mStatus = STOPPED; @@ -90,6 +100,8 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : mAPRThreadp(NULL), mStatus(STOPPED) { + mID = ++sIDIter; + // Thread creation probably CAN be paranoid about APR being initialized, if necessary if (poolp) { @@ -273,7 +285,7 @@ void LLThread::wakeLocked() //============================================================================ LLMutex::LLMutex(apr_pool_t *poolp) : - mAPRMutexp(NULL) + mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) { //if (poolp) //{ @@ -305,7 +317,18 @@ LLMutex::~LLMutex() void LLMutex::lock() { +#if LL_DARWIN + if (mLockingThread == LLThread::currentID()) +#else + if (mLockingThread == sThreadID) +#endif + { //redundant lock + mCount++; + return; + } + apr_thread_mutex_lock(mAPRMutexp); + #if MUTEX_DEBUG // Have to have the lock before we can access the debug info U32 id = LLThread::currentID(); @@ -313,10 +336,22 @@ void LLMutex::lock() llerrs << "Already locked in Thread: " << id << llendl; mIsLocked[id] = TRUE; #endif + +#if LL_DARWIN + mLockingThread = LLThread::currentID(); +#else + mLockingThread = sThreadID; +#endif } void LLMutex::unlock() { + if (mCount > 0) + { //not the root unlock + mCount--; + return; + } + #if MUTEX_DEBUG // Access the debug info while we have the lock U32 id = LLThread::currentID(); @@ -324,6 +359,8 @@ void LLMutex::unlock() llerrs << "Not locked in Thread: " << id << llendl; mIsLocked[id] = FALSE; #endif + + mLockingThread = NO_THREAD; apr_thread_mutex_unlock(mAPRMutexp); } @@ -341,6 +378,11 @@ bool LLMutex::isLocked() } } +U32 LLMutex::lockingThread() const +{ + return mLockingThread; +} + //============================================================================ LLCondition::LLCondition(apr_pool_t *poolp) : diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index dbb8ec5231..0dc3e0b694 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -41,8 +41,17 @@ class LLThread; class LLMutex; class LLCondition; +#if LL_WINDOWS +#define ll_thread_local __declspec(thread) +#else +#define ll_thread_local __thread +#endif + class LL_COMMON_API LLThread { +private: + static U32 sIDIter; + public: typedef enum e_thread_status { @@ -83,6 +92,8 @@ public: apr_pool_t *getAPRPool() { return mAPRPoolp; } LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } + U32 getID() const { return mID; } + private: BOOL mPaused; @@ -97,6 +108,7 @@ protected: apr_pool_t *mAPRPoolp; BOOL mIsLocalPool; EThreadStatus mStatus; + U32 mID; //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. @@ -134,17 +146,27 @@ protected: class LL_COMMON_API LLMutex { public: + typedef enum + { + NO_THREAD = 0xFFFFFFFF + } e_locking_thread; + LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex virtual ~LLMutex(); void lock(); // blocks void unlock(); bool isLocked(); // non-blocking, but does do a lock/unlock so not free + U32 lockingThread() const; //get ID of locking thread protected: apr_thread_mutex_t *mAPRMutexp; + mutable U32 mCount; + mutable U32 mLockingThread; + apr_pool_t *mAPRPoolp; BOOL mIsLocalPool; + #if MUTEX_DEBUG std::map<U32, BOOL> mIsLocked; #endif diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h index 1a5678dde1..6eead924da 100644 --- a/indra/llcommon/stdenums.h +++ b/indra/llcommon/stdenums.h @@ -55,7 +55,8 @@ enum EDragAndDropType DAD_ANIMATION = 12, DAD_GESTURE = 13, DAD_LINK = 14, - DAD_COUNT = 15, // number of types in this enum + DAD_MESH = 15, + DAD_COUNT = 16, // number of types in this enum }; // Reasons for drags to be denied. diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index c050f20a9d..5c5500b6f4 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -89,6 +89,7 @@ LLInventoryDictionary::LLInventoryDictionary() addEntry(LLInventoryType::IT_WEARABLE, new InventoryEntry("wearable", "wearable", 2, LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART)); addEntry(LLInventoryType::IT_ANIMATION, new InventoryEntry("animation", "animation", 1, LLAssetType::AT_ANIMATION)); addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE)); + addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH)); } @@ -123,6 +124,32 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_NONE, // AT_LINK LLInventoryType::IT_NONE, // AT_LINK_FOLDER + + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_NONE, // AT_NONE + LLInventoryType::IT_MESH // AT_MESH }; // static diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index 20da954002..17ed3df951 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -67,7 +67,8 @@ public: IT_WEARABLE = 18, IT_ANIMATION = 19, IT_GESTURE = 20, - IT_COUNT = 21, + IT_MESH = 22, + IT_COUNT = 23, IT_NONE = -1 }; diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index e93fe90650..dda07133d5 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -22,6 +22,7 @@ set(llmath_SOURCE_FILES llsphere.cpp llvolume.cpp llvolumemgr.cpp + llvolumeoctree.cpp llsdutil_math.cpp m3math.cpp m4math.cpp @@ -62,8 +63,11 @@ set(llmath_HEADER_FILES llv4matrix3.h llv4matrix4.h llv4vector3.h + llvector4a.h + llmatrix4a.h llvolume.h llvolumemgr.h + llvolumeoctree.h llsdutil_math.h m3math.h m4math.h diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp index 487ed6451f..6b56e4870e 100644 --- a/indra/llmath/llcamera.cpp +++ b/indra/llmath/llcamera.cpp @@ -48,10 +48,10 @@ LLCamera::LLCamera() : mPlaneCount(6), mFrustumCornerDist(0.f) { + alignPlanes(); calculateFrustumPlanes(); } - LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) : LLCoordFrame(), mViewHeightInPixels(view_height_in_pixels), @@ -59,6 +59,7 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p mPlaneCount(6), mFrustumCornerDist(0.f) { + alignPlanes(); mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO); mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE); if(far_plane < 0) far_plane = DEFAULT_FAR_PLANE; @@ -67,6 +68,23 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p setView(vertical_fov_rads); } +LLCamera::~LLCamera() +{ + +} + +const LLCamera& LLCamera::operator=(const LLCamera& rhs) +{ + memcpy(this, &rhs, sizeof(LLCamera)); + alignPlanes(); + LLVector4a::memcpyNonAliased16((F32*) mAgentPlanes, (F32*) rhs.mAgentPlanes, 4*7); + return *this; +} + +void LLCamera::alignPlanes() +{ + mAgentPlanes = (LLPlane*) LL_NEXT_ALIGNED_ADDRESS<U8>(mAgentPlaneBuffer); +} // ---------------- LLCamera::getFoo() member functions ---------------- @@ -91,8 +109,8 @@ F32 LLCamera::getMaxView() const void LLCamera::setUserClipPlane(LLPlane plane) { mPlaneCount = 7; - mAgentPlanes[6].p = plane; - mAgentPlanes[6].mask = calcPlaneMask(plane); + mAgentPlanes[6] = plane; + mPlaneMask[6] = calcPlaneMask(plane); } void LLCamera::disableUserClipPlane() @@ -164,129 +182,66 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer) // ---------------- test methods ---------------- -S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius) -{ - static const LLVector3 scaler[] = { - LLVector3(-1,-1,-1), - LLVector3( 1,-1,-1), - LLVector3(-1, 1,-1), - LLVector3( 1, 1,-1), - LLVector3(-1,-1, 1), - LLVector3( 1,-1, 1), - LLVector3(-1, 1, 1), - LLVector3( 1, 1, 1) +S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius) +{ + static const LLVector4a scaler[] = { + LLVector4a(-1,-1,-1), + LLVector4a( 1,-1,-1), + LLVector4a(-1, 1,-1), + LLVector4a( 1, 1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1,-1, 1), + LLVector4a(-1, 1, 1), + LLVector4a( 1, 1, 1) }; U8 mask = 0; S32 result = 2; - /*if (mFrustumCornerDist > 0.f && radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist) - { //box is larger than frustum, check frustum quads against box planes - - static const LLVector3 dir[] = - { - LLVector3(1, 0, 0), - LLVector3(-1, 0, 0), - LLVector3(0, 1, 0), - LLVector3(0, -1, 0), - LLVector3(0, 0, 1), - LLVector3(0, 0, -1) - }; - - U32 quads[] = + for (U32 i = 0; i < mPlaneCount; i++) + { + mask = mPlaneMask[i]; + if (mask == 0xff) { - 0, 1, 2, 3, - 0, 1, 5, 4, - 2, 3, 7, 6, - 3, 0, 7, 4, - 1, 2, 6, 4, - 4, 5, 6, 7 - }; - - result = 0; - - BOOL total_inside = TRUE; - for (U32 i = 0; i < 6; i++) - { - LLVector3 p = center + radius.scaledVec(dir[i]); - F32 d = -p*dir[i]; - - for (U32 j = 0; j < 6; j++) - { //for each quad - F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d; - if (dist > 0) - { //at least one frustum point is outside the AABB - total_inside = FALSE; - for (U32 k = 1; k < 4; k++) - { //for each other point on quad - if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d <= 0.f) - { //quad is straddling some plane of AABB - return 1; - } - } - } - else - { - for (U32 k = 1; k < 4; k++) - { - if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f) - { - return 1; - } - } - } - } + continue; } - if (total_inside) + const LLPlane& p = mAgentPlanes[i]; + const LLVector4a& n = reinterpret_cast<const LLVector4a&>(p); + float d = p.mV[3]; + LLVector4a rscale; + rscale.setMul(radius, scaler[mask]); + + LLVector4a minp, maxp; + minp.setSub(center, rscale); + maxp.setAdd(center, rscale); + + if (n.dot3(minp) > -d) { - result = 1; + return 0; } - } - else*/ - { - for (U32 i = 0; i < mPlaneCount; i++) + + if (n.dot3(maxp) > -d) { - mask = mAgentPlanes[i].mask; - if (mask == 0xff) - { - continue; - } - LLPlane p = mAgentPlanes[i].p; - LLVector3 n = LLVector3(p); - float d = p.mV[3]; - LLVector3 rscale = radius.scaledVec(scaler[mask]); - - LLVector3 minp = center - rscale; - LLVector3 maxp = center + rscale; - - if (n * minp > -d) - { - return 0; - } - - if (n * maxp > -d) - { - result = 1; - } + result = 1; } } - return result; } -S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius) -{ - static const LLVector3 scaler[] = { - LLVector3(-1,-1,-1), - LLVector3( 1,-1,-1), - LLVector3(-1, 1,-1), - LLVector3( 1, 1,-1), - LLVector3(-1,-1, 1), - LLVector3( 1,-1, 1), - LLVector3(-1, 1, 1), - LLVector3( 1, 1, 1) + +S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius) +{ + static const LLVector4a scaler[] = { + LLVector4a(-1,-1,-1), + LLVector4a( 1,-1,-1), + LLVector4a(-1, 1,-1), + LLVector4a( 1, 1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1,-1, 1), + LLVector4a(-1, 1, 1), + LLVector4a( 1, 1, 1) }; U8 mask = 0; @@ -299,25 +254,28 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& r continue; } - mask = mAgentPlanes[i].mask; + mask = mPlaneMask[i]; if (mask == 0xff) { continue; } - LLPlane p = mAgentPlanes[i].p; - LLVector3 n = LLVector3(p); + + const LLPlane& p = mAgentPlanes[i]; + const LLVector4a& n = reinterpret_cast<const LLVector4a&>(p); float d = p.mV[3]; - LLVector3 rscale = radius.scaledVec(scaler[mask]); + LLVector4a rscale; + rscale.setMul(radius, scaler[mask]); - LLVector3 minp = center - rscale; - LLVector3 maxp = center + rscale; + LLVector4a minp, maxp; + minp.setSub(center, rscale); + maxp.setAdd(center, rscale); - if (n * minp > -d) + if (n.dot3(minp) > -d) { return 0; } - if (n * maxp > -d) + if (n.dot3(maxp) > -d) { result = 1; } @@ -447,12 +405,12 @@ int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) int res = 2; for (int i = 0; i < 6; i++) { - if (mAgentPlanes[i].mask == 0xff) + if (mPlaneMask[i] == 0xff) { continue; } - float d = mAgentPlanes[i].p.dist(sphere_center); + float d = mAgentPlanes[i].dist(sphere_center); if (d > radius) { @@ -644,12 +602,14 @@ void LLCamera::ignoreAgentFrustumPlane(S32 idx) return; } - mAgentPlanes[idx].mask = 0xff; - mAgentPlanes[idx].p.clearVec(); + mPlaneMask[idx] = 0xff; + mAgentPlanes[idx].clearVec(); } void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) { + alignPlanes(); + for (int i = 0; i < 8; i++) { mAgentFrustum[i] = frust[i]; @@ -662,27 +622,27 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) //order of planes is important, keep most likely to fail in the front of the list //near - frust[0], frust[1], frust[2] - mAgentPlanes[2].p = planeFromPoints(frust[0], frust[1], frust[2]); + mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]); //far - mAgentPlanes[5].p = planeFromPoints(frust[5], frust[4], frust[6]); + mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]); //left - mAgentPlanes[0].p = planeFromPoints(frust[4], frust[0], frust[7]); + mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]); //right - mAgentPlanes[1].p = planeFromPoints(frust[1], frust[5], frust[6]); + mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]); //top - mAgentPlanes[4].p = planeFromPoints(frust[3], frust[2], frust[6]); + mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]); //bottom - mAgentPlanes[3].p = planeFromPoints(frust[1], frust[0], frust[4]); + mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]); //cache plane octant facing mask for use in AABBInFrustum for (U32 i = 0; i < mPlaneCount; i++) { - mAgentPlanes[i].mask = calcPlaneMask(mAgentPlanes[i].p); + mPlaneMask[i] = calcPlaneMask(mAgentPlanes[i]); } } diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index 0c81067919..c40e819dcf 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -37,6 +37,7 @@ #include "llmath.h" #include "llcoordframe.h" #include "llplane.h" +#include "llvector4a.h" const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD; const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f; @@ -79,6 +80,14 @@ class LLCamera : public LLCoordFrame { public: + + LLCamera(const LLCamera& rhs) + { + *this = rhs; + } + + const LLCamera& operator=(const LLCamera& rhs); + enum { PLANE_LEFT = 0, PLANE_RIGHT = 1, @@ -129,13 +138,9 @@ private: LLPlane mWorldPlanes[PLANE_NUM]; LLPlane mHorizPlanes[HORIZ_PLANE_NUM]; - struct frustum_plane - { - frustum_plane() : mask(0) {} - LLPlane p; - U8 mask; - }; - frustum_plane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP + LLPlane* mAgentPlanes; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP + U8 mAgentPlaneBuffer[sizeof(LLPlane)*8]; + U8 mPlaneMask[7]; U32 mPlaneCount; //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in @@ -143,12 +148,14 @@ private: public: LLVector3 mAgentFrustum[8]; //8 corners of 6-plane frustum F32 mFrustumCornerDist; //distance to corner of frustum against far clip plane - LLPlane getAgentPlane(U32 idx) { return mAgentPlanes[idx].p; } + LLPlane& getAgentPlane(U32 idx) { return mAgentPlanes[idx]; } public: LLCamera(); LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane); - virtual ~LLCamera(){} // no-op virtual destructor + virtual ~LLCamera(); + + void alignPlanes(); void setUserClipPlane(LLPlane plane); void disableUserClipPlane(); @@ -199,8 +206,8 @@ public: S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const; S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); } S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); } - S32 AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius); - S32 AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius); + S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius); + S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius); //does a quick 'n dirty sphere-sphere check S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius); diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 2f34fb1bb0..59828ae565 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -35,6 +35,7 @@ #include "lltreenode.h" #include "v3math.h" +#include "llvector4a.h" #include <vector> #include <set> @@ -73,6 +74,13 @@ public: }; template <class T> +class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T> +{ +public: + virtual void traverse(const LLOctreeNode<T>* node); +}; + +template <class T> class LLOctreeNode : public LLTreeNode<T> { public: @@ -87,23 +95,22 @@ public: typedef LLOctreeNode<T> oct_node; typedef LLOctreeListener<T> oct_listener; - static const U8 OCTANT_POSITIVE_X = 0x01; - static const U8 OCTANT_POSITIVE_Y = 0x02; - static const U8 OCTANT_POSITIVE_Z = 0x04; - - LLOctreeNode( LLVector3d center, - LLVector3d size, + LLOctreeNode( const LLVector4a& center, + const LLVector4a& size, BaseType* parent, - U8 octant = 255) + S32 octant = -1) : mParent((oct_node*)parent), - mCenter(center), - mSize(size), mOctant(octant) { + mD = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*4); + + mD[CENTER] = center; + mD[SIZE] = size; + updateMinMax(); - if ((mOctant == 255) && mParent) + if ((mOctant == -1) && mParent) { - mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV); + mOctant = ((oct_node*) mParent)->getOctant(mD[CENTER]); } clearChildren(); @@ -117,43 +124,30 @@ public: { delete getChild(i); } + + ll_aligned_free_16(mD); } inline const BaseType* getParent() const { return mParent; } - inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; } - inline const LLVector3d& getCenter() const { return mCenter; } - inline const LLVector3d& getSize() const { return mSize; } - inline void setCenter(LLVector3d center) { mCenter = center; } - inline void setSize(LLVector3d size) { mSize = size; } - inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); } - inline U8 getOctant() const { return mOctant; } - inline void setOctant(U8 octant) { mOctant = octant; } + inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; } + inline const LLVector4a& getCenter() const { return mD[CENTER]; } + inline const LLVector4a& getSize() const { return mD[SIZE]; } + inline void setCenter(const LLVector4a& center) { mD[CENTER] = center; } + inline void setSize(const LLVector4a& size) { mD[SIZE] = size; } + inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); } + inline S32 getOctant() const { return mOctant; } + inline void setOctant(S32 octant) { mOctant = octant; } inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); } inline oct_node* getOctParent() { return (oct_node*) getParent(); } - U8 getOctant(const F64 pos[]) const //get the octant pos is in + S32 getOctant(const LLVector4a& pos) const //get the octant pos is in { - U8 ret = 0; - - if (pos[0] > mCenter.mdV[0]) - { - ret |= OCTANT_POSITIVE_X; - } - if (pos[1] > mCenter.mdV[1]) - { - ret |= OCTANT_POSITIVE_Y; - } - if (pos[2] > mCenter.mdV[2]) - { - ret |= OCTANT_POSITIVE_Z; - } - - return ret; + return pos.greaterThan4(mD[CENTER]).getComparisonMask() & 0x7; } - inline bool isInside(const LLVector3d& pos, const F64& rad) const + inline bool isInside(const LLVector4a& pos, const F32& rad) const { - return rad <= mSize.mdV[0]*2.0 && isInside(pos); + return rad <= mD[SIZE][0]*2.f && isInside(pos); } inline bool isInside(T* data) const @@ -161,29 +155,27 @@ public: return isInside(data->getPositionGroup(), data->getBinRadius()); } - bool isInside(const LLVector3d& pos) const + bool isInside(const LLVector4a& pos) const { - const F64& x = pos.mdV[0]; - const F64& y = pos.mdV[1]; - const F64& z = pos.mdV[2]; - - if (x > mMax.mdV[0] || x <= mMin.mdV[0] || - y > mMax.mdV[1] || y <= mMin.mdV[1] || - z > mMax.mdV[2] || z <= mMin.mdV[2]) + S32 gt = pos.greaterThan4(mD[MAX]).getComparisonMask() & 0x7; + if (gt) { return false; } - + + S32 lt = pos.lessEqual4(mD[MIN]).getComparisonMask() & 0x7; + if (lt) + { + return false; + } + return true; } void updateMinMax() { - for (U32 i = 0; i < 3; i++) - { - mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i]; - mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i]; - } + mD[MAX].setAdd(mD[CENTER], mD[SIZE]); + mD[MIN].setSub(mD[CENTER], mD[SIZE]); } inline oct_listener* getOctListener(U32 index) @@ -196,34 +188,34 @@ public: return contains(xform->getBinRadius()); } - bool contains(F64 radius) + bool contains(F32 radius) { if (mParent == NULL) { //root node contains nothing return false; } - F64 size = mSize.mdV[0]; - F64 p_size = size * 2.0; + F32 size = mD[SIZE][0]; + F32 p_size = size * 2.f; - return (radius <= 0.001 && size <= 0.001) || + return (radius <= 0.001f && size <= 0.001f) || (radius <= p_size && radius > size); } - static void pushCenter(LLVector3d ¢er, const LLVector3d &size, const T* data) + static void pushCenter(LLVector4a ¢er, const LLVector4a &size, const T* data) { - const LLVector3d& pos = data->getPositionGroup(); - for (U32 i = 0; i < 3; i++) - { - if (pos.mdV[i] > center.mdV[i]) - { - center.mdV[i] += size.mdV[i]; - } - else - { - center.mdV[i] -= size.mdV[i]; - } - } + const LLVector4a& pos = data->getPositionGroup(); + + LLVector4a gt = pos.greaterThan4(center); + + LLVector4a up; + up.mQ = _mm_and_ps(size.mQ, gt.mQ); + + LLVector4a down; + down.mQ = _mm_andnot_ps(gt.mQ, size.mQ); + + center.add(up); + center.sub(down); } void accept(oct_traveler* visitor) { visitor->visit(this); } @@ -242,21 +234,21 @@ public: void accept(tree_traveler* visitor) const { visitor->visit(this); } void accept(oct_traveler* visitor) const { visitor->visit(this); } - oct_node* getNodeAt(const LLVector3d& pos, const F64& rad) + oct_node* getNodeAt(const LLVector4a& pos, const F32& rad) { LLOctreeNode<T>* node = this; if (node->isInside(pos, rad)) { //do a quick search by octant - U8 octant = node->getOctant(pos.mdV); + S32 octant = node->getOctant(pos); BOOL keep_going = TRUE; //traverse the tree until we find a node that has no node //at the appropriate octant or is smaller than the object. //by definition, that node is the smallest node that contains // the data - while (keep_going && node->getSize().mdV[0] >= rad) + while (keep_going && node->getSize()[0] >= rad) { keep_going = FALSE; for (U32 i = 0; i < node->getChildCount() && !keep_going; i++) @@ -264,7 +256,7 @@ public: if (node->getChild(i)->getOctant() == octant) { node = node->getChild(i); - octant = node->getOctant(pos.mdV); + octant = node->getOctant(pos); keep_going = TRUE; } } @@ -282,7 +274,7 @@ public: { if (data == NULL) { - //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl; + OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl; return false; } LLOctreeNode<T>* parent = getOctParent(); @@ -292,7 +284,7 @@ public: { if (getElementCount() < LL_OCTREE_MAX_CAPACITY && (contains(data->getBinRadius()) || - (data->getBinRadius() > getSize().mdV[0] && + (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) { //it belongs here #if LL_OCTREE_PARANOIA_CHECK @@ -323,16 +315,22 @@ public: } //it's here, but no kids are in the right place, make a new kid - LLVector3d center(getCenter()); - LLVector3d size(getSize()*0.5); + LLVector4a center = getCenter(); + LLVector4a size = getSize(); + size.mul(0.5f); //push center in direction of data LLOctreeNode<T>::pushCenter(center, size, data); // handle case where floating point number gets too small - if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO && - llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO && - llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO) + LLVector4a val; + val.setSub(center, getCenter()); + val.setAbs(val); + LLVector4a app_zero; + app_zero.mQ = F_APPROXIMATELY_ZERO_4A; + S32 lt = val.lessThan4(app_zero).getComparisonMask() & 0x7; + + if( lt == 0x7 ) { mData.insert(data); BaseType::insert(data); @@ -350,7 +348,7 @@ public: //make sure no existing node matches this position for (U32 i = 0; i < getChildCount(); i++) { - if (mChild[i]->getCenter() == center) + if (mChild[i]->getCenter().equal3(center)) { OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl; return false; @@ -368,7 +366,7 @@ public: else { //it's not in here, give it to the root - //OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl; + OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl; oct_node* node = this; @@ -475,13 +473,19 @@ public: void addChild(oct_node* child, BOOL silent = FALSE) { #if LL_OCTREE_PARANOIA_CHECK + + if (child->getSize().equal3(getSize())) + { + OCT_ERRS << "Child size is same as parent size!" << llendl; + } + for (U32 i = 0; i < getChildCount(); i++) { - if(mChild[i]->getSize() != child->getSize()) + if(!mChild[i]->getSize().equal3(child->getSize())) { OCT_ERRS <<"Invalid octree child size." << llendl; } - if (mChild[i]->getCenter() == child->getCenter()) + if (mChild[i]->getCenter().equal3(child->getCenter())) { OCT_ERRS <<"Duplicate octree child position." << llendl; } @@ -506,7 +510,7 @@ public: } } - void removeChild(U8 index, BOOL destroy = FALSE) + void removeChild(S32 index, BOOL destroy = FALSE) { for (U32 i = 0; i < this->getListenerCount(); i++) { @@ -547,18 +551,26 @@ public: } } - //OCT_ERRS << "Octree failed to delete requested child." << llendl; + OCT_ERRS << "Octree failed to delete requested child." << llendl; } protected: + typedef enum + { + CENTER = 0, + SIZE = 1, + MAX = 2, + MIN = 3 + } eDName; + + LLVector4a* mD; + + oct_node* mParent; + S32 mOctant; + child_list mChild; element_list mData; - oct_node* mParent; - LLVector3d mCenter; - LLVector3d mSize; - LLVector3d mMax; - LLVector3d mMin; - U8 mOctant; + }; //just like a regular node, except it might expand on insert and compress on balance @@ -569,9 +581,9 @@ public: typedef LLOctreeNode<T> BaseType; typedef LLOctreeNode<T> oct_node; - LLOctreeRoot( LLVector3d center, - LLVector3d size, - BaseType* parent) + LLOctreeRoot(const LLVector4a& center, + const LLVector4a& size, + BaseType* parent) : BaseType(center, size, parent) { } @@ -612,28 +624,33 @@ public: { if (data == NULL) { - //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl; + OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl; return false; } if (data->getBinRadius() > 4096.0) { - //OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl; + OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl; return false; } - const F64 MAX_MAG = 1024.0*1024.0; + LLVector4a MAX_MAG; + MAX_MAG.splat(1024.f*1024.f); + + const LLVector4a& v = data->getPositionGroup(); + + LLVector4a val; + val.setSub(v, BaseType::mD[BaseType::CENTER]); + val.setAbs(val); + S32 lt = val.lessThan4(MAX_MAG).getComparisonMask() & 0x7; - const LLVector3d& v = data->getPositionGroup(); - if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG && - fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG && - fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG)) + if (lt != 0x7) { - //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl; + OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl; return false; } - if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())) + if (this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())) { //we got it, just act like a branch oct_node* node = getNodeAt(data); @@ -649,31 +666,34 @@ public: else if (this->getChildCount() == 0) { //first object being added, just wrap it up - while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))) + while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))) { - LLVector3d center, size; + LLVector4a center, size; center = this->getCenter(); size = this->getSize(); LLOctreeNode<T>::pushCenter(center, size, data); this->setCenter(center); - this->setSize(size*2); + size.mul(2.f); + this->setSize(size); this->updateMinMax(); } LLOctreeNode<T>::insert(data); } else { - while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))) + while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))) { //the data is outside the root node, we need to grow - LLVector3d center(this->getCenter()); - LLVector3d size(this->getSize()); + LLVector4a center(this->getCenter()); + LLVector4a size(this->getSize()); //expand this node - LLVector3d newcenter(center); + LLVector4a newcenter(center); LLOctreeNode<T>::pushCenter(newcenter, size, data); this->setCenter(newcenter); - this->setSize(size*2); + LLVector4a size2 = size; + size2.mul(2.f); + this->setSize(size2); this->updateMinMax(); //copy our children to a new branch @@ -710,4 +730,15 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node) traverse(node->getChild(i)); } } + +template <class T> +void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node) +{ + for (U32 i = 0; i < node->getChildCount(); i++) + { + traverse(node->getChild(i)); + } + node->accept(this); +} + #endif diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h index ee9836241a..e6d2521b2a 100644 --- a/indra/llmath/lltreenode.h +++ b/indra/llmath/lltreenode.h @@ -34,6 +34,9 @@ #include "stdtypes.h" #include "xform.h" +#include "llpointer.h" +#include "llrefcount.h" + #include <vector> template <class T> class LLTreeNode; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 3c3356f41d..25db58491e 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,4 +1,5 @@ /** + * @file llvolume.cpp * * $LicenseInfo:firstyear=2002&license=viewergpl$ @@ -30,6 +31,7 @@ */ #include "linden_common.h" +#include "llmemory.h" #include "llmath.h" #include <set> @@ -43,9 +45,14 @@ #include "v4math.h" #include "m4math.h" #include "m3math.h" +#include "llmatrix4a.h" +#include "lloctree.h" #include "lldarray.h" #include "llvolume.h" +#include "llvolumeoctree.h" #include "llstl.h" +#include "llsdserialize.h" +#include "llvector4a.h" #define DEBUG_SILHOUETTE_BINORMALS 0 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette @@ -105,127 +112,264 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) { - float fAWdU[3]; - LLVector3 dir; - LLVector3 diff; + 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.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; + 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.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; + 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 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) { - F32 u, v, t; /* find vectors for two edges sharing vert0 */ - LLVector3 edge1 = vert1 - vert0; + LLVector4a edge1; + edge1.setSub(vert1, vert0); - LLVector3 edge2 = vert2 - vert0;; + LLVector4a edge2; + edge2.setSub(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; + LLVector4a pvec; + pvec.setCross3(dir, edge2); - if (!two_sided) + /* if determinant is near zero, ray lies in plane of triangle */ + LLVector4a det; + det.setAllDot3(edge1, pvec); + + if (det.greaterEqual4(LLVector4a::getApproximatelyZero()).getComparisonMask() & 0x7) { - if (det < F_APPROXIMATELY_ZERO) - { - return FALSE; - } - /* calculate distance from vert0 to ray origin */ - LLVector3 tvec = orig - vert0; + LLVector4a tvec; + tvec.setSub(orig, vert0); /* calculate U parameter and test bounds */ - u = tvec * pvec; + LLVector4a u; + u.setAllDot3(tvec,pvec); - if (u < 0.f || u > det) + if ((u.greaterEqual4(LLVector4a::getZero()).getComparisonMask() & 0x7) && + (u.lessEqual4(det).getComparisonMask() & 0x7)) { - return FALSE; + /* 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.greaterEqual4(LLVector4a::getZero()).getComparisonMask() & 0x7; + S32 sum_lequal = sum_uv.lessEqual4(det).getComparisonMask() & 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; + } } - - /* 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; - } + 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); - /* 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; + /* if determinant is near zero, ray lies in plane of triangle */ + F32 det = edge1.dot3(pvec); + + + 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); - else // two sided - { - if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) - { - return FALSE; - } - F32 inv_det = 1.0 / det; + /* calculate U parameter and test bounds */ + u = (tvec.dot3(pvec)) * inv_det; + if (u < 0.f || u > 1.f) + { + return FALSE; + } - /* calculate distance from vert0 to ray origin */ - LLVector3 tvec = orig - vert0; + /* prepare to test V parameter */ + tvec.sub(edge1); - /* calculate U parameter and test bounds */ - u = (tvec * pvec) * inv_det; - if (u < 0.f || u > 1.f) + /* calculate V parameter and test bounds */ + v = (dir.dot3(tvec)) * inv_det; + + if (v < 0.f || u + v > 1.f) + { + return FALSE; + } + + /* calculate t, ray intersects triangle */ + t = (edge2.dot3(tvec)) * 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) + { + LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); + + LLVector4a& min = node->mExtents[0]; + LLVector4a& max = node->mExtents[1]; + + if (branch->getElementCount() != 0) { - return FALSE; + const LLVolumeTriangle* tri = *(branch->getData().begin()); + + min = *(tri->mV[0]); + max = *(tri->mV[0]); + + for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = + branch->getData().begin(); iter != branch->getData().end(); ++iter) + { + //stretch by triangles in node + tri = *iter; + + min.setMin(*tri->mV[0]); + min.setMin(*tri->mV[1]); + min.setMin(*tri->mV[2]); + + max.setMax(*tri->mV[0]); + max.setMax(*tri->mV[1]); + max.setMax(*tri->mV[2]); } - /* 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) + for (S32 i = 0; i < branch->getChildCount(); ++i) + { //stretch by child extents + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); + min.setMin(child->mExtents[0]); + max.setMax(child->mExtents[1]); + } + } + else if (branch->getChildCount() != 0) { - return FALSE; + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0); + + min = child->mExtents[0]; + max = child->mExtents[1]; + + for (S32 i = 1; i < branch->getChildCount(); ++i) + { //stretch by child extents + child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); + min.setMin(child->mExtents[0]); + max.setMax(child->mExtents[1]); + } + } + else + { + llerrs << "WTF? Empty leaf" << llendl; } + + node->mBounds[0].setAdd(min, max); + node->mBounds[0].mul(0.5f); - /* calculate t, ray intersects triangle */ - t = (edge2 * qvec) * inv_det; + node->mBounds[1].setSub(max,min); + node->mBounds[1].mul(0.5f); } - - if (intersection_a != NULL) - *intersection_a = u; - if (intersection_b != NULL) - *intersection_b = v; - if (intersection_t != NULL) - *intersection_t = t; - - - return TRUE; -} +}; //------------------------------------------------------------------- @@ -1675,7 +1819,9 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mFaceMask = 0x0; mDetail = detail; mSculptLevel = -2; - + mIsTetrahedron = FALSE; + mLODScaleBias.setVec(1,1,1); + // set defaults if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) { @@ -1690,7 +1836,8 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mGenerateSingleFace = generate_single_face; generate(); - if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE) + + if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE) { createVolumeFaces(); } @@ -1841,6 +1988,585 @@ BOOL LLVolume::generate() return FALSE; } +void LLVolumeFace::VertexData::init() +{ + if (!mData) + { + mData = (LLVector4a*) ll_aligned_malloc_16(32); + } +} + +LLVolumeFace::VertexData::VertexData() +{ + mData = NULL; + init(); +} + +LLVolumeFace::VertexData::VertexData(const VertexData& rhs) +{ + mData = NULL; + *this = rhs; +} + +const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs) +{ + if (this != &rhs) + { + init(); + LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 8); + mTexCoord = rhs.mTexCoord; + } + return *this; +} + +LLVolumeFace::VertexData::~VertexData() +{ + ll_aligned_free_16(mData); +} + +LLVector4a& LLVolumeFace::VertexData::getPosition() +{ + return mData[POSITION]; +} + +LLVector4a& LLVolumeFace::VertexData::getNormal() +{ + return mData[NORMAL]; +} + +const LLVector4a& LLVolumeFace::VertexData::getPosition() const +{ + return mData[POSITION]; +} + +const LLVector4a& LLVolumeFace::VertexData::getNormal() const +{ + return mData[NORMAL]; +} + + +void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos) +{ + mData[POSITION] = pos; +} + +void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm) +{ + mData[NORMAL] = norm; +} + +bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const +{ + if (mData[POSITION].notEqual3(rhs.getPosition())) + { + return mData[POSITION].less3(rhs.getPosition()); + } + + if (mData[NORMAL].notEqual3(rhs.getNormal())) + { + return mData[NORMAL].less3(rhs.getNormal()); + } + + if (mTexCoord != rhs.mTexCoord) + { + return mTexCoord < rhs.mTexCoord; + } + + return false; +} + +bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const +{ + return mData[POSITION].equal3(rhs.getPosition()) && + mData[NORMAL].equal3(rhs.getNormal()) && + mTexCoord == rhs.mTexCoord; +} + +bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const +{ + bool retval = false; + if (rhs.mData[POSITION].equal3(mData[POSITION]) && rhs.mTexCoord == mTexCoord) + { + if (angle_cutoff > 1.f) + { + retval = (mData[NORMAL].equal3(rhs.mData[NORMAL])); + } + else + { + F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]); + retval = cur_angle > angle_cutoff; + } + } + + return retval; +} + +BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name) +{ + std::ifstream is; + + is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary); + + BOOL success = createVolumeFacesFromStream(is); + + is.close(); + + return success; +} + +BOOL LLVolume::createVolumeFacesFromStream(std::istream& is) +{ + mSculptLevel = -1; // default is an error occured + + LLSD header; + { + if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024)) + { + llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; + return FALSE; + } + } + + std::string nm[] = + { + "lowest_lod", + "low_lod", + "medium_lod", + "high_lod" + }; + + S32 lod = llclamp((S32) mDetail, 0, 3); + + while (lod < 4 && + (header[nm[lod]]["offset"].asInteger() == -1 || + header[nm[lod]]["size"].asInteger() == 0 )) + { + ++lod; + } + + if (lod >= 4) + { + lod = llclamp((S32) mDetail, 0, 3); + + while (lod >= 0 && + (header[nm[lod]]["offset"].asInteger() == -1 || + header[nm[lod]]["size"].asInteger() == 0) ) + { + --lod; + } + + if (lod < 0) + { + llwarns << "Mesh header missing LOD offsets. Not a valid mesh asset!" << llendl; + return FALSE; + } + } + + is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); + + return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()); +} + +bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) +{ + //input stream is now pointing at a zlib compressed block of LLSD + //decompress block + LLSD mdl; + if (!unzip_llsd(mdl, is, size)) + { + llwarns << "not a valid mesh asset!" << llendl; + return false; + } + + { + U32 face_count = mdl.size(); + + if (face_count == 0) + { + llerrs << "WTF?" << llendl; + } + + mVolumeFaces.resize(face_count); + + for (U32 i = 0; i < face_count; ++i) + { + LLSD::Binary pos = mdl[i]["Position"]; + LLSD::Binary norm = mdl[i]["Normal"]; + LLSD::Binary tc = mdl[i]["TexCoord0"]; + LLSD::Binary idx = mdl[i]["TriangleList"]; + + LLVolumeFace& face = mVolumeFaces[i]; + + //copy out indices + face.resizeIndices(idx.size()/2); + + if (idx.empty() || face.mNumIndices < 3) + { //why is there an empty index list? + llerrs <<"WTF?" << llendl; + continue; + } + + U16* indices = (U16*) &(idx[0]); + for (U32 j = 0; j < idx.size()/2; ++j) + { + face.mIndices[j] = indices[j]; + } + + //copy out vertices + U32 num_verts = pos.size()/(3*2); + face.resizeVertices(num_verts); + + if (mdl[i].has("Weights")) + { + face.allocateWeights(num_verts); + + LLSD::Binary weights = mdl[i]["Weights"]; + + U32 idx = 0; + + U32 cur_vertex = 0; + while (idx < weights.size() && cur_vertex < num_verts) + { + const U8 END_INFLUENCES = 0xFF; + U8 joint = weights[idx++]; + + U32 cur_influence = 0; + LLVector4 wght(0,0,0,0); + + while (joint != END_INFLUENCES) + { + U16 influence = weights[idx++]; + influence |= ((U16) weights[idx++] << 8); + + F32 w = llmin((F32) influence / 65535.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& min = face.mExtents[0]; + LLVector4a& max = face.mExtents[1]; + + min.clear(); + max.clear(); + + 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); + + if (j == 0) + { + min = *pos_out; + max = min; + } + else + { + min.setMin(*pos_out); + max.setMax(*pos_out); + } + + 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; + } + } + + } + } + + mSculptLevel = 0; // success! + 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(LLVolume* volume) +{ + mVolumeFaces = volume->mVolumeFaces; + mSculptLevel = 0; + mIsTetrahedron = FALSE; +} + + +S32 LLVolume::getNumFaces() const +{ +#if LL_MESH_ENABLED + U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK); + + if (sculpt_type == LL_SCULPT_TYPE_MESH) + { + return LL_SCULPT_MESH_MAX_FACES; + } +#endif + + return (S32)mProfilep->mFaces.size(); +} + void LLVolume::createVolumeFaces() { @@ -2320,7 +3046,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const return mSculptID < params.mSculptID; } - return mSculptType < params.mSculptType; @@ -3378,34 +4103,66 @@ S32 LLVolume::getNumTriangleIndices() const 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, - const LLMatrix4& mat, - const LLMatrix3& norm_mat, + 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 LL_MESH_ENABLED + if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + { + return; + } +#endif + S32 cur_index = 0; //for each face for (face_list_t::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); ++iter) { - const LLVolumeFace& face = *iter; + LLVolumeFace& face = *iter; - if (!(face_mask & (0x1 << cur_index++))) + if (!(face_mask & (0x1 << cur_index++)) || + face.mNumIndices == 0 || face.mEdge.empty()) { continue; } + if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { } @@ -3418,7 +4175,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, #if DEBUG_SILHOUETTE_EDGE_MAP //for each triangle - U32 count = face.mIndices.size(); + U32 count = face.mNumIndices; for (U32 j = 0; j < count/3; j++) { //get vertices S32 v1 = face.mIndices[j*3+0]; @@ -3426,9 +4183,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, 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; + 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++) { @@ -3446,9 +4203,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, 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; + LLVector3 nCenter = (face.mVertices[v1].getPosition() + + face.mVertices[v2].getPosition() + + face.mVertices[v3].getPosition()) / 3.0f; //draw line vertices.push_back(cCenter); @@ -3471,15 +4228,15 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, #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); + 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].mPosition); - vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f); + 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()); @@ -3497,26 +4254,36 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, //for each triangle std::vector<U8> fFacing; - vector_append(fFacing, face.mIndices.size()/3); - for (U32 j = 0; j < face.mIndices.size()/3; j++) + 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]; - LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) % - (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition); - - if (norm.magVecSquared() < 0.00000001f) + 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 - LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition); - bool away = view * norm > 0.0f; + LLVector4a view; + view.setSub(obj_cam_vec, v[v1]); + bool away = view.dot3(norm) > 0.0f; if (away) { fFacing[j] = AWAY; @@ -3529,7 +4296,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, } //for each triangle - for (U32 j = 0; j < face.mIndices.size()/3; j++) + for (U32 j = 0; j < face.mNumIndices/3; j++) { if (fFacing[j] == (AWAY | TOWARDS)) { //this is a degenerate triangle @@ -3562,15 +4329,21 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, 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); + LLVector4a t; + mat.affineTransform(v[v1], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); - vertices.push_back(face.mVertices[v2].mPosition*mat); - LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat; - norm2.normVec(); - normals.push_back(norm2); + 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()); } @@ -3585,6 +4358,19 @@ 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; @@ -3601,16 +4387,23 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, end_face = face; } - LLVector3 dir = end - start; + 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++) { - const LLVolumeFace &face = getVolumeFace((U32)i); + LLVolumeFace &face = mVolumeFaces[i]; + + LLVector4a box_center; + box_center.setAdd(face.mExtents[0], face.mExtents[1]); + box_center.mul(0.5f); - LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f; - LLVector3 box_size = face.mExtents[1] - face.mExtents[0]; + LLVector4a box_size; + box_size.setSub(face.mExtents[1], face.mExtents[0]); if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) { @@ -3618,56 +4411,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, { 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 (!face.mOctree) + { + face.createOctree(); + } - 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; + //LLVector4a* p = (LLVector4a*) face.mPositions; - if (intersection != NULL) - { - *intersection = start + dir * closest_t; - } - - if (tex_coord != NULL) + LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal); + intersect.traverse(face.mOctree); + if (intersect.mHitFace) { - *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); - } - - } - } + hit_face = i; } } } @@ -4115,11 +4871,28 @@ BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const 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; } @@ -4127,6 +4900,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd) { mPathParams.fromLLSD(sd["path"]); mProfileParams.fromLLSD(sd["profile"]); + sculptFromLLSD(sd["sculpt"]); + return true; } @@ -4169,6 +4944,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity // 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(); @@ -4409,9 +5190,156 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) 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*) ll_aligned_malloc_16(48); + 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*) ll_aligned_malloc_16(48); + 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, 12); + + resizeVertices(src.mNumVertices); + resizeIndices(src.mNumIndices); + + if (mNumVertices) + { + S32 vert_size = mNumVertices*4; + S32 tc_size = (mNumVertices*8+0xF) & ~0xF; + tc_size /= 4; + + 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 + { + ll_aligned_free_16(mBinormals); + mBinormals = NULL; + } + + if (src.mWeights) + { + allocateWeights(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); + } + else + { + ll_aligned_free_16(mWeights); + mWeights = NULL; + } + } + + if (mNumIndices) + { + S32 idx_size = (mNumIndices*2+0xF) & ~0xF; + idx_size /= 4; + + LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); + } + + //delete + return *this; +} + +LLVolumeFace::~LLVolumeFace() +{ + ll_aligned_free_16(mExtents); + mExtents = NULL; + + freeData(); +} + +void LLVolumeFace::freeData() +{ + ll_aligned_free_16(mPositions); + mPositions = NULL; + ll_aligned_free_16(mNormals); + mNormals = NULL; + ll_aligned_free_16(mTexCoords); + mTexCoords = NULL; + ll_aligned_free_16(mIndices); + mIndices = NULL; + ll_aligned_free_16(mBinormals); + mBinormals = NULL; + ll_aligned_free_16(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); @@ -4427,6 +5355,155 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) } } +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().equal3(rhs.getPosition()) && + mTexCoord == rhs.mTexCoord && + getNormal().equal3(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; + + 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().getF32())); + 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().getF32())].push_back(d); + } + } + } + + swapData(new_face); +} + + +void LLVolumeFace::createOctree() +{ + LLVector4a center; + LLVector4a size; + center.splat(0.f); + size.splat(1.f); + + mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL); + new LLVolumeOctreeListener(mOctree); + + for (U32 i = 0; i < mNumIndices; i+= 3) + { + 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]]; + + tri->mV[0] = &v0; + tri->mV[1] = &v1; + tri->mV[2] = &v2; + + tri->mIndex[0] = mIndices[i]; + tri->mIndex[1] = mIndices[i+1]; + tri->mIndex[2] = mIndices[i+2]; + + LLVector4a min = v0; + min.setMin(v1); + min.setMin(v2); + + LLVector4a max = v0; + max.setMax(v1); + max.setMax(v2); + + LLVector4a center; + center.setAdd(min, max); + center.mul(0.5f); + + *tri->mPositionGroup = center; + + LLVector4a size; + size.setSub(max,min); + + tri->mRadius = size.length3() * 0.5f; + + mOctree->insert(tri); + } + + LLVolumeOctreeRebound rebound(this); + rebound.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, @@ -4434,10 +5511,21 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0, F32 coef01, F32 coef02) { - vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*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.mNormal = v0.mNormal; - vout.mBinormal = v0.mBinormal; + vout.setNormal(v0.getNormal()); } BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) @@ -4457,84 +5545,112 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) num_vertices = (grid_size+1)*(grid_size+1); num_indices = quad_count * 4; - LLVector3& min = mExtents[0]; - LLVector3& max = mExtents[1]; + 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(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(); - } + 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]; + } - 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); + { + 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 (gx == 0 && gy == 0) - { - min = max = newVert.mPosition; - } - else + 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++) { - update_min_max(min,max,newVert.mPosition); + 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 = max = newVert.getPosition(); + } + else + { + min.setMin(newVert.getPosition()); + max.setMax(newVert.getPosition()); + } } } - } - mCenter = (min + max) * 0.5f; + mCenter->setAdd(min, max); + mCenter->mul(0.5f); + } if (!partial_build) { -#if GEN_TRI_STRIP - mTriStrip.clear(); -#endif + 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++) { @@ -4545,59 +5661,23 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) { for(S32 i=5;i>=0;i--) { - mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); - } - + *out++ = ((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]); + *out++ = ((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 } @@ -4629,17 +5709,31 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) num_vertices = profile.size(); num_indices = (profile.size() - 2)*3; - mVertices.resize(num_vertices); + if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) + { + resizeVertices(num_vertices+1); + allocateBinormals(num_vertices+1); - if (!partial_build) + if (!partial_build) + { + resizeIndices(num_indices+3); + } + } + else { - mIndices.resize(num_indices); + 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.clearVec(); + mCenter->clear(); S32 offset = 0; if (mTypeMask & TOP_MASK) @@ -4657,82 +5751,90 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) LLVector2 cuv; LLVector2 min_uv, max_uv; - LLVector3& min = mExtents[0]; - LLVector3& max = mExtents[1]; + 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) { - mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; - mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f; + tc[i].mV[0] = profile[i].mV[0]+0.5f; + tc[i].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]; + tc[i].mV[0] = profile[i].mV[0]+0.5f; + tc[i].mV[1] = 0.5f - profile[i].mV[1]; } - mVertices[i].mPosition = mesh[i + offset].mPos; + pos[i].load3(mesh[i + offset].mPos.mV); if (i == 0) { - min = max = mVertices[i].mPosition; - min_uv = max_uv = mVertices[i].mTexCoord; + min = max = pos[i]; + min_uv = max_uv = tc[i]; } else { - update_min_max(min,max, mVertices[i].mPosition); - update_min_max(min_uv, max_uv, mVertices[i].mTexCoord); + update_min_max(min,max,pos[i]); + update_min_max(min_uv, max_uv, tc[i]); } } - mCenter = (min+max)*0.5f; + mCenter->setAdd(min, max); + mCenter->mul(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(); + LLVector4a binormal; + calc_binormal_from_triangle(binormal, + *mCenter, cuv, + pos[0], tc[0], + pos[1], tc[1]); + binormal.normalize3fast(); - LLVector3 d0; - LLVector3 d1; - LLVector3 normal; + LLVector4a normal; + LLVector4a d0, d1; + - d0 = mCenter-mVertices[0].mPosition; - d1 = mCenter-mVertices[1].mPosition; + d0.setSub(*mCenter, pos[0]); + d1.setSub(*mCenter, pos[1]); - normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0); - normal.normVec(); + if (mTypeMask & TOP_MASK) + { + normal.setCross3(d0, d1); + } + else + { + normal.setCross3(d1, d0); + } + + normal.normalize3fast(); VertexData vd; - vd.mPosition = mCenter; - vd.mNormal = normal; - vd.mBinormal = binormal; + vd.setPosition(*mCenter); vd.mTexCoord = cuv; if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) { - mVertices.push_back(vd); + pos[num_vertices] = *mCenter; + tc[num_vertices] = cuv; num_vertices++; - if (!partial_build) - { - vector_append(mIndices, 3); - } } - for (S32 i = 0; i < num_vertices; i++) { - mVertices[i].mBinormal = binormal; - mVertices[i].mNormal = normal; + binorm[i].load4a((F32*) &binormal.mQ); + norm[i].load4a((F32*) &normal.mQ); } - mHasBinormals = TRUE; - if (partial_build) { return TRUE; @@ -4840,8 +5942,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) pt2--; } } - - makeTriStrip(); } else { @@ -4946,8 +6046,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) pt2--; } } - - makeTriStrip(); } } else @@ -4969,131 +6067,320 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) 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) + + } + + 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; + + 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) { - mTriStrip.push_back(0); - for (S32 i = 0; i <= j; ++i) - { - mTriStrip.push_back(i); - if (i != j) - { - mTriStrip.push_back(j); - } - --j; - } + binorm[i2].add(binormal); } - else + else { - mTriStrip.push_back(j); - for (S32 i = 0; i <= j; ++i) - { - if (i != j) - { - mTriStrip.push_back(j); - } - mTriStrip.push_back(i); - --j; - } + binorm[i1].add(binormal); } - - mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + } - if (mTriStrip.size()%2 == 1) - { - mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); - } + //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(); } -#endif } - - return TRUE; } -void LLVolumeFace::makeTriStrip() +void LLVolumeFace::resizeVertices(S32 num_verts) { -#if GEN_TRI_STRIP - for (U32 i = 0; i < mIndices.size(); i+=3) + ll_aligned_free_16(mPositions); + ll_aligned_free_16(mNormals); + ll_aligned_free_16(mBinormals); + ll_aligned_free_16(mTexCoords); + + mBinormals = NULL; + + if (num_verts) + { + mPositions = (LLVector4a*) ll_aligned_malloc_16(num_verts*16); + mNormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16); + + //pad texture coordinate block end to allow for QWORD reads + S32 size = ((num_verts*8) + 0xF) & ~0xF; + mTexCoords = (LLVector2*) ll_aligned_malloc_16(size); + } + else { - U16 i0 = mIndices[i]; - U16 i1 = mIndices[i+1]; - U16 i2 = mIndices[i+2]; + 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 + LLVector4a* dst = (LLVector4a*) ll_aligned_malloc_16(new_size); + if (mPositions) + { + LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mPositions, old_size/4); + ll_aligned_free_16(mPositions); + } + mPositions = dst; - if ((i/3)%2 == 1) + //normals + dst = (LLVector4a*) ll_aligned_malloc_16(new_size); + if (mNormals) + { + LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mNormals, old_size/4); + ll_aligned_free_16(mNormals); + } + mNormals = dst; + + //tex coords + new_size = ((new_verts*8)+0xF) & ~0xF; + old_size = ((mNumVertices*8)+0xF) & ~0xF; + + dst = (LLVector4a*) ll_aligned_malloc_16(new_size); + { + LLVector2* dst = (LLVector2*) ll_aligned_malloc_16(new_size); + if (mTexCoords) { - mTriStrip.push_back(i0); - mTriStrip.push_back(i0); - mTriStrip.push_back(i1); - mTriStrip.push_back(i2); - mTriStrip.push_back(i2); + LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mTexCoords, old_size/4); + ll_aligned_free_16(mTexCoords); } - else + } + mTexCoords = (LLVector2*) dst; + + //just clear binormals + ll_aligned_free_16(mBinormals); + mBinormals = NULL; + + mPositions[mNumVertices] = pos; + mNormals[mNumVertices] = norm; + mTexCoords[mNumVertices] = tc; + + mNumVertices++; +} + +void LLVolumeFace::allocateBinormals(S32 num_verts) +{ + ll_aligned_free_16(mBinormals); + mBinormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16); +} + +void LLVolumeFace::allocateWeights(S32 num_verts) +{ + ll_aligned_free_16(mWeights); + mWeights = (LLVector4a*) ll_aligned_malloc_16(num_verts*16); +} + +void LLVolumeFace::resizeIndices(S32 num_indices) +{ + ll_aligned_free_16(mIndices); + + if (num_indices) + { + //pad index block end to allow for QWORD reads + S32 size = ((num_indices*2) + 0xF) & ~0xF; + + mIndices = (U16*) ll_aligned_malloc_16(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) + { + U16* dst = (U16*) ll_aligned_malloc_16(new_size); + if (mIndices) { - mTriStrip.push_back(i2); - mTriStrip.push_back(i2); - mTriStrip.push_back(i1); - mTriStrip.push_back(i0); - mTriStrip.push_back(i0); + LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mIndices, old_size/4); + ll_aligned_free_16(mIndices); } + mIndices = dst; } + + mIndices[mNumIndices++] = idx; +} + +void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx) +{ + resizeVertices(v.size()); + resizeIndices(idx.size()); - if (mTriStrip.size()%2 == 1) + for (U32 i = 0; i < v.size(); ++i) { - mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]); + 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]; } -#endif } -void LLVolumeFace::createBinormals() +void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in) { - LLMemType m1(LLMemType::MTYPE_VOLUME); + U16 offset = mNumVertices; + + S32 new_count = face.mNumVertices + mNumVertices; + + if (new_count > 65536) + { + llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl; + } - if (!mHasBinormals) + if (face.mNumVertices == 0) { - //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); + llerrs << "Cannot append empty face." << llendl; + } - 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; - } + //allocate new buffer space + LLVector4a* new_pos = (LLVector4a*) ll_aligned_malloc_16(new_count*16); + LLVector4a* new_norm = (LLVector4a*) ll_aligned_malloc_16(new_count*16); + LLVector2* new_tc = (LLVector2*) ll_aligned_malloc_16((new_count*8+0xF) & ~0xF); + - //even out quad contributions - if (i % 2 == 0) - { - mVertices[mIndices[i*3+2]].mBinormal += binorm; - } - else - { - mVertices[mIndices[i*3+1]].mBinormal += binorm; - } - } + if (mNumVertices > 0) + { //copy old buffers + LLVector4a::memcpyNonAliased16((F32*) new_pos, (F32*) mPositions, mNumVertices*4); + LLVector4a::memcpyNonAliased16((F32*) new_norm, (F32*) mNormals, mNumVertices*4); + LLVector4a::memcpyNonAliased16((F32*) new_tc, (F32*) mTexCoords, mNumVertices*2); + } - //normalize binormals - for (U32 i = 0; i < mVertices.size(); i++) + //free old buffer space + ll_aligned_free_16(mPositions); + ll_aligned_free_16(mNormals); + ll_aligned_free_16(mTexCoords); + + //point to new buffers + mPositions = new_pos; + mNormals = new_norm; + mTexCoords = new_tc; + + 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 { - mVertices[i].mBinormal.normVec(); - mVertices[i].mNormal.normVec(); + //stretch bounding box + update_min_max(mExtents[0], mExtents[1], dst_pos[i]); } + } - mHasBinormals = TRUE; + + new_count = mNumIndices + face.mNumIndices; + + //allocate new index buffer + U16* new_indices = (U16*) ll_aligned_malloc_16((new_count*2+0xF) & ~0xF); + if (mNumIndices > 0) + { //copy old index buffer + S32 old_size = (mNumIndices*2+0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*) new_indices, (F32*) mIndices, old_size/4); + } + + //free old index buffer + ll_aligned_free_16(mIndices); + + //point to new index buffer + mIndices = new_indices; + + //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; } } @@ -5123,18 +6410,24 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) num_vertices = mNumS*mNumT; num_indices = (mNumS-1)*(mNumT-1)*6; - mVertices.resize(num_vertices); - if (!partial_build) { - mIndices.resize(num_indices); + resizeVertices(num_vertices); + resizeIndices(num_indices); + +#if LL_MESH_ENABLED + if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) + { + mEdge.resize(num_indices); + } +#else mEdge.resize(num_indices); - } - else - { - mHasBinormals = FALSE; +#endif } + 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; @@ -5185,21 +6478,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) i = mBeginS + s + max_s*t; } - mVertices[cur_vertex].mPosition = mesh[i].mPos; - mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); + pos[cur_vertex].load3(mesh[i].mPos.mV); + tc[cur_vertex] = LLVector2(ss,tt); - mVertices[cur_vertex].mNormal = LLVector3(0,0,0); - mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); - + norm[cur_vertex].clear(); 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); + + pos[cur_vertex].load3(mesh[i].mPos.mV); + tc[cur_vertex] = LLVector2(ss,tt); - mVertices[cur_vertex].mNormal = LLVector3(0,0,0); - mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); + norm[cur_vertex].clear(); + cur_vertex++; } } @@ -5217,29 +6509,29 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) 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); - + 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 - LLVector3& face_min = mExtents[0]; - LLVector3& face_max = mExtents[1]; - mCenter.clearVec(); + LLVector4a& face_min = mExtents[0]; + LLVector4a& face_max = mExtents[1]; + mCenter->clear(); + + face_min = face_max = pos[0]; - face_min = face_max = mVertices[0].mPosition; - for (U32 i = 1; i < mVertices.size(); ++i) + for (U32 i = 1; i < mNumVertices; ++i) { - update_min_max(face_min, face_max, mVertices[i].mPosition); + update_min_max(face_min, face_max, pos[i]); } - mCenter = (face_min + face_max) * 0.5f; + mCenter->setAdd(face_min, face_max); + mCenter->mul(0.5f); S32 cur_index = 0; S32 cur_edge = 0; @@ -5248,17 +6540,12 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) 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 @@ -5269,15 +6556,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) 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; @@ -5319,51 +6598,58 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) 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 + for (U32 i = 0; i < mNumIndices/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; + 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 - v[i%2+1]->mNormal += norm; + n[i%2+1]->add(c); } // 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); + 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++) { - LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; - mVertices[i].mNormal = norm; - mVertices[mNumS*(mNumT-1)+i].mNormal = norm; + LLVector4a n; + n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); + norm[i] = n; + norm[mNumS*(mNumT-1)+i] = n; } } @@ -5371,9 +6657,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //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; + LLVector4a n; + n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); + norm[mNumS * i] = n; + norm[mNumS * i+mNumS-1] = n; } } @@ -5384,7 +6671,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //all lower S have same normal for (S32 i = 0; i < mNumT; i++) { - mVertices[mNumS*i].mNormal = LLVector3(1,0,0); + norm[mNumS*i].set(1,0,0); } } @@ -5392,7 +6679,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //all upper S have same normal for (S32 i = 0; i < mNumT; i++) { - mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0); + norm[mNumS*i+mNumS-1].set(-1,0,0); } } } @@ -5420,30 +6707,33 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { // average normals for north pole - LLVector3 average(0.0, 0.0, 0.0); + LLVector4a average; + average.clear(); + for (S32 i = 0; i < mNumS; i++) { - average += mVertices[i].mNormal; + average.add(norm[i]); } // set average for (S32 i = 0; i < mNumS; i++) { - mVertices[i].mNormal = average; + norm[i] = average; } // average normals for south pole - average = LLVector3(0.0, 0.0, 0.0); + average.clear(); + for (S32 i = 0; i < mNumS; i++) { - average += mVertices[i + mNumS * (mNumT - 1)].mNormal; + average.add(norm[i + mNumS * (mNumT - 1)]); } // set average for (S32 i = 0; i < mNumS; i++) { - mVertices[i + mNumS * (mNumT - 1)].mNormal = average; + norm[i + mNumS * (mNumT - 1)] = average; } } @@ -5453,23 +6743,22 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { 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; + 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++) { - LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; - mVertices[i].mNormal = norm; - mVertices[mNumS*(mNumT-1)+i].mNormal = norm; + LLVector4a n; + n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); + norm[i] = n; + norm[mNumS*(mNumT-1)+i] = n; } - } } @@ -5479,41 +6768,51 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) // 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, +void calc_binormal_from_triangle(LLVector4a& binormal, + + const LLVector4a& pos0, const LLVector2& tex0, - const LLVector3& pos1, + const LLVector4a& pos1, const LLVector2& tex1, - const LLVector3& pos2, + const LLVector4a& 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] ); + 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] ); - 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] ); + 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] ); - 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] ); + 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] ); - LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2); - LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2); - LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2); + 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.mV[VX] && r1.mV[VX] && r2.mV[VX] ) + if( r0[VX] && r1[VX] && r2[VX] ) { - LLVector3 binormal( - -r0.mV[VZ] / r0.mV[VX], - -r1.mV[VZ] / r1.mV[VX], - -r2.mV[VZ] / r2.mV[VX]); + binormal.set( + -r0[VZ] / r0[VX], + -r1[VZ] / r1[VX], + -r2[VZ] / r2[VX]); // binormal.normVec(); - return binormal; } else { - return LLVector3( 0, 1 , 0 ); + binormal.set( 0, 1 , 0 ); } } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index d9f80f0e30..af28337f57 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -40,8 +40,15 @@ class LLPathParams; class LLVolumeParams; class LLProfile; class LLPath; + +#define LL_MESH_ENABLED 1 + +template <class T> class LLOctreeNode; + +class LLVector4a; class LLVolumeFace; class LLVolume; +class LLVolumeTriangle; #include "lldarray.h" #include "lluuid.h" @@ -49,6 +56,8 @@ class LLVolume; //#include "vmath.h" #include "v2math.h" #include "v3math.h" +#include "v3dmath.h" +#include "v4math.h" #include "llquaternion.h" #include "llstrider.h" #include "v4coloru.h" @@ -183,12 +192,20 @@ 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_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER; +#if LL_MESH_ENABLED +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; +#else +const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | + LL_SCULPT_TYPE_CYLINDER; +#endif const U8 LL_SCULPT_FLAG_INVERT = 64; const U8 LL_SCULPT_FLAG_MIRROR = 128; +const S32 LL_SCULPT_MESH_MAX_FACES = 8; class LLProfileParams { @@ -575,6 +592,9 @@ public: 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); @@ -634,7 +654,6 @@ public: const F32& getSkew() const { return mPathParams.getSkew(); } const LLUUID& getSculptID() const { return mSculptID; } const U8& getSculptType() const { return mSculptType; } - BOOL isConvex() const; // 'begin' and 'end' should be in range [0, 1] (they will be clamped) @@ -785,30 +804,86 @@ public: class LLVolumeFace { public: - LLVolumeFace() : - mID(0), - mTypeMask(0), - mHasBinormals(FALSE), - mBeginS(0), - mBeginT(0), - mNumS(0), - mNumT(0) + class VertexData { - } + enum + { + POSITION = 0, + NORMAL = 1 + }; + + private: + void init(); + public: + VertexData(); + VertexData(const VertexData& rhs); + const VertexData& operator=(const VertexData& rhs); + + ~VertexData(); + LLVector4a& getPosition(); + LLVector4a& getNormal(); + const LLVector4a& getPosition() const; + const LLVector4a& getNormal() const; + void setPosition(const LLVector4a& pos); + void setNormal(const LLVector4a& norm); + + + LLVector2 mTexCoord; + + bool operator<(const VertexData& rhs) const; + bool operator==(const VertexData& rhs) const; + bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const; + + private: + LLVector4a* mData; + }; + + LLVolumeFace(); + LLVolumeFace(const LLVolumeFace& src); + LLVolumeFace& operator=(const LLVolumeFace& rhs); + + ~LLVolumeFace(); +private: + void freeData(); +public: BOOL create(LLVolume* volume, BOOL partial_build = FALSE); void createBinormals(); - void makeTriStrip(); - class VertexData + 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: - LLVector3 mPosition; - LLVector3 mNormal; - LLVector3 mBinormal; - LLVector2 mTexCoord; + 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 createOctree(); + enum { SINGLE_MASK = 0x0001, @@ -827,22 +902,34 @@ public: public: S32 mID; U32 mTypeMask; - LLVector3 mCenter; - BOOL mHasBinormals; - + // Only used for INNER/OUTER faces S32 mBeginS; S32 mBeginT; S32 mNumS; S32 mNumT; - LLVector3 mExtents[2]; //minimum and maximum point of face + 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<VertexData> mVertices; - std::vector<U16> mIndices; - std::vector<U16> mTriStrip; 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); @@ -853,8 +940,7 @@ class LLVolume : public LLRefCount { friend class LLVolumeLODGroup; -private: - LLVolume(const LLVolume&); // Don't implement +protected: ~LLVolume(); // use unref public: @@ -876,7 +962,7 @@ public: U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } U8 getPathType() const { return mParams.getPathParams().getCurveType(); } - S32 getNumFaces() const { return (S32)mProfilep->mFaces.size(); } + S32 getNumFaces() const; S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } F32 getDetail() const { return mDetail; } const LLVolumeParams& getParams() const { return mParams; } @@ -898,12 +984,15 @@ public: 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, @@ -922,6 +1011,13 @@ public: 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, @@ -948,6 +1044,8 @@ public: 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(LLVolume* volume); + private: void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); F32 sculptGetSurfaceArea(); @@ -958,11 +1056,19 @@ private: 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; @@ -976,17 +1082,26 @@ protected: std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); -LLVector3 calc_binormal_from_triangle( - const LLVector3& pos0, +void calc_binormal_from_triangle( + LLVector4a& binormal, + const LLVector4a& pos0, const LLVector2& tex0, - const LLVector3& pos1, + const LLVector4a& pos1, const LLVector2& tex1, - const LLVector3& pos2, + 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); + 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); diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 53641fceab..419e0015ba 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -320,7 +320,7 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep) { llassert_always(mLODRefs[i] > 0); mLODRefs[i]--; -#if 1 // SJB: Possible opt: keep other lods around +#if 0 // SJB: Possible opt: keep other lods around if (!mLODRefs[i]) { mVolumeLODs[i] = NULL; @@ -375,6 +375,19 @@ F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail) return mDetailScales[detail]; } +S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail) +{ + for (S32 i = 1; i < 4; i++) + { + if (mDetailScales[i] > detail) + { + return i-1; + } + } + + return 3; +} + F32 LLVolumeLODGroup::dump() { F32 usage = 0.f; diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h index a78ea76a1a..f5dc4cd748 100644 --- a/indra/llmath/llvolumemgr.h +++ b/indra/llmath/llvolumemgr.h @@ -59,6 +59,7 @@ public: static S32 getDetailFromTan(const F32 tan_angle); static void getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher); static F32 getVolumeScaleFromDetail(const S32 detail); + static S32 getVolumeDetailFromScale(F32 scale); LLVolume* refLOD(const S32 detail); BOOL derefLOD(LLVolume *volumep); diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index d8e7b4aaf9..ce5428f0e1 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -221,8 +221,33 @@ const LLMatrix4& LLMatrix4::transpose() F32 LLMatrix4::determinant() const { - llerrs << "Not implemented!" << llendl; - return 0.f; + F32 value = + mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][0] - + mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][0] - + mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][0] + + mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][0] + + mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][0] - + mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][0] - + mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][1] + + mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][1] + + mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][1] - + mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][1] - + mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][1] + + mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][1] + + mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][2] - + mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][2] - + mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][2] + + mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][2] + + mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][2] - + mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][2] - + mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][3] + + mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][3] + + mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][3] - + mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][3] - + mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][3] + + mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][3]; + + return value; } // Only works for pure orthonormal, homogeneous transform matrices. @@ -428,6 +453,17 @@ const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector return (*this); } +const LLMatrix4& LLMatrix4::initScale(const LLVector3 &scale) +{ + setIdentity(); + + mMatrix[VX][VX] = scale.mV[VX]; + mMatrix[VY][VY] = scale.mV[VY]; + mMatrix[VZ][VZ] = scale.mV[VZ]; + + return (*this); +} + const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos) { F32 sx, sy, sz; @@ -648,37 +684,6 @@ const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 & // LLMatrix4 Operators - -/* Not implemented to help enforce code consistency with the syntax of - row-major notation. This is a Good Thing. -LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b) -{ - // Operate "to the right" on column-vector b - LLVector4 vec; - vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] + - a.mMatrix[VY][VX] * b.mV[VY] + - a.mMatrix[VZ][VX] * b.mV[VZ] + - a.mMatrix[VW][VX] * b.mV[VW]; - - vec.mV[VY] = a.mMatrix[VX][VY] * b.mV[VX] + - a.mMatrix[VY][VY] * b.mV[VY] + - a.mMatrix[VZ][VY] * b.mV[VZ] + - a.mMatrix[VW][VY] * b.mV[VW]; - - vec.mV[VZ] = a.mMatrix[VX][VZ] * b.mV[VX] + - a.mMatrix[VY][VZ] * b.mV[VY] + - a.mMatrix[VZ][VZ] * b.mV[VZ] + - a.mMatrix[VW][VZ] * b.mV[VW]; - - vec.mV[VW] = a.mMatrix[VX][VW] * b.mV[VX] + - a.mMatrix[VY][VW] * b.mV[VY] + - a.mMatrix[VZ][VW] * b.mV[VZ] + - a.mMatrix[VW][VW] * b.mV[VW]; - return vec; -} -*/ - - LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b) { // Operate "to the left" on row-vector a @@ -774,6 +779,23 @@ bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b) return FALSE; } +bool operator<(const LLMatrix4& a, const LLMatrix4 &b) +{ + U32 i, j; + for (i = 0; i < NUM_VALUES_IN_MAT4; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT4; j++) + { + if (a.mMatrix[i][j] != b.mMatrix[i][j]) + { + return a.mMatrix[i][j] < b.mMatrix[i][j]; + } + } + } + + return false; +} + const LLMatrix4& operator*=(LLMatrix4 &a, F32 k) { U32 i, j; diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index e74b7afe9b..40599a0886 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -159,6 +159,7 @@ public: const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position + const LLMatrix4& initScale(const LLVector3 &scale); // Set all const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos); @@ -225,10 +226,7 @@ public: // Operators // -// Not implemented to enforce code that agrees with symbolic syntax -// friend LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b); // Apply rotation a to vector b - -// friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b + // friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b friend LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b); // Return transform of vector a by matrix b friend const LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b); // Return full transform of a by matrix b friend LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b); // Rotates a but does not translate @@ -236,6 +234,7 @@ public: friend bool operator==(const LLMatrix4 &a, const LLMatrix4 &b); // Return a == b friend bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b); // Return a != b + friend bool operator<(const LLMatrix4 &a, const LLMatrix4& b); // Return a < b friend const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b); // Return a + b friend const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b); // Return a - b diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp index 555e1f92bb..220336e0c2 100644 --- a/indra/llmath/v2math.cpp +++ b/indra/llmath/v2math.cpp @@ -115,3 +115,18 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u) a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u ); } + +LLSD LLVector2::getValue() const +{ + LLSD ret; + ret[0] = mV[0]; + ret[1] = mV[1]; + return ret; +} + +void LLVector2::setValue(LLSD& sd) +{ + mV[0] = (F32) sd[0].asReal(); + mV[1] = (F32) sd[1].asReal(); +} + diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index 65f3714313..ae26c85ce4 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -66,6 +66,9 @@ class LLVector2 void set(const LLVector2 &vec); // Sets LLVector2 to vec void set(const F32 *vec); // Sets LLVector2 to vec + LLSD getValue() const; + void setValue(LLSD& sd); + void setVec(F32 x, F32 y); // deprecated void setVec(const LLVector2 &vec); // deprecated void setVec(const F32 *vec); // deprecated diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index 63683ed496..82aad6550b 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -197,6 +197,28 @@ const LLVector3& LLVector3::rotVec(const LLQuaternion &q) return *this; } +const LLVector3& LLVector3::transVec(const LLMatrix4& mat) +{ + setVec( + mV[VX] * mat.mMatrix[VX][VX] + + mV[VY] * mat.mMatrix[VX][VY] + + mV[VZ] * mat.mMatrix[VX][VZ] + + mat.mMatrix[VX][VW], + + mV[VX] * mat.mMatrix[VY][VX] + + mV[VY] * mat.mMatrix[VY][VY] + + mV[VZ] * mat.mMatrix[VY][VZ] + + mat.mMatrix[VY][VW], + + mV[VX] * mat.mMatrix[VZ][VX] + + mV[VY] * mat.mMatrix[VZ][VY] + + mV[VZ] * mat.mMatrix[VZ][VZ] + + mat.mMatrix[VZ][VW]); + + return *this; +} + + const LLVector3& LLVector3::rotVec(F32 angle, const LLVector3 &vec) { if ( !vec.isExactlyZero() && angle ) diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 73738cffd2..75c860a91e 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -40,6 +40,7 @@ class LLVector2; class LLVector4; class LLMatrix3; +class LLMatrix4; class LLVector3d; class LLQuaternion; @@ -115,6 +116,7 @@ class LLVector3 const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q + const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v) const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec @@ -529,6 +531,21 @@ inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos) } } +inline void update_min_max(LLVector3& min, LLVector3& max, const F32* pos) +{ + for (U32 i = 0; i < 3; i++) + { + if (min.mV[i] > pos[i]) + { + min.mV[i] = pos[i]; + } + if (max.mV[i] < pos[i]) + { + max.mV[i] = pos[i]; + } + } +} + inline F32 angle_between(const LLVector3& a, const LLVector3& b) { LLVector3 an = a; diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index d6fbdec61e..6b63b976b0 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -114,6 +114,7 @@ class LLColor4 const LLColor4& operator=(const LLColor3 &a); // Assigns vec3 to vec4 and returns vec4 + bool operator<(const LLColor4& rhs) const; friend std::ostream& operator<<(std::ostream& s, const LLColor4 &a); // Print a friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b); // Return vector a + b friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b); // Return vector a minus b @@ -595,6 +596,23 @@ inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u) a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u); } +inline bool LLColor4::operator<(const LLColor4& rhs) const +{ + if (mV[0] != rhs.mV[0]) + { + return mV[0] < rhs.mV[0]; + } + if (mV[1] != rhs.mV[1]) + { + return mV[1] < rhs.mV[1]; + } + if (mV[2] != rhs.mV[2]) + { + return mV[2] < rhs.mV[2]; + } + + return mV[3] < rhs.mV[3]; +} void LLColor4::clamp() { diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 970b6747f7..468dfaf397 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -546,7 +546,7 @@ void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType at tpvf.setAsset(uuid, atype); tpvf.setCallback(downloadCompleteCallback, req); - llinfos << "Starting transfer for " << uuid << llendl; + //llinfos << "Starting transfer for " << uuid << llendl; LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); } diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 36874a5d48..16af7ea4fa 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -55,6 +55,7 @@ #include "llstl.h" #include "llsdserialize.h" #include "llthread.h" +#include "lltimer.h" ////////////////////////////////////////////////////////////////////////////// /* @@ -240,7 +241,12 @@ public: void resetState(); + static CURL* allocEasyHandle(); + static void releaseEasyHandle(CURL* handle); + private: + friend class LLCurl; + CURL* mCurlEasyHandle; struct curl_slist* mHeaders; @@ -255,8 +261,62 @@ private: std::vector<char*> mStrings; ResponderPtr mResponder; + + static std::set<CURL*> sFreeHandles; + static std::set<CURL*> sActiveHandles; + static LLMutex* sHandleMutex; }; +std::set<CURL*> LLCurl::Easy::sFreeHandles; +std::set<CURL*> LLCurl::Easy::sActiveHandles; +LLMutex* LLCurl::Easy::sHandleMutex = NULL; + + +//static +CURL* LLCurl::Easy::allocEasyHandle() +{ + CURL* ret = NULL; + LLMutexLock lock(sHandleMutex); + if (sFreeHandles.empty()) + { + ret = curl_easy_init(); + } + else + { + ret = *(sFreeHandles.begin()); + sFreeHandles.erase(ret); + curl_easy_reset(ret); + } + + if (ret) + { + sActiveHandles.insert(ret); + } + + return ret; +} + +//static +void LLCurl::Easy::releaseEasyHandle(CURL* handle) +{ + if (!handle) + { + llerrs << "handle cannot be NULL!" << llendl; + } + + LLMutexLock lock(sHandleMutex); + + if (sActiveHandles.find(handle) != sActiveHandles.end()) + { + sActiveHandles.erase(handle); + sFreeHandles.insert(handle); + } + else + { + llerrs << "Invalid handle." << llendl; + } +} + LLCurl::Easy::Easy() : mHeaders(NULL), mCurlEasyHandle(NULL) @@ -267,25 +327,27 @@ LLCurl::Easy::Easy() LLCurl::Easy* LLCurl::Easy::getEasy() { Easy* easy = new Easy(); - easy->mCurlEasyHandle = curl_easy_init(); + easy->mCurlEasyHandle = allocEasyHandle(); + if (!easy->mCurlEasyHandle) { // this can happen if we have too many open files (fails in c-ares/ares_init.c) - llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl; + llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl; delete easy; return NULL; } - // set no DMS caching as default for all easy handles. This prevents them adopting a + // set no DNS caching as default for all easy handles. This prevents them adopting a // multi handles cache if they are added to one. curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); + ++gCurlEasyCount; return easy; } LLCurl::Easy::~Easy() { - curl_easy_cleanup(mCurlEasyHandle); + releaseEasyHandle(mCurlEasyHandle); --gCurlEasyCount; curl_slist_free_all(mHeaders); for_each(mStrings.begin(), mStrings.end(), DeletePointerArray()); @@ -363,6 +425,7 @@ U32 LLCurl::Easy::report(CURLcode code) { responseCode = 499; responseReason = strerror(code) + " : " + mErrorBuffer; + setopt(CURLOPT_FRESH_CONNECT, TRUE); } if(responseCode >= 300 && responseCode < 400) //redirect @@ -456,7 +519,7 @@ void LLCurl::Easy::prepRequest(const std::string& url, if (post) setoptString(CURLOPT_ENCODING, ""); -// setopt(CURLOPT_VERBOSE, 1); // usefull for debugging + //setopt(CURLOPT_VERBOSE, 1); // usefull for debugging setopt(CURLOPT_NOSIGNAL, 1); mOutput.reset(new LLBufferArray); @@ -473,6 +536,9 @@ void LLCurl::Easy::prepRequest(const std::string& url, setCA(); setopt(CURLOPT_SSL_VERIFYPEER, true); + + //don't verify host name so urls with scrubbed host names will work (improves DNS performance) + setopt(CURLOPT_SSL_VERIFYHOST, 0); setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT); setoptString(CURLOPT_URL, url); @@ -533,6 +599,7 @@ LLCurl::Multi::Multi() mErrorCount(0) { mCurlMultiHandle = curl_multi_init(); + if (!mCurlMultiHandle) { llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl; @@ -700,6 +767,7 @@ LLCurlRequest::LLCurlRequest() : mActiveRequestCount(0) { mThreadID = LLThread::currentID(); + mProcessing = FALSE; } LLCurlRequest::~LLCurlRequest() @@ -734,6 +802,11 @@ LLCurl::Easy* LLCurlRequest::allocEasy() bool LLCurlRequest::addEasy(LLCurl::Easy* easy) { llassert_always(mActiveMulti); + + if (mProcessing) + { + llerrs << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << llendl; + } bool res = mActiveMulti->addEasy(easy); return res; } @@ -791,12 +864,41 @@ bool LLCurlRequest::post(const std::string& url, bool res = addEasy(easy); return res; } + +bool LLCurlRequest::post(const std::string& url, + const headers_t& headers, + const std::string& data, + LLCurl::ResponderPtr responder) +{ + LLCurl::Easy* easy = allocEasy(); + if (!easy) + { + return false; + } + easy->prepRequest(url, headers, responder); + + easy->getInput().write(data.data(), data.size()); + S32 bytes = easy->getInput().str().length(); + easy->setopt(CURLOPT_POST, 1); + easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); + easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); + + easy->slist_append("Content-Type: application/octet-stream"); + easy->setHeaders(); + + lldebugs << "POSTING: " << bytes << " bytes." << llendl; + bool res = addEasy(easy); + return res; +} + // Note: call once per frame S32 LLCurlRequest::process() { llassert_always(mThreadID == LLThread::currentID()); S32 res = 0; + + mProcessing = TRUE; for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ) { @@ -810,6 +912,7 @@ S32 LLCurlRequest::process() delete multi; } } + mProcessing = FALSE; return res; } @@ -1041,6 +1144,8 @@ void LLCurl::initClass() // - http://curl.haxx.se/libcurl/c/curl_global_init.html curl_global_init(CURL_GLOBAL_ALL); + Easy::sHandleMutex = new LLMutex(NULL); + #if SAFE_SSL S32 mutex_count = CRYPTO_num_locks(); for (S32 i=0; i<mutex_count; i++) @@ -1058,6 +1163,21 @@ void LLCurl::cleanupClass() CRYPTO_set_locking_callback(NULL); for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer()); #endif - curl_global_cleanup(); + + delete Easy::sHandleMutex; + Easy::sHandleMutex = NULL; + + for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter) + { + CURL* curl = *iter; + curl_easy_cleanup(curl); + } + + Easy::sFreeHandles.clear(); + + if (!Easy::sActiveHandles.empty()) + { + llerrs << "CURL easy handles not cleaned up on shutdown!" << llendl; + } } diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index b6a637ae5b..882d036705 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -202,6 +202,8 @@ public: void get(const std::string& url, LLCurl::ResponderPtr responder); bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder); bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder); + bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder); + S32 process(); S32 getQueued(); @@ -215,6 +217,7 @@ private: curlmulti_set_t mMultiSet; LLCurl::Multi* mActiveMulti; S32 mActiveRequestCount; + BOOL mProcessing; U32 mThreadID; // debug }; diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp index d64b666ede..de9c609500 100644 --- a/indra/llmessage/lltransfermanager.cpp +++ b/indra/llmessage/lltransfermanager.cpp @@ -344,7 +344,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) } } - llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl; + //llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl; ttp->setSize(size); ttp->setGotInfo(TRUE); diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 43f7c07e94..8c0520687a 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -257,3 +257,4 @@ BOOL LLTransferSourceParamsAsset::unpackParams(LLDataPacker &dp) return TRUE; } + diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index 4c955e875a..febce9bcb7 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -286,7 +286,7 @@ int main(int argc, char **argv) } // Check for a change in this process's frontmost window. - if(FrontWindow() != front_window) + if(ActiveNonFloatingWindow() != front_window) { ProcessSerialNumber self = { 0, kCurrentProcess }; ProcessSerialNumber parent = { 0, kNoProcess }; @@ -312,7 +312,7 @@ int main(int argc, char **argv) } } - if((FrontWindow() != NULL) && (front_window == NULL)) + if((ActiveNonFloatingWindow() != NULL) && (front_window == NULL)) { // Opening the first window @@ -324,7 +324,7 @@ int main(int argc, char **argv) if(layer_group) { - SetWindowGroup(FrontWindow(), layer_group); + SetWindowGroup(ActiveNonFloatingWindow(), layer_group); } if(parent_is_front_process) @@ -333,9 +333,9 @@ int main(int argc, char **argv) (void) SetFrontProcess( &self ); } - ActivateWindow(FrontWindow(), true); + ActivateWindow(ActiveNonFloatingWindow(), true); } - else if((FrontWindow() == NULL) && (front_window != NULL)) + else if((ActiveNonFloatingWindow() == NULL) && (front_window != NULL)) { // Closing the last window @@ -355,7 +355,7 @@ int main(int argc, char **argv) window_hack_state = 2; } - front_window = FrontWindow(); + front_window = ActiveNonFloatingWindow(); } } diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index 68a3d54597..af78ed7936 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -13,11 +13,14 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LIBS_PREBUILT_DIR}/include/collada + ${LIBS_PREBUILT_DIR}/include/collada/1.4 ) set(llprimitive_SOURCE_FILES llmaterialtable.cpp llmediaentry.cpp + llmodel.cpp llprimitive.cpp llprimtexturelist.cpp lltextureanim.cpp @@ -34,6 +37,7 @@ set(llprimitive_HEADER_FILES legacy_object_types.h llmaterialtable.h llmediaentry.h + llmodel.h llprimitive.h llprimtexturelist.h lltextureanim.h diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index b75d1b0f67..732f5a698b 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -744,7 +744,11 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai setNumTEs(mVolumep->getNumFaces()); return TRUE; } - + +#if 0 + // #if 0'd out by davep + // this is a lot of cruft to set texture entry values that just stay the same for LOD switch + // or immediately get overridden by an object update message, also crashes occasionally U32 old_face_mask = mVolumep->mFaceMask; S32 face_bit = 0; @@ -942,6 +946,13 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit]))); } } +#else + // build the new object + sVolumeManager->unrefVolume(mVolumep); + mVolumep = volumep; + + setNumTEs(mVolumep->getNumFaces()); +#endif return TRUE; } @@ -1084,7 +1095,7 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const U8 packed_buffer[MAX_TE_BUFFER]; U8 *cur_ptr = packed_buffer; - S32 last_face_index = getNumTEs() - 1; + S32 last_face_index = llmin((U32) getNumTEs(), MAX_TES) - 1; if (last_face_index > -1) { @@ -1365,7 +1376,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) return retval; } - face_count = getNumTEs(); + face_count = llmin((U32) getNumTEs(), MAX_TES); U32 i; cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID); diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index e67d436887..a44b9a6c1f 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -329,7 +329,7 @@ public: const LLVolume *getVolumeConst() const { return mVolumep; } // HACK for Windoze confusion about ostream operator in LLVolume LLVolume *getVolume() const { return mVolumep; } virtual BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false); - + // Modify texture entry properties inline BOOL validTE(const U8 te_num) const; LLTextureEntry* getTE(const U8 te_num) const; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 6eb5e0eff4..f1f25a9bac 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -273,7 +273,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } } - const LLFontGlyphInfo* next_glyph = NULL; for (i = begin_offset; i < begin_offset + length; i++) diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index ca92cb6580..9256e3959c 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -61,7 +61,7 @@ BOOL shouldChange(const LLVector4& v1, const LLVector4& v2) LLShaderFeatures::LLShaderFeatures() : calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false), -hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false), +hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false), hasGamma(false), hasLighting(false), calculatesAtmospherics(false) { } @@ -124,7 +124,7 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes, { GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second); LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL; - if (mShaderLevel > 0) + if (shaderhandle > 0) { attachObject(shaderhandle); } @@ -717,6 +717,18 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform) return -1; } +GLint LLGLSLShader::getAttribLocation(U32 attrib) +{ + if (attrib < mAttribute.size()) + { + return mAttribute[attrib]; + } + else + { + return -1; + } +} + void LLGLSLShader::uniform1i(const string& uniform, GLint v) { GLint location = getUniformLocation(uniform); diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 166d4af04c..dc493ba162 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -48,6 +48,7 @@ public: bool hasWaterFog; // implies no gamma bool hasTransport; // implies no lighting (it's possible to have neither though) bool hasSkinning; + bool hasObjectSkinning; bool hasAtmospherics; bool hasGamma; @@ -109,7 +110,7 @@ public: void vertexAttrib4fv(U32 index, GLfloat* v); GLint getUniformLocation(const std::string& uniform); - + GLint getAttribLocation(U32 attrib); GLint mapUniformTextureChannel(GLint location, GLenum type); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index e22f8d2ddc..db5835b73a 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1694,6 +1694,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) sample[asum/(16*4)] += 4; } + rowstart += 2 * w * mAlphaStride; } length *= 2; // we sampled everything twice, essentially diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 5597b23c69..70601663e6 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -39,6 +39,7 @@ #include "llimagegl.h" #include "llrendertarget.h" #include "lltexture.h" +#include "llvector4a.h" LLRender gGL; @@ -53,6 +54,7 @@ U32 LLRender::sUICalls = 0; U32 LLRender::sUIVerts = 0; static const U32 LL_NUM_TEXTURE_LAYERS = 16; +static const U32 LL_MAX_UI_STACK_DEPTH = 32; static GLenum sGLTextureType[] = { @@ -165,6 +167,7 @@ void LLTexUnit::enable(eTextureType type) if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) ) { activate(); + if (mCurrTexType != TT_NONE && !gGL.mDirty) { disable(); // Force a disable of a previous texture type if it's enabled. @@ -756,14 +759,27 @@ LLRender::LLRender() mCount(0), mMode(LLRender::TRIANGLES), mCurrTextureUnitIndex(0), - mMaxAnisotropy(0.f) + mMaxAnisotropy(0.f), + mUIStackDepth(0) { mBuffer = new LLVertexBuffer(immediate_mask, 0); mBuffer->allocateBuffer(4096, 0, TRUE); - mBuffer->getVertexStrider(mVerticesp); - mBuffer->getTexCoord0Strider(mTexcoordsp); - mBuffer->getColorStrider(mColorsp); - + + LLStrider<LLVector3> vert; + LLStrider<LLVector2> tc; + LLStrider<LLColor4U> color; + + mBuffer->getVertexStrider(vert); + mBuffer->getTexCoord0Strider(tc); + mBuffer->getColorStrider(color); + + mVerticesp = (LLVector4a*) vert.get(); + mTexcoordsp = tc.get(); + mColorsp = color.get(); + + mUIOffset = (LLVector4a*) ll_aligned_malloc_16(LL_MAX_UI_STACK_DEPTH*sizeof(LLVector4a)); + mUIScale = (LLVector4a*) ll_aligned_malloc_16(LL_MAX_UI_STACK_DEPTH*sizeof(LLVector4a)); + mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS); for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++) { @@ -778,6 +794,7 @@ LLRender::LLRender() mCurrAlphaFunc = CF_DEFAULT; mCurrAlphaFuncVal = 0.01f; + mCurrBlendColorSFactor = BF_UNDEF; mCurrBlendAlphaSFactor = BF_UNDEF; mCurrBlendColorDFactor = BF_UNDEF; @@ -798,6 +815,11 @@ void LLRender::shutdown() mTexUnits.clear(); delete mDummyTexUnit; mDummyTexUnit = NULL; + + ll_aligned_free_16(mUIOffset); + mUIOffset = NULL; + ll_aligned_free_16(mUIScale); + mUIScale = NULL; } void LLRender::refreshState(void) @@ -846,84 +868,83 @@ void LLRender::popMatrix() void LLRender::translateUI(F32 x, F32 y, F32 z) { - if (mUIOffset.empty()) + if (mUIStackDepth == 0) { llerrs << "Need to push a UI translation frame before offsetting" << llendl; } - mUIOffset.front().mV[0] += x; - mUIOffset.front().mV[1] += y; - mUIOffset.front().mV[2] += z; + LLVector4a trans(x,y,z); + mUIOffset[mUIStackDepth-1].add(trans); } void LLRender::scaleUI(F32 x, F32 y, F32 z) { - if (mUIScale.empty()) + if (mUIStackDepth == 0) { llerrs << "Need to push a UI transformation frame before scaling." << llendl; } - mUIScale.front().scaleVec(LLVector3(x,y,z)); + LLVector4a scale(x,y,z); + mUIScale[mUIStackDepth-1].mul(scale); } void LLRender::pushUIMatrix() { - if (mUIOffset.empty()) + if (mUIStackDepth == 0) { - mUIOffset.push_front(LLVector3(0,0,0)); + mUIOffset[0].clear(); + mUIScale[0].splat(1.f); } - else + else if (mUIStackDepth < LL_MAX_UI_STACK_DEPTH) { - mUIOffset.push_front(mUIOffset.front()); - } - - if (mUIScale.empty()) - { - mUIScale.push_front(LLVector3(1,1,1)); + mUIOffset[mUIStackDepth] = mUIOffset[mUIStackDepth-1]; + mUIScale[mUIStackDepth] = mUIScale[mUIStackDepth-1]; } else { - mUIScale.push_front(mUIScale.front()); + llerrs << "Blown UI matrix stack." << llendl; } + + ++mUIStackDepth; + } void LLRender::popUIMatrix() { - if (mUIOffset.empty()) + if (mUIStackDepth == 0) { llerrs << "UI offset stack blown." << llendl; } - mUIOffset.pop_front(); - mUIScale.pop_front(); + --mUIStackDepth; } LLVector3 LLRender::getUITranslation() { - if (mUIOffset.empty()) + if (mUIStackDepth == 0) { llerrs << "UI offset stack empty." << llendl; } - return mUIOffset.front(); + return LLVector3(mUIOffset[mUIStackDepth-1].getF32()); } LLVector3 LLRender::getUIScale() { - if (mUIScale.empty()) + if (mUIStackDepth == 0) { llerrs << "UI scale stack empty." << llendl; } - return mUIScale.front(); + return LLVector3(mUIScale[mUIStackDepth-1].getF32()); } void LLRender::loadUIIdentity() { - if (mUIOffset.empty()) + if (mUIStackDepth == 0) { llerrs << "Need to push UI translation frame before clearing offset." << llendl; } - mUIOffset.front().setVec(0,0,0); - mUIScale.front().setVec(1,1,1); + mUIOffset[mUIStackDepth-1].clear(); + mUIScale[mUIStackDepth-1].splat(1.f); } void LLRender::setColorMask(bool writeColor, bool writeAlpha) @@ -1152,7 +1173,7 @@ void LLRender::flush() } #endif - if (!mUIOffset.empty()) + if (mUIStackDepth > 0) { sUICalls++; sUIVerts += mCount; @@ -1204,24 +1225,22 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) return; } - if (mUIOffset.empty()) + LLVector3& v = reinterpret_cast<LLVector3&>(mVerticesp[mCount]); + v.set(x,y,z); + if (mUIStackDepth != 0) { - mVerticesp[mCount] = LLVector3(x,y,z); - } - else - { - LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.front()).scaledVec(mUIScale.front()); - mVerticesp[mCount] = vert; + v += reinterpret_cast<LLVector3&>(mUIOffset[mUIStackDepth-1]); + v.scaleVec(reinterpret_cast<LLVector3&>(mUIScale[mUIStackDepth-1])); } mCount++; if (mCount < 4096) { - mVerticesp[mCount] = mVerticesp[mCount-1]; mColorsp[mCount] = mColorsp[mCount-1]; mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; } } + void LLRender::vertex2i(const GLint& x, const GLint& y) { vertex3f((GLfloat) x, (GLfloat) y, 0); diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index f6c87aa1db..11cd95646f 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -45,6 +45,7 @@ #include "v4coloru.h" #include "llstrider.h" #include "llpointer.h" +#include "llmemory.h" #include "llglheaders.h" class LLVertexBuffer; @@ -52,6 +53,7 @@ class LLCubeMap; class LLImageGL; class LLRenderTarget; class LLTexture ; +class LLVector4a; class LLTexUnit { @@ -360,9 +362,10 @@ private: F32 mCurrAlphaFuncVal; LLPointer<LLVertexBuffer> mBuffer; - LLStrider<LLVector3> mVerticesp; - LLStrider<LLVector2> mTexcoordsp; - LLStrider<LLColor4U> mColorsp; + LLVector4a* mVerticesp; + LLVector2* mTexcoordsp; + LLColor4U* mColorsp; + std::vector<LLTexUnit*> mTexUnits; LLTexUnit* mDummyTexUnit; @@ -370,12 +373,12 @@ private: eBlendFactor mCurrBlendColorDFactor; eBlendFactor mCurrBlendAlphaSFactor; eBlendFactor mCurrBlendAlphaDFactor; - F32 mMaxAnisotropy; - std::list<LLVector3> mUIOffset; - std::list<LLVector3> mUIScale; + LLVector4a* mUIOffset; + LLVector4a* mUIScale; + U32 mUIStackDepth; }; extern F64 gGLModelView[16]; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 1286e91e49..0f54ebeb69 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -152,6 +152,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) return FALSE; } } + + if (features->hasObjectSkinning) + { + if (!shader->attachObject("avatar/objectSkinV.glsl")) + { + return FALSE; + } + } /////////////////////////////////////// // Attach Fragment Shader Features Next @@ -313,11 +321,14 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type) { - GLenum error; - error = glGetError(); - if (error != GL_NO_ERROR) + GLenum error = GL_NO_ERROR; + if (gDebugGL) { - LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL; + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL; + } } LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL; @@ -372,31 +383,39 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade //create shader object GLhandleARB ret = glCreateShaderObjectARB(type); - error = glGetError(); - if (error != GL_NO_ERROR) + if (gDebugGL) { - LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL; + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL; + } } - else + + //load source + glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL); + + if (gDebugGL) { - //load source - glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL); error = glGetError(); if (error != GL_NO_ERROR) { LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL; } - else + } + + //compile source + glCompileShaderARB(ret); + + if (gDebugGL) + { + error = glGetError(); + if (error != GL_NO_ERROR) { - //compile source - glCompileShaderARB(ret); - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL; - } + LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL; } } + //free memory for (GLuint i = 0; i < count; i++) { @@ -407,13 +426,16 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade //check for errors GLint success = GL_TRUE; glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success); - error = glGetError(); - if (error != GL_NO_ERROR || success == GL_FALSE) + if (gDebugGL || success == GL_FALSE) { - //an error occured, print log - LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL; - dumpObjectLog(ret); - ret = 0; + error = glGetError(); + if (error != GL_NO_ERROR || success == GL_FALSE) + { + //an error occured, print log + LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL; + dumpObjectLog(ret); + ret = 0; + } } } else diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 8012bbb6c8..9783435e2f 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -31,6 +31,7 @@ */ #include "linden_common.h" +#include "llmemory.h" #include <boost/static_assert.hpp> @@ -39,6 +40,7 @@ #include "llglheaders.h" #include "llmemtype.h" #include "llrender.h" +#include "llvector4a.h" //============================================================================ @@ -62,9 +64,31 @@ BOOL LLVertexBuffer::sIBOActive = FALSE; U32 LLVertexBuffer::sAllocatedBytes = 0; BOOL LLVertexBuffer::sMapped = FALSE; BOOL LLVertexBuffer::sUseStreamDraw = TRUE; +S32 LLVertexBuffer::sWeight4Loc = -1; std::vector<U32> LLVertexBuffer::sDeleteList; +#define LL_ALIGNED_VB 1 + +#if LL_ALIGNED_VB + +S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] = +{ + sizeof(LLVector4), // TYPE_VERTEX, + sizeof(LLVector4), // TYPE_NORMAL, + sizeof(LLVector2), // TYPE_TEXCOORD0, + sizeof(LLVector2), // TYPE_TEXCOORD1, + sizeof(LLVector2), // TYPE_TEXCOORD2, + sizeof(LLVector2), // TYPE_TEXCOORD3, + sizeof(LLColor4U), // TYPE_COLOR, + sizeof(LLVector4), // TYPE_BINORMAL, + sizeof(F32), // TYPE_WEIGHT, + sizeof(LLVector4), // TYPE_WEIGHT4, + sizeof(LLVector4), // TYPE_CLOTHWEIGHT, +}; + +#else + S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] = { sizeof(LLVector3), // TYPE_VERTEX, @@ -76,9 +100,12 @@ S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] = sizeof(LLColor4U), // TYPE_COLOR, sizeof(LLVector3), // TYPE_BINORMAL, sizeof(F32), // TYPE_WEIGHT, + sizeof(LLVector4), // TYPE_WEIGHT4, sizeof(LLVector4), // TYPE_CLOTHWEIGHT, }; +#endif + U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = { GL_TRIANGLES, @@ -210,18 +237,37 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) glClientActiveTextureARB(GL_TEXTURE0_ARB); } + if (sLastMask & MAP_WEIGHT4) + { + if (sWeight4Loc < 0) + { + llerrs << "Weighting disabled but vertex buffer still bound!" << llendl; + } + + if (!(data_mask & MAP_WEIGHT4)) + { //disable 4-component skin weight + glDisableVertexAttribArrayARB(sWeight4Loc); + } + } + else if (data_mask & MAP_WEIGHT4) + { + if (sWeight4Loc >= 0) + { //enable 4-component skin weight + glEnableVertexAttribArrayARB(sWeight4Loc); + } + } + + sLastMask = data_mask; } } -void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const +void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const { - llassert(mRequestedNumVerts >= 0); - if (start >= (U32) mRequestedNumVerts || end >= (U32) mRequestedNumVerts) { - llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "]" << llendl; + llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mRequestedNumVerts << llendl; } llassert(mRequestedNumIndices >= 0); @@ -232,6 +278,25 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; } + if (gDebugGL && !useVBOs()) + { + U16* idx = ((U16*) getIndicesPointer())+indices_offset; + for (U32 i = 0; i < count; ++i) + { + if (idx[i] < start || idx[i] > end) + { + llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl; + } + } + } +} + +void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const +{ + validateRange(start, end, count, indices_offset); + + llassert(mRequestedNumVerts >= 0); + if (mGLIndices != sGLRenderIndices) { llerrs << "Wrong index buffer bound." << llendl; @@ -248,9 +313,11 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi return; } + U16* idx = ((U16*) getIndicesPointer())+indices_offset; + stop_glerror(); glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, - ((U16*) getIndicesPointer()) + indices_offset); + idx); stop_glerror(); } @@ -397,11 +464,42 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mTypeMask = typemask; mStride = stride; + mAlignedOffset = 0; + mAlignedIndexOffset = 0; + sCount++; } +#if LL_ALIGNED_VB //static -S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets) +S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets, S32 num_vertices) +{ + S32 offset = 0; + for (S32 i=0; i<TYPE_MAX; i++) + { + U32 mask = 1<<i; + if (typemask & mask) + { + if (offsets) + { + offsets[i] = offset; + offset += LLVertexBuffer::sTypeOffsets[i]*num_vertices; + offset = (offset + 0xF) & ~0xF; + } + } + } + + return offset+16; +} + +S32 LLVertexBuffer::getSize() const +{ + return mStride; +} + +#else +//static +S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets, S32 num_vertices) { S32 stride = 0; for (S32 i=0; i<TYPE_MAX; i++) @@ -420,6 +518,12 @@ S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets) return stride; } +S32 LLVertexBuffer::getSize() const +{ + return mNumVerts*mStride; +} + +#endif // protected, use unref() //virtual LLVertexBuffer::~LLVertexBuffer() @@ -529,7 +633,7 @@ void LLVertexBuffer::createGLBuffer() { static int gl_buffer_idx = 0; mGLBuffer = ++gl_buffer_idx; - mMappedData = new U8[size]; + mMappedData = (U8*) ll_aligned_malloc_16(size); memset(mMappedData, 0, size); } } @@ -551,16 +655,20 @@ void LLVertexBuffer::createGLIndices() mEmpty = TRUE; + //pad by 16 bytes for aligned copies + size += 16; + if (useVBOs()) { + //pad by another 16 bytes for VBO pointer adjustment + size += 16; mMappedIndexData = NULL; genIndices(); mResized = TRUE; } else { - mMappedIndexData = new U8[size]; - memset(mMappedIndexData, 0, size); + mMappedIndexData = (U8*) ll_aligned_malloc_16(size); static int gl_buffer_idx = 0; mGLIndices = ++gl_buffer_idx; } @@ -581,7 +689,7 @@ void LLVertexBuffer::destroyGLBuffer() } else { - delete [] mMappedData; + ll_aligned_free_16(mMappedData); mMappedData = NULL; mEmpty = TRUE; } @@ -590,7 +698,7 @@ void LLVertexBuffer::destroyGLBuffer() } mGLBuffer = 0; - unbind(); + //unbind(); } void LLVertexBuffer::destroyGLIndices() @@ -608,7 +716,7 @@ void LLVertexBuffer::destroyGLIndices() } else { - delete [] mMappedIndexData; + ll_aligned_free_16(mMappedIndexData); mMappedIndexData = NULL; mEmpty = TRUE; } @@ -617,7 +725,7 @@ void LLVertexBuffer::destroyGLIndices() } mGLIndices = 0; - unbind(); + //unbind(); } void LLVertexBuffer::updateNumVerts(S32 nverts) @@ -633,7 +741,7 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) } mRequestedNumVerts = nverts; - + if (!mDynamicSize) { mNumVerts = nverts; @@ -648,6 +756,9 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) } mNumVerts = nverts; } +#if LL_ALIGNED_VB + mStride = calcStride(mTypeMask, mOffsets, mNumVerts); +#endif } @@ -679,6 +790,12 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) { LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER); + if (nverts < 0 || nindices < 0 || + nverts > 65536) + { + llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl; + } + updateNumVerts(nverts); updateNumIndices(nindices); @@ -717,9 +834,6 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { sAllocatedBytes -= getSize() + getIndicesSize(); - S32 oldsize = getSize(); - S32 old_index_size = getIndicesSize(); - updateNumVerts(newnverts); updateNumIndices(newnindices); @@ -736,26 +850,10 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) } else { - //delete old buffer, keep GL buffer for now if (!useVBOs()) { - U8* old = mMappedData; - mMappedData = new U8[newsize]; - if (old) - { - memcpy(mMappedData, old, llmin(newsize, oldsize)); - if (newsize > oldsize) - { - memset(mMappedData+oldsize, 0, newsize-oldsize); - } - - delete [] old; - } - else - { - memset(mMappedData, 0, newsize); - mEmpty = TRUE; - } + ll_aligned_free_16(mMappedData); + mMappedData = (U8*) ll_aligned_malloc_16(newsize); } mResized = TRUE; } @@ -775,24 +873,8 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { if (!useVBOs()) { - //delete old buffer, keep GL buffer for now - U8* old = mMappedIndexData; - mMappedIndexData = new U8[new_index_size]; - - if (old) - { - memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size)); - if (new_index_size > old_index_size) - { - memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size); - } - delete [] old; - } - else - { - memset(mMappedIndexData, 0, new_index_size); - mEmpty = TRUE; - } + ll_aligned_free_16(mMappedIndexData); + mMappedIndexData = (U8*) ll_aligned_malloc_16(new_index_size); } mResized = TRUE; } @@ -849,12 +931,19 @@ U8* LLVertexBuffer::mapBuffer(S32 access) setBuffer(0); mLocked = TRUE; stop_glerror(); - mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + + U8* src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src); + mAlignedOffset = mMappedData - src; + stop_glerror(); } { LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES); - mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + U8* src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + mMappedIndexData = LL_NEXT_ALIGNED_ADDRESS<U8>(src); + mAlignedIndexOffset = mMappedIndexData - src; + stop_glerror(); } @@ -938,6 +1027,45 @@ void LLVertexBuffer::unmapBuffer() //---------------------------------------------------------------------------- +#if LL_ALIGNED_VB + +template <class T,S32 type> struct VertexBufferStrider +{ + typedef LLStrider<T> strider_t; + static bool get(LLVertexBuffer& vbo, + strider_t& strider, + S32 index) + { + if (vbo.mapBuffer() == NULL) + { + llwarns << "mapBuffer failed!" << llendl; + return FALSE; + } + + if (type == LLVertexBuffer::TYPE_INDEX) + { + S32 stride = sizeof(T); + strider = (T*)(vbo.getMappedIndices() + index*stride); + strider.setStride(0); + return TRUE; + } + else if (vbo.hasDataType(type)) + { + S32 stride = LLVertexBuffer::sTypeOffsets[type]; + strider = (T*)(vbo.getMappedData() + vbo.getOffset(type)+index*stride); + strider.setStride(stride); + return TRUE; + } + else + { + llerrs << "VertexBufferStrider could not find valid vertex data." << llendl; + } + return FALSE; + } +}; + +#else + template <class T,S32 type> struct VertexBufferStrider { typedef LLStrider<T> strider_t; @@ -973,6 +1101,7 @@ template <class T,S32 type> struct VertexBufferStrider } }; +#endif bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index) { @@ -1014,6 +1143,12 @@ bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index) { return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index); } + +bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index) +{ + return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index); +} + bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index) { return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index); @@ -1229,6 +1364,81 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } } +#if LL_ALIGNED_VB + +// virtual (default) +void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const +{ + LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER); + stop_glerror(); + U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; + + if ((data_mask & mTypeMask) != data_mask) + { + llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; + } + + if (data_mask & MAP_NORMAL) + { + glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); + } + if (data_mask & MAP_TEXCOORD3) + { + glClientActiveTextureARB(GL_TEXTURE3_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_TEXCOORD2) + { + glClientActiveTextureARB(GL_TEXTURE2_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_TEXCOORD1) + { + glClientActiveTextureARB(GL_TEXTURE1_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_BINORMAL) + { + glClientActiveTextureARB(GL_TEXTURE2_ARB); + glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_TEXCOORD0) + { + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); + } + if (data_mask & MAP_COLOR) + { + glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeOffsets[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); + } + + if (data_mask & MAP_WEIGHT) + { + glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT])); + } + + if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1) + { + glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4])); + } + + if (data_mask & MAP_CLOTHWEIGHT) + { + glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeOffsets[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT])); + } + if (data_mask & MAP_VERTEX) + { + glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_VERTEX], (void*)(base + 0)); + } + + llglassertok(); +} + +#else + // virtual (default) void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const { @@ -1283,6 +1493,12 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const { glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT])); } + + if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1) + { + glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, stride, (void*)(base+mOffsets[TYPE_WEIGHT4])); + } + if (data_mask & MAP_CLOTHWEIGHT) { glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT])); @@ -1295,6 +1511,8 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const llglassertok(); } +#endif + void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count) { // TODO: use GL_APPLE_flush_buffer_range here diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index e2fecdffef..715309b64a 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -79,11 +79,24 @@ protected: class LLVertexBuffer : public LLRefCount { public: + LLVertexBuffer(const LLVertexBuffer& rhs) + { + *this = rhs; + } + + const LLVertexBuffer& operator=(const LLVertexBuffer& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + static LLVBOPool sStreamVBOPool; static LLVBOPool sDynamicVBOPool; static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; + static S32 sWeight4Loc; + static BOOL sUseStreamDraw; static void initClass(bool use_vbo); @@ -96,7 +109,7 @@ public: //if offsets is not NULL, its contents will be filled //with the offset of each vertex component in the buffer, // indexed by the following enum - static S32 calcStride(const U32& typemask, S32* offsets = NULL); + static S32 calcStride(const U32& typemask, S32* offsets = NULL, S32 num_vertices = 0); enum { TYPE_VERTEX, @@ -109,6 +122,7 @@ public: // These use VertexAttribPointer and should possibly be made generic TYPE_BINORMAL, TYPE_WEIGHT, + TYPE_WEIGHT4, TYPE_CLOTHWEIGHT, TYPE_MAX, TYPE_INDEX, @@ -124,6 +138,7 @@ public: // These use VertexAttribPointer and should possibly be made generic MAP_BINORMAL = (1<<TYPE_BINORMAL), MAP_WEIGHT = (1<<TYPE_WEIGHT), + MAP_WEIGHT4 = (1<<TYPE_WEIGHT4), MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT), }; @@ -173,6 +188,7 @@ public: bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0); bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0); bool getWeightStrider(LLStrider<F32>& strider, S32 index=0); + bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0); bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0); BOOL isEmpty() const { return mEmpty; } @@ -182,12 +198,12 @@ public: S32 getRequestedVerts() const { return mRequestedNumVerts; } S32 getRequestedIndices() const { return mRequestedNumIndices; } - U8* getIndicesPointer() const { return useVBOs() ? NULL : mMappedIndexData; } + U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } U8* getVerticesPointer() const { return useVBOs() ? NULL : mMappedData; } S32 getStride() const { return mStride; } - S32 getTypeMask() const { return mTypeMask; } + U32 getTypeMask() const { return mTypeMask; } BOOL hasDataType(S32 type) const { return ((1 << type) & getTypeMask()) ? TRUE : FALSE; } - S32 getSize() const { return mNumVerts*mStride; } + S32 getSize() const; S32 getIndicesSize() const { return mNumIndices * sizeof(U16); } U8* getMappedData() const { return mMappedData; } U8* getMappedIndices() const { return mMappedIndexData; } @@ -202,12 +218,19 @@ public: void drawArrays(U32 mode, U32 offset, U32 count) const; void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const; + //for debugging, validate data in given range is valid + void validateRange(U32 start, U32 end, U32 count, U32 offset) const; + + + protected: S32 mNumVerts; // Number of vertices allocated S32 mNumIndices; // Number of indices allocated S32 mRequestedNumVerts; // Number of vertices requested S32 mRequestedNumIndices; // Number of indices requested + ptrdiff_t mAlignedOffset; + ptrdiff_t mAlignedIndexOffset; S32 mStride; U32 mTypeMask; S32 mUsage; // GL usage @@ -222,7 +245,7 @@ protected: S32 mOffsets[TYPE_MAX]; BOOL mResized; // if TRUE, client buffer has been resized and GL buffer has not BOOL mDynamicSize; // if TRUE, buffer has been resized at least once (and should be padded) - + class DirtyRegion { public: diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index c93ca1af88..c0cc294c02 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -377,7 +377,11 @@ void LLLineEditor::setText(const LLStringExplicit &new_text) setCursor(llmin((S32)mText.length(), getCursor())); // Set current history line to end of history. - if(mLineHistory.end() != mLineHistory.begin()) + if (mLineHistory.empty()) + { + mCurrentHistoryLine = mLineHistory.end(); + } + else { mCurrentHistoryLine = mLineHistory.end() - 1; } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 394ec957d5..ca554db6d3 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -123,7 +123,8 @@ LLView::Params::Params() } LLView::LLView(const LLView::Params& p) -: mName(p.name), +: mVisible(p.visible), + mName(p.name), mParentView(NULL), mReshapeFlags(FOLLOWS_NONE), mFromXUI(p.from_xui), @@ -132,7 +133,6 @@ LLView::LLView(const LLView::Params& p) mNextInsertionOrdinal(0), mHoverCursor(getCursorFromString(p.hover_cursor)), mEnabled(p.enabled), - mVisible(p.visible), mMouseOpaque(p.mouse_opaque), mSoundFlags(p.sound_flags), mUseBoundingRect(p.use_bounding_rect), @@ -1309,7 +1309,13 @@ void LLView::drawChildren() { if (!mChildList.empty()) { - LLRect rootRect = getRootView()->getRect(); + static const LLRect* rootRect = NULL; + + if (!mParentView) + { + rootRect = &mRect; + } + LLRect screenRect; ++sDepth; @@ -1323,7 +1329,7 @@ void LLView::drawChildren() { // Only draw views that are within the root view localRectToScreen(viewp->getRect(),&screenRect); - if ( rootRect.overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect)) + if ( rootRect->overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect)) { LLUI::pushMatrix(); { diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 8e705ed701..7e05468590 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -294,7 +294,7 @@ public: void setAllChildrenEnabled(BOOL b); virtual void setVisible(BOOL visible); - BOOL getVisible() const { return mVisible; } + const BOOL& getVisible() const { return mVisible; } virtual void setEnabled(BOOL enabled); BOOL getEnabled() const { return mEnabled; } /// 'available' in this context means 'visible and enabled': in other @@ -555,11 +555,13 @@ private: LLView* mParentView; child_list_t mChildList; - std::string mName; // location in pixels, relative to surrounding structure, bottom,left=0,0 + BOOL mVisible; LLRect mRect; LLRect mBoundingRect; + std::string mLayout; + std::string mName; U32 mReshapeFlags; @@ -581,8 +583,6 @@ private: LLRootHandle<LLView> mHandle; BOOL mLastVisible; - BOOL mVisible; - S32 mNextInsertionOrdinal; static LLWindow* sWindow; // All root views must know about their window. diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp index 5fdf41188d..6751f3eb93 100644 --- a/indra/llvfs/llvfile.cpp +++ b/indra/llvfs/llvfile.cpp @@ -320,7 +320,7 @@ BOOL LLVFile::setMaxSize(S32 size) if (!mVFS->checkAvailable(size)) { - LLFastTimer t(FTM_VFILE_WAIT); + //LLFastTimer t(FTM_VFILE_WAIT); S32 count = 0; while (sVFSThread->getPending() > 1000) { @@ -428,7 +428,7 @@ bool LLVFile::isLocked(EVFSLock lock) void LLVFile::waitForLock(EVFSLock lock) { - LLFastTimer t(FTM_VFILE_WAIT); + //LLFastTimer t(FTM_VFILE_WAIT); // spin until the lock clears while (isLocked(lock)) { diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 9ce1e75d06..2b01288fd7 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -2041,6 +2041,11 @@ std::string get_extension(LLAssetType::EType type) case LLAssetType::AT_ANIMATION: extension = ".lla"; break; +#if LL_MESH_ENABLED + case LLAssetType::AT_MESH: + extension = ".slm"; + break; +#endif default: // Just use the asset server filename extension in most cases extension += "."; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 4e87dd9225..fc5e192d74 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -16,6 +16,7 @@ include(FindOpenGL) include(LLAudio) include(LLCharacter) include(LLCommon) +include(LLConvexDecomposition) include(LLImage) include(LLImageJ2COJ) include(LLInventory) @@ -39,14 +40,17 @@ include(UnixInstall) include(LLKDU) include(ViewerMiscLibs) include(LLLogin) +include(GLOD) include(CMakeCopyIfDifferent) include_directories( ${DBUSGLIB_INCLUDE_DIRS} ${ELFIO_INCLUDE_DIR} + ${GLOD_INCLUDE_DIR} ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} + ${LLCONVEXDECOMP_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} @@ -62,6 +66,8 @@ include_directories( ${LSCRIPT_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS}/lscript_compile ${LLLOGIN_INCLUDE_DIRS} + ${LIBS_PREBUILT_DIR}/include/collada + ${LIBS_PREBUILT_DIR}/include/collada/1.4 ) set(viewer_SOURCE_FILES @@ -177,6 +183,7 @@ set(viewer_SOURCE_FILES llfloaterhelpbrowser.cpp llfloaterhud.cpp llfloaterimagepreview.cpp + llfloaterimportcollada.cpp llfloaterinspect.cpp llfloaterinventory.cpp llfloaterjoystick.cpp @@ -187,6 +194,7 @@ set(viewer_SOURCE_FILES llfloatermediabrowser.cpp llfloatermediasettings.cpp llfloatermemleak.cpp + llfloatermodelpreview.cpp llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloateropenobject.cpp @@ -286,6 +294,8 @@ set(viewer_SOURCE_FILES llmediadataclient.cpp llmemoryview.cpp llmenucommands.cpp + llmeshrepository.cpp + llmeshreduction.cpp llmetricperformancetester.cpp llmimetypes.cpp llmorphview.cpp @@ -704,6 +714,7 @@ set(viewer_HEADER_FILES llfloaterhelpbrowser.h llfloaterhud.h llfloaterimagepreview.h + llfloaterimportcollada.h llfloaterinspect.h llfloaterinventory.h llfloaterjoystick.h @@ -714,6 +725,7 @@ set(viewer_HEADER_FILES llfloatermediabrowser.h llfloatermediasettings.h llfloatermemleak.h + llfloatermodelpreview.h llfloaternamedesc.h llfloaternotificationsconsole.h llfloateropenobject.h @@ -813,6 +825,8 @@ set(viewer_HEADER_FILES llmediadataclient.h llmemoryview.h llmenucommands.h + llmeshrepository.h + llmeshreduction.h llmetricperformancetester.h llmimetypes.h llmorphview.h @@ -1241,6 +1255,7 @@ if (WINDOWS) ${DINPUT_LIBRARY} ${DXGUID_LIBRARY} kernel32 + libboost_system odbc32 odbccp32 ole32 @@ -1662,6 +1677,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} ${FMODWRAPPER_LIBRARY} # must come after LLAudio + ${GLOD_LIBRARIES} ${OPENGL_LIBRARIES} ${SDL_LIBRARY} ${SMARTHEAP_LIBRARY} @@ -1673,6 +1689,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${CRYPTO_LIBRARIES} ${LLLOGIN_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} + ${LLCONVEXDECOMP_LIBRARY} ) build_version(viewer) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 4a04aeb948..05197f70cd 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1787,7 +1787,7 @@ <key>DebugShowRenderInfo</key> <map> <key>Comment</key> - <string>Show depth buffer contents</string> + <string>Show stats about current scene</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -1795,6 +1795,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>DebugShowUploadCost</key> + <map> + <key>Comment</key> + <string>Show what it would cost to upload assets in current scene</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>DebugShowRenderMatrices</key> <map> <key>Comment</key> @@ -5284,7 +5295,18 @@ <key>Value</key> <real>0</real> </map> - <key>MigrateCacheDirectory</key> + <key>MeshEnabled</key> + <map> + <key>Comment</key> + <string>Expose UI for mesh functionality (may require restart to take effect).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <real>1</real> + </map> + <key>MigrateCacheDirectory</key> <map> <key>Comment</key> <string>Check for old version of disk cache to migrate to current location</string> @@ -5958,6 +5980,66 @@ <key>Value</key> <real>0.0</real> </map> + <key>ObjectCostHighThreshold</key> + <map> + <key>Comment</key> + <string>Threshold at which object cost is considered high (displayed in red).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>50.0</real> + </map> + <key>ObjectCostLowColor</key> + <map> + <key>Comment</key> + <string>Color for object with a low object cost.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>0.0</real> + <real>0.5</real> + <real>1.0</real> + <real>0.5</real> + </array> + </map> + <key>ObjectCostMidColor</key> + <map> + <key>Comment</key> + <string>Color for object with a medium object cost.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>1.0</real> + <real>0.75</real> + <real>0.0</real> + <real>0.65</real> + </array> + </map> + <key>ObjectCostHighColor</key> + <map> + <key>Comment</key> + <string>Color for object a high object cost.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>1.0</real> + <real>0.0</real> + <real>0.0</real> + <real>0.75</real> + </array> + </map> + <key>ParcelMediaAutoPlayEnable</key> <map> <key>Comment</key> @@ -6622,7 +6704,19 @@ <key>Value</key> <integer>1</integer> </map> - + + <key>RenderLightingDetail</key> + <map> + <key>Comment</key> + <string>Amount of detail for lighting objects/avatars/terrain (0=sun/moon only, 1=enable local lights)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>RenderShadowNearDist</key> <map> <key>Comment</key> @@ -6819,7 +6913,18 @@ <key>Value</key> <integer>0</integer> </map> - <key>RenderDebugPipeline</key> + <key>RenderDebugNormalScale</key> + <map> + <key>Comment</key> + <string>Scale of normals in debug display.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.03</real> + </map> + <key>RenderDebugPipeline</key> <map> <key>Comment</key> <string>Enable strict pipeline debugging.</string> @@ -6852,6 +6957,7 @@ <key>Value</key> <integer>0</integer> </map> + <key>RenderAnimateRes</key> <map> <key>Comment</key> @@ -6863,7 +6969,31 @@ <key>Value</key> <integer>0</integer> </map> - + + <key>RenderBakeSunlight</key> + <map> + <key>Comment</key> + <string>Bake sunlight into vertex buffers for static objects.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + + <key>RenderNoAlpha</key> + <map> + <key>Comment</key> + <string>Disable rendering of alpha objects (render all alpha objects as alpha masks).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>RenderAnimateTrees</key> <map> <key>Comment</key> @@ -7020,6 +7150,18 @@ <real>16.0</real> </map> + <key>RenderMinimumLODTriangleCount</key> + <map> + <key>Comment</key> + <string>Triangle count threshold at which automatic LOD generation stops</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <real>16</real> + </map> + <key>RenderEdgeDepthCutoff</key> <map> <key>Comment</key> @@ -7155,7 +7297,7 @@ <key>Type</key> <string>F32</string> <key>Value</key> - <real>0.0</real> + <real>-0.001</real> </map> <key>RenderSpotShadowOffset</key> <map> @@ -8172,7 +8314,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>1</integer> </map> <key>RenderUseTriStrips</key> <map> @@ -8185,6 +8327,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>RenderUseTriStrips</key> + <map> + <key>Comment</key> + <string>Use triangle strips for rendering prims.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>RenderUseFarClip</key> <map> <key>Comment</key> @@ -8328,7 +8481,30 @@ <key>Value</key> <integer>0</integer> </map> - <key>SafeMode</key> + <key>MeshThreadCount</key> + <map> + <key>Comment</key> + <string>Number of threads to use for loading meshes.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>8</integer> + </map> + <key>MeshMaxConcurrentRequests</key> + <map> + <key>Comment</key> + <string>Number of threads to use for loading meshes.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>32</integer> + </map> + + <key>SafeMode</key> <map> <key>Comment</key> <string>Reset preferences, run in safe mode.</string> @@ -10966,7 +11142,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>1</integer> + <integer>0</integer> </map> <key>SpeakerParticipantRemoveDelay</key> <map> diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl index fea2e16090..7d18ae5036 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl @@ -22,7 +22,6 @@ varying vec3 vary_ambient; varying vec3 vary_directional; varying vec3 vary_fragcoord; varying vec3 vary_position; -varying vec3 vary_light; uniform mat4 inv_proj; @@ -55,7 +54,6 @@ void main() color.rgb = scaleSoftClip(color.rgb); - //gl_FragColor = gl_Color; gl_FragColor = color; //gl_FragColor = vec4(1,0,1,1); //gl_FragColor = vec4(1,0,1,1)*shadow; diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl index 04e556c11a..43200f1b07 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl @@ -36,7 +36,7 @@ void main() vec4 pos = (gl_ModelViewMatrix * gl_Vertex); vec3 norm = normalize(gl_NormalMatrix * gl_Normal); - vary_position = pos.xyz + norm.xyz * (-pos.z/64.0*shadow_offset+shadow_bias); + vary_position = pos.xyz; calcAtmospherics(pos.xyz); diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl index 650fbcc3f5..da1dafda36 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl @@ -17,7 +17,7 @@ vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 scaleDownLight(vec3 light); vec3 scaleUpLight(vec3 light); -varying vec4 vary_position; +varying vec3 vary_position; varying vec3 vary_ambient; varying vec3 vary_directional; varying vec3 vary_normal; @@ -41,7 +41,7 @@ void main() norm = normalize(norm); gl_Position = gl_ProjectionMatrix * pos; - vary_position = pos; + vary_position = pos.xyz; vary_normal = norm; calcAtmospherics(pos.xyz); diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl index c2e1ddf734..101458c438 100644 --- a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl @@ -12,7 +12,7 @@ uniform vec4 origin; void main() { //transform vertex - gl_Position = ftransform(); //gl_ModelViewProjectionMatrix * gl_Vertex; + gl_Position = ftransform(); vec4 pos = (gl_ModelViewMatrix * gl_Vertex); vec3 norm = normalize(gl_NormalMatrix * gl_Normal); diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 665fe16b43..fa6b4e2afb 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -115,7 +115,7 @@ void main() //gl_FragColor = gl_Color; gl_FragColor = color; - //gl_FragColor = vec4(1,0,1,1)*shadow; + //gl_FragColor = vec4(1,shadow,1,1); } diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl index f8dd1b7431..de423ee22a 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl @@ -21,6 +21,7 @@ varying vec3 vary_position; varying vec3 vary_ambient; varying vec3 vary_directional; varying vec3 vary_normal; +varying vec3 vary_fragcoord; uniform float near_clip; uniform float shadow_offset; @@ -77,7 +78,7 @@ void main() gl_FrontColor = col; gl_FogFragCoord = pos.z; - + vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip); } diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 9440e877df..5705aa8b05 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -55,10 +55,11 @@ Disregard128DefaultDrawDistance 1 1 Disregard96DefaultDrawDistance 1 1 RenderTextureMemoryMultiple 1 1.0 RenderShaderLightingMaxLevel 1 3 +RenderDeferred 1 1 SkyUseClassicClouds 1 1 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 +RenderDeferredSSAO 1 1 +RenderShadowDetail 1 2 +RenderUseFBO 1 1 WatchdogDisabled 1 1 RenderUseStreamVBO 1 1 @@ -167,9 +168,10 @@ RenderVolumeLODFactor 1 2.0 VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 +RenderDeferred 1 1 +RenderDeferredSSAO 1 1 +RenderShadowDetail 1 2 + // // Class Unknown Hardware (unknown) @@ -227,6 +229,7 @@ RenderDeferred 0 0 RenderDeferredSSAO 0 0 RenderShadowDetail 0 0 + // // "Default" setups for safe, low, medium, high // @@ -245,6 +248,7 @@ RenderDeferred 0 0 RenderDeferredSSAO 0 0 RenderShadowDetail 0 0 + // // CPU based feature masks // diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index 85b8564138..fda897756e 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -57,9 +57,9 @@ RenderTextureMemoryMultiple 1 1.0 SkyUseClassicClouds 1 1 RenderShaderLightingMaxLevel 1 3 RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 -WatchdogDisabled 1 1 +RenderDeferred 1 1 +RenderDeferredSSAO 1 1 +RenderShadowDetail 1 2 // // Low Graphics Settings @@ -166,9 +166,9 @@ RenderVolumeLODFactor 1 2.0 VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderShadowDetail 1 0 +RenderDeferred 1 1 +RenderDeferredSSAO 1 1 +RenderShadowDetail 1 2 // diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt index 7e6d4b4561..8736626907 100644 --- a/indra/newview/licenses-win32.txt +++ b/indra/newview/licenses-win32.txt @@ -769,3 +769,72 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +============= +GLOD license +============= +The GLOD Open-Source License Version 1.0 June 16, 2004 + +Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns +Hopkins University and David Luebke, Brenden Schubert, University of +Virginia. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer and + request. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer and + request in the documentation and/or other materials provided with + the distribution. + +3. The name "GLOD" must not be used to endorse or promote products + derived from this software without prior written permission. + +4. Redistributions of any modified version of this source, whether in + source or binary form , must include a form of the following + acknowledgment: "This product is derived from the GLOD library, + which is available from http://www.cs.jhu.edu/~graphics/GLOD." + +5. Redistributions of any modified version of this source in binary + form must provide, free of charge, access to the modified version + of the code. + +6. This license shall be governed by and construed and enforced in + accordance with the laws of the State of Maryland, without + reference to its conflicts of law provisions. The exclusive + jurisdiction and venue for all legal actions relating to this + license shall be in courts of competent subject matter jurisdiction + located in the State of Maryland. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED +UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR +PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH +YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE +COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY +NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY +CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS +AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY +SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF +PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS. + +YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE +COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS, +DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM +YOUR ACCEPTANCE AND USE OF GLOD. + +Although NOT REQUIRED, we would appreciate it if active users of GLOD +put a link on their web site to the GLOD web site when possible. + + diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 1ef9e34f87..95dafb4aa2 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -557,7 +557,9 @@ BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance) { BOOL soft_limit = FALSE; // is the bounding box to be treated literally (volumes) or as an approximation (avatars) - if (!mFocusObject || mFocusObject->isDead()) + if (!mFocusObject || mFocusObject->isDead() || + mFocusObject->isMesh() || + gSavedSettings.getBOOL("DisableCameraConstraints")) { obj_min_distance = 0.f; return TRUE; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b111dfe94c..0ef403720b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -49,6 +49,7 @@ #include "llwindow.h" #include "llviewerstats.h" #include "llmd5.h" +#include "llmeshrepository.h" #include "llpumpio.h" #include "llmimetypes.h" #include "llslurl.h" @@ -78,6 +79,8 @@ #include "llteleporthistory.h" #include "lllocationhistory.h" #include "llfasttimerview.h" +#include "llvector4a.h" +#include "llviewermenufile.h" #include "llvoicechannel.h" #include "llvoavatarself.h" #include "llsidetray.h" @@ -617,6 +620,9 @@ bool LLAppViewer::init() // LLFastTimer::reset(); + // initialize SSE options + LLVector4a::initClass(); + // Need to do this initialization before we do anything else, since anything // that touches files should really go through the lldir API gDirUtilp->initAppDirs("SecondLife"); @@ -1344,6 +1350,11 @@ bool LLAppViewer::cleanup() llinfos << "Cleaning Up" << llendflush; +#if LL_MESH_ENABLED + // shut down mesh streamer + gMeshRepo.shutdown(); +#endif + // Must clean up texture references before viewer window is destroyed. LLHUDManager::getInstance()->updateEffects(); LLHUDObject::updateAll(); @@ -1618,6 +1629,8 @@ bool LLAppViewer::cleanup() sTextureFetch->shutDownTextureCacheThread() ; sTextureFetch->shutDownImageDecodeThread() ; + LLFilePickerThread::cleanupClass(); + delete sTextureCache; sTextureCache = NULL; delete sTextureFetch; @@ -1757,6 +1770,13 @@ bool LLAppViewer::initThreads() mFastTimerLogThread->start(); } +#if LL_MESH_ENABLED + // Mesh streaming and caching + gMeshRepo.init(); +#endif + + LLFilePickerThread::initClass(); + // *FIX: no error handling here! return true; } @@ -2443,6 +2463,7 @@ bool LLAppViewer::initWindow() gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); gPipeline.init(); + stop_glerror(); gViewerWindow->initGLDefaults(); @@ -3493,6 +3514,10 @@ static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist"); static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region"); static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World"); static LLFastTimer::DeclareTimer FTM_NETWORK("Network"); +static LLFastTimer::DeclareTimer FTM_AGENT_NETWORK("Agent Network"); +static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot"); +static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update"); +static LLFastTimer::DeclareTimer FTM_VLMANAGER("VL Manager"); /////////////////////////////////////////////////////// // idle() @@ -3513,6 +3538,8 @@ void LLAppViewer::idle() LLEventTimer::updateClass(); LLCriticalDamp::updateInterpolants(); LLMortician::updateClass(); + LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() + F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); // Cap out-of-control frame times @@ -3563,7 +3590,7 @@ void LLAppViewer::idle() if (!gDisconnected) { - LLFastTimer t(FTM_NETWORK); + LLFastTimer t(FTM_AGENT_NETWORK); // Update spaceserver timeinfo LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC)); @@ -3760,7 +3787,7 @@ void LLAppViewer::idle() // { - LLFastTimer t(FTM_NETWORK); + LLFastTimer t(FTM_VLMANAGER); gVLManager.unpackData(); } @@ -4006,6 +4033,11 @@ static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; #endif static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Idle Network"); +static LLFastTimer::DeclareTimer FTM_MESSAGE_ACKS("Message Acks"); +static LLFastTimer::DeclareTimer FTM_RETRANSMIT("Retransmit"); +static LLFastTimer::DeclareTimer FTM_TIMEOUT_CHECK("Timeout Check"); +static LLFastTimer::DeclareTimer FTM_DYNAMIC_THROTTLE("Dynamic Throttle"); +static LLFastTimer::DeclareTimer FTM_CHECK_REGION_CIRCUIT("Check Region Circuit"); void LLAppViewer::idleNetwork() { @@ -4056,7 +4088,10 @@ void LLAppViewer::idleNetwork() } // Handle per-frame message system processing. - gMessageSystem->processAcks(); + { + LLFastTimer ftm(FTM_MESSAGE_ACKS); + gMessageSystem->processAcks(); + } #ifdef TIME_THROTTLE_MESSAGES if (total_time >= CheckMessagesMaxTime) @@ -4093,24 +4128,39 @@ void LLAppViewer::idleNetwork() LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects); // Retransmit unacknowledged packets. - gXferManager->retransmitUnackedPackets(); - gAssetStorage->checkForTimeouts(); - gViewerThrottle.updateDynamicThrottle(); + { + LLFastTimer ftm(FTM_RETRANSMIT); + gXferManager->retransmitUnackedPackets(); + } + + { + LLFastTimer ftm(FTM_TIMEOUT_CHECK); + gAssetStorage->checkForTimeouts(); + } + + + { + LLFastTimer ftm(FTM_DYNAMIC_THROTTLE); + gViewerThrottle.updateDynamicThrottle(); + } // Check that the circuit between the viewer and the agent's current // region is still alive - LLViewerRegion *agent_region = gAgent.getRegion(); - if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED)) { - LLUUID this_region_id = agent_region->getRegionID(); - bool this_region_alive = agent_region->isAlive(); - if ((mAgentRegionLastAlive && !this_region_alive) // newly dead - && (mAgentRegionLastID == this_region_id)) // same region + LLFastTimer ftm(FTM_CHECK_REGION_CIRCUIT); + LLViewerRegion *agent_region = gAgent.getRegion(); + if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED)) { - forceDisconnect(LLTrans::getString("AgentLostConnection")); + LLUUID this_region_id = agent_region->getRegionID(); + bool this_region_alive = agent_region->isAlive(); + if ((mAgentRegionLastAlive && !this_region_alive) // newly dead + && (mAgentRegionLastID == this_region_id)) // same region + { + forceDisconnect(LLTrans::getString("AgentLostConnection")); + } + mAgentRegionLastID = this_region_id; + mAgentRegionLastAlive = this_region_alive; } - mAgentRegionLastID = this_region_id; - mAgentRegionLastAlive = this_region_alive; } } diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 116c4cafc2..afb76735ec 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -42,6 +42,7 @@ #include "llinventorydefines.h" #include "llinventoryobserver.h" #include "llinventorypanel.h" +#include "llfloaterimportcollada.h" #include "llpermissionsflags.h" #include "llpreviewnotecard.h" #include "llpreviewscript.h" @@ -66,6 +67,7 @@ #include "llnotificationsutil.h" #include "llscrolllistctrl.h" #include "llsdserialize.h" +#include "llsdutil.h" #include "llvfs.h" // When uploading multiple files, don't display any of them when uploading more than this number. @@ -73,6 +75,106 @@ static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5; void dialog_refresh_all(); +void on_new_single_inventory_upload_complete( + LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + const std::string inventory_type_string, + const LLUUID& item_folder_id, + const std::string& item_name, + const std::string& item_description, + const LLSD& server_response, + S32 upload_price) +{ + if ( upload_price > 0 ) + { + // this upload costed us L$, update our balance + // and display something saying that it cost L$ + LLStatusBar::sendMoneyBalanceRequest(); + + LLSD args; + args["AMOUNT"] = llformat("%d", upload_price); + LLNotificationsUtil::add("UploadPayment", args); + } + + if( item_folder_id.notNull() ) + { + U32 everyone_perms = PERM_NONE; + U32 group_perms = PERM_NONE; + U32 next_owner_perms = PERM_ALL; + if( server_response.has("new_next_owner_mask") ) + { + // The server provided creation perms so use them. + // Do not assume we got the perms we asked for in + // since the server may not have granted them all. + everyone_perms = server_response["new_everyone_mask"].asInteger(); + group_perms = server_response["new_group_mask"].asInteger(); + next_owner_perms = server_response["new_next_owner_mask"].asInteger(); + } + else + { + // The server doesn't provide creation perms + // so use old assumption-based perms. + if( inventory_type_string != "snapshot") + { + next_owner_perms = PERM_MOVE | PERM_TRANSFER; + } + } + + LLPermissions new_perms; + new_perms.init( + gAgent.getID(), + gAgent.getID(), + LLUUID::null, + LLUUID::null); + + new_perms.initMasks( + PERM_ALL, + PERM_ALL, + everyone_perms, + group_perms, + next_owner_perms); + + S32 creation_date_now = time_corrected(); + LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem( + server_response["new_inventory_item"].asUUID(), + item_folder_id, + new_perms, + server_response["new_asset"].asUUID(), + asset_type, + inventory_type, + item_name, + item_description, + LLSaleInfo::DEFAULT, + LLInventoryItemFlags::II_FLAGS_NONE, + creation_date_now); + + gInventory.updateItem(item); + gInventory.notifyObservers(); + + // Show the preview panel for textures and sounds to let + // user know that the image (or snapshot) arrived intact. + LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); + if ( panel ) + { + LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + + panel->setSelection( + server_response["new_inventory_item"].asUUID(), + TAKE_FOCUS_NO); + + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus); + } + } + else + { + llwarns << "Can't find a folder to put it in" << llendl; + } + + // remove the "Uploading..." message + LLUploadDialog::modalUploadFinished(); +} + LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type) @@ -90,9 +192,10 @@ LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, } } -LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, - const std::string& file_name, - LLAssetType::EType asset_type) +LLAssetUploadResponder::LLAssetUploadResponder( + const LLSD &post_data, + const std::string& file_name, + LLAssetType::EType asset_type) : LLHTTPClient::Responder(), mPostData(post_data), mFileName(file_name), @@ -140,6 +243,7 @@ void LLAssetUploadResponder::result(const LLSD& content) lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl; std::string state = content["state"]; + if (state == "upload") { uploadUpload(content); @@ -201,16 +305,37 @@ void LLAssetUploadResponder::uploadComplete(const LLSD& content) { } -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, vfile_id, asset_type) +#if LL_MESH_ENABLED +LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, vfile_id, asset_type) { } -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, file_name, asset_type) +LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, file_name, asset_type) +{ +} + +// virtual +void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reason) { + LLAssetUploadResponder::error(statusNum, reason); + LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE); +} + + +//virtual +void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content) +{ + LLAssetUploadResponder::uploadFailure(content); + + LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE); } //virtual @@ -224,95 +349,31 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString()); LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString()); - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + S32 expected_upload_cost = 0; // Update L$ and ownership credit information // since it probably changed on the server if (asset_type == LLAssetType::AT_TEXTURE || asset_type == LLAssetType::AT_SOUND || - asset_type == LLAssetType::AT_ANIMATION) + asset_type == LLAssetType::AT_ANIMATION || + asset_type == LLAssetType::AT_MESH) { - LLStatusBar::sendMoneyBalanceRequest(); - - LLSD args; - args["AMOUNT"] = llformat("%d", expected_upload_cost); - LLNotificationsUtil::add("UploadPayment", args); + expected_upload_cost = + LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); } - // Actually add the upload to viewer inventory - llinfos << "Adding " << content["new_inventory_item"].asUUID() << " " - << content["new_asset"].asUUID() << " to inventory." << llendl; - if(mPostData["folder_id"].asUUID().notNull()) - { - //std::ostringstream out; - //LLSDXMLFormatter *formatter = new LLSDXMLFormatter; - //formatter->format(mPostData, out, LLSDFormatter::OPTIONS_PRETTY); - //llinfos << "Post Data: " << out.str() << llendl; + on_new_single_inventory_upload_complete( + asset_type, + inventory_type, + mPostData["asset_type"].asString(), + mPostData["folder_id"].asUUID(), + mPostData["name"], + mPostData["description"], + content, + expected_upload_cost); - U32 everyone_perms = PERM_NONE; - U32 group_perms = PERM_NONE; - U32 next_owner_perms = PERM_ALL; - if(content.has("new_next_owner_mask")) - { - // This is a new sim that provides creation perms so use them. - // Do not assume we got the perms we asked for in mPostData - // since the sim may not have granted them all. - everyone_perms = content["new_everyone_mask"].asInteger(); - group_perms = content["new_group_mask"].asInteger(); - next_owner_perms = content["new_next_owner_mask"].asInteger(); - } - else - { - // This old sim doesn't provide creation perms so use old assumption-based perms. - if(mPostData["inventory_type"].asString() != "snapshot") - { - next_owner_perms = PERM_MOVE | PERM_TRANSFER; - } - } - LLPermissions new_perms; - new_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); - new_perms.initMasks(PERM_ALL, PERM_ALL, everyone_perms, group_perms, next_owner_perms); - S32 creation_date_now = time_corrected(); - LLPointer<LLViewerInventoryItem> item - = new LLViewerInventoryItem(content["new_inventory_item"].asUUID(), - mPostData["folder_id"].asUUID(), - new_perms, - content["new_asset"].asUUID(), - asset_type, - inventory_type, - mPostData["name"].asString(), - mPostData["description"].asString(), - LLSaleInfo::DEFAULT, - LLInventoryItemFlags::II_FLAGS_NONE, - creation_date_now); - gInventory.updateItem(item); - gInventory.notifyObservers(); - - // Show the preview panel for textures and sounds to let - // user know that the image (or snapshot) arrived intact. - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if (active_panel) - { - active_panel->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); - if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type) - && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD) - { - active_panel->openSelected(); - } - //LLFloaterInventory::dumpSelectionInformation((void*)view); - // restore keyboard focus - LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); - gFocusMgr.setKeyboardFocus(focus); - } - } - else - { - llwarns << "Can't find a folder to put it in" << llendl; - } + // continue uploading for bulk uploads - // remove the "Uploading..." message - LLUploadDialog::modalUploadFinished(); - // *FIX: This is a pretty big hack. What this does is check the // file picker if there are any more pending uploads. If so, // upload that file. @@ -329,20 +390,44 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // Continuing the horrible hack above, we need to extract the originally requested permissions data, if any, // and use them for each next file to be uploaded. Note the requested perms are not the same as the - // granted ones found in the given "content" structure but can still be found in mPostData. -MG - U32 everyone_perms = mPostData.has("everyone_mask") ? mPostData.get("everyone_mask" ).asInteger() : PERM_NONE; - U32 group_perms = mPostData.has("group_mask") ? mPostData.get("group_mask" ).asInteger() : PERM_NONE; - U32 next_owner_perms = mPostData.has("next_owner_mask") ? mPostData.get("next_owner_mask").asInteger() : PERM_NONE; + U32 everyone_perms = + content.has("everyone_mask") ? + content["everyone_mask"].asInteger() : + PERM_NONE; + + U32 group_perms = + content.has("group_mask") ? + content["group_mask"].asInteger() : + PERM_NONE; + + U32 next_owner_perms = + content.has("next_owner_mask") ? + content["next_owner_mask"].asInteger() : + PERM_NONE; + std::string display_name = LLStringUtil::null; LLAssetStorage::LLStoreAssetCallback callback = NULL; void *userdata = NULL; - upload_new_resource(next_file, asset_name, asset_name, - 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - next_owner_perms, group_perms, - everyone_perms, display_name, - callback, expected_upload_cost, userdata); + + upload_new_resource( + next_file, + asset_name, + asset_name, + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_NONE, + next_owner_perms, + group_perms, + everyone_perms, + display_name, + callback, + LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), + userdata); } + + LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE); } +#endif LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, const LLUUID& vfile_id, @@ -395,17 +480,19 @@ void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason) mBakedUploadData = NULL; // deleted in onTextureUploadComplete() } -LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, vfile_id, asset_type) +LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, vfile_id, asset_type) { } -LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, file_name, asset_type) +LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, file_name, asset_type) { } @@ -588,3 +675,475 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) break; } } + + +#if LL_MESH_ENABLED +///////////////////////////////////////////////////// +// LLNewAgentInventoryVariablePriceResponder::Impl // +///////////////////////////////////////////////////// +class LLNewAgentInventoryVariablePriceResponder::Impl +{ +public: + Impl( + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + const LLSD& inventory_data) : + mVFileID(vfile_id), + mAssetType(asset_type), + mInventoryData(inventory_data), + mFileName("") + { + if (!gVFS->getExists(vfile_id, asset_type)) + { + llwarns + << "LLAssetUploadResponder called with nonexistant " + << "vfile_id " << vfile_id << llendl; + mVFileID.setNull(); + mAssetType = LLAssetType::AT_NONE; + } + } + + Impl( + const std::string& file_name, + LLAssetType::EType asset_type, + const LLSD& inventory_data) : + mFileName(file_name), + mAssetType(asset_type), + mInventoryData(inventory_data) + { + mVFileID.setNull(); + } + + std::string getFilenameOrIDString() const + { + return (mFileName.empty() ? mVFileID.asString() : mFileName); + } + + LLUUID getVFileID() const + { + return mVFileID; + } + + std::string getFilename() const + { + return mFileName; + } + + LLAssetType::EType getAssetType() const + { + return mAssetType; + } + + LLInventoryType::EType getInventoryType() const + { + return LLInventoryType::lookup( + mInventoryData["inventory_type"].asString()); + } + + std::string getInventoryTypeString() const + { + return mInventoryData["inventory_type"].asString(); + } + + LLUUID getFolderID() const + { + return mInventoryData["folder_id"].asUUID(); + } + + std::string getItemName() const + { + return mInventoryData["name"].asString(); + } + + std::string getItemDescription() const + { + return mInventoryData["description"].asString(); + } + + void displayCannotUploadReason(const std::string& reason) + { + LLSD args; + args["FILE"] = getFilenameOrIDString(); + args["REASON"] = reason; + + + LLNotificationsUtil::add("CannotUploadReason", args); + LLUploadDialog::modalUploadFinished(); + } + + void onApplicationLevelError(const LLSD& error) + { + static const std::string _IDENTIFIER = "identifier"; + + static const std::string _INSUFFICIENT_FUNDS = + "NewAgentInventory_InsufficientLindenDollarBalance"; + static const std::string _MISSING_REQUIRED_PARAMETER = + "NewAgentInventory_MissingRequiredParamater"; + static const std::string _INVALID_REQUEST_BODY = + "NewAgentInventory_InvalidRequestBody"; + static const std::string _RESOURCE_COST_DIFFERS = + "NewAgentInventory_ResourceCostDiffers"; + + static const std::string _MISSING_PARAMETER = "missing_parameter"; + static const std::string _INVALID_PARAMETER = "invalid_parameter"; + static const std::string _MISSING_RESOURCE = "missing_resource"; + static const std::string _INVALID_RESOURCE = "invalid_resource"; + + // TODO* Add the other error_identifiers + + std::string error_identifier = error[_IDENTIFIER].asString(); + + // TODO*: Pull these user visible strings from an xml file + // to be localized + if ( _INSUFFICIENT_FUNDS == error_identifier ) + { + displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload."); + } + else if ( _MISSING_REQUIRED_PARAMETER == error_identifier ) + { + // Missing parameters + if (error.has(_MISSING_PARAMETER) ) + { + std::string message = + "Upload request was missing required parameter '[P]'"; + LLStringUtil::replaceString( + message, + "[P]", + error[_MISSING_PARAMETER].asString()); + + displayCannotUploadReason(message); + } + else + { + std::string message = + "Upload request was missing a required parameter"; + displayCannotUploadReason(message); + } + } + else if ( _INVALID_REQUEST_BODY == error_identifier ) + { + // Invalid request body, check to see if + // a particular parameter was invalid + if ( error.has(_INVALID_PARAMETER) ) + { + std::string message = "Upload parameter '[P]' is invalid."; + LLStringUtil::replaceString( + message, + "[P]", + error[_INVALID_PARAMETER].asString()); + + // See if the server also responds with what resource + // is missing. + if ( error.has(_MISSING_RESOURCE) ) + { + message += "\nMissing resource '[R]'."; + + LLStringUtil::replaceString( + message, + "[R]", + error[_MISSING_RESOURCE].asString()); + } + else if ( error.has(_INVALID_RESOURCE) ) + { + message += "\nInvalid resource '[R]'."; + + LLStringUtil::replaceString( + message, + "[R]", + error[_INVALID_RESOURCE].asString()); + } + + displayCannotUploadReason(message); + } + else + { + std::string message = "Upload request was malformed"; + displayCannotUploadReason(message); + } + } + else if ( _RESOURCE_COST_DIFFERS == error_identifier ) + { + displayCannotUploadReason("The resource cost associated with this upload is not consistent with the server."); + } + else + { + displayCannotUploadReason("Unknown Error"); + } + } + + void onTransportError() + { + displayCannotUploadReason( + "The server is experiencing unexpected difficulties."); + } + + void onTransportError(const LLSD& error) + { + static const std::string _IDENTIFIER = "identifier"; + + static const std::string _SERVER_ERROR_AFTER_CHARGE = + "NewAgentInventory_ServerErrorAfterCharge"; + + std::string error_identifier = error[_IDENTIFIER].asString(); + + // TODO*: Pull the user visible strings from an xml file + // to be localized + + if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier ) + { + displayCannotUploadReason( + "The server is experiencing unexpected difficulties. You may have been charged for the upload."); + } + else + { + displayCannotUploadReason( + "The server is experiencing unexpected difficulties."); + } + } + + bool uploadConfirmationCallback( + const LLSD& notification, + const LLSD& response, + boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> responder) + { + S32 option; + std::string confirmation_url; + + option = LLNotificationsUtil::getSelectedOption( + notification, + response); + + confirmation_url = + notification["payload"]["confirmation_url"].asString(); + + // Yay! We are confirming or cancelling our upload + switch(option) + { + case 0: + { + confirmUpload(confirmation_url, responder); + } + break; + case 1: + default: + break; + } + + return false; + } + + void confirmUpload( + const std::string& confirmation_url, + boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> responder) + { + if ( getFilename().empty() ) + { + // we have no filename, use virtual file ID instead + LLHTTPClient::postFile( + confirmation_url, + getVFileID(), + getAssetType(), + responder); + } + else + { + LLHTTPClient::postFile( + confirmation_url, + getFilename(), + responder); + } + } + + +private: + std::string mFileName; + + LLSD mInventoryData; + LLAssetType::EType mAssetType; + LLUUID mVFileID; +}; + +/////////////////////////////////////////////// +// LLNewAgentInventoryVariablePriceResponder // +/////////////////////////////////////////////// +LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + const LLSD& inventory_info) +{ + mImpl = new Impl( + vfile_id, + asset_type, + inventory_info); +} + +LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( + const std::string& file_name, + LLAssetType::EType asset_type, + const LLSD& inventory_info) +{ + mImpl = new Impl( + file_name, + asset_type, + inventory_info); +} + +LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder() +{ + delete mImpl; +} + +void LLNewAgentInventoryVariablePriceResponder::errorWithContent( + U32 statusNum, + const std::string& reason, + const LLSD& content) +{ + lldebugs + << "LLNewAgentInventoryVariablePrice::error " << statusNum + << " reason: " << reason << llendl; + + if ( content.has("error") ) + { + static const std::string _ERROR = "error"; + + mImpl->onTransportError(content[_ERROR]); + } + else + { + mImpl->onTransportError(); + } +} + +void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) +{ + // Parse out application level errors and the appropriate + // responses for them + static const std::string _ERROR = "error"; + static const std::string _STATE = "state"; + + static const std::string _COMPLETE = "complete"; + static const std::string _CONFIRM_UPLOAD = "confirm_upload"; + + static const std::string _UPLOAD_PRICE = "upload_price"; + static const std::string _RESOURCE_COST = "resource_cost"; + static const std::string _RSVP = "rsvp"; + + // Check for application level errors + if ( content.has(_ERROR) ) + { + onApplicationLevelError(content[_ERROR]); + return; + } + + std::string state = content[_STATE]; + LLAssetType::EType asset_type = mImpl->getAssetType(); + + if ( _COMPLETE == state ) + { + // rename file in VFS with new asset id + if (mImpl->getFilename().empty()) + { + // rename the file in the VFS to the actual asset id + // llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl; + gVFS->renameFile( + mImpl->getVFileID(), + asset_type, + content["new_asset"].asUUID(), + asset_type); + } + + on_new_single_inventory_upload_complete( + asset_type, + mImpl->getInventoryType(), + mImpl->getInventoryTypeString(), + mImpl->getFolderID(), + mImpl->getItemName(), + mImpl->getItemDescription(), + content, + content[_UPLOAD_PRICE].asInteger()); + + // TODO* Add bulk (serial) uploading or add + // a super class of this that does so + } + else if ( _CONFIRM_UPLOAD == state ) + { + showConfirmationDialog( + content[_UPLOAD_PRICE].asInteger(), + content[_RESOURCE_COST].asInteger(), + content[_RSVP].asString()); + } + else + { + onApplicationLevelError(""); + } +} + +void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError( + const LLSD& error) +{ + mImpl->onApplicationLevelError(error); +} + +void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( + S32 upload_price, + S32 resource_cost, + const std::string& confirmation_url) +{ + if ( 0 == upload_price ) + { + // don't show confirmation dialog for free uploads, I mean, + // they're free! + + // The creating of a new instrusive_ptr(this) + // creates a new boost::intrusive_ptr + // which is a copy of this. This code is required because + // 'this' is always of type Class* and not the intrusive_ptr, + // and thus, a reference to 'this' is not registered + // by using just plain 'this'. + + // Since LLNewAgentInventoryVariablePriceResponder is a + // reference counted class, it is possible (since the + // reference to a plain 'this' would be missed here) that, + // when using plain ol' 'this', that this object + // would be deleted before the callback is triggered + // and cause sadness. + mImpl->confirmUpload( + confirmation_url, + boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this)); + } + else + { + LLSD substitutions; + LLSD payload; + + substitutions["PRICE"] = upload_price; + + payload["confirmation_url"] = confirmation_url; + + // The creating of a new instrusive_ptr(this) + // creates a new boost::intrusive_ptr + // which is a copy of this. This code is required because + // 'this' is always of type Class* and not the intrusive_ptr, + // and thus, a reference to 'this' is not registered + // by using just plain 'this'. + + // Since LLNewAgentInventoryVariablePriceResponder is a + // reference counted class, it is possible (since the + // reference to a plain 'this' would be missed here) that, + // when using plain ol' 'this', that this object + // would be deleted before the callback is triggered + // and cause sadness. + LLNotificationsUtil::add( + "UploadCostConfirmation", + substitutions, + payload, + boost::bind( + &LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback, + mImpl, + _1, + _2, + boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this))); + } +} +#endif + diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 91fb39916d..a85e84e9f8 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -34,6 +34,7 @@ #define LL_LLASSETUPLOADRESPONDER_H #include "llhttpclient.h" +#include "llvolume.h" //for LL_MESH_ENABLED // Abstract class for supporting asset upload // via capabilities @@ -61,16 +62,61 @@ protected: std::string mFileName; }; +#if LL_MESH_ENABLED +// TODO*: Remove this once deprecated class LLNewAgentInventoryResponder : public LLAssetUploadResponder { public: - LLNewAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type); - LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name, - LLAssetType::EType asset_type); + LLNewAgentInventoryResponder( + const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type); + LLNewAgentInventoryResponder( + const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type); + virtual void error(U32 statusNum, const std::string& reason); virtual void uploadComplete(const LLSD& content); + virtual void uploadFailure(const LLSD& content); +}; + +// A base class which goes through and performs some default +// actions for variable price uploads. If more specific actions +// are needed (such as different confirmation messages, etc.) +// the functions onApplicationLevelError and showConfirmationDialog. +class LLNewAgentInventoryVariablePriceResponder : + public LLHTTPClient::Responder +{ +public: + LLNewAgentInventoryVariablePriceResponder( + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + const LLSD& inventory_info); + + LLNewAgentInventoryVariablePriceResponder( + const std::string& file_name, + LLAssetType::EType asset_type, + const LLSD& inventory_info); + virtual ~LLNewAgentInventoryVariablePriceResponder(); + + void errorWithContent( + U32 statusNum, + const std::string& reason, + const LLSD& content); + void result(const LLSD& content); + + virtual void onApplicationLevelError( + const LLSD& error); + virtual void showConfirmationDialog( + S32 upload_price, + S32 resource_cost, + const std::string& confirmation_url); + +private: + class Impl; + Impl* mImpl; }; +#endif struct LLBakedUploadData; class LLSendTexLayerResponder : public LLAssetUploadResponder diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 4f56d6395f..8d0a06378f 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -41,6 +41,7 @@ #include "llcriticaldamp.h" #include "llface.h" #include "lllightconstants.h" +#include "llmatrix4a.h" #include "llsky.h" #include "llsurfacepatch.h" #include "llviewercamera.h" @@ -91,8 +92,12 @@ void LLDrawable::incrementVisible() sCurVisible++; sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView(); } + void LLDrawable::init() { + mExtents = (LLVector4a*) ll_aligned_malloc_32(sizeof(LLVector4a)*3); + mPositionGroup = mExtents + 2; + // mXform mParent = NULL; mRenderType = 0; @@ -121,6 +126,11 @@ void LLDrawable::initClass() void LLDrawable::destroy() { + if (gDebugGL) + { + gPipeline.checkReferences(this); + } + if (isDead()) { sNumZombieDrawables--; @@ -139,6 +149,9 @@ void LLDrawable::destroy() { llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl; }*/ + + ll_aligned_free_32(mExtents); + mExtents = mPositionGroup = NULL; } void LLDrawable::markDead() @@ -189,20 +202,30 @@ BOOL LLDrawable::isLight() const } } +static LLFastTimer::DeclareTimer FTM_CLEANUP_DRAWABLE("Cleanup Drawable"); +static LLFastTimer::DeclareTimer FTM_DEREF_DRAWABLE("Deref"); +static LLFastTimer::DeclareTimer FTM_DELETE_FACES("Faces"); + void LLDrawable::cleanupReferences() { - LLFastTimer t(FTM_PIPELINE); + LLFastTimer t(FTM_CLEANUP_DRAWABLE); - std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); - mFaces.clear(); + { + LLFastTimer t(FTM_DELETE_FACES); + std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); + mFaces.clear(); + } gObjectList.removeDrawable(this); gPipeline.unlinkDrawable(this); - // Cleanup references to other objects - mVObjp = NULL; - mParent = NULL; + { + LLFastTimer t(FTM_DEREF_DRAWABLE); + // Cleanup references to other objects + mVObjp = NULL; + mParent = NULL; + } } void LLDrawable::cleanupDeadDrawables() @@ -704,12 +727,14 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) LLFace* facep = getFace(i); if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA) { - LLVector3 box = (facep->mExtents[1] - facep->mExtents[0]) * 0.25f; + LLVector4a box; + box.setSub(facep->mExtents[1], facep->mExtents[0]); + box.mul(0.25f); LLVector3 v = (facep->mCenterLocal-camera.getOrigin()); const LLVector3& at = camera.getAtAxis(); for (U32 j = 0; j < 3; j++) { - v.mV[j] -= box.mV[j] * at.mV[j]; + v.mV[j] -= box[j] * at.mV[j]; } facep->mDistance = v * camera.getAtAxis(); } @@ -718,7 +743,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) } else { - pos = LLVector3(getPositionGroup()); + pos = LLVector3(getPositionGroup().getF32()); } pos -= camera.getOrigin(); @@ -767,7 +792,7 @@ BOOL LLDrawable::updateGeometry(BOOL priority) return res; } -void LLDrawable::shiftPos(const LLVector3 &shift_vector) +void LLDrawable::shiftPos(const LLVector4a &shift_vector) { if (isDead()) { @@ -799,9 +824,9 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector) for (S32 i = 0; i < getNumFaces(); i++) { LLFace *facep = getFace(i); - facep->mCenterAgent += shift_vector; - facep->mExtents[0] += shift_vector; - facep->mExtents[1] += shift_vector; + facep->mCenterAgent += LLVector3(shift_vector.getF32()); + facep->mExtents[0].add(shift_vector); + facep->mExtents[1].add(shift_vector); if (!volume && facep->hasGeometry()) { @@ -810,9 +835,9 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector) } } - mExtents[0] += shift_vector; - mExtents[1] += shift_vector; - mPositionGroup += LLVector3d(shift_vector); + mExtents[0].add(shift_vector); + mExtents[1].add(shift_vector); + mPositionGroup->add(shift_vector); } else if (mSpatialBridge) { @@ -820,9 +845,9 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector) } else if (isAvatar()) { - mExtents[0] += shift_vector; - mExtents[1] += shift_vector; - mPositionGroup += LLVector3d(shift_vector); + mExtents[0].add(shift_vector); + mExtents[1].add(shift_vector); + mPositionGroup->add(shift_vector); } mVObjp->onShift(shift_vector); @@ -834,21 +859,26 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const return mXform.getPositionW(); } -const LLVector3* LLDrawable::getSpatialExtents() const +const LLVector4a* LLDrawable::getSpatialExtents() const { return mExtents; } -void LLDrawable::setSpatialExtents(LLVector3 min, LLVector3 max) +void LLDrawable::setSpatialExtents(const LLVector3& min, const LLVector3& max) +{ + mExtents[0].load3(min.mV); + mExtents[1].load3(max.mV); +} + +void LLDrawable::setSpatialExtents(const LLVector4a& min, const LLVector4a& max) { - LLVector3 size = max - min; mExtents[0] = min; - mExtents[1] = max; + mExtents[1] = max; } -void LLDrawable::setPositionGroup(const LLVector3d& pos) +void LLDrawable::setPositionGroup(const LLVector4a& pos) { - mPositionGroup.setVec(pos); + *mPositionGroup = pos; } void LLDrawable::updateSpatialExtents() @@ -862,7 +892,7 @@ void LLDrawable::updateSpatialExtents() if (mSpatialBridge.notNull()) { - mPositionGroup.setVec(0,0,0); + mPositionGroup->splat(0.f); } } @@ -1073,59 +1103,72 @@ void LLSpatialBridge::updateSpatialExtents() root->rebound(); } - LLXformMatrix* mat = mDrawable->getXform(); - - LLVector3 offset = root->mBounds[0]; - LLVector3 size = root->mBounds[1]; + LLVector4a offset; + LLVector4a size = root->mBounds[1]; - LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix(); - LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix()); + //VECTORIZE THIS + LLMatrix4a mat; + mat.loadu(mDrawable->getXform()->getWorldMatrix()); + + LLVector4a t; + t.splat(0.f); + + LLVector4a center; + mat.affineTransform(t, center); - offset *= rotation; - center += offset; + mat.rotate(root->mBounds[0], offset); + center.add(offset); - LLVector3 v[4]; + LLVector4a v[4]; + //get 4 corners of bounding box - v[0] = (size * rotation); - v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation); - v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation); - v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation); + mat.rotate(size,v[0]); + + LLVector4a scale; + + scale.set(-1.f, -1.f, 1.f); + scale.mul(size); + mat.rotate(scale, v[1]); + + scale.set(1.f, -1.f, -1.f); + scale.mul(size); + mat.rotate(scale, v[2]); + + scale.set(-1.f, 1.f, -1.f); + scale.mul(size); + mat.rotate(scale, v[3]); - LLVector3& newMin = mExtents[0]; - LLVector3& newMax = mExtents[1]; + + LLVector4a& newMin = mExtents[0]; + LLVector4a& newMax = mExtents[1]; newMin = newMax = center; for (U32 i = 0; i < 4; i++) { - for (U32 j = 0; j < 3; j++) - { - F32 delta = fabsf(v[i].mV[j]); - F32 min = center.mV[j] - delta; - F32 max = center.mV[j] + delta; - - if (min < newMin.mV[j]) - { - newMin.mV[j] = min; - } - - if (max > newMax.mV[j]) - { - newMax.mV[j] = max; - } - } - } + LLVector4a delta; + delta.setAbs(v[i]); + LLVector4a min; + min.setSub(center, delta); + LLVector4a max; + max.setAdd(center, delta); - LLVector3 diagonal = newMax - newMin; - mRadius = diagonal.magVec() * 0.5f; + newMin.setMin(min); + newMax.setMax(max); + } + + LLVector4a diagonal; + diagonal.setSub(newMax, newMin); + mRadius = diagonal.length3() * 0.5f; - mPositionGroup.setVec((newMin + newMax) * 0.5f); + mPositionGroup->setAdd(newMin,newMax); + mPositionGroup->mul(0.5f); updateBinRadius(); } void LLSpatialBridge::updateBinRadius() { - mBinRadius = llmin((F32) mOctree->getSize().mdV[0]*0.5f, 256.f); + mBinRadius = llmin( mOctree->getSize()[0]*0.5f, 256.f); } LLCamera LLSpatialBridge::transformCamera(LLCamera& camera) @@ -1266,8 +1309,12 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); - LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f; - LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f; + LLVector4a center; + center.setAdd(mExtents[0], mExtents[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(mExtents[1], mExtents[0]); + size.mul(0.5f); if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) || LLPipeline::sImpostorRender || @@ -1380,11 +1427,11 @@ BOOL LLSpatialBridge::updateMove() return TRUE; } -void LLSpatialBridge::shiftPos(const LLVector3& vec) +void LLSpatialBridge::shiftPos(const LLVector4a& vec) { - mExtents[0] += vec; - mExtents[1] += vec; - mPositionGroup += LLVector3d(vec); + mExtents[0].add(vec); + mExtents[1].add(vec); + mPositionGroup->add(vec); } void LLSpatialBridge::cleanupReferences() @@ -1502,7 +1549,7 @@ F32 LLHUDBridge::calcPixelArea(LLSpatialGroup* group, LLCamera& camera) } -void LLHUDBridge::shiftPos(const LLVector3& vec) +void LLHUDBridge::shiftPos(const LLVector4a& vec) { //don't shift hud bridges on region crossing } diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 08972853c3..fc90bc57c4 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -41,6 +41,7 @@ #include "v4math.h" #include "m4math.h" #include "v4coloru.h" +#include "llvector4a.h" #include "llquaternion.h" #include "xform.h" #include "llmemtype.h" @@ -66,6 +67,17 @@ const U32 SILHOUETTE_HIGHLIGHT = 0; class LLDrawable : public LLRefCount { public: + LLDrawable(const LLDrawable& rhs) + { + *this = rhs; + } + + const LLDrawable& operator=(const LLDrawable& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + static void initClass(); LLDrawable() { init(); } @@ -94,14 +106,14 @@ public: const LLVector3& getPosition() const { return mXform.getPosition(); } const LLVector3& getWorldPosition() const { return mXform.getPositionW(); } const LLVector3 getPositionAgent() const; - const LLVector3d& getPositionGroup() const { return mPositionGroup; } + const LLVector4a& getPositionGroup() const { return *mPositionGroup; } const LLVector3& getScale() const { return mCurrentScale; } void setScale(const LLVector3& scale) { mCurrentScale = scale; } const LLQuaternion& getWorldRotation() const { return mXform.getWorldRotation(); } const LLQuaternion& getRotation() const { return mXform.getRotation(); } F32 getIntensity() const { return llmin(mXform.getScale().mV[0], 4.f); } S32 getLOD() const { return mVObjp ? mVObjp->getLOD() : 1; } - F64 getBinRadius() const { return mBinRadius; } + F32 getBinRadius() const { return mBinRadius; } void getMinMax(LLVector3& min,LLVector3& max) const { mXform.getMinMax(min,max); } LLXformMatrix* getXform() { return &mXform; } @@ -155,7 +167,7 @@ public: void updateSpecialHoverCursor(BOOL enabled); - virtual void shiftPos(const LLVector3 &shift_vector); + virtual void shiftPos(const LLVector4a &shift_vector); S32 getGeneration() const { return mGeneration; } @@ -173,11 +185,12 @@ public: const LLVector3& getBounds(LLVector3& min, LLVector3& max) const; virtual void updateSpatialExtents(); virtual void updateBinRadius(); - const LLVector3* getSpatialExtents() const; - void setSpatialExtents(LLVector3 min, LLVector3 max); - void setPositionGroup(const LLVector3d& pos); - void setPositionGroup(const LLVector3& pos) { setPositionGroup(LLVector3d(pos)); } + const LLVector4a* getSpatialExtents() const; + void setSpatialExtents(const LLVector3& min, const LLVector3& max); + void setSpatialExtents(const LLVector4a& min, const LLVector4a& max); + void setPositionGroup(const LLVector4a& pos); + void setRenderType(S32 type) { mRenderType = type; } BOOL isRenderType(S32 type) { return mRenderType == type; } S32 getRenderType() { return mRenderType; } @@ -288,6 +301,9 @@ public: private: typedef std::vector<LLFace*> face_list_t; + LLVector4a* mExtents; + LLVector4a* mPositionGroup; + U32 mState; S32 mRenderType; LLPointer<LLViewerObject> mVObjp; @@ -297,9 +313,7 @@ private: mutable U32 mVisible; F32 mRadius; - LLVector3 mExtents[2]; - LLVector3d mPositionGroup; - F64 mBinRadius; + F32 mBinRadius; S32 mGeneration; LLVector3 mCurrentScale; diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index ae30af3647..a99b80d618 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -248,11 +248,6 @@ void LLFacePool::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures { } -BOOL LLFacePool::moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data) -{ - return TRUE; -} - // static S32 LLFacePool::drawLoop(face_array_t& face_list) { diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index f85b46cfba..ec870f59c6 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -188,8 +188,6 @@ public: virtual void resetDrawOrders(); void resetAll(); - BOOL moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data = FALSE); - void destroy(); void buildEdges(); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 60844ae8ca..c7e77fd6ba 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -39,13 +39,17 @@ #include "m3math.h" #include "lldrawable.h" +#include "lldrawpoolbump.h" #include "llface.h" +#include "llmeshrepository.h" #include "llsky.h" #include "llviewercamera.h" #include "llviewerregion.h" #include "noise.h" #include "pipeline.h" #include "llviewershadermgr.h" +#include "llvovolume.h" +#include "llvolume.h" #include "llappviewer.h" #include "llrendersphere.h" #include "llviewerpartsim.h" @@ -53,10 +57,15 @@ static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK; static U32 sBufferUsage = GL_STREAM_DRAW_ARB; static U32 sShaderLevel = 0; -static LLGLSLShader* sVertexProgram = NULL; + +LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = NULL; BOOL LLDrawPoolAvatar::sSkipOpaque = FALSE; BOOL LLDrawPoolAvatar::sSkipTransparent = FALSE; +S32 LLDrawPoolAvatar::sDiffuseChannel = 0; + + +static bool is_deferred_render = false; extern BOOL gUseGLPick; @@ -92,7 +101,22 @@ BOOL gAvatarEmbossBumpMap = FALSE; static BOOL sRenderingSkinned = FALSE; S32 normal_channel = -1; S32 specular_channel = -1; -S32 diffuse_channel = -1; +S32 cube_channel = -1; + +#if LL_MESH_ENABLED +static const U32 rigged_data_mask[] = { + LLDrawPoolAvatar::RIGGED_SIMPLE_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK, + LLDrawPoolAvatar::RIGGED_SHINY_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK, + LLDrawPoolAvatar::RIGGED_GLOW_MASK, + LLDrawPoolAvatar::RIGGED_ALPHA_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK, + LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK, + LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK, +}; +#endif + static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow"); @@ -148,21 +172,17 @@ LLMatrix4& LLDrawPoolAvatar::getModelView() //----------------------------------------------------------------------------- -S32 LLDrawPoolAvatar::getNumDeferredPasses() -{ - return getNumPasses(); -} void LLDrawPoolAvatar::beginDeferredPass(S32 pass) { LLFastTimer t(FTM_RENDER_CHARACTERS); sSkipTransparent = TRUE; - + is_deferred_render = true; + if (LLPipeline::sImpostorRender) - { - beginDeferredSkinned(); - return; + { //impostor pass does not have rigid or impostor rendering + pass += 2; } switch (pass) @@ -176,6 +196,14 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass) case 2: beginDeferredSkinned(); break; +#if LL_MESH_ENABLED + case 3: + beginDeferredRiggedSimple(); + break; + case 4: + beginDeferredRiggedBump(); + break; +#endif } } @@ -184,11 +212,11 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass) LLFastTimer t(FTM_RENDER_CHARACTERS); sSkipTransparent = FALSE; + is_deferred_render = false; if (LLPipeline::sImpostorRender) { - endDeferredSkinned(); - return; + pass += 2; } switch (pass) @@ -202,6 +230,14 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass) case 2: endDeferredSkinned(); break; +#if LL_MESH_ENABLED + case 3: + endDeferredRiggedSimple(); + break; + case 4: + endDeferredRiggedBump(); + break; +#endif } } @@ -212,11 +248,42 @@ void LLDrawPoolAvatar::renderDeferred(S32 pass) S32 LLDrawPoolAvatar::getNumPostDeferredPasses() { +#if LL_MESH_ENABLED + return 6; +#else return 1; +#endif } void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass) { + switch (pass) + { + case 0: + beginPostDeferredAlpha(); + break; +#if LL_MESH_ENABLED + case 1: + beginRiggedFullbright(); + break; + case 2: + beginRiggedFullbrightShiny(); + break; + case 3: + beginDeferredRiggedAlpha(); + break; + case 4: + beginRiggedFullbrightAlpha(); + break; + case 5: + beginRiggedGlow(); + break; +#endif + } +} + +void LLDrawPoolAvatar::beginPostDeferredAlpha() +{ sSkipOpaque = TRUE; sShaderLevel = mVertexShaderLevel; sVertexProgram = &gDeferredAvatarAlphaProgram; @@ -225,64 +292,144 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass) gPipeline.bindDeferredShader(*sVertexProgram); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]); } +#if LL_MESH_ENABLED +void LLDrawPoolAvatar::beginDeferredRiggedAlpha() +{ + sVertexProgram = &gDeferredSkinnedAlphaProgram; + gPipeline.bindDeferredShader(*sVertexProgram); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); + gPipeline.enableLightsDynamic(); +} + +void LLDrawPoolAvatar::endDeferredRiggedAlpha() +{ + LLVertexBuffer::unbind(); + gPipeline.unbindDeferredShader(*sVertexProgram); + sDiffuseChannel = 0; + LLVertexBuffer::sWeight4Loc = -1; + sVertexProgram = NULL; +} +#endif + void LLDrawPoolAvatar::endPostDeferredPass(S32 pass) { + switch (pass) + { + case 0: + endPostDeferredAlpha(); + break; +#if LL_MESH_ENABLED + case 1: + endRiggedFullbright(); + break; + case 2: + endRiggedFullbrightShiny(); + break; + case 3: + endDeferredRiggedAlpha(); + break; + case 4: + endRiggedFullbrightAlpha(); + break; + case 5: + endRiggedGlow(); + break; +#endif + } +} + +void LLDrawPoolAvatar::endPostDeferredAlpha() +{ // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done sRenderingSkinned = FALSE; sSkipOpaque = FALSE; disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]); gPipeline.unbindDeferredShader(*sVertexProgram); - + sDiffuseChannel = 0; sShaderLevel = mVertexShaderLevel; } void LLDrawPoolAvatar::renderPostDeferred(S32 pass) { - render(2); //pass 2 = skinned + const S32 actual_pass[] = + { //map post deferred pass numbers to what render() expects + 2, //skinned + 4, // rigged fullbright + 6, //rigged fullbright shiny + 7, //rigged alpha + 8, //rigged fullbright alpha + 9, //rigged glow + }; + + render(actual_pass[pass]); } S32 LLDrawPoolAvatar::getNumShadowPasses() { +#if LL_MESH_ENABLED + return 2; +#else return 1; +#endif } void LLDrawPoolAvatar::beginShadowPass(S32 pass) { LLFastTimer t(FTM_SHADOW_AVATAR); - sVertexProgram = &gDeferredAvatarShadowProgram; - if (sShaderLevel > 0) + + if (pass == 0) { - gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX]; - } - gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f); - - glColor4f(1,1,1,1); + sVertexProgram = &gDeferredAvatarShadowProgram; + if (sShaderLevel > 0) + { + gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX]; + } + gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f); + + glColor4f(1,1,1,1); - if ((sShaderLevel > 0)) // for hardware blending + if ((sShaderLevel > 0)) // for hardware blending + { + sRenderingSkinned = TRUE; + sVertexProgram->bind(); + enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]); + } + } + else { - sRenderingSkinned = TRUE; + sVertexProgram = &gDeferredAttachmentShadowProgram; + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->bind(); - enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); } - } void LLDrawPoolAvatar::endShadowPass(S32 pass) { LLFastTimer t(FTM_SHADOW_AVATAR); - if (sShaderLevel > 0) + if (pass == 0) { - sRenderingSkinned = FALSE; + if (sShaderLevel > 0) + { + sRenderingSkinned = FALSE; + sVertexProgram->unbind(); + disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]); + } + } + else + { + LLVertexBuffer::unbind(); sVertexProgram->unbind(); - disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]); + LLVertexBuffer::sWeight4Loc = -1; + sVertexProgram = NULL; } - - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } void LLDrawPoolAvatar::renderShadow(S32 pass) @@ -312,20 +459,69 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) return; } - if (sShaderLevel > 0) + if (pass == 0) { - gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX]; - } - - avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE); + if (sShaderLevel > 0) + { + gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX]; + } + avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE); + } +#if LL_MESH_ENABLED + else + { + renderRigged(avatarp, RIGGED_SIMPLE); + renderRigged(avatarp, RIGGED_ALPHA); + renderRigged(avatarp, RIGGED_FULLBRIGHT); + renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY); + renderRigged(avatarp, RIGGED_SHINY); + renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA); + } +#endif } S32 LLDrawPoolAvatar::getNumPasses() { - return LLPipeline::sImpostorRender ? 1 : 3; +#if LL_MESH_ENABLED + if (LLPipeline::sImpostorRender) + { + return 8; + } + else if (getVertexShaderLevel() > 0) + { + return 10; + } + else + { + return 3; + } +#else + if (LLPipeline::sImpostorRender) + { + return 1; + } + else + { + return 3; + } +#endif +} + + +S32 LLDrawPoolAvatar::getNumDeferredPasses() +{ + if (LLPipeline::sImpostorRender) + { + return 3; + } + else + { + return 5; + } } + void LLDrawPoolAvatar::render(S32 pass) { LLFastTimer t(FTM_RENDER_CHARACTERS); @@ -345,9 +541,8 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass) LLVertexBuffer::unbind(); if (LLPipeline::sImpostorRender) - { - beginSkinned(); - return; + { //impostor render does not have impostors or rigid rendering + pass += 2; } switch (pass) @@ -361,6 +556,29 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass) case 2: beginSkinned(); break; +#if LL_MESH_ENABLED + case 3: + beginRiggedSimple(); + break; + case 4: + beginRiggedFullbright(); + break; + case 5: + beginRiggedShinySimple(); + break; + case 6: + beginRiggedFullbrightShiny(); + break; + case 7: + beginRiggedAlpha(); + break; + case 8: + beginRiggedFullbrightAlpha(); + break; + case 9: + beginRiggedGlow(); + break; +#endif } } @@ -370,8 +588,7 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass) if (LLPipeline::sImpostorRender) { - endSkinned(); - return; + pass += 2; } switch (pass) @@ -384,6 +601,30 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass) break; case 2: endSkinned(); + break; +#if LL_MESH_ENABLED + case 3: + endRiggedSimple(); + break; + case 4: + endRiggedFullbright(); + break; + case 5: + endRiggedShinySimple(); + break; + case 6: + endRiggedFullbrightShiny(); + break; + case 7: + endRiggedAlpha(); + break; + case 8: + endRiggedFullbrightAlpha(); + break; + case 9: + endRiggedGlow(); + break; +#endif } } @@ -396,7 +637,7 @@ void LLDrawPoolAvatar::beginImpostor() } gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); - diffuse_channel = 0; + sDiffuseChannel = 0; } void LLDrawPoolAvatar::endImpostor() @@ -447,9 +688,9 @@ void LLDrawPoolAvatar::beginDeferredImpostor() sVertexProgram = &gDeferredImpostorProgram; - normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL); specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP); - diffuse_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->bind(); } @@ -569,6 +810,161 @@ void LLDrawPoolAvatar::endSkinned() gGL.getTexUnit(0)->activate(); } +#if LL_MESH_ENABLED +void LLDrawPoolAvatar::beginRiggedSimple() +{ + sVertexProgram = &gSkinnedObjectSimpleProgram; + sDiffuseChannel = 0; + gSkinnedObjectSimpleProgram.bind(); + LLVertexBuffer::sWeight4Loc = gSkinnedObjectSimpleProgram.getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endRiggedSimple() +{ + sVertexProgram = NULL; + LLVertexBuffer::unbind(); + gSkinnedObjectSimpleProgram.unbind(); + LLVertexBuffer::sWeight4Loc = -1; +} + +void LLDrawPoolAvatar::beginRiggedAlpha() +{ + sVertexProgram = &gSkinnedObjectSimpleProgram; + sDiffuseChannel = 0; + sVertexProgram->bind(); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endRiggedAlpha() +{ + sVertexProgram->unbind(); + sVertexProgram = NULL; + LLVertexBuffer::unbind(); + LLVertexBuffer::sWeight4Loc = -1; +} + + +void LLDrawPoolAvatar::beginRiggedFullbrightAlpha() +{ + sVertexProgram = &gSkinnedObjectFullbrightProgram; + sDiffuseChannel = 0; + sVertexProgram->bind(); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endRiggedFullbrightAlpha() +{ + sVertexProgram->unbind(); + sVertexProgram = NULL; + LLVertexBuffer::unbind(); + LLVertexBuffer::sWeight4Loc = -1; +} + +void LLDrawPoolAvatar::beginRiggedGlow() +{ + sVertexProgram = &gSkinnedObjectFullbrightProgram; + sDiffuseChannel = 0; + sVertexProgram->bind(); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endRiggedGlow() +{ + sVertexProgram->unbind(); + sVertexProgram = NULL; + LLVertexBuffer::unbind(); + LLVertexBuffer::sWeight4Loc = -1; +} + +void LLDrawPoolAvatar::beginRiggedFullbright() +{ + sVertexProgram = &gSkinnedObjectFullbrightProgram; + sDiffuseChannel = 0; + gSkinnedObjectFullbrightProgram.bind(); + LLVertexBuffer::sWeight4Loc = gSkinnedObjectFullbrightProgram.getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endRiggedFullbright() +{ + sVertexProgram = NULL; + LLVertexBuffer::unbind(); + gSkinnedObjectFullbrightProgram.unbind(); + LLVertexBuffer::sWeight4Loc = -1; +} + +void LLDrawPoolAvatar::beginRiggedShinySimple() +{ + sVertexProgram = &gSkinnedObjectShinySimpleProgram; + sVertexProgram->bind(); + LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endRiggedShinySimple() +{ + LLVertexBuffer::unbind(); + LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); + sVertexProgram->unbind(); + sVertexProgram = NULL; + LLVertexBuffer::sWeight4Loc = -1; +} + +void LLDrawPoolAvatar::beginRiggedFullbrightShiny() +{ + sVertexProgram = &gSkinnedObjectFullbrightShinyProgram; + sVertexProgram->bind(); + LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endRiggedFullbrightShiny() +{ + LLVertexBuffer::unbind(); + LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); + sVertexProgram->unbind(); + sVertexProgram = NULL; + LLVertexBuffer::sWeight4Loc = -1; +} + + +void LLDrawPoolAvatar::beginDeferredRiggedSimple() +{ + sVertexProgram = &gDeferredSkinnedDiffuseProgram; + sDiffuseChannel = 0; + sVertexProgram->bind(); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endDeferredRiggedSimple() +{ + LLVertexBuffer::unbind(); + sVertexProgram->unbind(); + LLVertexBuffer::sWeight4Loc = -1; + sVertexProgram = NULL; +} + +void LLDrawPoolAvatar::beginDeferredRiggedBump() +{ + sVertexProgram = &gDeferredSkinnedBumpProgram; + sVertexProgram->bind(); + normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT); +} + +void LLDrawPoolAvatar::endDeferredRiggedBump() +{ + LLVertexBuffer::unbind(); + sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP); + sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + sVertexProgram->unbind(); + LLVertexBuffer::sWeight4Loc = -1; + normal_channel = -1; + sDiffuseChannel = 0; + sVertexProgram = NULL; +} +#endif + void LLDrawPoolAvatar::beginDeferredSkinned() { sShaderLevel = mVertexShaderLevel; @@ -696,7 +1092,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) avatarp->mImpostor.bindTexture(1, specular_channel); } } - avatarp->renderImpostor(LLColor4U(255,255,255,255), diffuse_channel); + avatarp->renderImpostor(LLColor4U(255,255,255,255), sDiffuseChannel); } return; } @@ -712,6 +1108,90 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) avatarp->renderRigid(); return; } + +#if LL_MESH_ENABLED + if (pass == 3) + { + if (is_deferred_render) + { + renderDeferredRiggedSimple(avatarp); + } + else + { + renderRiggedSimple(avatarp); + } + return; + } + + if (pass == 4) + { + if (is_deferred_render) + { + renderDeferredRiggedBump(avatarp); + } + else + { + renderRiggedFullbright(avatarp); + } + + return; + } + + if (pass == 5) + { + renderRiggedShinySimple(avatarp); + return; + } + + if (pass == 6) + { + renderRiggedFullbrightShiny(avatarp); + return; + } + + if (pass >= 7 && pass < 9) + { + LLGLEnable blend(GL_BLEND); + + gGL.setColorMask(true, true); + gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, + LLRender::BF_ONE_MINUS_SOURCE_ALPHA, + LLRender::BF_ZERO, + LLRender::BF_ONE_MINUS_SOURCE_ALPHA); + + + if (pass == 7) + { + renderRiggedAlpha(avatarp); + return; + } + + if (pass == 8) + { + renderRiggedFullbrightAlpha(avatarp); + return; + } + } + + if (pass == 9) + { + LLGLEnable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + gGL.flush(); + + LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.0f, -1.0f); + gGL.setSceneBlendType(LLRender::BT_ADD); + + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + gGL.setColorMask(false, true); + + renderRiggedGlow(avatarp); + gGL.setColorMask(true, false); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + return; + } +#endif if (sShaderLevel > 0) { @@ -749,13 +1229,205 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } } +#if LL_MESH_ENABLED +void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face) +{ + U32 data_mask = 0; + for (U32 i = 0; i < face->mRiggedIndex.size(); ++i) + { + if (face->mRiggedIndex[i] > -1) + { + data_mask |= rigged_data_mask[i]; + } + } + + LLVertexBuffer* buff = face->mVertexBuffer; + + if (!buff || + buff->getTypeMask() != data_mask || + buff->getRequestedVerts() != vol_face.mNumVertices) + { + face->setGeomIndex(0); + face->setIndicesIndex(0); + face->setSize(vol_face.mNumVertices, vol_face.mNumIndices, true); + + face->mVertexBuffer = new LLVertexBuffer(data_mask, 0); + face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), true); + + U16 offset = 0; + + LLMatrix4 mat_vert = skin->mBindShapeMatrix; + glh::matrix4f m((F32*) mat_vert.mMatrix); + m = m.inverse().transpose(); + + F32 mat3[] = + { m.m[0], m.m[1], m.m[2], + m.m[4], m.m[5], m.m[6], + m.m[8], m.m[9], m.m[10] }; + + LLMatrix3 mat_normal(mat3); + + face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true); + buff = face->mVertexBuffer; + } +} + +void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) +{ + for (U32 i = 0; i < mRiggedFace[type].size(); ++i) + { + LLFace* face = mRiggedFace[type][i]; + LLDrawable* drawable = face->getDrawable(); + if (!drawable) + { + continue; + } + + LLVOVolume* vobj = drawable->getVOVolume(); + + if (!vobj) + { + continue; + } + + LLVolume* volume = vobj->getVolume(); + S32 te = face->getTEOffset(); + + if (!volume || volume->getNumVolumeFaces() <= te) + { + continue; + } + + LLUUID mesh_id = volume->getParams().getSculptID(); + if (mesh_id.isNull()) + { + continue; + } + + const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id); + if (!skin) + { + continue; + } + + const LLVolumeFace& vol_face = volume->getVolumeFace(te); + updateRiggedFaceVertexBuffer(face, skin, volume, vol_face); + + U32 data_mask = rigged_data_mask[type]; + + LLVertexBuffer* buff = face->mVertexBuffer; + + if (buff) + { + LLMatrix4 mat[64]; + + for (U32 i = 0; i < skin->mJointNames.size(); ++i) + { + LLJoint* joint = avatar->getJoint(skin->mJointNames[i]); + if (joint) + { + mat[i] = skin->mInvBindMatrix[i]; + mat[i] *= joint->getWorldMatrix(); + } + } + + LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette", + skin->mJointNames.size(), + FALSE, + (GLfloat*) mat[0].mMatrix); + LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette[0]", + skin->mJointNames.size(), + FALSE, + (GLfloat*) mat[0].mMatrix); + + buff->setBuffer(data_mask); + + U16 start = face->getGeomStart(); + U16 end = start + face->getGeomCount()-1; + S32 offset = face->getIndicesStart(); + U32 count = face->getIndicesCount(); + + if (glow) + { + glColor4f(0,0,0,face->getTextureEntry()->getGlow()); + } + + gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture()); + if (normal_channel > -1) + { + LLDrawPoolBump::bindBumpMap(face, normal_channel); + } + + if (face->mTextureMatrix) + { + glMatrixMode(GL_TEXTURE); + glLoadMatrixf((F32*) face->mTextureMatrix->mMatrix); + buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + } + else + { + buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); + } + } + } +} + +void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_DEFERRED_SIMPLE); +} + +void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_DEFERRED_BUMP); +} + +void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_SIMPLE); +} + +void LLDrawPoolAvatar::renderRiggedFullbright(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_FULLBRIGHT); +} + + +void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_SHINY); +} + +void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_FULLBRIGHT_SHINY); +} + +void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_ALPHA); +} + +void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA); +} + +void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar) +{ + renderRigged(avatar, RIGGED_GLOW, true); +} +#endif + + + //----------------------------------------------------------------------------- // renderForSelect() //----------------------------------------------------------------------------- void LLDrawPoolAvatar::renderForSelect() { - - if (mDrawFace.empty()) { return; @@ -849,6 +1521,63 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const return LLColor3(0.f, 1.f, 0.f); } +#if LL_MESH_ENABLED +void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type) +{ + if (facep->mRiggedIndex.empty()) + { + facep->mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES); + for (U32 i = 0; i < facep->mRiggedIndex.size(); ++i) + { + facep->mRiggedIndex[i] = -1; + } + } + + if (type >= NUM_RIGGED_PASSES) + { + llerrs << "Invalid rigged face type." << llendl; + } + + if (facep->mRiggedIndex[type] != -1) + { + llerrs << "Tried to add a rigged face that's referenced elsewhere." << llendl; + } + + + facep->mRiggedIndex[type] = mRiggedFace[type].size(); + facep->mDrawPoolp = this; + mRiggedFace[type].push_back(facep); +} + +void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep) +{ + + facep->mDrawPoolp = NULL; + + for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) + { + S32 index = facep->mRiggedIndex[i]; + + if (index > -1) + { + if (mRiggedFace[i].size() > index && mRiggedFace[i][index] == facep) + { + facep->mRiggedIndex[i] = -1; + mRiggedFace[i].erase(mRiggedFace[i].begin()+index); + for (U32 j = index; j < mRiggedFace[i].size(); ++j) + { //bump indexes down for faces referenced after erased face + mRiggedFace[i][j]->mRiggedIndex[i] = j; + } + } + else + { + llerrs << "Face reference data corrupt for rigged type " << i << llendl; + } + } + } +} +#endif + LLVertexBufferAvatar::LLVertexBufferAvatar() : LLVertexBuffer(sDataMask, GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets @@ -863,20 +1592,23 @@ void LLVertexBufferAvatar::setupVertexBuffer(U32 data_mask) const { U8* base = useVBOs() ? NULL : mMappedData; - glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0)); - glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL])); - glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD0])); + glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_VERTEX], (void*)(base + 0)); + glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); - set_vertex_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT], mStride, (F32*)(base + mOffsets[TYPE_WEIGHT])); + set_vertex_weights(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT], + LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_WEIGHT], (F32*)(base + mOffsets[TYPE_WEIGHT])); if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_BUMP) { - set_binormals(sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL], mStride, (LLVector3*)(base + mOffsets[TYPE_BINORMAL])); + set_binormals(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL], + LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_BINORMAL], (LLVector3*)(base + mOffsets[TYPE_BINORMAL])); } if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH) { - set_vertex_clothing_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING], mStride, (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT])); + set_vertex_clothing_weights(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING], + LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_CLOTHWEIGHT], (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT])); } } else diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index d247260527..b01394534b 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -1,4 +1,4 @@ -/** + /** * @file lldrawpoolavatar.h * @brief LLDrawPoolAvatar class definition * @@ -34,8 +34,15 @@ #define LL_LLDRAWPOOLAVATAR_H #include "lldrawpool.h" +#include "llvolume.h" // for LL_MESH_ENABLED class LLVOAvatar; +class LLGLSLShader; +class LLFace; +class LLMeshSkinInfo; +class LLVolume; +class LLVolumeFace; + class LLDrawPoolAvatar : public LLFacePool { @@ -90,7 +97,7 @@ public: void beginRigid(); void beginImpostor(); void beginSkinned(); - + void endRigid(); void endImpostor(); void endSkinned(); @@ -102,14 +109,114 @@ public: void endDeferredImpostor(); void endDeferredRigid(); void endDeferredSkinned(); + + void beginPostDeferredAlpha(); + void endPostDeferredAlpha(); + +#if LL_MESH_ENABLED + void beginRiggedSimple(); + void beginRiggedFullbright(); + void beginRiggedFullbrightShiny(); + void beginRiggedShinySimple(); + void beginRiggedAlpha(); + void beginRiggedFullbrightAlpha(); + void beginRiggedGlow(); + void beginDeferredRiggedAlpha(); + + void endRiggedSimple(); + void endRiggedFullbright(); + void endRiggedFullbrightShiny(); + void endRiggedShinySimple(); + void endRiggedAlpha(); + void endRiggedFullbrightAlpha(); + void endRiggedGlow(); + void endDeferredRiggedAlpha(); + + void beginDeferredRiggedSimple(); + void beginDeferredRiggedBump(); + + void endDeferredRiggedSimple(); + void endDeferredRiggedBump(); + void updateRiggedFaceVertexBuffer(LLFace* facep, + const LLMeshSkinInfo* skin, + LLVolume* volume, + const LLVolumeFace& vol_face); + + void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false); + void renderRiggedSimple(LLVOAvatar* avatar); + void renderRiggedAlpha(LLVOAvatar* avatar); + void renderRiggedFullbrightAlpha(LLVOAvatar* avatar); + void renderRiggedFullbright(LLVOAvatar* avatar); + void renderRiggedShinySimple(LLVOAvatar* avatar); + void renderRiggedFullbrightShiny(LLVOAvatar* avatar); + void renderRiggedGlow(LLVOAvatar* avatar); + void renderDeferredRiggedSimple(LLVOAvatar* avatar); + void renderDeferredRiggedBump(LLVOAvatar* avatar); + + typedef enum + { + RIGGED_SIMPLE = 0, + RIGGED_FULLBRIGHT, + RIGGED_SHINY, + RIGGED_FULLBRIGHT_SHINY, + RIGGED_GLOW, + RIGGED_ALPHA, + RIGGED_FULLBRIGHT_ALPHA, + RIGGED_DEFERRED_BUMP, + RIGGED_DEFERRED_SIMPLE, + NUM_RIGGED_PASSES, + RIGGED_UNKNOWN, + } eRiggedPass; + + typedef enum + { + RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4, + RIGGED_FULLBRIGHT_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4, + RIGGED_SHINY_MASK = RIGGED_SIMPLE_MASK, + RIGGED_FULLBRIGHT_SHINY_MASK = RIGGED_SIMPLE_MASK, + RIGGED_GLOW_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_WEIGHT4, + RIGGED_ALPHA_MASK = RIGGED_SIMPLE_MASK, + RIGGED_FULLBRIGHT_ALPHA_MASK = RIGGED_FULLBRIGHT_MASK, + RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_BINORMAL | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4, + RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4, + } eRiggedDataMask; + + void addRiggedFace(LLFace* facep, U32 type); + void removeRiggedFace(LLFace* facep); + + std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES]; +#endif + /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null. + static BOOL sSkipOpaque; static BOOL sSkipTransparent; + static S32 sDiffuseChannel; + + static LLGLSLShader* sVertexProgram; }; class LLVertexBufferAvatar : public LLVertexBuffer diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 2206ed406f..20097e29fe 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -340,30 +340,43 @@ void LLDrawPoolBump::beginShiny(bool invisible) sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; } - if (LLPipeline::sUnderWaterRender) + if (getVertexShaderLevel() > 0) { - shader = &gObjectShinyWaterProgram; + if (LLPipeline::sUnderWaterRender) + { + shader = &gObjectShinyWaterProgram; + } + else + { + shader = &gObjectShinyProgram; + } + shader->bind(); } else { - shader = &gObjectShinyProgram; + shader = NULL; } + bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible); +} + +//static +void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible) +{ LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { - if (!invisible && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0 ) + if (!invisible && shader ) { LLMatrix4 mat; mat.initRows(LLVector4(gGLModelView+0), LLVector4(gGLModelView+4), LLVector4(gGLModelView+8), LLVector4(gGLModelView+12)); - shader->bind(); LLVector3 vec = LLVector3(gShinyOrigin) * mat; LLVector4 vec4(vec, gShinyOrigin.mV[3]); shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); - if (mVertexShaderLevel > 1) + if (shader_level > 1) { cube_map->setMatrix(1); // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for @@ -425,22 +438,16 @@ void LLDrawPoolBump::renderShiny(bool invisible) } } -void LLDrawPoolBump::endShiny(bool invisible) +//static +void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible) { - LLFastTimer t(FTM_RENDER_SHINY); - if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| - (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) - { - return; - } - LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { cube_map->disable(); cube_map->restoreMatrix(); - if (!invisible && mVertexShaderLevel > 1) + if (!invisible && shader_level > 1) { shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); @@ -451,7 +458,6 @@ void LLDrawPoolBump::endShiny(bool invisible) shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } } - shader->unbind(); } } gGL.getTexUnit(diffuse_channel)->disable(); @@ -459,6 +465,22 @@ void LLDrawPoolBump::endShiny(bool invisible) gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); +} + +void LLDrawPoolBump::endShiny(bool invisible) +{ + LLFastTimer t(FTM_RENDER_SHINY); + if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| + (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) + { + return; + } + + unbindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible); + if (shader) + { + shader->unbind(); + } diffuse_channel = -1; cube_channel = 0; @@ -586,18 +608,37 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL // static BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel) { - LLViewerTexture* bump = NULL; - U8 bump_code = params.mBump; + return bindBumpMap(bump_code, params.mTexture, params.mVSize, channel); +} + +//static +BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel) +{ + const LLTextureEntry* te = face->getTextureEntry(); + if (te) + { + U8 bump_code = te->getBumpmap(); + return bindBumpMap(bump_code, face->getTexture(), face->getVirtualSize(), channel); + } + + return FALSE; +} + +//static +BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsize, S32 channel) +{ //Note: texture atlas does not support bump texture now. - LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params.mTexture) ; + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ; if(!tex) { //if the texture is not a fetched texture return FALSE; } + LLViewerTexture* bump = NULL; + switch( bump_code ) { case BE_NO_BUMP: @@ -611,7 +652,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel) if( bump_code < LLStandardBumpmap::sStandardBumpmapCount ) { bump = gStandardBumpmapList[bump_code].mImage; - gBumpImageList.addTextureStats(bump_code, tex->getID(), params.mVSize); + gBumpImageList.addTextureStats(bump_code, tex->getID(), vsize); } break; } diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 07846c2812..d634b7329e 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -41,6 +41,7 @@ class LLImageRaw; class LLSpatialGroup; class LLDrawInfo; +class LLGLSLShader; class LLViewerFetchedTexture; class LLDrawPoolBump : public LLRenderPass @@ -79,6 +80,9 @@ public: void renderBump(U32 pass = LLRenderPass::PASS_BUMP); void endBump(U32 pass = LLRenderPass::PASS_BUMP); + static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible); + static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible); + virtual S32 getNumDeferredPasses(); /*virtual*/ void beginDeferredPass(S32 pass); /*virtual*/ void endDeferredPass(S32 pass); @@ -89,7 +93,12 @@ public: /*virtual*/ void endPostDeferredPass(S32 pass); /*virtual*/ void renderPostDeferred(S32 pass); - BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2); + static BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2); + static BOOL bindBumpMap(LLFace* face, S32 channel = -2); + +private: + static BOOL bindBumpMap(U8 bump_code, LLViewerTexture* tex, F32 vsize, S32 channel); + }; enum EBumpEffect diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 67a45e06c3..91191287cd 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -151,7 +151,7 @@ void LLDrawPoolSimple::render(S32 pass) renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask()); if (LLPipeline::sRenderDeferred) - { //if deferred rendering is enabled, bump faces aren't registered as simple + { //if deferred rendering is enabled, bump faces aren't reigstered as simple //render bump faces here as simple so bump faces will appear under water renderTexture(LLRenderPass::PASS_BUMP, getVertexDataMask()); } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 6a1a9dd4e1..8533f9710c 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -39,8 +39,10 @@ #include "llviewercontrol.h" #include "llvolume.h" #include "m3math.h" +#include "llmatrix4a.h" #include "v3color.h" +#include "lldrawpoolavatar.h" #include "lldrawpoolbump.h" #include "llgl.h" #include "llrender.h" @@ -73,35 +75,43 @@ The resulting texture coordinate <u,v> is: u = 2(B dot P) v = 2(T dot P) */ -void planarProjection(LLVector2 &tc, const LLVector3& normal, - const LLVector3 &mCenter, const LLVector3& vec) -{ //DONE! - LLVector3 binormal; - float d = normal * LLVector3(1,0,0); +void planarProjection(LLVector2 &tc, const LLVector4a& normal, + const LLVector4a ¢er, const LLVector4a& vec) +{ + LLVector4a binormal; + F32 d = normal[0]; + if (d >= 0.5f || d <= -0.5f) { - binormal = LLVector3(0,1,0); - if (normal.mV[0] < 0) + if (d < 0) { - binormal = -binormal; + binormal.set(0,-1,0); + } + else + { + binormal.set(0, 1, 0); } } else { - binormal = LLVector3(1,0,0); - if (normal.mV[1] > 0) + if (normal[1] > 0) + { + binormal.set(-1,0,0); + } + else { - binormal = -binormal; + binormal.set(1,0,0); } } - LLVector3 tangent = binormal % normal; + LLVector4a tangent; + tangent.setCross3(binormal,normal); - tc.mV[1] = -((tangent*vec)*2 - 0.5f); - tc.mV[0] = 1.0f+((binormal*vec)*2 - 0.5f); + tc.mV[1] = -((tangent.dot3(vec))*2 - 0.5f); + tc.mV[0] = 1.0f+((binormal.dot3(vec))*2 - 0.5f); } -void sphericalProjection(LLVector2 &tc, const LLVector3& normal, - const LLVector3 &mCenter, const LLVector3& vec) +void sphericalProjection(LLVector2 &tc, const LLVector4a& normal, + const LLVector4a &mCenter, const LLVector4a& vec) { //BROKEN /*tc.mV[0] = acosf(vd.mNormal * LLVector3(1,0,0))/3.14159f; @@ -112,7 +122,7 @@ void sphericalProjection(LLVector2 &tc, const LLVector3& normal, }*/ } -void cylindricalProjection(LLVector2 &tc, const LLVector3& normal, const LLVector3 &mCenter, const LLVector3& vec) +void cylindricalProjection(LLVector2 &tc, const LLVector4a& normal, const LLVector4a &mCenter, const LLVector4a& vec) { //BROKEN /*LLVector3 binormal; float d = vd.mNormal * LLVector3(1,0,0); @@ -142,6 +152,8 @@ void cylindricalProjection(LLVector2 &tc, const LLVector3& normal, const LLVecto void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) { + mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*2); + mLastUpdateTime = gFrameTimeSeconds; mLastMoveTime = 0.f; mVSize = 0.f; @@ -185,22 +197,50 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mHasMedia = FALSE ; } +static LLFastTimer::DeclareTimer FTM_DESTROY_FACE("Destroy Face"); +static LLFastTimer::DeclareTimer FTM_DESTROY_TEXTURE("Texture"); +static LLFastTimer::DeclareTimer FTM_DESTROY_DRAWPOOL("Drawpool"); +static LLFastTimer::DeclareTimer FTM_DESTROY_TEXTURE_MATRIX("Texture Matrix"); +static LLFastTimer::DeclareTimer FTM_DESTROY_DRAW_INFO("Draw Info"); +static LLFastTimer::DeclareTimer FTM_DESTROY_ATLAS("Atlas"); +static LLFastTimer::DeclareTimer FTM_FACE_DEREF("Deref"); void LLFace::destroy() { + LLFastTimer t(FTM_DESTROY_FACE); + + if (gDebugGL) + { + gPipeline.checkReferences(this); + } + if(mTexture.notNull()) { + LLFastTimer t(FTM_DESTROY_TEXTURE); mTexture->removeFace(this) ; } if (mDrawPoolp) { - mDrawPoolp->removeFace(this); + LLFastTimer t(FTM_DESTROY_DRAWPOOL); + +#if LL_MESH_ENABLED + if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR) + { + ((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this); + } + else +#endif + { + mDrawPoolp->removeFace(this); + } + mDrawPoolp = NULL; } if (mTextureMatrix) { + LLFastTimer t(FTM_DESTROY_TEXTURE_MATRIX); delete mTextureMatrix; mTextureMatrix = NULL; @@ -215,11 +255,24 @@ void LLFace::destroy() } } - setDrawInfo(NULL); + { + LLFastTimer t(FTM_DESTROY_DRAW_INFO); + setDrawInfo(NULL); + } - removeAtlas(); - mDrawablep = NULL; - mVObjp = NULL; + { + LLFastTimer t(FTM_DESTROY_ATLAS); + removeAtlas(); + } + + { + LLFastTimer t(FTM_FACE_DEREF); + mDrawablep = NULL; + mVObjp = NULL; + } + + ll_aligned_free_16(mExtents); + mExtents = NULL; } @@ -335,8 +388,21 @@ void LLFace::setDrawable(LLDrawable *drawable) mXform = &drawable->mXform; } -void LLFace::setSize(const S32 num_vertices, const S32 num_indices) +void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) { + if (align) + { + //allocate vertices in blocks of 4 for alignment + num_vertices = (num_vertices + 0x3) & ~0x3; + } + else + { + if (mDrawablep->getVOVolume()) + { + llerrs << "WTF?" << llendl; + } + } + if (mGeomCount != num_vertices || mIndicesCount != num_indices) { @@ -672,95 +738,117 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, - const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL global_volume) + const LLMatrix4& mat_vert_in, const LLMatrix3& mat_normal_in, BOOL global_volume) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); //get bounding box if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION)) { + //VECTORIZE THIS + LLMatrix4a mat_vert; + mat_vert.loadu(mat_vert_in); + + LLMatrix4a mat_normal; + mat_normal.loadu(mat_normal_in); + //if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) //{ //vertex buffer no longer valid // mVertexBuffer = NULL; // mLastVertexBuffer = NULL; //} - LLVector3 min,max; + //VECTORIZE THIS + LLVector4a min,max; if (f >= volume.getNumVolumeFaces()) { - min = LLVector3(-1,-1,-1); - max = LLVector3(1,1,1); - } - else - { - const LLVolumeFace &face = volume.getVolumeFace(f); - min = face.mExtents[0]; - max = face.mExtents[1]; + llwarns << "Generating bounding box for invalid face index!" << llendl; + f = 0; } + const LLVolumeFace &face = volume.getVolumeFace(f); + min = face.mExtents[0]; + max = face.mExtents[1]; + + //min, max are in volume space, convert to drawable render space - LLVector3 center = ((min + max) * 0.5f)*mat_vert; - LLVector3 size = ((max-min) * 0.5f); + LLVector4a center; + LLVector4a t; + t.setAdd(min, max); + t.mul(0.5f); + mat_vert.affineTransform(t, center); + LLVector4a size; + size.setSub(max, min); + size.mul(0.5f); + if (!global_volume) { - size.scaleVec(mDrawablep->getVObj()->getScale()); + //VECTORIZE THIS + LLVector4a scale; + scale.load3(mDrawablep->getVObj()->getScale().mV); + size.mul(scale); } - LLMatrix3 mat = mat_normal; - LLVector3 x = mat.getFwdRow(); - LLVector3 y = mat.getLeftRow(); - LLVector3 z = mat.getUpRow(); - x.normVec(); - y.normVec(); - z.normVec(); + mat_normal.mMatrix[0].normalize3fast(); + mat_normal.mMatrix[1].normalize3fast(); + mat_normal.mMatrix[2].normalize3fast(); + + LLVector4a v[4]; - mat.setRows(x,y,z); + //get 4 corners of bounding box + mat_normal.rotate(size,v[0]); - LLQuaternion rotation = LLQuaternion(mat); + //VECTORIZE THIS + LLVector4a scale; - LLVector3 v[4]; - //get 4 corners of bounding box - v[0] = (size * rotation); - v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation); - v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation); - v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation); + scale.set(-1.f, -1.f, 1.f); + scale.mul(size); + mat_normal.rotate(scale, v[1]); + + scale.set(1.f, -1.f, -1.f); + scale.mul(size); + mat_normal.rotate(scale, v[2]); + + scale.set(-1.f, 1.f, -1.f); + scale.mul(size); + mat_normal.rotate(scale, v[3]); - LLVector3& newMin = mExtents[0]; - LLVector3& newMax = mExtents[1]; + LLVector4a& newMin = mExtents[0]; + LLVector4a& newMax = mExtents[1]; newMin = newMax = center; for (U32 i = 0; i < 4; i++) { - for (U32 j = 0; j < 3; j++) - { - F32 delta = fabsf(v[i].mV[j]); - F32 min = center.mV[j] - delta; - F32 max = center.mV[j] + delta; - - if (min < newMin.mV[j]) - { - newMin.mV[j] = min; - } - - if (max > newMax.mV[j]) - { - newMax.mV[j] = max; - } - } + LLVector4a delta; + delta.setAbs(v[i]); + LLVector4a min; + min.setSub(center, delta); + LLVector4a max; + max.setAdd(center, delta); + + newMin.setMin(min); + newMax.setMax(max); } if (!mDrawablep->isActive()) { - LLVector3 offset = mDrawablep->getRegion()->getOriginAgent(); - newMin += offset; - newMax += offset; + LLVector4a offset; + offset.load3(mDrawablep->getRegion()->getOriginAgent().mV); + newMin.add(offset); + newMax.add(offset); } - mCenterLocal = (newMin+newMax)*0.5f; - LLVector3 tmp = (newMin - newMax) ; - mBoundingSphereRadius = tmp.length() * 0.5f ; + t.setAdd(newMin, newMax); + t.mul(0.5f); + + //VECTORIZE THIS + mCenterLocal.set(t.getF32()); + + t.setSub(newMax,newMin); + t.mul(0.5f); + mBoundingSphereRadius = t.length3(); updateCenterAgent(); } @@ -787,18 +875,26 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, return surface_coord; } + //VECTORIZE THIS // see if we have a non-default mapping U8 texgen = getTextureEntry()->getTexGen(); if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { - LLVector3 center = mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter; + LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter); + + LLVector4a volume_position; + volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(position).mV); - LLVector3 scale = (mDrawablep->getVOVolume()->isVolumeGlobal()) ? LLVector3(1,1,1) : mVObjp->getScale(); - LLVector3 volume_position = mDrawablep->getVOVolume()->agentPositionToVolume(position); - volume_position.scaleVec(scale); + if (!mDrawablep->getVOVolume()->isVolumeGlobal()) + { + LLVector4a scale; + scale.load3(mVObjp->getScale().mV); + volume_position.mul(scale); + } - LLVector3 volume_normal = mDrawablep->getVOVolume()->agentDirectionToVolume(normal); - volume_normal.normalize(); + LLVector4a volume_normal; + volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(normal).mV); + volume_normal.normalize3fast(); switch (texgen) { @@ -865,6 +961,11 @@ void LLFace::updateRebuildFlags() bool LLFace::canRenderAsMask() { + if (LLPipeline::sNoAlpha) + { + return true; + } + const LLTextureEntry* te = getTextureEntry(); return ( ( @@ -886,13 +987,14 @@ static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom"); BOOL LLFace::getGeometryVolume(const LLVolume& volume, const S32 &f, - const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, - const U16 &index_offset) + const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in, + const U16 &index_offset, + bool force_rebuild) { LLFastTimer t(FTM_FACE_GET_GEOM); const LLVolumeFace &vf = volume.getVolumeFace(f); - S32 num_vertices = (S32)vf.mVertices.size(); - S32 num_indices = LLPipeline::sUseTriStrips ? (S32)vf.mTriStrip.size() : (S32) vf.mIndices.size(); + S32 num_vertices = (S32)vf.mNumVertices; + S32 num_indices = (S32) vf.mNumIndices; if (mVertexBuffer.notNull()) { @@ -917,15 +1019,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } - LLStrider<LLVector3> vertices; + LLStrider<LLVector3> vert; + LLVector4a* vertices = NULL; LLStrider<LLVector2> tex_coords; LLStrider<LLVector2> tex_coords2; - LLStrider<LLVector3> normals; + LLVector4a* normals = NULL; + LLStrider<LLVector3> norm; LLStrider<LLColor4U> colors; - LLStrider<LLVector3> binormals; + LLVector4a* binormals = NULL; + LLStrider<LLVector3> binorm; LLStrider<U16> indicesp; + LLVector4a* weights = NULL; + LLStrider<LLVector4> wght; - BOOL full_rebuild = mDrawablep->isState(LLDrawable::REBUILD_VOLUME); + BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal(); LLVector3 scale; @@ -938,28 +1045,37 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, scale = mVObjp->getScale(); } - BOOL rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); - BOOL rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); - BOOL rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); - BOOL rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - BOOL rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL); + bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); + bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); + bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); + bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); + bool rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL); + bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4); const LLTextureEntry *tep = mVObjp->getTE(f); - U8 bump_code = tep ? tep->getBumpmap() : 0; + const U8 bump_code = tep ? tep->getBumpmap() : 0; if (rebuild_pos) { - mVertexBuffer->getVertexStrider(vertices, mGeomIndex); + mVertexBuffer->getVertexStrider(vert, mGeomIndex); + vertices = (LLVector4a*) vert.get(); } if (rebuild_normal) { - mVertexBuffer->getNormalStrider(normals, mGeomIndex); + mVertexBuffer->getNormalStrider(norm, mGeomIndex); + normals = (LLVector4a*) norm.get(); } if (rebuild_binormal) { - mVertexBuffer->getBinormalStrider(binormals, mGeomIndex); + mVertexBuffer->getBinormalStrider(binorm, mGeomIndex); + binormals = (LLVector4a*) binorm.get(); } - + if (rebuild_weights) + { + mVertexBuffer->getWeight4Strider(wght, mGeomIndex); + weights = (LLVector4a*) wght.get(); + } + F32 tcoord_xoffset = 0.f ; F32 tcoord_yoffset = 0.f ; F32 tcoord_xscale = 1.f ; @@ -991,8 +1107,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mVertexBuffer->getColorStrider(colors, mGeomIndex); } - F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; - BOOL is_static = mDrawablep->isStatic(); BOOL is_global = is_static; @@ -1007,59 +1121,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, clearState(GLOBAL); } - LLVector2 tmin, tmax; - - - - if (rebuild_tcoord) - { - if (tep) - { - r = tep->getRotation(); - os = tep->mOffsetS; - ot = tep->mOffsetT; - ms = tep->mScaleS; - mt = tep->mScaleT; - cos_ang = cos(r); - sin_ang = sin(r); - } - else - { - cos_ang = 1.0f; - sin_ang = 0.0f; - os = 0.0f; - ot = 0.0f; - ms = 1.0f; - mt = 1.0f; - } - } - - U8 tex_mode = 0; - - if (isState(TEXTURE_ANIM)) - { - LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; - tex_mode = vobj->mTexAnimMode; - - if (!tex_mode) - { - clearState(TEXTURE_ANIM); - } - else - { - os = ot = 0.f; - r = 0.f; - cos_ang = 1.f; - sin_ang = 0.f; - ms = mt = 1.f; - } - - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) - { //don't override texture transform during tc bake - tex_mode = 0; - } - } - LLColor4U color = tep->getColor(); if (rebuild_color) @@ -1081,265 +1142,460 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } - // INDICES + // INDICES if (full_rebuild) { mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); - if (LLPipeline::sUseTriStrips) + __m128i* dst = (__m128i*) indicesp.get(); + __m128i* src = (__m128i*) vf.mIndices; + __m128i offset = _mm_set1_epi16(index_offset); + + S32 end = num_indices/8; + + for (S32 i = 0; i < end; i++) { - for (U32 i = 0; i < (U32) num_indices; i++) - { - *indicesp++ = vf.mTriStrip[i] + index_offset; - } + __m128i res = _mm_add_epi16(src[i], offset); + _mm_storeu_si128(dst+i, res); } - else + + for (S32 i = end*8; i < num_indices; ++i) { - for (U32 i = 0; i < (U32) num_indices; i++) - { - *indicesp++ = vf.mIndices[i] + index_offset; - } + indicesp[i] = vf.mIndices[i]+index_offset; } } + LLMatrix4a mat_normal; + mat_normal.loadu(mat_norm_in); - //bump setup - LLVector3 binormal_dir( -sin_ang, cos_ang, 0 ); - LLVector3 bump_s_primary_light_ray; - LLVector3 bump_t_primary_light_ray; + //if it's not fullbright and has no normals, bake sunlight based on face normal + //bool bake_sunlight = !getTextureEntry()->getFullbright() && + // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - LLQuaternion bump_quat; - if (mDrawablep->isActive()) - { - bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); - } - - if (bump_code) + F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; + + if (rebuild_tcoord) { - mVObjp->getVolume()->genBinormals(f); - F32 offset_multiple; - switch( bump_code ) + bool do_xform; + + if (tep) { - case BE_NO_BUMP: - offset_multiple = 0.f; - break; - case BE_BRIGHTNESS: - case BE_DARKNESS: - if( mTexture.notNull() && mTexture->hasGLTexture()) + r = tep->getRotation(); + os = tep->mOffsetS; + ot = tep->mOffsetT; + ms = tep->mScaleS; + mt = tep->mScaleT; + cos_ang = cos(r); + sin_ang = sin(r); + + if (cos_ang != 1.f || + sin_ang != 0.f || + os != 0.f || + ot != 0.f || + ms != 1.f || + mt != 1.f) { - // Offset by approximately one texel - S32 cur_discard = mTexture->getDiscardLevel(); - S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); - max_size <<= cur_discard; - const F32 ARTIFICIAL_OFFSET = 2.f; - offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; + do_xform = true; } else { - offset_multiple = 1.f/256; - } - break; - - default: // Standard bumpmap textures. Assumed to be 256x256 - offset_multiple = 1.f / 256; - break; + do_xform = false; + } } - - F32 s_scale = 1.f; - F32 t_scale = 1.f; - if( tep ) + else { - tep->getScale( &s_scale, &t_scale ); + do_xform = false; } - // Use the nudged south when coming from above sun angle, such - // that emboss mapping always shows up on the upward faces of cubes when - // it's noon (since a lot of builders build with the sun forced to noon). - LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; - LLVector3 moon_ray = gSky.getMoonDirection(); - LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; - - bump_s_primary_light_ray = offset_multiple * s_scale * primary_light_ray; - bump_t_primary_light_ray = offset_multiple * t_scale * primary_light_ray; - } - - U8 texgen = getTextureEntry()->getTexGen(); - if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { //planar texgen needs binormals - mVObjp->getVolume()->genBinormals(f); - } + + //bump setup + LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); + LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); + LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); - for (S32 i = 0; i < num_vertices; i++) - { - if (rebuild_tcoord) + LLQuaternion bump_quat; + if (mDrawablep->isActive()) { - LLVector2 tc = vf.mVertices[i].mTexCoord; + bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); + } - if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) + if (bump_code) + { + mVObjp->getVolume()->genBinormals(f); + F32 offset_multiple; + switch( bump_code ) { - LLVector3 vec = vf.mVertices[i].mPosition; - - vec.scaleVec(scale); - - switch (texgen) + case BE_NO_BUMP: + offset_multiple = 0.f; + break; + case BE_BRIGHTNESS: + case BE_DARKNESS: + if( mTexture.notNull() && mTexture->hasGLTexture()) { - case LLTextureEntry::TEX_GEN_PLANAR: - planarProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec); - break; - case LLTextureEntry::TEX_GEN_SPHERICAL: - sphericalProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec); - break; - case LLTextureEntry::TEX_GEN_CYLINDRICAL: - cylindricalProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec); - break; - default: - break; - } + // Offset by approximately one texel + S32 cur_discard = mTexture->getDiscardLevel(); + S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); + max_size <<= cur_discard; + const F32 ARTIFICIAL_OFFSET = 2.f; + offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; + } + else + { + offset_multiple = 1.f/256; + } + break; + + default: // Standard bumpmap textures. Assumed to be 256x256 + offset_multiple = 1.f / 256; + break; + } + + F32 s_scale = 1.f; + F32 t_scale = 1.f; + if( tep ) + { + tep->getScale( &s_scale, &t_scale ); } + // Use the nudged south when coming from above sun angle, such + // that emboss mapping always shows up on the upward faces of cubes when + // it's noon (since a lot of builders build with the sun forced to noon). + LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; + LLVector3 moon_ray = gSky.getMoonDirection(); + LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; + + bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); + bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); + } + + U8 texgen = getTextureEntry()->getTexGen(); + if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { //planar texgen needs binormals + mVObjp->getVolume()->genBinormals(f); + } - if (tex_mode && mTextureMatrix) + U8 tex_mode = 0; + + if (isState(TEXTURE_ANIM)) + { + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + tex_mode = vobj->mTexAnimMode; + + if (!tex_mode) { - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; + clearState(TEXTURE_ANIM); } else { - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + os = ot = 0.f; + r = 0.f; + cos_ang = 1.f; + sin_ang = 0.f; + ms = mt = 1.f; + + do_xform = false; } - if(in_atlas) - { - // - //manually calculate tex-coord per vertex for varying address modes. - //should be removed if shader can handle this. - // + if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) + { //don't override texture transform during tc bake + tex_mode = 0; + } + } - S32 int_part = 0 ; - switch(mTexture->getAddressMode()) - { - case LLTexUnit::TAM_CLAMP: - if(tc.mV[0] < 0.f) - { - tc.mV[0] = 0.f ; - } - else if(tc.mV[0] > 1.f) - { - tc.mV[0] = 1.f; - } + LLVector4a scalea; + scalea.load3(scale.mV); - if(tc.mV[1] < 0.f) - { - tc.mV[1] = 0.f ; - } - else if(tc.mV[1] > 1.f) - { - tc.mV[1] = 1.f; - } - break; - case LLTexUnit::TAM_MIRROR: - if(tc.mV[0] < 0.f) - { - tc.mV[0] = -tc.mV[0] ; - } - int_part = (S32)tc.mV[0] ; - if(int_part & 1) //odd number - { - tc.mV[0] = int_part + 1 - tc.mV[0] ; - } - else //even number - { - tc.mV[0] -= int_part ; - } + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); + bool do_tex_mat = tex_mode && mTextureMatrix; - if(tc.mV[1] < 0.f) + if (!in_atlas && !do_bump) + { //not in atlas or not bump mapped, might be able to do a cheap update + if (texgen != LLTextureEntry::TEX_GEN_PLANAR) + { + if (!do_tex_mat) + { + if (!do_xform) { - tc.mV[1] = -tc.mV[1] ; + LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2); } - int_part = (S32)tc.mV[1] ; - if(int_part & 1) //odd number + else { - tc.mV[1] = int_part + 1 - tc.mV[1] ; + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + *tex_coords++ = tc; + } } - else //even number - { - tc.mV[1] -= int_part ; + } + else + { //do tex mat, no texgen, no atlas, no bump + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + //LLVector4a& norm = vf.mNormals[i]; + //LLVector4a& center = *(vf.mCenter); + + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + *tex_coords++ = tc; } - break; - case LLTexUnit::TAM_WRAP: - if(tc.mV[0] > 1.f) - tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ; - else if(tc.mV[0] < -1.f) - tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ; - - if(tc.mV[1] > 1.f) - tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ; - else if(tc.mV[1] < -1.f) - tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ; - - if(tc.mV[0] < 0.f) - { - tc.mV[0] = 1.0f + tc.mV[0] ; + } + } + else + { //no bump, no atlas, tex gen planar + if (do_tex_mat) + { + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + LLVector4a& center = *(vf.mCenter); + LLVector4a vec = vf.mPositions[i]; + vec.mul(scalea); + planarProjection(tc, norm, center, vec); + + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + + *tex_coords++ = tc; } - if(tc.mV[1] < 0.f) - { - tc.mV[1] = 1.0f + tc.mV[1] ; + } + else + { + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + LLVector4a& center = *(vf.mCenter); + LLVector4a vec = vf.mPositions[i]; + vec.mul(scalea); + planarProjection(tc, norm, center, vec); + + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + + *tex_coords++ = tc; } - break; - default: - break; } - - tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ; - tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ; } + } + else + { //either bump mapped or in atlas, just do the whole expensive loop + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + + LLVector4a& center = *(vf.mCenter); - *tex_coords++ = tc; - - if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1)) - { - LLVector3 tangent = vf.mVertices[i].mBinormal % vf.mVertices[i].mNormal; - - LLMatrix3 tangent_to_object; - tangent_to_object.setRows(tangent, vf.mVertices[i].mBinormal, vf.mVertices[i].mNormal); - LLVector3 binormal = binormal_dir * tangent_to_object; - binormal = binormal * mat_normal; + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { + LLVector4a vec = vf.mPositions[i]; - if (mDrawablep->isActive()) + vec.mul(scalea); + + switch (texgen) + { + case LLTextureEntry::TEX_GEN_PLANAR: + planarProjection(tc, norm, center, vec); + break; + case LLTextureEntry::TEX_GEN_SPHERICAL: + sphericalProjection(tc, norm, center, vec); + break; + case LLTextureEntry::TEX_GEN_CYLINDRICAL: + cylindricalProjection(tc, norm, center, vec); + break; + default: + break; + } + } + + if (tex_mode && mTextureMatrix) + { + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + } + else { - binormal *= bump_quat; + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); } - binormal.normVec(); - tc += LLVector2( bump_s_primary_light_ray * tangent, bump_t_primary_light_ray * binormal ); + if(in_atlas) + { + // + //manually calculate tex-coord per vertex for varying address modes. + //should be removed if shader can handle this. + // + + S32 int_part = 0 ; + switch(mTexture->getAddressMode()) + { + case LLTexUnit::TAM_CLAMP: + if(tc.mV[0] < 0.f) + { + tc.mV[0] = 0.f ; + } + else if(tc.mV[0] > 1.f) + { + tc.mV[0] = 1.f; + } + + if(tc.mV[1] < 0.f) + { + tc.mV[1] = 0.f ; + } + else if(tc.mV[1] > 1.f) + { + tc.mV[1] = 1.f; + } + break; + case LLTexUnit::TAM_MIRROR: + if(tc.mV[0] < 0.f) + { + tc.mV[0] = -tc.mV[0] ; + } + int_part = (S32)tc.mV[0] ; + if(int_part & 1) //odd number + { + tc.mV[0] = int_part + 1 - tc.mV[0] ; + } + else //even number + { + tc.mV[0] -= int_part ; + } + + if(tc.mV[1] < 0.f) + { + tc.mV[1] = -tc.mV[1] ; + } + int_part = (S32)tc.mV[1] ; + if(int_part & 1) //odd number + { + tc.mV[1] = int_part + 1 - tc.mV[1] ; + } + else //even number + { + tc.mV[1] -= int_part ; + } + break; + case LLTexUnit::TAM_WRAP: + if(tc.mV[0] > 1.f) + tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ; + else if(tc.mV[0] < -1.f) + tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ; + + if(tc.mV[1] > 1.f) + tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ; + else if(tc.mV[1] < -1.f) + tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ; + + if(tc.mV[0] < 0.f) + { + tc.mV[0] = 1.0f + tc.mV[0] ; + } + if(tc.mV[1] < 0.f) + { + tc.mV[1] = 1.0f + tc.mV[1] ; + } + break; + default: + break; + } - *tex_coords2++ = tc; - } + tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ; + tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ; + } + + + *tex_coords++ = tc; + + if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1)) + { + LLVector4a tangent; + tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]); + + LLMatrix4a tangent_to_object; + tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]); + LLVector4a t; + tangent_to_object.rotate(binormal_dir, t); + LLVector4a binormal; + mat_normal.rotate(t, binormal); + + //VECTORIZE THIS + if (mDrawablep->isActive()) + { + LLVector3 t; + t.set(binormal.getF32()); + t *= bump_quat; + binormal.load3(t.mV); + } + + binormal.normalize3fast(); + tc += LLVector2( bump_s_primary_light_ray.dot3(tangent), bump_t_primary_light_ray.dot3(binormal) ); + + *tex_coords2++ = tc; + } + } } - - if (rebuild_pos) - { - *vertices++ = vf.mVertices[i].mPosition * mat_vert; + } + + if (rebuild_pos) + { + LLMatrix4a mat_vert; + mat_vert.loadu(mat_vert_in); + + LLVector4a* src = vf.mPositions; + LLVector4a* dst = vertices; + + LLVector4a* end = dst+num_vertices; + do + { + mat_vert.affineTransform(*src++, *dst++); } + while(dst < end); + } - if (rebuild_normal) - { - LLVector3 normal = vf.mVertices[i].mNormal * mat_normal; - normal.normVec(); - - *normals++ = normal; + if (rebuild_normal) + { + for (S32 i = 0; i < num_vertices; i++) + { + LLVector4a normal; + mat_normal.rotate(vf.mNormals[i], normal); + normal.normalize3fast(); + normals[i] = normal; } + } - if (rebuild_binormal) - { - LLVector3 binormal = vf.mVertices[i].mBinormal * mat_normal; - binormal.normVec(); - *binormals++ = binormal; + if (rebuild_binormal) + { + for (S32 i = 0; i < num_vertices; i++) + { + LLVector4a binormal; + mat_normal.rotate(vf.mBinormals[i], binormal); + binormal.normalize3fast(); + binormals[i] = binormal; } - - if (rebuild_color) - { - *colors++ = color; + } + + if (rebuild_weights && vf.mWeights) + { + LLVector4a::memcpyNonAliased16((F32*) weights, (F32*) vf.mWeights, num_vertices*4); + } + + if (rebuild_color) + { + LLVector4a src; + + src.splat(reinterpret_cast<F32&>(color.mAll)); + + F32* dst = (F32*) colors.get(); + for (S32 i = 0; i < num_vertices; i+=4) + { + LLVector4a::copy4a(dst+i, (F32*) &src); } } @@ -1439,20 +1695,31 @@ F32 LLFace::getTextureVirtualSize() BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) { + //VECTORIZE THIS //get area of circle around face - LLVector3 center = getPositionAgent(); - LLVector3 size = (mExtents[1] - mExtents[0]) * 0.5f; + LLVector4a center; + center.load3(getPositionAgent().mV); + LLVector4a size; + size.setSub(mExtents[1], mExtents[0]); + size.mul(0.5f); + LLViewerCamera* camera = LLViewerCamera::getInstance(); - F32 size_squared = size.lengthSquared() ; - LLVector3 lookAt = center - camera->getOrigin(); - F32 dist = lookAt.normVec() ; + F32 size_squared = size.dot3(size); + LLVector4a lookAt; + LLVector4a t; + t.load3(camera->getOrigin().mV); + lookAt.setSub(center, t); + F32 dist = lookAt.length3(); + lookAt.normalize3fast() ; //get area of circle around node F32 app_angle = atanf(fsqrtf(size_squared) / dist); radius = app_angle*LLDrawable::sCurPixelAngle; mPixelArea = radius*radius * 3.14159f; - cos_angle_to_view_dir = lookAt * camera->getXAxis() ; + LLVector4a x_axis; + x_axis.load3(camera->getXAxis().mV); + cos_angle_to_view_dir = lookAt.dot3(x_axis); //if has media, check if the face is out of the view frustum. if(hasMedia()) @@ -1468,7 +1735,10 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) } else { - if(dist * dist * (lookAt - camera->getXAxis()).lengthSquared() < size_squared) + LLVector4a d; + d.setSub(lookAt, x_axis); + + if(dist * dist * d.dot3(d) < size_squared) { cos_angle_to_view_dir = 1.0f ; } diff --git a/indra/newview/llface.h b/indra/newview/llface.h index b20ecfe2b8..b6a67c7fc4 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -65,6 +65,17 @@ class LLFace { public: + LLFace(const LLFace& rhs) + { + *this = rhs; + } + + const LLFace& operator=(const LLFace& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + enum EMasks { LIGHT = 0x0001, @@ -73,6 +84,7 @@ public: HUD_RENDER = 0x0008, USE_FACE_COLOR = 0x0010, TEXTURE_ANIM = 0x0020, + RIGGED = 0x0040, }; static void initClass(); @@ -145,7 +157,8 @@ public: BOOL getGeometryVolume(const LLVolume& volume, const S32 &f, const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, - const U16 &index_offset); + const U16 &index_offset, + bool force_rebuild = false); // For avatar U16 getGeometryAvatar( @@ -164,7 +177,7 @@ public: S32 getColors(LLStrider<LLColor4U> &colors); S32 getIndices(LLStrider<U16> &indices); - void setSize(const S32 numVertices, const S32 num_indices = 0); + void setSize(S32 numVertices, S32 num_indices = 0, bool align = false); BOOL genVolumeBBoxes(const LLVolume &volume, S32 f, const LLMatrix4& mat, const LLMatrix3& inv_trans_mat, BOOL global_volume = FALSE); @@ -219,7 +232,9 @@ public: LLVector3 mCenterLocal; LLVector3 mCenterAgent; - LLVector3 mExtents[2]; + + LLVector4a* mExtents; + LLVector2 mTexExtents[2]; F32 mDistance; LLPointer<LLVertexBuffer> mVertexBuffer; @@ -232,6 +247,7 @@ public: private: friend class LLGeometryManager; friend class LLVolumeGeometryManager; + friend class LLDrawPoolAvatar; U32 mState; LLFacePool* mDrawPoolp; @@ -257,6 +273,8 @@ private: S32 mTEOffset; S32 mReferenceIndex; + std::vector<S32> mRiggedIndex; + F32 mVSize; F32 mPixelArea; diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 2873057c19..324d99937e 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -55,12 +55,14 @@ LLFilePicker LLFilePicker::sInstance; #define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0" #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" #define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0" +#define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0" #ifdef _CORY_TESTING #define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" #endif #define XML_FILTER L"XML files (*.xml)\0*.xml\0" #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0" #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" +#define MODEL_FILTER L"Model files (*.dae)\0*.dae\0" #endif // @@ -176,6 +178,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = ANIM_FILTER \ L"\0"; break; + case FFLOAD_COLLADA: + mOFN.lpstrFilter = COLLADA_FILTER \ + L"\0"; + break; #ifdef _CORY_TESTING case FFLOAD_GEOMETRY: mOFN.lpstrFilter = GEOMETRY_FILTER \ @@ -194,6 +200,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = RAW_FILTER \ L"\0"; break; + case FFLOAD_MODEL: + mOFN.lpstrFilter = MODEL_FILTER \ + L"\0"; + break; default: res = FALSE; break; @@ -201,7 +211,7 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) return res; } -BOOL LLFilePicker::getOpenFile(ELoadFilter filter) +BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { if( mLocked ) { @@ -220,8 +230,11 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter) setupFilter(filter); - // Modal, so pause agent - send_agent_pause(); + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } reset(); @@ -232,10 +245,14 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter) std::string filename = utf16str_to_utf8str(llutf16string(mFilesW)); mFiles.push_back(filename); } - send_agent_resume(); - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); + if (blocking) + { + send_agent_resume(); + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + } + return success; } @@ -543,6 +560,15 @@ Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callB result = false; } } + else if (filter == FFLOAD_COLLADA) + { + if (fileInfo.filetype != 'DAE ' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dae"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + ) + { + result = false; + } + } #ifdef _CORY_TESTING else if (filter == FFLOAD_GEOMETRY) { @@ -808,7 +834,7 @@ OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& fi return error; } -BOOL LLFilePicker::getOpenFile(ELoadFilter filter) +BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking) { if( mLocked ) return FALSE; @@ -827,20 +853,29 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter) mNavOptions.optionFlags |= kNavSupportPackages; } - // Modal, so pause agent - send_agent_pause(); + if (blocking) + { + // Modal, so pause agent + send_agent_pause(); + } + { error = doNavChooseDialog(filter); } - send_agent_resume(); + if (error == noErr) { if (getFileCount()) success = true; } - // Account for the fact that the app has been stalled. - LLFrameTimer::updateFrameTime(); + if (blocking) + { + send_agent_resume(); + // Account for the fact that the app has been stalled. + LLFrameTimer::updateFrameTime(); + } + return success; } @@ -1089,6 +1124,12 @@ static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker) LLTrans::getString("animation_files") + " (*.bvh)"); } +static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker) +{ + return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae", + LLTrans::getString("scene_files") + " (*.dae)"); +} + static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) { GtkFileFilter *gfilter = gtk_file_filter_new(); @@ -1191,7 +1232,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename return rtn; } -BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) +BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) { BOOL rtn = FALSE; @@ -1213,6 +1254,9 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter ) case FFLOAD_ANIM: filtername = add_bvh_filter_to_gtkchooser(picker); break; + case FFLOAD_COLLADA: + filtername = add_collada_filter_to_gtkchooser(picker); + break; case FFLOAD_IMAGE: filtername = add_imageload_filter_to_gtkchooser(picker); break; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 4f254ff67e..10fb30af9f 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -88,6 +88,8 @@ public: FFLOAD_XML = 6, FFLOAD_SLOBJECT = 7, FFLOAD_RAW = 8, + FFLOAD_MODEL = 9, + FFLOAD_COLLADA = 10, }; enum ESaveFilter @@ -111,7 +113,7 @@ public: // open the dialog. This is a modal operation BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null ); - BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL ); + BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true ); BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL ); // Get the filename(s) found. getFirstFile() sets the pointer to @@ -192,4 +194,6 @@ public: ~LLFilePicker(); }; +const std::string upload_pick(void* data); + #endif diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 561965d021..8be4e34748 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -97,11 +97,13 @@ void LLVolumeImplFlexible::onParameterChanged(U16 param_type, LLNetworkData *dat } } -void LLVolumeImplFlexible::onShift(const LLVector3 &shift_vector) +void LLVolumeImplFlexible::onShift(const LLVector4a &shift_vector) { + //VECTORIZE THIS + LLVector3 shift(shift_vector.getF32()); for (int section = 0; section < (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1; ++section) { - mSection[section].mPosition += shift_vector; + mSection[section].mPosition += shift; } } diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h index 811ae24df2..bdfbded82d 100644 --- a/indra/newview/llflexibleobject.h +++ b/indra/newview/llflexibleobject.h @@ -90,7 +90,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface void onSetVolume(const LLVolumeParams &volume_params, const S32 detail); void onSetScale(const LLVector3 &scale, BOOL damped); void onParameterChanged(U16 param_type, LLNetworkData *data, BOOL in_use, bool local_origin); - void onShift(const LLVector3 &shift_vector); + void onShift(const LLVector4a &shift_vector); bool isVolumeUnique() const { return true; } bool isVolumeGlobal() const { return true; } bool isActive() const { return true; } diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp index f14e64e3e4..b78e219504 100644 --- a/indra/newview/llfloateranimpreview.cpp +++ b/indra/newview/llfloateranimpreview.cpp @@ -1014,6 +1014,7 @@ void LLFloaterAnimPreview::onBtnOK(void* userdata) LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), name, callback, expected_upload_cost, userdata); + } else { diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 8a20712ea8..28fe2a14b7 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -69,7 +69,7 @@ const S32 PREVIEW_BORDER_WIDTH = 2; const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; -const S32 PREVIEW_TEXTURE_HEIGHT = 300; +const S32 PREVIEW_TEXTURE_HEIGHT = 320; //----------------------------------------------------------------------------- // LLFloaterImagePreview() @@ -864,8 +864,8 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance) } const LLVolumeFace &vf = mVolume->getVolumeFace(0); - U32 num_indices = vf.mIndices.size(); - U32 num_vertices = vf.mVertices.size(); + U32 num_indices = vf.mNumIndices; + U32 num_vertices = vf.mNumVertices; mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0); mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE); @@ -879,10 +879,16 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance) mVertexBuffer->getIndexStrider(index_strider); // build vertices and normals + LLStrider<LLVector3> pos; + pos = (LLVector3*) vf.mPositions; pos.setStride(16); + LLStrider<LLVector3> norm; + norm = (LLVector3*) vf.mNormals; norm.setStride(16); + + for (U32 i = 0; i < num_vertices; i++) { - *(vertex_strider++) = vf.mVertices[i].mPosition; - LLVector3 normal = vf.mVertices[i].mNormal; + *(vertex_strider++) = *pos++; + LLVector3 normal = *norm++; normal.normalize(); *(normal_strider++) = normal; } @@ -901,7 +907,6 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance) BOOL LLImagePreviewSculpted::render() { mNeedsUpdate = FALSE; - LLGLSUIDefault def; LLGLDisable no_blend(GL_BLEND); LLGLEnable cull(GL_CULL_FACE); @@ -946,7 +951,7 @@ BOOL LLImagePreviewSculpted::render() LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); const LLVolumeFace &vf = mVolume->getVolumeFace(0); - U32 num_indices = vf.mIndices.size(); + U32 num_indices = vf.mNumIndices; mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); @@ -959,7 +964,6 @@ BOOL LLImagePreviewSculpted::render() mVertexBuffer->draw(LLRender::TRIANGLES, num_indices, 0); gGL.popMatrix(); - return TRUE; } diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 43ea6143b1..187a5e2040 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -999,7 +999,7 @@ void LLSnapshotLivePreview::saveTexture() void *userdata = NULL; upload_new_resource(tid, // tid LLAssetType::AT_TEXTURE, - "Snapshot : " + pos_string, + snapname, "Taken by " + who_took_it + " at " + pos_string, 0, LLFolderType::FT_SNAPSHOT_CATEGORY, @@ -1007,7 +1007,7 @@ void LLSnapshotLivePreview::saveTexture() PERM_ALL, // Note: Snapshots to inventory is a special case of content upload PERM_NONE, // that ignores the user's premissions preferences and continues to PERM_NONE, // always use these fairly permissive hard-coded initial perms. - MG - "Snapshot : " + pos_string, + snapname, callback, expected_upload_cost, userdata); gViewerWindow->playSnapshotAnimAndSound(); } diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 565f0619a5..03c9bd4e4f 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -419,12 +419,12 @@ void LLFloaterTools::refresh() // Refresh object and prim count labels LLLocale locale(LLLocale::USER_LOCALE); - std::string obj_count_string; - LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount()); - childSetTextArg("obj_count", "[COUNT]", obj_count_string); - std::string prim_count_string; - LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount()); - childSetTextArg("prim_count", "[COUNT]", prim_count_string); + + F32 obj_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectCost(); + F32 link_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost(); + + childSetTextArg("obj_count", "[COUNT]", llformat("%.1f", obj_cost)); + childSetTextArg("prim_count", "[COUNT]", llformat("%.1f", link_cost)); // calculate selection rendering cost if (sShowObjectCost) diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp index 28b0e7356a..63040904df 100644 --- a/indra/newview/llhudicon.cpp +++ b/indra/newview/llhudicon.cpp @@ -39,6 +39,7 @@ #include "llviewerobject.h" #include "lldrawable.h" +#include "llvector4a.h" #include "llviewercamera.h" #include "llviewertexture.h" #include "llviewerwindow.h" @@ -266,21 +267,42 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& en LLVector3 x_scale = image_aspect * (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * x_pixel_vec; LLVector3 y_scale = (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * y_pixel_vec; - LLVector3 lower_left = icon_position - (x_scale * 0.5f); - LLVector3 lower_right = icon_position + (x_scale * 0.5f); - LLVector3 upper_left = icon_position - (x_scale * 0.5f) + y_scale; - LLVector3 upper_right = icon_position + (x_scale * 0.5f) + y_scale; + LLVector4a x_scalea; + LLVector4a icon_positiona; + LLVector4a y_scalea; - - F32 t = 0.f; - LLVector3 dir = end-start; + x_scalea.load3(x_scale.mV); + x_scalea.mul(0.5f); + y_scalea.load3(y_scale.mV); + + icon_positiona.load3(icon_position.mV); + + LLVector4a lower_left; + lower_left.setSub(icon_positiona, x_scalea); + LLVector4a lower_right; + lower_right.setAdd(icon_positiona, x_scalea); + LLVector4a upper_left; + upper_left.setAdd(lower_left, y_scalea); + LLVector4a upper_right; + upper_right.setAdd(lower_right, y_scalea); + + LLVector4a enda; + enda.load3(end.mV); + LLVector4a starta; + starta.load3(start.mV); + LLVector4a dir; + dir.setSub(enda, starta); + + F32 a,b,t; - if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, start, dir, NULL, NULL, &t, FALSE) || - LLTriangleRayIntersect(upper_left, lower_left, lower_right, start, dir, NULL, NULL, &t, FALSE)) + if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, starta, dir, a,b,t) || + LLTriangleRayIntersect(upper_left, lower_left, lower_right, starta, dir, a,b,t)) { if (intersection) { - *intersection = start + dir*t; + dir.mul(t); + starta.add(dir); + *intersection = LLVector3((F32*) &starta.mQ); } return TRUE; } diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 8d1d27444b..7f9eddc837 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -207,10 +207,11 @@ BOOL LLHUDText::lineSegmentIntersect(const LLVector3& start, const LLVector3& en } LLVector3 dir = end-start; - F32 t = 0.f; + F32 a,b,t; - if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) || - LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) ) + + if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE) || + LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, a, b, t, FALSE) ) { if (t <= 1.f) { @@ -567,6 +568,18 @@ void LLHUDText::setStringUTF8(const std::string &wtext) setString(utf8str_to_wstring(wtext)); } +std::string LLHUDText::getString() +{ + std::ostringstream ostr; + for (U32 i = 0; i < mTextSegments.size(); ++i) + { + const std::string str = wstring_to_utf8str(mTextSegments[i].getText()); + ostr << str; + } + + return ostr.str(); +} + void LLHUDText::setString(const LLWString &wtext) { mTextSegments.clear(); diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h index dc14a8c764..4787a15eaf 100644 --- a/indra/newview/llhudtext.h +++ b/indra/newview/llhudtext.h @@ -90,6 +90,7 @@ public: public: void setStringUTF8(const std::string &utf8string); + std::string getString(); void setString(const LLWString &wstring); void clearString(); void addLine(const std::string &text, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 7ec6440dc3..3319bdf9fd 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -920,6 +920,16 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, // Only should happen for broken links. new_listener = new LLLinkItemBridge(inventory, root, uuid); break; +#if LL_MESH_ENABLED + case LLAssetType::AT_MESH: + if(!(inv_type == LLInventoryType::IT_MESH)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLMeshBridge(inventory, root, uuid); + break; +#endif + default: llinfos << "Unhandled asset type (llassetstorage.h): " << (S32)asset_type << llendl; @@ -2231,6 +2241,9 @@ LLUIImagePtr LLFolderBridge::getIcon() const LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type) { return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, FALSE)); + /*case LLAssetType::AT_MESH: + control = "inv_folder_mesh.tga"; + break;*/ } LLUIImagePtr LLFolderBridge::getOpenIcon() const @@ -2663,6 +2676,9 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_ANIMATION: case DAD_GESTURE: case DAD_LINK: +#if LL_MESH_ENABLED + case DAD_MESH: +#endif accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, drop); break; @@ -3572,6 +3588,9 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_BODYPART: case DAD_ANIMATION: case DAD_GESTURE: +#if LL_MESH_ENABLED + case DAD_MESH: +#endif { LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; const LLPermissions& perm = inv_item->getPermissions(); @@ -4726,6 +4745,7 @@ void LLWearableBridge::removeFromAvatar() } } + // +=================================================+ // | LLLinkItemBridge | // +=================================================+ @@ -4755,6 +4775,65 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } +#if LL_MESH_ENABLED +// +=================================================+ +// | LLMeshBridge | +// +=================================================+ + +LLUIImagePtr LLMeshBridge::getIcon() const +{ + return LLInventoryIcon::getIcon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE); +} + +void LLMeshBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + // open mesh + } +} + +void LLMeshBridge::previewItem() +{ + LLViewerInventoryItem* item = getItem(); + if(item) + { + // preview mesh + } +} + + +void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLMeshBridge::buildContextMenu()" << llendl; + std::vector<std::string> items; + std::vector<std::string> disabled_items; + + if(isItemInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + } + + + hide_context_entries(menu, items, disabled_items); +} + +#endif + // +=================================================+ // | LLLinkBridge | // +=================================================+ @@ -5061,6 +5140,7 @@ public: { wearOnAvatar(); } + virtual ~LLWearableBridgeAction(){} protected: LLWearableBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 9dc50b542d..12c6a33214 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -40,6 +40,7 @@ #include "llinventoryobserver.h" #include "llviewercontrol.h" #include "llwearable.h" +#include "llvolume.h" //for LL_MESH_ENABLED class LLInventoryPanel; class LLInventoryModel; @@ -47,6 +48,7 @@ class LLMenuGL; class LLCallingCardObserver; class LLViewerJointAttachment; + typedef std::vector<std::string> menuentry_vec_t; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -525,6 +527,27 @@ protected: static std::string sPrefix; }; + +#if LL_MESH_ENABLED +class LLMeshBridge : public LLItemBridge +{ + friend class LLInvFVBridge; +public: + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual void previewItem(); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + +protected: + LLMeshBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid) : + LLItemBridge(inventory, root, uuid) {} +}; +#endif + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvFVBridgeAction // @@ -555,13 +578,23 @@ protected: LLInventoryModel* mModel; }; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Recent Inventory Panel related classes -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLMeshBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLMeshBridgeAction(){} +protected: + LLMeshBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + // Overridden version of the Inventory-Folder-View-Bridge for Folders class LLRecentItemsFolderBridge : public LLFolderBridge { + friend class LLInvFVBridgeAction; public: // Creates context menu for Folders related to Recent Inventory Panel. // Uses base logic and than removes from visible items "New..." menu items. diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index f20acbd016..3bd722198d 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -831,3 +831,4 @@ void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder) folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); } } + diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index ba50081fb2..91166b0f5b 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -159,6 +159,9 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, case DAD_ANIMATION: case DAD_GESTURE: case DAD_CALLINGCARD: +#if LL_MESH_ENABLED + case DAD_MESH: +#endif { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index a1b3114bb4..63490d4fa2 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -138,6 +138,26 @@ BOOL LLPanelObject::postBuild() mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl"); childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); + // PhysicsShapeType combobox + mComboPhysicsShapeType = getChild<LLComboBox>("Physics Shape Type Combo Ctrl"); + childSetCommitCallback("Physics Shape Type Combo Ctrl", onCommitPhysicsParam, this); + + // PhysicsGravity + mSpinPhysicsGravity = getChild<LLSpinCtrl>("Physics Gravity"); + childSetCommitCallback("Physics Gravity", onCommitPhysicsParam, this); + + // PhysicsFriction + mSpinPhysicsFriction = getChild<LLSpinCtrl>("Physics Friction"); + childSetCommitCallback("Physics Friction", onCommitPhysicsParam, this); + + // PhysicsDensity + mSpinPhysicsDensity = getChild<LLSpinCtrl>("Physics Density"); + childSetCommitCallback("Physics Density", onCommitPhysicsParam, this); + + // PhysicsRestitution + mSpinPhysicsRestitution = getChild<LLSpinCtrl>("Physics Restitution"); + childSetCommitCallback("Physics Restitution", onCommitPhysicsParam, this); + // Position mLabelPosition = getChild<LLTextBox>("label position"); mCtrlPosX = getChild<LLSpinCtrl>("Pos X"); @@ -525,6 +545,21 @@ void LLPanelObject::getState( ) mCheckPhantom->set( mIsPhantom ); mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible ); + mComboPhysicsShapeType->setCurrentByIndex(objectp->getPhysicsShapeType()); + mComboPhysicsShapeType->setEnabled(editable); + + mSpinPhysicsGravity->set(objectp->getPhysicsGravity()); + mSpinPhysicsGravity->setEnabled(editable); + + mSpinPhysicsFriction->set(objectp->getPhysicsFriction()); + mSpinPhysicsFriction->setEnabled(editable); + + mSpinPhysicsDensity->set(objectp->getPhysicsDensity()); + mSpinPhysicsDensity->setEnabled(editable); + + mSpinPhysicsRestitution->set(objectp->getPhysicsRestitution()); + mSpinPhysicsRestitution->setEnabled(editable); + #if 0 // 1.9.2 mCastShadows = root_objectp->flagCastShadows(); mCheckCastShadows->set( mCastShadows ); @@ -1227,6 +1262,33 @@ void LLPanelObject::sendIsPhantom() } } +#include "llsdutil.h" +class CostResponder : public LLHTTPClient::Responder +{ +public: + CostResponder(U32 id) { mID = id; } + virtual void result(const LLSD& content) { llinfos << ll_pretty_print_sd(content) << llendl; } + + U32 mID; +}; + +void LLPanelObject::sendPhysicsParam() +{ + U8 type = (U8)mComboPhysicsShapeType->getCurrentIndex(); + F32 gravity = mSpinPhysicsGravity->get(); + F32 friction = mSpinPhysicsFriction->get(); + F32 density = mSpinPhysicsDensity->get(); + F32 restitution = mSpinPhysicsRestitution->get(); + + LLSelectMgr::getInstance()->selectionUpdatePhysicsParam(type, gravity, friction, + density, restitution); + + std::string url = gAgent.getRegion()->getCapability("GetObjectCost"); + LLSD body = LLSD::emptyArray(); + + body.append(LLSelectMgr::getInstance()->getSelection()->getFirstObject()->getID()); + + LLHTTPClient::post( url, body, new CostResponder(body[0].asInteger()) ); void LLPanelObject::sendCastShadows() { BOOL value = mCheckCastShadows->get(); @@ -1900,6 +1962,12 @@ void LLPanelObject::clearCtrls() mCheckTemporary ->setEnabled( FALSE ); mCheckPhantom ->set(FALSE); mCheckPhantom ->setEnabled( FALSE ); + + mSpinPhysicsGravity->setEnabled(FALSE); + mSpinPhysicsFriction->setEnabled(FALSE); + mSpinPhysicsDensity->setEnabled(FALSE); + mSpinPhysicsRestitution->setEnabled(FALSE); + #if 0 // 1.9.2 mCheckCastShadows->set(FALSE); mCheckCastShadows->setEnabled( FALSE ); @@ -1993,6 +2061,13 @@ void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata ) } // static +void LLPanelObject::onCommitPhysicsParam(LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendPhysicsParam(); +} + +// static void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) { LLPanelObject* self = (LLPanelObject*) userdata; diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index b4e1eee8fb..518e6c0678 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -71,6 +71,7 @@ public: static void onCommitPhysics( LLUICtrl* ctrl, void* userdata); static void onCommitTemporary( LLUICtrl* ctrl, void* userdata); static void onCommitPhantom( LLUICtrl* ctrl, void* userdata); + static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata); static void onCommitCastShadows( LLUICtrl* ctrl, void* userdata); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -93,6 +94,7 @@ protected: void sendIsPhysical(); void sendIsTemporary(); void sendIsPhantom(); + void sendPhysicsParam(); void sendCastShadows(); void sendSculpt(); @@ -165,6 +167,12 @@ protected: LLCheckBoxCtrl *mCheckPhantom; LLCheckBoxCtrl *mCheckCastShadows; + LLComboBox* mComboPhysicsShapeType; + LLSpinCtrl* mSpinPhysicsGravity; + LLSpinCtrl* mSpinPhysicsFriction; + LLSpinCtrl* mSpinPhysicsDensity; + LLSpinCtrl* mSpinPhysicsRestitution; + LLTextureCtrl *mCtrlSculptTexture; LLTextBox *mLabelSculptType; LLComboBox *mCtrlSculptType; diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index ca1361c84b..9d0effc164 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -820,6 +820,9 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_ANIMATION: case DAD_GESTURE: case DAD_CALLINGCARD: +#if LL_MESH_ENABLED + case DAD_MESH: +#endif accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); if(accept && drop) { @@ -1245,6 +1248,119 @@ LLUIImagePtr LLTaskWearableBridge::getIcon() const return LLInventoryIcon::getIcon(mAssetType, mInventoryType, mFlags, FALSE ); } +#if LL_MESH_ENABLED +///---------------------------------------------------------------------------- +/// Class LLTaskMeshBridge +///---------------------------------------------------------------------------- + +class LLTaskMeshBridge : public LLTaskInvFVBridge +{ +public: + LLTaskMeshBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name); + + virtual LLUIImagePtr getIcon() const; + virtual void openItem(); + virtual void performAction(LLInventoryModel* model, std::string action); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); +}; + +LLTaskMeshBridge::LLTaskMeshBridge( + LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) +{ +} + +LLUIImagePtr LLTaskMeshBridge::getIcon() const +{ + return LLInventoryIcon::getIcon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE); +} + +void LLTaskMeshBridge::openItem() +{ + // open mesh +} + + +// virtual +void LLTaskMeshBridge::performAction(LLInventoryModel* model, std::string action) +{ + if (action == "mesh action") + { + LLInventoryItem* item = findItem(); + if(item) + { + // do action + } + } + LLTaskInvFVBridge::performAction(model, action); +} + +void LLTaskMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + LLInventoryItem* item = findItem(); + if(!item) return; + std::vector<std::string> items; + std::vector<std::string> disabled_items; + + if(item->getPermissions().getOwner() != gAgent.getID() + && item->getSaleInfo().isForSale()) + { + items.push_back(std::string("Task Buy")); + + std::string label= LLTrans::getString("Buy"); + // Check the price of the item. + S32 price = getPrice(); + if (-1 == price) + { + llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; + } + else + { + std::ostringstream info; + info << LLTrans::getString("BuyforL$") << price; + label.assign(info.str()); + } + + const LLView::child_list_t *list = menu.getChildList(); + LLView::child_list_t::const_iterator itor; + for (itor = list->begin(); itor != list->end(); ++itor) + { + std::string name = (*itor)->getName(); + LLMenuItemCallGL* menu_itemp = dynamic_cast<LLMenuItemCallGL*>(*itor); + if (name == "Task Buy" && menu_itemp) + { + menu_itemp->setLabel(label); + } + } + } + else + { + items.push_back(std::string("Task Open")); + if (!isItemCopyable()) + { + disabled_items.push_back(std::string("Task Open")); + } + } + items.push_back(std::string("Task Properties")); + if(isItemRenameable()) + { + items.push_back(std::string("Task Rename")); + } + if(isItemRemovable()) + { + items.push_back(std::string("Task Remove")); + } + + + hide_context_entries(menu, items, disabled_items); +} + +#endif ///---------------------------------------------------------------------------- /// LLTaskInvFVBridge impl @@ -1325,6 +1441,13 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* object->getUUID(), object->getName()); break; +#if LL_MESH_ENABLED + case LLAssetType::AT_MESH: + new_bridge = new LLTaskMeshBridge(panel, + object->getUUID(), + object->getName()); + break; +#endif default: llinfos << "Unhandled inventory type (llassetstorage.h): " << (S32)type << llendl; diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 0648d99685..98fbebbc5d 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -65,6 +65,7 @@ #include "llweb.h" #include "llwindow.h" #include "llfloatertools.h" // to enable hide if build tools are up +#include "llvector4a.h" // Functions pulled from pipeline.cpp glh::matrix4f glh_get_current_modelview(); @@ -574,7 +575,9 @@ void LLPanelPrimMediaControls::updateShape() { const LLVolumeFace& vf = volume->getVolumeFace(mTargetObjectFace); - const LLVector3* ext = vf.mExtents; + LLVector3 ext[2]; + ext[0].set(vf.mExtents[0].getF32()); + ext[1].set(vf.mExtents[1].getF32()); LLVector3 center = (ext[0]+ext[1])*0.5f; LLVector3 size = (ext[1]-ext[0])*0.5f; diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index d5a2d66bcf..d10e4fee3a 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -35,7 +35,8 @@ //----------------------------------------------------------------------------- #include "llviewerprecompiledheaders.h" -#include "llpolymesh.h" +#include "llfasttimer.h" +#include "llmemory.h" #include "llviewercontrol.h" #include "llxmltree.h" @@ -45,7 +46,7 @@ #include "llvolume.h" #include "llendianswizzle.h" -#include "llfasttimer.h" +#include "llpolymesh.h" #define HEADER_ASCII "Linden Mesh 1.0" #define HEADER_BINARY "Linden Binary Mesh 1.0" @@ -140,7 +141,7 @@ void LLPolyMeshSharedData::freeMeshData() delete [] mDetailTexCoords; mDetailTexCoords = NULL; - delete [] mWeights; + ll_aligned_free_16(mWeights); mWeights = NULL; } @@ -230,7 +231,7 @@ BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices ) mBaseBinormals = new LLVector3[ numVertices ]; mTexCoords = new LLVector2[ numVertices ]; mDetailTexCoords = new LLVector2[ numVertices ]; - mWeights = new F32[ numVertices ]; + mWeights = (F32*) ll_aligned_malloc_16((numVertices*sizeof(F32)+0xF) & ~0xF); for (i = 0; i < numVertices; i++) { mWeights[i] = 0.f; @@ -708,20 +709,29 @@ LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_ mClothingWeights = reference_mesh->mClothingWeights; } else - { + { #if 1 // Allocate memory without initializing every vector // NOTE: This makes asusmptions about the size of LLVector[234] int nverts = mSharedData->mNumVertices; - int nfloats = nverts * (3*5 + 2 + 4); - mVertexData = new F32[nfloats]; + int nfloats = nverts * (2*4 + 3*3 + 2 + 4); + + //use aligned vertex data to make LLPolyMesh SSE friendly + mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4); int offset = 0; - mCoords = (LLVector3*)(mVertexData + offset); offset += 3*nverts; - mNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; - mScaledNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; - mBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; - mScaledBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; - mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts; - mClothingWeights = (LLVector4*)(mVertexData + offset); offset += 4*nverts; + + //all members must be 16-byte aligned except the last 3 + mCoords = (LLVector4*)(mVertexData + offset); offset += 4*nverts; + mNormals = (LLVector4*)(mVertexData + offset); offset += 4*nverts; + mClothingWeights = (LLVector4*)(mVertexData + offset); offset += 4*nverts; + mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts; + + // these members don't need to be 16-byte aligned, but the first one might be + // read during an aligned memcpy of mTexCoords + mScaledNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; + mBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; + mScaledBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; + + #else mCoords = new LLVector3[mSharedData->mNumVertices]; mNormals = new LLVector3[mSharedData->mNumVertices]; @@ -757,7 +767,7 @@ LLPolyMesh::~LLPolyMesh() delete [] mClothingWeights; delete [] mTexCoords; #else - delete [] mVertexData; + ll_aligned_free_16(mVertexData); #endif } @@ -864,7 +874,7 @@ void LLPolyMesh::dumpDiagInfo() //----------------------------------------------------------------------------- // getWritableCoords() //----------------------------------------------------------------------------- -LLVector3 *LLPolyMesh::getWritableCoords() +LLVector4 *LLPolyMesh::getWritableCoords() { return mCoords; } @@ -872,7 +882,7 @@ LLVector3 *LLPolyMesh::getWritableCoords() //----------------------------------------------------------------------------- // getWritableNormals() //----------------------------------------------------------------------------- -LLVector3 *LLPolyMesh::getWritableNormals() +LLVector4 *LLPolyMesh::getWritableNormals() { return mNormals; } @@ -927,8 +937,12 @@ void LLPolyMesh::initializeForMorph() if (!mSharedData) return; - memcpy(mCoords, mSharedData->mBaseCoords, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ - memcpy(mNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ + for (U32 i = 0; i < mSharedData->mNumVertices; ++i) + { + mCoords[i] = LLVector4(mSharedData->mBaseCoords[i]); + mNormals[i] = LLVector4(mSharedData->mBaseNormals[i]); + } + memcpy(mScaledNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ memcpy(mBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ memcpy(mScaledBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h index c2e5451dfe..d86568a1ba 100644 --- a/indra/newview/llpolymesh.h +++ b/indra/newview/llpolymesh.h @@ -223,15 +223,15 @@ public: } // Get coords - const LLVector3 *getCoords() const{ + const LLVector4 *getCoords() const{ return mCoords; } // non const version - LLVector3 *getWritableCoords(); + LLVector4 *getWritableCoords(); // Get normals - const LLVector3 *getNormals() const{ + const LLVector4 *getNormals() const{ return mNormals; } @@ -253,7 +253,7 @@ public: } // intermediate morphed normals and output normals - LLVector3 *getWritableNormals(); + LLVector4 *getWritableNormals(); LLVector3 *getScaledNormals(); LLVector3 *getWritableBinormals(); @@ -347,11 +347,11 @@ protected: // Single array of floats for allocation / deletion F32 *mVertexData; // deformed vertices (resulting from application of morph targets) - LLVector3 *mCoords; + LLVector4 *mCoords; // deformed normals (resulting from application of morph targets) LLVector3 *mScaledNormals; // output normals (after normalization) - LLVector3 *mNormals; + LLVector4 *mNormals; // deformed binormals (resulting from application of morph targets) LLVector3 *mScaledBinormals; // output binormals (after normalization) diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index 80983cad24..2058c351c4 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -461,10 +461,10 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) if (delta_weight != 0.f) { llassert(!mMesh->isLOD()); - LLVector3 *coords = mMesh->getWritableCoords(); + LLVector4 *coords = mMesh->getWritableCoords(); LLVector3 *scaled_normals = mMesh->getScaledNormals(); - LLVector3 *normals = mMesh->getWritableNormals(); + LLVector4 *normals = mMesh->getWritableNormals(); LLVector3 *scaled_binormals = mMesh->getScaledBinormals(); LLVector3 *binormals = mMesh->getWritableBinormals(); @@ -484,7 +484,8 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) maskWeight = maskWeightArray[vert_index_morph]; } - coords[vert_index_mesh] += mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight; + coords[vert_index_mesh] += LLVector4(mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight); + if (getInfo()->mIsClothingMorph && clothing_weights) { LLVector3 clothing_offset = mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight; @@ -499,7 +500,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) scaled_normals[vert_index_mesh] += mMorphData->mNormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR; LLVector3 normalized_normal = scaled_normals[vert_index_mesh]; normalized_normal.normVec(); - normals[vert_index_mesh] = normalized_normal; + normals[vert_index_mesh] = LLVector4(normalized_normal); // calculate new binormals scaled_binormals[vert_index_mesh] += mMorphData->mBinormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR; @@ -548,7 +549,7 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 if (maskWeights) { - LLVector3 *coords = mMesh->getWritableCoords(); + LLVector4 *coords = mMesh->getWritableCoords(); LLVector3 *scaled_normals = mMesh->getScaledNormals(); LLVector3 *scaled_binormals = mMesh->getScaledBinormals(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); @@ -559,7 +560,7 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 S32 out_vert = mMorphData->mVertexIndices[vert]; // remove effect of existing masked morph - coords[out_vert] -= mMorphData->mCoords[vert] * lastMaskWeight; + coords[out_vert] -= LLVector4(mMorphData->mCoords[vert]) * lastMaskWeight; scaled_normals[out_vert] -= mMorphData->mNormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR; scaled_binormals[out_vert] -= mMorphData->mBinormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR; tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 050b87bbe0..6aadf0afd2 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -70,6 +70,7 @@ #include "llhudmanager.h" #include "llinventorymodel.h" #include "llmenugl.h" +#include "llmeshrepository.h" #include "llmutelist.h" #include "llsidepaneltaskinfo.h" #include "llslurl.h" @@ -181,7 +182,6 @@ LLObjectSelection *get_null_object_selection() // Build time optimization, generate this function once here template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance(); - //----------------------------------------------------------------------------- // LLSelectMgr() //----------------------------------------------------------------------------- @@ -1100,8 +1100,8 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & mGridRotation = first_grid_object->getRenderRotation(); LLVector3 first_grid_obj_pos = first_grid_object->getRenderPosition(); - LLVector3 min_extents(F32_MAX, F32_MAX, F32_MAX); - LLVector3 max_extents(-F32_MAX, -F32_MAX, -F32_MAX); + LLVector4a min_extents(F32_MAX); + LLVector4a max_extents(-F32_MAX); BOOL grid_changed = FALSE; for (LLObjectSelection::iterator iter = mGridObjects.begin(); iter != mGridObjects.end(); ++iter) @@ -1110,7 +1110,7 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & LLDrawable* drawable = object->mDrawable; if (drawable) { - const LLVector3* ext = drawable->getSpatialExtents(); + const LLVector4a* ext = drawable->getSpatialExtents(); update_min_max(min_extents, max_extents, ext[0]); update_min_max(min_extents, max_extents, ext[1]); grid_changed = TRUE; @@ -1118,13 +1118,19 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & } if (grid_changed) { - mGridOrigin = lerp(min_extents, max_extents, 0.5f); + LLVector4a center, size; + center.setAdd(min_extents, max_extents); + center.mul(0.5f); + size.setSub(max_extents, min_extents); + size.mul(0.5f); + + mGridOrigin.set(center.getF32()); LLDrawable* drawable = first_grid_object->mDrawable; if (drawable && drawable->isActive()) { mGridOrigin = mGridOrigin * first_grid_object->getRenderMatrix(); } - mGridScale = (max_extents - min_extents) * 0.5f; + mGridScale.set(size.getF32()); } } else // GRID_MODE_WORLD or just plain default @@ -3932,6 +3938,44 @@ void LLSelectMgr::selectionUpdateCastShadows(BOOL cast_shadows) getSelection()->applyToObjects(&func); } +struct LLSelectMgrApplyPhysicsParam : public LLSelectedObjectFunctor +{ + LLSelectMgrApplyPhysicsParam(U8 type, F32 gravity, F32 friction, + F32 density, F32 restitution) : + mType(type), + mGravity(gravity), + mFriction(friction), + mDensity(density), + mRestitution(restitution) + {} + U8 mType; + F32 mGravity; + F32 mFriction; + F32 mDensity; + F32 mRestitution; + virtual bool apply(LLViewerObject* object) + { + if ( object->permModify() ) // preemptive permissions check + { + object->setPhysicsShapeType( mType ); + object->setPhysicsGravity(mGravity); + object->setPhysicsFriction(mFriction); + object->setPhysicsDensity(mDensity); + object->setPhysicsRestitution(mRestitution); + object->updateFlags(); + } + return true; + } +}; + + +void LLSelectMgr::selectionUpdatePhysicsParam(U8 type, F32 gravity, F32 friction, + F32 density, F32 restitution) +{ + llwarns << "physics shape type ->" << (U32)type << llendl; + LLSelectMgrApplyPhysicsParam func(type, gravity, friction, density, restitution); + getSelection()->applyToObjects(&func); +} //---------------------------------------------------------------------- // Helpful packing functions for sendObjectMessage() @@ -4621,7 +4665,6 @@ void LLSelectMgr::processForceObjectSelect(LLMessageSystem* msg, void**) LLSelectMgr::getInstance()->highlightObjectAndFamily(objects); } - extern LLGLdouble gGLModelView[16]; void LLSelectMgr::updateSilhouettes() @@ -5349,6 +5392,78 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power) return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id)); } +void LLSelectNode::renderOneWireframe(const LLColor4& color) +{ + LLViewerObject* objectp = getObject(); + if (!objectp) + { + return; + } + + LLDrawable* drawable = objectp->mDrawable; + if(!drawable) + { + return; + } + + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + + BOOL is_hud_object = objectp->isHUDAttachment(); + + if (!is_hud_object) + { + glLoadIdentity(); + glMultMatrixd(gGLModelView); + } + + if (drawable->isActive()) + { + glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix); + } + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible()) + { + gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE); + LLGLEnable fog(GL_FOG); + glFogi(GL_FOG_MODE, GL_LINEAR); + float d = (LLViewerCamera::getInstance()->getPointOfInterest()-LLViewerCamera::getInstance()->getOrigin()).magVec(); + LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal()-gAgentCamera.getCameraPositionGlobal()).magVec()/(LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec()*4), 0.0, 1.0); + glFogf(GL_FOG_START, d); + glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV()))); + glFogfv(GL_FOG_COLOR, fogCol.mV); + + LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + { + glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* face = drawable->getFace(i); + pushVerts(face, LLVertexBuffer::MAP_VERTEX); + } + } + } + + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2); + LLGLEnable offset(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(3.f, 2.f); + glLineWidth(3.f); + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* face = drawable->getFace(i); + pushVerts(face, LLVertexBuffer::MAP_VERTEX); + } + glLineWidth(1.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.popMatrix(); +} + //----------------------------------------------------------------------------- // renderOneSilhouette() //----------------------------------------------------------------------------- @@ -5366,6 +5481,13 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) return; } + LLVOVolume* vobj = drawable->getVOVolume(); + if (vobj && vobj->isMesh()) + { + renderOneWireframe(color); + return; + } + if (!mSilhouetteExists) { return; @@ -6055,13 +6177,84 @@ BOOL LLObjectSelection::isEmpty() const //----------------------------------------------------------------------------- // getObjectCount() - returns number of non null objects //----------------------------------------------------------------------------- -S32 LLObjectSelection::getObjectCount() +S32 LLObjectSelection::getObjectCount(BOOL mesh_adjust) { cleanupNodes(); S32 count = mList.size(); + +#if LL_MESH_ENABLED + if (mesh_adjust) + { + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object && object->getVolume()) + { + LLVOVolume* vobj = (LLVOVolume*) object; + if (vobj->isMesh()) + { + LLUUID mesh_id = vobj->getVolume()->getParams().getSculptID(); + U32 cost = gMeshRepo.getResourceCost(mesh_id); + count += cost-1; + } + } + + } + } +#endif + return count; } +F32 LLObjectSelection::getSelectedObjectCost() +{ + cleanupNodes(); + F32 cost = 0.f; + + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + cost += object->getObjectCost(); + } + } + + return cost; +} + +F32 LLObjectSelection::getSelectedLinksetCost() +{ + cleanupNodes(); + F32 cost = 0.f; + + std::set<LLViewerObject*> me_roots; + + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + LLViewerObject* root = static_cast<LLViewerObject*>(object->getRoot()); + if (root) + { + if (me_roots.find(root) == me_roots.end()) + { + me_roots.insert(root); + cost += root->getLinksetCost(); + } + } + } + } + + return cost; +} //----------------------------------------------------------------------------- // getTECount() diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 668c04cf15..45ab40fae2 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -140,6 +140,7 @@ public: BOOL isTESelected(S32 te_index); S32 getLastSelectedTE(); S32 getTESelectMask() { return mTESelectMask; } + void renderOneWireframe(const LLColor4& color); void renderOneSilhouette(const LLColor4 &color); void setTransient(BOOL transient) { mTransient = transient; } BOOL isTransient() { return mTransient; } @@ -284,7 +285,10 @@ public: LLSelectNode* findNode(LLViewerObject* objectp); // count members - S32 getObjectCount(); + S32 getObjectCount(BOOL mesh_adjust = FALSE); + F32 getSelectedObjectCost(); + F32 getSelectedLinksetCost(); + S32 getTECount(); S32 getRootObjectCount(); @@ -484,6 +488,8 @@ public: void saveSelectedObjectTextures(); void selectionUpdatePhysics(BOOL use_physics); + void selectionUpdatePhysicsParam(U8 type, F32 gravity, F32 friction, + F32 density, F32 restitution); void selectionUpdateTemporary(BOOL is_temporary); void selectionUpdatePhantom(BOOL is_ghost); void selectionUpdateCastShadows(BOOL cast_shadows); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index f37b1d40c2..2335c7bb8e 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -38,12 +38,14 @@ #include "llviewerobjectlist.h" #include "llvovolume.h" #include "llvolume.h" +#include "llvolumeoctree.h" #include "llviewercamera.h" #include "llface.h" #include "llviewercontrol.h" #include "llviewerregion.h" #include "llcamera.h" #include "pipeline.h" +#include "llmeshrepository.h" #include "llrender.h" #include "lloctree.h" #include "llvoavatar.h" @@ -101,23 +103,6 @@ void sg_assert(BOOL expr) #endif } -#if LL_DEBUG -void validate_drawable(LLDrawable* drawablep) -{ - F64 rad = drawablep->getBinRadius(); - const LLVector3* ext = drawablep->getSpatialExtents(); - - if (rad < 0 || rad > 4096 || - (ext[1]-ext[0]).magVec() > 4096) - { - llwarns << "Invalid drawable found in octree." << llendl; - } -} -#else -#define validate_drawable(x) -#endif - - S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad) { return AABBSphereIntersectR2(min, max, origin, rad*rad); @@ -157,6 +142,55 @@ S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVe } +S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad) +{ + return AABBSphereIntersectR2(min, max, origin, rad*rad); +} + +S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) +{ + F32 d = 0.f; + F32 t; + + LLVector4a origina; + origina.load3(origin.mV); + + LLVector4a v; + v.setSub(min, origina); + + if (v.dot3(v) < r) + { + v.setSub(max, origina); + if (v.dot3(v) < r) + { + return 2; + } + } + + + for (U32 i = 0; i < 3; i++) + { + if (origin.mV[i] < min[i]) + { + t = min[i] - origin.mV[i]; + d += t*t; + } + else if (origin.mV[i] > max[i]) + { + t = origin.mV[i] - max[i]; + d += t*t; + } + + if (d > r) + { + return 0; + } + } + + return 1; +} + + typedef enum { b000 = 0x00, @@ -174,42 +208,31 @@ typedef enum //gives you a triangle fan index array static U8 sOcclusionIndices[] = { - // 000 + //000 b111, b110, b010, b011, b001, b101, b100, b110, - //001 - b110, b000, b010, b011, b111, b101, b100, b000, + //001 + b011, b010, b000, b001, b101, b111, b110, b010, //010 b101, b100, b110, b111, b011, b001, b000, b100, //011 - b100, b010, b110, b111, b101, b001, b000, b010, - //100 - b011, b010, b000, b001, b101, b111, b110, b010, + b001, b000, b100, b101, b111, b011, b010, b000, + //100 + b110, b000, b010, b011, b111, b101, b100, b000, //101 b010, b100, b000, b001, b011, b111, b110, b100, //110 - b001, b000, b100, b101, b111, b011, b010, b000, + b100, b010, b110, b111, b101, b001, b000, b010, //111 b000, b110, b100, b101, b001, b011, b010, b110, }; -U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center) +U8* get_box_fan_indices(LLCamera* camera, const LLVector4a& center) { - LLVector3 d = center - camera->getOrigin(); - - U8 cypher = 0; - if (d.mV[0] > 0) - { - cypher |= b100; - } - if (d.mV[1] > 0) - { - cypher |= b010; - } - if (d.mV[2] > 0) - { - cypher |= b001; - } + LLVector4a origin; + origin.load3(camera->getOrigin().mV); + S32 cypher = center.greaterThan4(origin).getComparisonMask() & 0x7; + return sOcclusionIndices+cypher*8; } @@ -217,33 +240,49 @@ void LLSpatialGroup::buildOcclusion() { if (!mOcclusionVerts) { - mOcclusionVerts = new F32[8*3]; + mOcclusionVerts = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*8); } - LLVector3 r = mBounds[1] + LLVector3(SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE); + LLVector4a fudge; + fudge.splat(SG_OCCLUSION_FUDGE); - for (U32 k = 0; k < 3; k++) - { - r.mV[k] = llmin(mBounds[1].mV[k]+0.25f, r.mV[k]); - } + LLVector4a r; + r.setAdd(mBounds[1], fudge); + + LLVector4a r2; + r2.splat(0.25f); + r2.add(mBounds[1]); - F32* v = mOcclusionVerts; - F32* c = mBounds[0].mV; - F32* s = r.mV; + r.setMin(r2); + + LLVector4a* v = mOcclusionVerts; + const LLVector4a& c = mBounds[0]; + const LLVector4a& s = r; + static const LLVector4a octant[] = + { + LLVector4a(-1.f, -1.f, -1.f), + LLVector4a(-1.f, -1.f, 1.f), + LLVector4a(-1.f, 1.f, -1.f), + LLVector4a(-1.f, 1.f, 1.f), + + LLVector4a(1.f, -1.f, -1.f), + LLVector4a(1.f, -1.f, 1.f), + LLVector4a(1.f, 1.f, -1.f), + LLVector4a(1.f, 1.f, 1.f), + }; + //vertex positions are encoded so the 3 bits of their vertex index //correspond to their axis facing, with bit position 3,2,1 matching //axis facing x,y,z, bit set meaning positive facing, bit clear //meaning negative facing - v[0] = c[0]-s[0]; v[1] = c[1]-s[1]; v[2] = c[2]-s[2]; // 0 - 0000 - v[3] = c[0]-s[0]; v[4] = c[1]-s[1]; v[5] = c[2]+s[2]; // 1 - 0001 - v[6] = c[0]-s[0]; v[7] = c[1]+s[1]; v[8] = c[2]-s[2]; // 2 - 0010 - v[9] = c[0]-s[0]; v[10] = c[1]+s[1]; v[11] = c[2]+s[2]; // 3 - 0011 - - v[12] = c[0]+s[0]; v[13] = c[1]-s[1]; v[14] = c[2]-s[2]; // 4 - 0100 - v[15] = c[0]+s[0]; v[16] = c[1]-s[1]; v[17] = c[2]+s[2]; // 5 - 0101 - v[18] = c[0]+s[0]; v[19] = c[1]+s[1]; v[20] = c[2]-s[2]; // 6 - 0110 - v[21] = c[0]+s[0]; v[22] = c[1]+s[1]; v[23] = c[2]+s[2]; // 7 - 0111 + + for (S32 i = 0; i < 8; ++i) + { + v[i] = s; + v[i].mul(octant[i]); + v[i].add(c); + } clearState(LLSpatialGroup::OCCLUSION_DIRTY); } @@ -287,6 +326,11 @@ LLSpatialGroup::~LLSpatialGroup() llerrs << "Illegal deletion of LLSpatialGroup!" << llendl; }*/ + if (gDebugGL) + { + gPipeline.checkReferences(this); + } + if (isState(DEAD)) { sZombieGroups--; @@ -299,12 +343,14 @@ LLSpatialGroup::~LLSpatialGroup() sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); } - delete [] mOcclusionVerts; + ll_aligned_free_16(mOcclusionVerts); mOcclusionVerts = NULL; LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); clearDrawMap(); clearAtlasList() ; + + ll_aligned_free_16(mBounds); } BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp) @@ -456,8 +502,10 @@ void LLSpatialGroup::validate() sg_assert(!isState(DIRTY)); sg_assert(!isDead()); - LLVector3 myMin = mBounds[0] - mBounds[1]; - LLVector3 myMax = mBounds[0] + mBounds[1]; + LLVector4a myMin; + myMin.setSub(mBounds[0], mBounds[1]); + LLVector4a myMax; + myMax.setAdd(mBounds[0], mBounds[1]); validateDrawMap(); @@ -489,16 +537,18 @@ void LLSpatialGroup::validate() group->validate(); //ensure all children are enclosed in this node - LLVector3 center = group->mBounds[0]; - LLVector3 size = group->mBounds[1]; + LLVector4a center = group->mBounds[0]; + LLVector4a size = group->mBounds[1]; - LLVector3 min = center - size; - LLVector3 max = center + size; + LLVector4a min; + min.setSub(center, size); + LLVector4a max; + max.setAdd(center, size); for (U32 j = 0; j < 3; j++) { - sg_assert(min.mV[j] >= myMin.mV[j]-0.02f); - sg_assert(max.mV[j] <= myMax.mV[j]+0.02f); + sg_assert(min[j] >= myMin[j]-0.02f); + sg_assert(max[j] <= myMax[j]+0.02f); } } @@ -508,52 +558,8 @@ void LLSpatialGroup::validate() void LLSpatialGroup::checkStates() { #if LL_OCTREE_PARANOIA_CHECK - LLOctreeStateCheck checker; - checker.traverse(mOctreeNode); -#endif -} - -void validate_draw_info(LLDrawInfo& params) -{ -#if LL_OCTREE_PARANOIA_CHECK - if (params.mVertexBuffer.isNull()) - { - llerrs << "Draw batch has no vertex buffer." << llendl; - } - - //bad range - if (params.mStart >= params.mEnd) - { - llerrs << "Draw batch has invalid range." << llendl; - } - - if (params.mEnd >= (U32) params.mVertexBuffer->getNumVerts()) - { - llerrs << "Draw batch has buffer overrun error." << llendl; - } - - if (params.mOffset + params.mCount > (U32) params.mVertexBuffer->getNumIndices()) - { - llerrs << "Draw batch has index buffer ovverrun error." << llendl; - } - - //bad indices - U16* indicesp = (U16*) params.mVertexBuffer->getIndicesPointer(); - if (indicesp) - { - for (U32 i = params.mOffset; i < params.mOffset+params.mCount; i++) - { - if (indicesp[i] < (U16)params.mStart) - { - llerrs << "Draw batch has vertex buffer index out of range error (index too low)." << llendl; - } - - if (indicesp[i] > (U16)params.mEnd) - { - llerrs << "Draw batch has vertex buffer index out of range error (index too high)." << llendl; - } - } - } + //LLOctreeStateCheck checker; + //checker.traverse(mOctreeNode); #endif } @@ -566,8 +572,8 @@ void LLSpatialGroup::validateDrawMap() for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) { LLDrawInfo& params = **j; - - validate_draw_info(params); + + params.validate(); } } #endif @@ -578,19 +584,17 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); drawablep->updateSpatialExtents(); - validate_drawable(drawablep); OctreeNode* parent = mOctreeNode->getOctParent(); if (mOctreeNode->isInside(drawablep->getPositionGroup()) && (mOctreeNode->contains(drawablep) || - (drawablep->getBinRadius() > mOctreeNode->getSize().mdV[0] && + (drawablep->getBinRadius() > mOctreeNode->getSize()[0] && parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) { unbound(); setState(OBJECT_DIRTY); //setState(GEOM_DIRTY); - validate_drawable(drawablep); return TRUE; } @@ -608,7 +612,6 @@ BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_oc else { drawablep->setSpatialGroup(this); - validate_drawable(drawablep); setState(OBJECT_DIRTY | GEOM_DIRTY); setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS); gPipeline.markRebuild(this, TRUE); @@ -709,7 +712,7 @@ void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group) } -BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxOut) +BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) { const OctreeNode* node = mOctreeNode; @@ -722,8 +725,8 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO return FALSE; } - LLVector3& newMin = mObjectExtents[0]; - LLVector3& newMax = mObjectExtents[1]; + LLVector4a& newMin = mObjectExtents[0]; + LLVector4a& newMax = mObjectExtents[1]; if (isState(OBJECT_DIRTY)) { //calculate new bounding box @@ -732,10 +735,10 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO //initialize bounding box to first element OctreeNode::const_element_iter i = node->getData().begin(); LLDrawable* drawablep = *i; - const LLVector3* minMax = drawablep->getSpatialExtents(); + const LLVector4a* minMax = drawablep->getSpatialExtents(); - newMin.setVec(minMax[0]); - newMax.setVec(minMax[1]); + newMin = minMax[0]; + newMax = minMax[1]; for (++i; i != node->getData().end(); ++i) { @@ -759,8 +762,10 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO }*/ } - mObjectBounds[0] = (newMin + newMax) * 0.5f; - mObjectBounds[1] = (newMax - newMin) * 0.5f; + mObjectBounds[0].setAdd(newMin, newMax); + mObjectBounds[0].mul(0.5f); + mObjectBounds[1].setSub(newMax, newMin); + mObjectBounds[1].mul(0.5f); } if (empty) @@ -770,17 +775,8 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO } else { - for (U32 i = 0; i < 3; i++) - { - if (newMin.mV[i] < minOut.mV[i]) - { - minOut.mV[i] = newMin.mV[i]; - } - if (newMax.mV[i] > maxOut.mV[i]) - { - maxOut.mV[i] = newMax.mV[i]; - } - } + minOut.setMin(newMin); + maxOut.setMax(newMax); } return TRUE; @@ -871,18 +867,19 @@ BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) return TRUE; } -void LLSpatialGroup::shift(const LLVector3 &offset) +void LLSpatialGroup::shift(const LLVector4a &offset) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - LLVector3d offsetd(offset); - mOctreeNode->setCenter(mOctreeNode->getCenter()+offsetd); + LLVector4a t = mOctreeNode->getCenter(); + t.add(offset); + mOctreeNode->setCenter(t); mOctreeNode->updateMinMax(); - mBounds[0] += offset; - mExtents[0] += offset; - mExtents[1] += offset; - mObjectBounds[0] += offset; - mObjectExtents[0] += offset; - mObjectExtents[1] += offset; + mBounds[0].add(offset); + mExtents[0].add(offset); + mExtents[1].add(offset); + mObjectBounds[0].add(offset); + mObjectExtents[0].add(offset); + mObjectExtents[1].add(offset); //if (!mSpatialPartition->mRenderByGroup) { @@ -894,10 +891,7 @@ void LLSpatialGroup::shift(const LLVector3 &offset) { for (U32 i = 0; i < 8; i++) { - F32* v = mOcclusionVerts+i*3; - v[0] += offset.mV[0]; - v[1] += offset.mV[1]; - v[2] += offset.mV[2]; + mOcclusionVerts[i].add(offset); } } } @@ -1163,8 +1157,6 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : mDepth(0.f), mLastUpdateDistance(-1.f), mLastUpdateTime(gFrameTimeSeconds), - mViewAngle(0.f), - mLastUpdateViewAngle(-1.f), mAtlasList(4), mCurUpdatingTime(0), mCurUpdatingSlotp(NULL), @@ -1173,13 +1165,25 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : sNodeCount++; LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + mBounds = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a) * V4_COUNT); + mExtents = mBounds + EXTENTS; + mObjectBounds = mBounds + OBJECT_BOUNDS; + mObjectExtents = mBounds + OBJECT_EXTENTS; + mViewAngle = mBounds+VIEW_ANGLE; + mLastUpdateViewAngle = mBounds+LAST_VIEW_ANGLE; + + mViewAngle->splat(0.f); + mLastUpdateViewAngle->splat(-1.f); + mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] = + mObjectExtents[0] = mObjectExtents[1] = *mViewAngle; + sg_assert(mOctreeNode->getListenerCount() == 0); mOctreeNode->addListener(this); setState(SG_INITIAL_STATE_MASK); gPipeline.markRebuild(this, TRUE); - mBounds[0] = LLVector3(node->getCenter()); - mBounds[1] = LLVector3(node->getSize()); + mBounds[0] = node->getCenter(); + mBounds[1] = node->getSize(); part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod; mLODHash = part->mLODSeed; @@ -1216,8 +1220,8 @@ void LLSpatialGroup::updateDistance(LLCamera &camera) #endif if (!getData().empty()) { - mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].magVec() : - (F32) mOctreeNode->getSize().magVec(); + mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].length3() : + (F32) mOctreeNode->getSize().length3(); mDistance = mSpatialPartition->calcDistance(this, camera); mPixelArea = mSpatialPartition->calcPixelArea(this, camera); } @@ -1225,27 +1229,34 @@ void LLSpatialGroup::updateDistance(LLCamera &camera) F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) { - LLVector3 eye = group->mObjectBounds[0] - camera.getOrigin(); + LLVector4a eye; + LLVector4a origin; + origin.load3(camera.getOrigin().mV); + + eye.setSub(group->mObjectBounds[0], origin); F32 dist = 0.f; if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end()) { - LLVector3 v = eye; - dist = eye.normVec(); + LLVector4a v = eye; + + dist = eye.length3(); + eye.normalize3fast(); if (!group->isState(LLSpatialGroup::ALPHA_DIRTY)) { if (!group->mSpatialPartition->isBridge()) { - LLVector3 view_angle = LLVector3(eye * LLVector3(1,0,0), - eye * LLVector3(0,1,0), - eye * LLVector3(0,0,1)); + LLVector4a view_angle = eye; - if ((view_angle-group->mLastUpdateViewAngle).magVec() > 0.64f) + LLVector4a diff; + diff.setSub(view_angle, *group->mLastUpdateViewAngle); + + if (diff.length3() > 0.64f) { - group->mViewAngle = view_angle; - group->mLastUpdateViewAngle = view_angle; + *group->mViewAngle = view_angle; + *group->mLastUpdateViewAngle = view_angle; //for occasional alpha sorting within the group //NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order, //not setting this node to dirty would be a very good thing @@ -1259,17 +1270,20 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) LLVector3 at = camera.getAtAxis(); - //front of bounding box - for (U32 i = 0; i < 3; i++) - { - v.mV[i] -= group->mObjectBounds[1].mV[i]*0.25f * at.mV[i]; - } + LLVector4a ata; + ata.load3(at.mV); - group->mDepth = v * at; + LLVector4a t = ata; + //front of bounding box + t.mul(0.25f); + t.mul(group->mObjectBounds[1]); + v.sub(t); + + group->mDepth = v.dot3(ata); } else { - dist = eye.magVec(); + dist = eye.length3(); } if (dist < 16.f) @@ -1422,7 +1436,7 @@ void LLSpatialGroup::destroyGL() } } - delete [] mOcclusionVerts; + ll_aligned_free_16(mOcclusionVerts); mOcclusionVerts = NULL; for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) @@ -1465,8 +1479,8 @@ BOOL LLSpatialGroup::rebound() } else { - LLVector3& newMin = mExtents[0]; - LLVector3& newMax = mExtents[1]; + LLVector4a& newMin = mExtents[0]; + LLVector4a& newMax = mExtents[1]; LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); group->clearState(SKIP_FRUSTUM_CHECK); group->rebound(); @@ -1480,26 +1494,19 @@ BOOL LLSpatialGroup::rebound() group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); group->clearState(SKIP_FRUSTUM_CHECK); group->rebound(); - const LLVector3& max = group->mExtents[1]; - const LLVector3& min = group->mExtents[0]; + const LLVector4a& max = group->mExtents[1]; + const LLVector4a& min = group->mExtents[0]; - for (U32 j = 0; j < 3; j++) - { - if (max.mV[j] > newMax.mV[j]) - { - newMax.mV[j] = max.mV[j]; - } - if (min.mV[j] < newMin.mV[j]) - { - newMin.mV[j] = min.mV[j]; - } - } + newMax.setMax(max); + newMin.setMin(min); } boundObjects(FALSE, newMin, newMax); - mBounds[0] = (newMin + newMax)*0.5f; - mBounds[1] = (newMax - newMin)*0.5f; + mBounds[0].setAdd(newMin, newMax); + mBounds[0].mul(0.5f); + mBounds[1].setSub(newMax, newMin); + mBounds[1].mul(0.5f); } setState(OCCLUSION_DIRTY); @@ -1584,7 +1591,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) } glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery[LLViewerCamera::sCurCameraID]); - glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts); + glVertexPointer(3, GL_FLOAT, 16, mOcclusionVerts); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, @@ -1625,8 +1632,11 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 LLGLNamePool::registerPool(&sQueryPool); - mOctree = new LLSpatialGroup::OctreeRoot(LLVector3d(0,0,0), - LLVector3d(1,1,1), + LLVector4a center, size; + center.splat(0.f); + size.splat(1.f); + + mOctree = new LLSpatialGroup::OctreeRoot(center,size, NULL); new LLSpatialGroup(mOctree, this); } @@ -1646,7 +1656,6 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); drawablep->updateSpatialExtents(); - validate_drawable(drawablep); //keep drawable from being garbage collected LLPointer<LLDrawable> ptr = drawablep; @@ -1730,16 +1739,16 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL class LLSpatialShift : public LLSpatialGroup::OctreeTraveler { public: - LLSpatialShift(LLVector3 offset) : mOffset(offset) { } + const LLVector4a& mOffset; + + LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { } virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); } - - LLVector3 mOffset; }; -void LLSpatialPartition::shift(const LLVector3 &offset) +void LLSpatialPartition::shift(const LLVector4a &offset) { //shift octree node bounding boxes by offset LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); LLSpatialShift shifter(offset); @@ -1901,7 +1910,7 @@ public: class LLOctreeCullVisExtents: public LLOctreeCullShadow { public: - LLOctreeCullVisExtents(LLCamera* camera, LLVector3& min, LLVector3& max) + LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max) : LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { } virtual bool earlyFail(LLSpatialGroup* group) @@ -1968,8 +1977,8 @@ public: } BOOL mEmpty; - LLVector3& mMin; - LLVector3& mMax; + LLVector4a& mMin; + LLVector4a& mMax; }; class LLOctreeCullDetectVisible: public LLOctreeCullShadow @@ -2038,6 +2047,8 @@ public: void drawBox(const LLVector3& c, const LLVector3& r) { + LLVertexBuffer::unbind(); + gGL.begin(LLRender::TRIANGLE_STRIP); //left front gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); @@ -2073,6 +2084,11 @@ void drawBox(const LLVector3& c, const LLVector3& r) gGL.end(); } +void drawBox(const LLVector4a& c, const LLVector4a& r) +{ + drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r)); +} + void drawBoxOutline(const LLVector3& pos, const LLVector3& size) { LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1)); @@ -2119,6 +2135,11 @@ void drawBoxOutline(const LLVector3& pos, const LLVector3& size) gGL.end(); } +void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size) +{ + drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size)); +} + class LLOctreeDirty : public LLOctreeTraveler<LLDrawable> { public: @@ -2162,14 +2183,21 @@ BOOL LLSpatialPartition::isOcclusionEnabled() BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax) { + LLVector4a visMina, visMaxa; + visMina.load3(visMin.mV); + visMaxa.load3(visMax.mV); + { LLFastTimer ftm(FTM_CULL_REBOUND); LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); } - LLOctreeCullVisExtents vis(&camera, visMin, visMax); + LLOctreeCullVisExtents vis(&camera, visMina, visMaxa); vis.traverse(mOctree); + + visMin.set(visMina.getF32()); + visMax.set(visMaxa.getF32()); return vis.mEmpty; } @@ -2232,25 +2260,36 @@ BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group) } const F32 vel = SG_OCCLUSION_FUDGE*2.f; - LLVector3 c = group->mBounds[0]; - LLVector3 r = group->mBounds[1] + LLVector3(vel,vel,vel); - + LLVector4a fudge; + fudge.splat(vel); + + const LLVector4a& c = group->mBounds[0]; + LLVector4a r; + r.setAdd(group->mBounds[1], fudge); + /*if (r.magVecSquared() > 1024.0*1024.0) { return TRUE; }*/ - LLVector3 e = camera->getOrigin(); + LLVector4a e; + e.load3(camera->getOrigin().mV); - LLVector3 min = c - r; - LLVector3 max = c + r; + LLVector4a min; + min.setSub(c,r); + LLVector4a max; + max.setAdd(c,r); - for (U32 j = 0; j < 3; j++) + S32 lt = e.lessThan4(min).getComparisonMask() & 0x7; + if (lt) { - if (e.mV[j] < min.mV[j] || e.mV[j] > max.mV[j]) - { - return FALSE; - } + return FALSE; + } + + S32 gt = e.greaterThan4(max).getComparisonMask() & 0x7; + if (gt) + { + return FALSE; } return TRUE; @@ -2292,7 +2331,14 @@ void pushVerts(LLFace* face, U32 mask) U16 offset = face->getIndicesStart(); buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); } +} +void pushVerts(LLDrawable* drawable, U32 mask) +{ + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + pushVerts(drawable->getFace(i), mask); + } } void pushBufferVerts(LLVertexBuffer* buffer, U32 mask) @@ -2456,7 +2502,13 @@ void renderOctree(LLSpatialGroup* group) } gGL.color4fv(col.mV); - drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f)); + LLVector4a fudge; + fudge.splat(0.001f); + LLVector4a size = group->mObjectBounds[1]; + size.mul(1.01f); + size.add(fudge); + + drawBox(group->mObjectBounds[0], fudge); gGL.setSceneBlendType(LLRender::BT_ALPHA); @@ -2487,8 +2539,12 @@ void renderOctree(LLSpatialGroup* group) for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) { LLDrawInfo* draw_info = *j; - LLVector3 center = (draw_info->mExtents[1] + draw_info->mExtents[0])*0.5f; - LLVector3 size = (draw_info->mExtents[1] - draw_info->mExtents[0])*0.5f; + LLVector4a center; + center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]); + center.mul(0.5f); + LLVector4a size; + size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]); + size.mul(0.5f); drawBoxOutline(center, size); } } @@ -2538,7 +2594,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera) else if (camera && group->mOcclusionVerts) { LLVertexBuffer::unbind(); - glVertexPointer(3, GL_FLOAT, 0, group->mOcclusionVerts); + glVertexPointer(3, GL_FLOAT, 16, group->mOcclusionVerts); glColor4f(1.0f, 0.f, 0.f, 0.5f); glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0])); @@ -2617,8 +2673,8 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) } } - const LLVector3* ext; - LLVector3 pos, size; + const LLVector4a* ext; + LLVector4a pos, size; //render face bounding boxes for (S32 i = 0; i < drawable->getNumFaces(); i++) @@ -2627,20 +2683,21 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) ext = facep->mExtents; - if (ext[0].isExactlyZero() && ext[1].isExactlyZero()) - { - continue; - } - pos = (ext[0] + ext[1]) * 0.5f; - size = (ext[1] - ext[0]) * 0.5f; + pos.setAdd(ext[0], ext[1]); + pos.mul(0.5f); + size.setSub(ext[1], ext[0]); + size.mul(0.5f); + drawBoxOutline(pos,size); } //render drawable bounding box ext = drawable->getSpatialExtents(); - pos = (ext[0] + ext[1]) * 0.5f; - size = (ext[1] - ext[0]) * 0.5f; + pos.setAdd(ext[0], ext[1]); + pos.mul(0.5f); + size.setSub(ext[1], ext[0]); + size.mul(0.5f); LLViewerObject* vobj = drawable->getVObj(); if (vobj && vobj->onActiveList()) @@ -2657,7 +2714,131 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) { drawBoxOutline(pos,size); } - +} + +void renderNormals(LLDrawable* drawablep) +{ + LLVertexBuffer::unbind(); + + LLVOVolume* vol = drawablep->getVOVolume(); + if (vol) + { + LLVolume* volume = vol->getVolume(); + gGL.pushMatrix(); + glMultMatrixf((F32*) vol->getRelativeXform().mMatrix); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale")); + + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + + gGL.begin(LLRender::LINES); + + for (S32 j = 0; j < face.mNumVertices; ++j) + { + LLVector4a n,p; + + n.setMul(face.mNormals[j], scale); + p.setAdd(face.mPositions[j], n); + + gGL.color4f(1,1,1,1); + gGL.vertex3fv(face.mPositions[j].getF32()); + gGL.vertex3fv(p.getF32()); + + if (face.mBinormals) + { + n.setMul(face.mBinormals[j], scale); + p.setAdd(face.mPositions[j], n); + + gGL.color4f(0,1,1,1); + gGL.vertex3fv(face.mPositions[j].getF32()); + gGL.vertex3fv(p.getF32()); + } + } + + gGL.end(); + } + + gGL.popMatrix(); + } +} + +void renderPhysicsShape(LLDrawable* drawable) +{ + LLVOVolume* volume = drawable->getVOVolume(); + if (volume) + { + F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold"); + F32 cost = volume->getObjectCost(); + + LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor"); + LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor"); + LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor"); + + F32 normalizedCost = 1.f - exp( -(cost / threshold) ); + + LLColor4 color; + if ( normalizedCost <= 0.5f ) + { + color = lerp( low, mid, 2.f * normalizedCost ); + } + else + { + color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) ); + } + + U32 data_mask = LLVertexBuffer::MAP_VERTEX; + +#if LL_MESH_ENABLED + if (volume->isMesh()) + { + LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); + const LLMeshDecomposition* decomp = gMeshRepo.getDecomposition(mesh_id); + if (decomp) + { + gGL.pushMatrix(); + glMultMatrixf((F32*) volume->getRelativeXform().mMatrix); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + for (U32 i = 0; i < decomp->mHull.size(); ++i) + { + LLVertexBuffer* buff = decomp->mMesh[i]; + + buff->setBuffer(data_mask); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glColor3fv(color.mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + { + LLGLEnable blend(GL_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + glColor4fv(color.mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + } + } + + gGL.popMatrix(); + + return; + } + } +#endif //LL_MESH_ENABLED + + //push faces + glColor3fv(color.mV); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + pushVerts(drawable, data_mask); + glColor4fv(color.mV); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + pushVerts(drawable, data_mask); + } } void renderTexturePriority(LLDrawable* drawable) @@ -2696,8 +2877,13 @@ void renderTexturePriority(LLDrawable* drawable) // gGL.color4f(1,0,1,1); //} - LLVector3 center = (facep->mExtents[1]+facep->mExtents[0])*0.5f; - LLVector3 size = (facep->mExtents[1]-facep->mExtents[0])*0.5f + LLVector3(0.01f, 0.01f, 0.01f); + LLVector4a center; + center.setAdd(facep->mExtents[1],facep->mExtents[0]); + center.mul(0.5f); + LLVector4a size; + size.setSub(facep->mExtents[1],facep->mExtents[0]); + size.mul(0.5f); + size.add(LLVector4a(0.01f)); drawBox(center, size); /*S32 boost = imagep->getBoostLevel(); @@ -2721,7 +2907,6 @@ void renderPoints(LLDrawable* drawablep) { gGL.begin(LLRender::POINTS); gGL.color3f(1,1,1); - LLVector3 center(drawablep->getPositionGroup()); for (S32 i = 0; i < drawablep->getNumFaces(); i++) { gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV); @@ -2753,8 +2938,12 @@ void renderShadowFrusta(LLDrawInfo* params) LLGLEnable blend(GL_BLEND); gGL.setSceneBlendType(LLRender::BT_ADD); - LLVector3 center = (params->mExtents[1]+params->mExtents[0])*0.5f; - LLVector3 size = (params->mExtents[1]-params->mExtents[0])*0.5f; + LLVector4a center; + center.setAdd(params->mExtents[1], params->mExtents[0]); + center.mul(0.5f); + LLVector4a size; + size.setSub(params->mExtents[1],params->mExtents[0]); + size.mul(0.5f); if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size)) { @@ -2798,10 +2987,14 @@ void renderLights(LLDrawable* drawablep) pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); } - const LLVector3* ext = drawablep->getSpatialExtents(); + const LLVector4a* ext = drawablep->getSpatialExtents(); - LLVector3 pos = (ext[0] + ext[1]) * 0.5f; - LLVector3 size = (ext[1] - ext[0]) * 0.5f; + LLVector4a pos; + pos.setAdd(ext[0], ext[1]); + pos.mul(0.5f); + LLVector4a size; + size.setSub(ext[1], ext[0]); + size.mul(0.5f); { LLGLDepthTest depth(GL_FALSE, GL_TRUE); @@ -2811,10 +3004,32 @@ void renderLights(LLDrawable* drawablep) gGL.color4f(1,1,0,1); F32 rad = drawablep->getVOVolume()->getLightRadius(); - drawBoxOutline(pos, LLVector3(rad,rad,rad)); + drawBoxOutline(pos, LLVector4a(rad)); } } +class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect +{ +public: + + LLRenderOctreeRaycast(const LLVector3& start, const LLVector3& end) + { + mStart.load3(start.mV); + mEnd.load3(end.mV); + mDir.setSub(mEnd, mStart); + } + + void visit(const LLOctreeNode<LLVolumeTriangle>* branch) + { + LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0); + + LLVector3 center, size; + center.set(vl->mBounds[0].getF32()); + size.set(vl->mBounds[1].getF32()); + + drawBoxOutline(center, size); + } +}; void renderRaycast(LLDrawable* drawablep) { @@ -2833,6 +3048,27 @@ void renderRaycast(LLDrawable* drawablep) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + LLVOVolume* vobj = drawablep->getVOVolume(); + LLVolume* volume = vobj->getVolume(); + if (volume && volume->getNumVolumeFaces() > gDebugRaycastFaceHit) + { + const LLVolumeFace& face = volume->getVolumeFace(gDebugRaycastFaceHit); + if (!face.mOctree) + { + ((LLVolumeFace*) &face)->createOctree(); + } + + gGL.pushMatrix(); + glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix); + LLVector3 start, end; + start = vobj->agentPositionToVolume(gDebugRaycastStart); + end = vobj->agentPositionToVolume(gDebugRaycastEnd); + + LLRenderOctreeRaycast render(start, end); + render.traverse(face.mOctree); + gGL.popMatrix(); + } } else if (drawablep->isAvatar()) { @@ -2861,10 +3097,14 @@ void renderRaycast(LLDrawable* drawablep) glPopMatrix(); // draw bounding box of prim - const LLVector3* ext = drawablep->getSpatialExtents(); + const LLVector4a* ext = drawablep->getSpatialExtents(); - LLVector3 pos = (ext[0] + ext[1]) * 0.5f; - LLVector3 size = (ext[1] - ext[0]) * 0.5f; + LLVector4a pos; + pos.setAdd(ext[0], ext[1]); + pos.mul(0.5f); + LLVector4a size; + size.setSub(ext[1], ext[0]); + size.mul(0.5f); LLGLDepthTest depth(GL_FALSE, GL_TRUE); gGL.color4f(0,0.5f,0.5f,1); @@ -2951,8 +3191,8 @@ public: return; } - LLVector3 nodeCenter = group->mBounds[0]; - LLVector3 octCenter = LLVector3(group->mOctreeNode->getCenter()); + LLVector4a nodeCenter = group->mBounds[0]; + LLVector4a octCenter = group->mOctreeNode->getCenter(); group->rebuildGeom(); group->rebuildMesh(); @@ -2975,14 +3215,30 @@ public: { renderBoundingBox(drawable); } + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS)) + { + renderNormals(drawable); + } + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) + { + renderPhysicsShape(drawable); + } + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE)) { if (drawable->isState(LLDrawable::IN_REBUILD_Q2)) { gGL.color4f(0.6f, 0.6f, 0.1f, 1.f); - const LLVector3* ext = drawable->getSpatialExtents(); - drawBoxOutline((ext[0]+ext[1])*0.5f, (ext[1]-ext[0])*0.5f); + const LLVector4a* ext = drawable->getSpatialExtents(); + LLVector4a center; + center.setAdd(ext[0], ext[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(ext[1], ext[0]); + size.mul(0.5f); + drawBoxOutline(center, size); } } @@ -3168,6 +3424,7 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_LIGHTS | LLPipeline::RENDER_DEBUG_BATCH_SIZE | LLPipeline::RENDER_DEBUG_BBOXES | + LLPipeline::RENDER_DEBUG_NORMALS | LLPipeline::RENDER_DEBUG_POINTS | LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY | LLPipeline::RENDER_DEBUG_TEXTURE_ANIM | @@ -3175,7 +3432,8 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | LLPipeline::RENDER_DEBUG_AGENT_TARGET | LLPipeline::RENDER_DEBUG_BUILD_QUEUE | - LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | + LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) { return; } @@ -3213,7 +3471,11 @@ void LLSpatialPartition::renderDebug() void LLSpatialGroup::drawObjectBox(LLColor4 col) { gGL.color4fv(col.mV); - drawBox(mObjectBounds[0], mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f)); + LLVector4a size; + size = mObjectBounds[0]; + size.mul(1.01f); + size.add(LLVector4a(0.001f)); + drawBox(mObjectBounds[0], size); } @@ -3273,8 +3535,8 @@ public: LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0); - LLVector3 size; - LLVector3 center; + LLVector4a size; + LLVector4a center; size = group->mBounds[1]; center = group->mBounds[0]; @@ -3291,7 +3553,11 @@ public: local_end = mEnd * local_matrix; } - if (LLLineSegmentBoxIntersect(local_start, local_end, center, size)) + LLVector4a start, end; + start.load3(local_start.mV); + end.load3(local_end.mV); + + if (LLLineSegmentBoxIntersect(start, end, center, size)) { check(child); } @@ -3381,18 +3647,10 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, mDistance(0.f), mDrawMode(LLRender::TRIANGLES) { - mDebugColor = (rand() << 16) + rand(); - if (mStart >= mVertexBuffer->getRequestedVerts() || - mEnd >= mVertexBuffer->getRequestedVerts()) - { - llerrs << "Invalid draw info vertex range." << llendl; - } + mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); + mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*2); - if (mOffset >= (U32) mVertexBuffer->getRequestedIndices() || - mOffset + mCount > (U32) mVertexBuffer->getRequestedIndices()) - { - llerrs << "Invalid draw info index range." << llendl; - } + mDebugColor = (rand() << 16) + rand(); } LLDrawInfo::~LLDrawInfo() @@ -3406,6 +3664,18 @@ LLDrawInfo::~LLDrawInfo() { mFace->setDrawInfo(NULL); } + + if (gDebugGL) + { + gPipeline.checkReferences(this); + } + + ll_aligned_free_16(mExtents); +} + +void LLDrawInfo::validate() +{ + mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); } LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage) diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 924f38acb2..09fe4212a8 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -45,7 +45,7 @@ #include "lldrawpool.h" #include "llface.h" #include "llviewercamera.h" - +#include "llvector4a.h" #include <queue> #define SG_STATE_INHERIT_MASK (OCCLUDED) @@ -57,11 +57,15 @@ class LLSpatialGroup; class LLTextureAtlas; class LLTextureAtlasSlot; +S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad); +S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared); + S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad); S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared); +void pushVerts(LLFace* face, U32 mask); // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera -U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center); +U8* get_box_fan_indices(LLCamera* camera, const LLVector4a& center); class LLDrawInfo : public LLRefCount { @@ -69,11 +73,27 @@ protected: ~LLDrawInfo(); public: + + LLDrawInfo(const LLDrawInfo& rhs) + { + *this = rhs; + } + + const LLDrawInfo& operator=(const LLDrawInfo& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, LLViewerTexture* image, LLVertexBuffer* buffer, BOOL fullbright = FALSE, U8 bump = 0, BOOL particle = FALSE, F32 part_size = 0); + void validate(); + + LLVector4a* mExtents; + LLPointer<LLVertexBuffer> mVertexBuffer; LLPointer<LLViewerTexture> mTexture; LLColor4U mGlowColor; @@ -92,7 +112,6 @@ public: LLSpatialGroup* mGroup; LLFace* mFace; //associated face F32 mDistance; - LLVector3 mExtents[2]; U32 mDrawMode; struct CompareTexture @@ -155,11 +174,24 @@ public: }; }; +LL_ALIGN_PREFIX(64) class LLSpatialGroup : public LLOctreeListener<LLDrawable> { friend class LLSpatialPartition; friend class LLOctreeStateCheck; public: + + LLSpatialGroup(const LLSpatialGroup& rhs) + { + *this = rhs; + } + + const LLSpatialGroup& operator=(const LLSpatialGroup& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + static U32 sNodeCount; static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE @@ -268,8 +300,8 @@ public: BOOL isVisible() const; BOOL isRecentlyVisible() const; void setVisible(); - void shift(const LLVector3 &offset); - BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax); + void shift(const LLVector4a &offset); + BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax); void unbound(); BOOL rebound(); void buildOcclusion(); //rebuild mOcclusionVerts @@ -317,6 +349,27 @@ public: void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ; void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ; void clearAtlasList() ; + +public: + + typedef enum + { + BOUNDS = 0, + EXTENTS = 2, + OBJECT_BOUNDS = 4, + OBJECT_EXTENTS = 6, + VIEW_ANGLE = 8, + LAST_VIEW_ANGLE = 9, + V4_COUNT = 10 + } eV4Index; + + LLVector4a* mBounds; // bounding box (center, size) of this node and all its children (tight fit to objects) + LLVector4a* mExtents; // extents (min, max) of this node and all its children + LLVector4a* mObjectExtents; // extents (min, max) of objects in this node + LLVector4a* mObjectBounds; // bounding box (center, size) of objects in this node + LLVector4a* mViewAngle; + LLVector4a* mLastUpdateViewAngle; + private: U32 mCurUpdatingTime ; //do not make the below two to use LLPointer @@ -344,14 +397,9 @@ public: F32 mBuilt; OctreeNode* mOctreeNode; LLSpatialPartition* mSpatialPartition; - LLVector3 mBounds[2]; // bounding box (center, size) of this node and all its children (tight fit to objects) - LLVector3 mExtents[2]; // extents (min, max) of this node and all its children - LLVector3 mObjectExtents[2]; // extents (min, max) of objects in this node - LLVector3 mObjectBounds[2]; // bounding box (center, size) of objects in this node - LLPointer<LLVertexBuffer> mVertexBuffer; - F32* mOcclusionVerts; + LLVector4a* mOcclusionVerts; GLuint mOcclusionQuery[LLViewerCamera::NUM_CAMERAS]; U32 mBufferUsage; @@ -362,13 +410,10 @@ public: F32 mDepth; F32 mLastUpdateDistance; F32 mLastUpdateTime; - - LLVector3 mViewAngle; - LLVector3 mLastUpdateViewAngle; F32 mPixelArea; F32 mRadius; -}; +} LL_ALIGN_POSTFIX(64); class LLGeometryManager { @@ -404,7 +449,7 @@ public: // If the drawable moves, move it here. virtual void move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate = FALSE); - virtual void shift(const LLVector3 &offset); + virtual void shift(const LLVector4a &offset); virtual F32 calcDistance(LLSpatialGroup* group, LLCamera& camera); virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera); @@ -462,7 +507,7 @@ public: virtual void makeActive(); virtual void move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate = FALSE); virtual BOOL updateMove(); - virtual void shiftPos(const LLVector3& vec); + virtual void shiftPos(const LLVector4a& vec); virtual void cleanupReferences(); virtual LLSpatialPartition* asPartition() { return this; } virtual LLSpatialBridge* asBridge() { return this; } @@ -612,6 +657,13 @@ public: class LLVolumeGeometryManager: public LLGeometryManager { public: + typedef enum + { + NONE = 0, + BATCH_SORT, + DISTANCE_SORT + } eSortType; + virtual ~LLVolumeGeometryManager() { } virtual void rebuildGeom(LLSpatialGroup* group); virtual void rebuildMesh(LLSpatialGroup* group); @@ -646,7 +698,7 @@ class LLHUDBridge : public LLVolumeBridge { public: LLHUDBridge(LLDrawable* drawablep); - virtual void shiftPos(const LLVector3& vec); + virtual void shiftPos(const LLVector4a& vec); virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera); }; @@ -663,11 +715,9 @@ class LLHUDPartition : public LLBridgePartition { public: LLHUDPartition(); - virtual void shift(const LLVector3 &offset); + virtual void shift(const LLVector4a &offset); }; -void validate_draw_info(LLDrawInfo& params); - extern const F32 SG_BOX_SIDE; extern const F32 SG_BOX_OFFSET; extern const F32 SG_BOX_RAD; diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 48e4a6ccc7..06431d428f 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -860,8 +860,10 @@ void LLSurfacePatch::updateVisibility() F32 stride_per_distance = DEFAULT_DELTA_ANGLE / mSurfacep->getMetersPerGrid(); U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); - LLVector3 center = mCenterRegion + mSurfacep->getOriginAgent(); - LLVector3 radius = LLVector3(mRadius, mRadius, mRadius); + LLVector4a center; + center.load3( (mCenterRegion + mSurfacep->getOriginAgent()).mV); + LLVector4a radius; + radius.splat(mRadius); // sphere in frustum on global coordinates if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, radius)) diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 0b02861b75..cd9190bbb0 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -292,7 +292,11 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop( { BOOL handled = FALSE; - if (cargo_type == DAD_TEXTURE) + bool is_mesh = false; +#if LL_MESH_ENABLED + is_mesh = cargo_type == DAD_MESH; +#endif + if ((cargo_type == DAD_TEXTURE) || is_mesh) { LLInventoryItem *item = (LLInventoryItem *)cargo_data; @@ -1182,7 +1186,13 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, // returns true, then the cast was valid, and we can perform // the third test without problems. LLInventoryItem* item = (LLInventoryItem*)cargo_data; - if (getEnabled() && (cargo_type == DAD_TEXTURE) && allowDrop(item)) + bool is_mesh = false; +#if LL_MESH_ENABLED + is_mesh = cargo_type == DAD_MESH; +#endif + if (getEnabled() && + ((cargo_type == DAD_TEXTURE) || is_mesh) && + allowDrop(item)) { if (drop) { diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 3f34fc174c..b7dc624beb 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -331,6 +331,9 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() addEntry(DAD_ANIMATION, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_GESTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dActivateGesture, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL)); +#if LL_MESH_ENABLED + addEntry(DAD_MESH, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dMeshObject, &LLToolDragAndDrop::dad3dNULL)); +#endif // TODO: animation on self could play it? edit it? // TODO: gesture on self could play it? edit it? }; @@ -403,7 +406,7 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, { folder_ids.push_back(cargo_id); } - gInventory.collectDescendentsIf ( + gInventory.collectDescendentsIf( cargo_id, cats, items, @@ -474,7 +477,7 @@ void LLToolDragAndDrop::beginMultiDrag( { cat_ids.insert(cat->getUUID()); } - gInventory.collectDescendentsIf ( + gInventory.collectDescendentsIf( cat->getUUID(), cats, items, @@ -1034,6 +1037,33 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj, hit_obj->sendTEUpdate(); } +#if LL_MESH_ENABLED +void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj, + LLInventoryItem* item, + LLToolDragAndDrop::ESource source, + const LLUUID& src_id) +{ + if (!item) + { + llwarns << "no inventory item." << llendl; + return; + } + LLUUID asset_id = item->getAssetUUID(); + BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id); + if(!success) + { + return; + } + + LLSculptParams sculpt_params; + sculpt_params.setSculptTexture(asset_id); + sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH); + hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); + + dialog_refresh_all(); +} +#endif + /* void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item) { @@ -1130,9 +1160,9 @@ void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj, } void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, - BOOL bypass_sim_raycast, - BOOL from_task_inventory, - BOOL remove_from_inventory) + BOOL bypass_sim_raycast, + BOOL from_task_inventory, + BOOL remove_from_inventory) { LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mLastHitPos); if (!regionp) @@ -1368,7 +1398,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL // help make sure that drops that are from an object to an object // don't have to worry about order of evaluation. Think of this // like check for self in assignment. - if (obj->getID() == item->getParentUUID()) + if(obj->getID() == item->getParentUUID()) { return ACCEPT_NO; } @@ -1377,17 +1407,19 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL // gAgent.getGroupID()) // && (obj->mPermModify || obj->mFlagAllowInventoryAdd)); BOOL worn = FALSE; + LLVOAvatarSelf* my_avatar = NULL; switch(item->getType()) { case LLAssetType::AT_OBJECT: - if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getUUID())) + my_avatar = gAgentAvatarp; + if(my_avatar && my_avatar->isWearingAttachment(item->getUUID())) { worn = TRUE; } break; case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: - if (gAgentWearables.isWearingItem(item->getUUID())) + if(gAgentWearables.isWearingItem(item->getUUID())) { worn = TRUE; } @@ -1398,7 +1430,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL const LLPermissions& perm = item->getPermissions(); BOOL modify = (obj->permModify() || obj->flagAllowInventoryAdd()); BOOL transfer = FALSE; - if ((obj->permYouOwner() && (perm.getOwner() == gAgent.getID())) + if((obj->permYouOwner() && (perm.getOwner() == gAgent.getID())) || perm.allowOperationBy(PERM_TRANSFER, gAgent.getID())) { transfer = TRUE; @@ -1406,15 +1438,15 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL BOOL volume = (LL_PCODE_VOLUME == obj->getPCode()); BOOL attached = obj->isAttachment(); BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; - if (attached && !unrestricted) + if(attached && !unrestricted) { return ACCEPT_NO_LOCKED; } - else if (modify && transfer && volume && !worn) + else if(modify && transfer && volume && !worn) { return ACCEPT_YES_MULTI; } - else if (!modify) + else if(!modify) { return ACCEPT_NO_LOCKED; } @@ -1473,14 +1505,17 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ case DAD_ANIMATION: case DAD_GESTURE: case DAD_CALLINGCARD: +#if LL_MESH_ENABLED + case DAD_MESH: +#endif { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; - if (gInventory.getItem(inv_item->getUUID()) + if(gInventory.getItem(inv_item->getUUID()) && LLGiveInventory::isInventoryGiveAcceptable(inv_item)) { // *TODO: get multiple object transfers working *accept = ACCEPT_YES_COPY_SINGLE; - if (drop) + if(drop) { LLIMModel::LLIMSession * session = LLIMModel::instance().findIMSession(session_id); if (NULL == session) @@ -1512,11 +1547,11 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ case DAD_CATEGORY: { LLViewerInventoryCategory* inv_cat = (LLViewerInventoryCategory*)cargo_data; - if (gInventory.getCategory(inv_cat->getUUID())) + if( gInventory.getCategory( inv_cat->getUUID() ) ) { // *TODO: get multiple object transfers working *accept = ACCEPT_YES_COPY_SINGLE; - if (drop) + if(drop) { LLGiveInventory::doGiveInventoryCategory(dest_agent, inv_cat, session_id); } @@ -1557,7 +1592,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( { lldebugs << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << llendl; // must be in the user's inventory - if (mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY) + if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY) { return ACCEPT_NO; } @@ -1569,20 +1604,21 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( // must not be in the trash const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) + if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) ) { return ACCEPT_NO; } // must not be already wearing it - if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID())) + LLVOAvatarSelf* avatar = gAgentAvatarp; + if( !avatar || avatar->isWearingAttachment(item->getUUID()) ) { return ACCEPT_NO; } - if (drop) + if( drop ) { - if (mSource == SOURCE_LIBRARY) + if(mSource == SOURCE_LIBRARY) { LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0); copy_inventory_item( @@ -1616,7 +1652,8 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; - if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID())) + LLVOAvatarSelf* my_avatar = gAgentAvatarp; + if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) { return ACCEPT_NO; } @@ -1641,7 +1678,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( // check if the item can be copied. If not, send that to the sim // which will remove the inventory item. - if (!item->getPermissions().allowCopyBy(gAgent.getID())) + if(!item->getPermissions().allowCopyBy(gAgent.getID())) { accept = ACCEPT_YES_SINGLE; remove_inventory = TRUE; @@ -1649,13 +1686,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( // Check if it's in the trash. const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) + if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) { accept = ACCEPT_YES_SINGLE; remove_inventory = TRUE; } - if (drop) + if(drop) { dropObject(obj, TRUE, FALSE, remove_inventory); } @@ -1677,22 +1714,23 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( LLViewerInventoryCategory* cat; locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; - if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID())) + LLVOAvatarSelf* my_avatar = gAgentAvatarp; + if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) { return ACCEPT_NO; } - if ((mask & MASK_CONTROL)) + if((mask & MASK_CONTROL)) { // *HACK: In order to resolve SL-22177, we need to block drags // from notecards and objects onto other objects. - if (mSource == SOURCE_NOTECARD) + if(mSource == SOURCE_NOTECARD) { return ACCEPT_NO; } EAcceptance rv = willObjectAcceptInventory(obj, item); - if (drop && (ACCEPT_YES_SINGLE <= rv)) + if(drop && (ACCEPT_YES_SINGLE <= rv)) { dropInventory(obj, item, mSource, mSourceID); } @@ -1718,7 +1756,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( // check if the item can be copied. If not, send that to the sim // which will remove the inventory item. - if (!item->getPermissions().allowCopyBy(gAgent.getID())) + if(!item->getPermissions().allowCopyBy(gAgent.getID())) { accept = ACCEPT_YES_SINGLE; remove_inventory = TRUE; @@ -1726,13 +1764,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( // Check if it's in the trash. const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) + if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) { accept = ACCEPT_YES_SINGLE; remove_inventory = TRUE; } - if (drop) + if(drop) { dropObject(obj, FALSE, FALSE, remove_inventory); } @@ -1747,7 +1785,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript( // *HACK: In order to resolve SL-22177, we need to block drags // from notecards and objects onto other objects. - if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) + if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) { return ACCEPT_NO; } @@ -1757,7 +1795,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript( locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; EAcceptance rv = willObjectAcceptInventory(obj, item); - if (drop && (ACCEPT_YES_SINGLE <= rv)) + if(drop && (ACCEPT_YES_SINGLE <= rv)) { // rez in the script active by default, rez in inactive if the // control key is being held down. @@ -1778,14 +1816,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript( return rv; } -EAcceptance LLToolDragAndDrop::dad3dTextureObject( - LLViewerObject* obj, S32 face, MASK mask, BOOL drop) +EAcceptance LLToolDragAndDrop::dad3dApplyToObject( + LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type) { - lldebugs << "LLToolDragAndDrop::dad3dTextureObject()" << llendl; + lldebugs << "LLToolDragAndDrop::dad3dApplyToObject()" << llendl; // *HACK: In order to resolve SL-22177, we need to block drags // from notecards and objects onto other objects. - if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) + if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) { return ACCEPT_NO; } @@ -1795,33 +1833,46 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject( locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; EAcceptance rv = willObjectAcceptInventory(obj, item); - if ((mask & MASK_CONTROL)) + if((mask & MASK_CONTROL)) { - if ((ACCEPT_YES_SINGLE <= rv) && drop) + if((ACCEPT_YES_SINGLE <= rv) && drop) { dropInventory(obj, item, mSource, mSourceID); } return rv; } - if (!obj->permModify()) + if(!obj->permModify()) { return ACCEPT_NO_LOCKED; } //If texture !copyable don't texture or you'll never get it back. - if (!item->getPermissions().allowCopyBy(gAgent.getID())) + if(!item->getPermissions().allowCopyBy(gAgent.getID())) { return ACCEPT_NO; } - if (drop && (ACCEPT_YES_SINGLE <= rv)) + if(drop && (ACCEPT_YES_SINGLE <= rv)) { - if ((mask & MASK_SHIFT)) + if (cargo_type == DAD_TEXTURE) { - dropTextureAllFaces(obj, item, mSource, mSourceID); + if((mask & MASK_SHIFT)) + { + dropTextureAllFaces(obj, item, mSource, mSourceID); + } + else + { + dropTextureOneFace(obj, face, item, mSource, mSourceID); + } } +#if LL_MESH_ENABLED + else if (cargo_type == DAD_MESH) + { + dropMesh(obj, item, mSource, mSourceID); + } +#endif else { - dropTextureOneFace(obj, face, item, mSource, mSourceID); + llwarns << "unsupported asset type" << llendl; } // VEFFECT: SetTexture @@ -1835,14 +1886,33 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject( // enable multi-drop, although last texture will win return ACCEPT_YES_MULTI; } + + +EAcceptance LLToolDragAndDrop::dad3dTextureObject( + LLViewerObject* obj, S32 face, MASK mask, BOOL drop) +{ + return dad3dApplyToObject(obj, face, mask, drop, DAD_TEXTURE); +} + +#if LL_MESH_ENABLED +EAcceptance LLToolDragAndDrop::dad3dMeshObject( + LLViewerObject* obj, S32 face, MASK mask, BOOL drop) +{ + return dad3dApplyToObject(obj, face, mask, drop, DAD_MESH); +} +#endif + + + + /* EAcceptance LLToolDragAndDrop::dad3dTextureSelf( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { lldebugs << "LLToolDragAndDrop::dad3dTextureAvatar()" << llendl; - if (drop) + if(drop) { - if (!(mask & MASK_SHIFT)) + if( !(mask & MASK_SHIFT) ) { dropTextureOneFaceAvatar( (LLVOAvatar*)obj, face, (LLInventoryItem*)mCargoData); } @@ -1860,16 +1930,16 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; - if (mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) + if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) { // it's in the agent inventory const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) + if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) ) { return ACCEPT_NO; } - if (drop) + if( drop ) { // TODO: investigate wearables may not be loaded at this point EXT-8231 @@ -1893,19 +1963,19 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture( locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; - if (mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) + if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) { // it's in the agent inventory const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) + if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) ) { return ACCEPT_NO; } - if (drop) + if( drop ) { LLUUID item_id; - if (mSource == SOURCE_LIBRARY) + if(mSource == SOURCE_LIBRARY) { // create item based on that one, and put it on if that // was a success. @@ -1940,31 +2010,31 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( LLViewerInventoryItem* item; LLViewerInventoryCategory* category; locateInventory(item, category); - if (!category) return ACCEPT_NO; + if(!category) return ACCEPT_NO; if (drop) { // TODO: investigate wearables may not be loaded at this point EXT-8231 } - if (mSource == SOURCE_AGENT) + if(mSource == SOURCE_AGENT) { const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (gInventory.isObjectDescendentOf(category->getUUID(), trash_id)) + if( gInventory.isObjectDescendentOf( category->getUUID(), trash_id ) ) { return ACCEPT_NO; } - if (drop) + if(drop) { - BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE ); + BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE ); LLAppearanceMgr::instance().wearInventoryCategory(category, false, append); } return ACCEPT_YES_MULTI; } - else if (mSource == SOURCE_LIBRARY) + else if(mSource == SOURCE_LIBRARY) { - if (drop) + if(drop) { LLAppearanceMgr::instance().wearInventoryCategory(category, true, false); } @@ -1985,7 +2055,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory( // *HACK: In order to resolve SL-22177, we need to block drags // from notecards and objects onto other objects. - if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) + if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) { return ACCEPT_NO; } @@ -2005,7 +2075,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory( } EAcceptance rv = willObjectAcceptInventory(root_object, item); - if (root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv)) + if(root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv)) { dropInventory(root_object, item, mSource, mSourceID); } @@ -2049,7 +2119,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( LLDroppableItem droppable(!obj->permYouOwner()); LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; - gInventory.collectDescendentsIf (cat->getUUID(), + gInventory.collectDescendentsIf(cat->getUUID(), cats, items, LLInventoryModel::EXCLUDE_TRASH, @@ -2078,7 +2148,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( { const LLViewerInventoryCategory *cat = (*cat_iter); rv = gInventory.isCategoryComplete(cat->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO; - if (rv < ACCEPT_YES_SINGLE) + if(rv < ACCEPT_YES_SINGLE) { lldebugs << "Category " << cat->getUUID() << "is not complete." << llendl; break; @@ -2146,26 +2216,27 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject( lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryObject()" << llendl; // item has to be in agent inventory. - if (mSource != SOURCE_AGENT) return ACCEPT_NO; + if(mSource != SOURCE_AGENT) return ACCEPT_NO; // find the item now. LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; - if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) + if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) { // cannot give away no-transfer objects return ACCEPT_NO; } - if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getUUID())) + LLVOAvatarSelf* avatar = gAgentAvatarp; + if(avatar && avatar->isWearingAttachment( item->getUUID() ) ) { // You can't give objects that are attached to you return ACCEPT_NO; } - if (obj && isAgentAvatarValid()) + if( obj && avatar ) { - if (drop) + if(drop) { LLGiveInventory::doGiveInventoryItem(obj->getID(), item ); } @@ -2182,7 +2253,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventory( { lldebugs << "LLToolDragAndDrop::dad3dGiveInventory()" << llendl; // item has to be in agent inventory. - if (mSource != SOURCE_AGENT) return ACCEPT_NO; + if(mSource != SOURCE_AGENT) return ACCEPT_NO; LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); @@ -2204,12 +2275,12 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryCategory()" << llendl; - if (drop && obj) + if(drop && obj) { LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if (!cat) return ACCEPT_NO; + if(!cat) return ACCEPT_NO; LLGiveInventory::doGiveInventoryCategory(obj->getID(), cat); } // *TODO: deal with all the issues surrounding multi-object @@ -2227,12 +2298,12 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand( locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; - if (!gAgent.allowOperation(PERM_COPY, item->getPermissions()) + if(!gAgent.allowOperation(PERM_COPY, item->getPermissions()) || !item->getPermissions().allowTransferTo(LLUUID::null)) { return ACCEPT_NO_LOCKED; } - if (drop) + if(drop) { dropObject(obj, TRUE, TRUE, FALSE); } @@ -2247,7 +2318,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject( LLViewerInventoryCategory* cat; locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; - if ((mask & MASK_CONTROL)) + if((mask & MASK_CONTROL)) { // *HACK: In order to resolve SL-22177, we need to block drags // from notecards and objects onto other objects. @@ -2255,19 +2326,19 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject( // *HACK: uncomment this when appropriate //EAcceptance rv = willObjectAcceptInventory(obj, item); - //if (drop && (ACCEPT_YES_SINGLE <= rv)) + //if(drop && (ACCEPT_YES_SINGLE <= rv)) //{ // dropInventory(obj, item, mSource, mSourceID); //} //return rv; } - if (!item->getPermissions().allowCopyBy(gAgent.getID(), + if(!item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()) || !item->getPermissions().allowTransferTo(LLUUID::null)) { return ACCEPT_NO_LOCKED; } - if (drop) + if(drop) { dropObject(obj, FALSE, TRUE, FALSE); } @@ -2283,23 +2354,23 @@ EAcceptance LLToolDragAndDrop::dad3dCategoryOnLand( LLInventoryItem* item; LLInventoryCategory* cat; locateInventory(item, cat); - if (!cat) return ACCEPT_NO; + if(!cat) return ACCEPT_NO; EAcceptance rv = ACCEPT_NO; // find all the items in the category LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; LLDropCopyableItems droppable; - gInventory.collectDescendentsIf (cat->getUUID(), + gInventory.collectDescendentsIf(cat->getUUID(), cats, items, LLInventoryModel::EXCLUDE_TRASH, droppable); - if (items.count() > 0) + if(items.count() > 0) { rv = ACCEPT_YES_SINGLE; } - if ((rv >= ACCEPT_YES_COPY_SINGLE) && drop) + if((rv >= ACCEPT_YES_COPY_SINGLE) && drop) { createContainer(items, cat->getName()); return ACCEPT_NO; @@ -2322,19 +2393,19 @@ EAcceptance LLToolDragAndDrop::dad3dAssetOnLand( LLViewerInventoryItem::item_array_t items; LLViewerInventoryItem::item_array_t copyable_items; locateMultipleInventory(items, cats); - if (!items.count()) return ACCEPT_NO; + if(!items.count()) return ACCEPT_NO; EAcceptance rv = ACCEPT_NO; for (S32 i = 0; i < items.count(); i++) { LLInventoryItem* item = items[i]; - if (item->getPermissions().allowCopyBy(gAgent.getID())) + if(item->getPermissions().allowCopyBy(gAgent.getID())) { copyable_items.put(item); rv = ACCEPT_YES_SINGLE; } } - if ((rv >= ACCEPT_YES_COPY_SINGLE) && drop) + if((rv >= ACCEPT_YES_COPY_SINGLE) && drop) { createContainer(copyable_items, NULL); } @@ -2349,20 +2420,20 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory( { item = NULL; cat = NULL; - if (mCargoIDs.empty()) return NULL; - if ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)) + if(mCargoIDs.empty()) return NULL; + if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)) { // The object should be in user inventory. item = (LLViewerInventoryItem*)gInventory.getItem(mCargoIDs[mCurItemIndex]); cat = (LLViewerInventoryCategory*)gInventory.getCategory(mCargoIDs[mCurItemIndex]); } - else if (mSource == SOURCE_WORLD) + else if(mSource == SOURCE_WORLD) { // This object is in some task inventory somewhere. LLViewerObject* obj = gObjectList.findObject(mSourceID); - if (obj) + if(obj) { - if ((mCargoTypes[mCurItemIndex] == DAD_CATEGORY) + if((mCargoTypes[mCurItemIndex] == DAD_CATEGORY) || (mCargoTypes[mCurItemIndex] == DAD_ROOT_CATEGORY)) { cat = (LLViewerInventoryCategory*)obj->getInventoryObject(mCargoIDs[mCurItemIndex]); @@ -2373,16 +2444,16 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory( } } } - else if (mSource == SOURCE_NOTECARD) + else if(mSource == SOURCE_NOTECARD) { LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", mSourceID); - if (preview) + if(preview) { item = (LLViewerInventoryItem*)preview->getDragItem(); } } - if (item) return item; - if (cat) return cat; + if(item) return item; + if(cat) return cat; return NULL; } @@ -2390,8 +2461,8 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory( LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryCategory::cat_array_t& cats, LLViewerInventoryItem::item_array_t& items) { - if (mCargoIDs.count() == 0) return NULL; - if ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)) + if(mCargoIDs.count() == 0) return NULL; + if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)) { // The object should be in user inventory. for (S32 i = 0; i < mCargoIDs.count(); i++) @@ -2408,13 +2479,13 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC } } } - else if (mSource == SOURCE_WORLD) + else if(mSource == SOURCE_WORLD) { // This object is in some task inventory somewhere. LLViewerObject* obj = gObjectList.findObject(mSourceID); - if (obj) + if(obj) { - if ((mCargoType == DAD_CATEGORY) + if((mCargoType == DAD_CATEGORY) || (mCargoType == DAD_ROOT_CATEGORY)) { // The object should be in user inventory. @@ -2440,17 +2511,17 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC } } } - else if (mSource == SOURCE_NOTECARD) + else if(mSource == SOURCE_NOTECARD) { LLPreviewNotecard* card; card = (LLPreviewNotecard*)LLPreview::find(mSourceID); - if (card) + if(card) { items.put((LLInventoryItem*)card->getDragItem()); } } - if (items.count()) return items[0]; - if (cats.count()) return cats[0]; + if(items.count()) return items[0]; + if(cats.count()) return cats[0]; return NULL; } */ diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 36e69c1db3..09da4c2955 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -43,6 +43,7 @@ #include "llpermissions.h" #include "llwindow.h" #include "llviewerinventory.h" +#include "llvolume.h" //for LL_MESH_ENABLED class LLToolDragAndDrop; class LLViewerRegion; @@ -154,6 +155,10 @@ protected: MASK mask, BOOL drop); EAcceptance dad3dTextureObject(LLViewerObject* obj, S32 face, MASK mask, BOOL drop); +#if LL_MESH_ENABLED + EAcceptance dad3dMeshObject(LLViewerObject* obj, S32 face, + MASK mask, BOOL drop); +#endif // EAcceptance dad3dTextureSelf(LLViewerObject* obj, S32 face, // MASK mask, BOOL drop); EAcceptance dad3dWearItem(LLViewerObject* obj, S32 face, @@ -185,6 +190,11 @@ protected: EAcceptance dad3dActivateGesture(LLViewerObject *obj, S32 face, MASK mask, BOOL drop); + // helper called by methods above to handle "application" of an item + // to an object (texture applied to face, mesh applied to shape, etc.) + EAcceptance dad3dApplyToObject(LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type); + + // set the LLToolDragAndDrop's cursor based on the given acceptance ECursorType acceptanceToCursor( EAcceptance acceptance ); @@ -235,6 +245,13 @@ public: LLInventoryItem* item, ESource source, const LLUUID& src_id); +#if LL_MESH_ENABLED + static void dropMesh(LLViewerObject* hit_obj, + LLInventoryItem* item, + ESource source, + const LLUUID& src_id); +#endif + //static void dropTextureOneFaceAvatar(LLVOAvatar* avatar,S32 hit_face, // LLInventoryItem* item) diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp index b382ff6306..370767002a 100644 --- a/indra/newview/llviewerassettype.cpp +++ b/indra/newview/llviewerassettype.cpp @@ -85,6 +85,10 @@ LLViewerAssetDictionary::LLViewerAssetDictionary() addEntry(LLViewerAssetType::AT_LINK, new ViewerAssetEntry(DAD_LINK)); addEntry(LLViewerAssetType::AT_LINK_FOLDER, new ViewerAssetEntry(DAD_LINK)); +#if LL_MESH_ENABLED + addEntry(LLViewerAssetType::AT_MESH, new ViewerAssetEntry(DAD_MESH)); +#endif + addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE)); }; diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index aa82c216d9..cef7c4abbb 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -38,6 +38,7 @@ // Viewer includes #include "llagent.h" #include "llagentcamera.h" +#include "llmatrix4a.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" @@ -787,21 +788,29 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) LLMatrix4 render_mat(vo_volume->getRenderRotation(), LLVector4(vo_volume->getRenderPosition())); + LLMatrix4a render_mata; + render_mata.loadu(render_mat); + LLMatrix4a mata; + mata.loadu(mat); + num_faces = volume->getNumVolumeFaces(); for (i = 0; i < num_faces; i++) { const LLVolumeFace& face = volume->getVolumeFace(i); - for (U32 v = 0; v < face.mVertices.size(); v++) + for (U32 v = 0; v < face.mNumVertices; v++) { - LLVector4 vec = LLVector4(face.mVertices[v].mPosition) * mat; + const LLVector4a& src_vec = face.mPositions[v]; + LLVector4a vec; + mata.affineTransform(src_vec, vec); if (drawablep->isActive()) { - vec = vec * render_mat; + LLVector4a t = vec; + render_mata.affineTransform(t, vec); } - BOOL in_frustum = pointInFrustum(LLVector3(vec)) > 0; + BOOL in_frustum = pointInFrustum(LLVector3(vec.getF32())) > 0; if (( !in_frustum && all_verts) || (in_frustum && !all_verts)) diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index a02946d3f4..8eeffb84b0 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -497,6 +497,8 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderTerrainDetail")->getSignal()->connect(boost::bind(&handleTerrainDetailChanged, _2)); gSavedSettings.getControl("RenderUseTriStrips")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderBakeSunlight")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderNoAlpha")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 702bc59b9d..b277efc85a 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -861,10 +861,26 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { gPipeline.mDeferredScreen.flush(); + if(LLRenderTarget::sUseFBO) + { + LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), + gPipeline.mDeferredScreen.getHeight(), 0, 0, + gPipeline.mDeferredScreen.getWidth(), + gPipeline.mDeferredScreen.getHeight(), + GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } } else { gPipeline.mScreen.flush(); + if(LLRenderTarget::sUseFBO) + { + LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(), + gPipeline.mScreen.getHeight(), 0, 0, + gPipeline.mScreen.getWidth(), + gPipeline.mScreen.getHeight(), + GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } } } @@ -882,9 +898,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) render_ui(); } - gPipeline.rebuildGroups(); - + LLSpatialGroup::sNoDelete = FALSE; + gPipeline.clearReferences(); + + gPipeline.rebuildGroups(); } LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats"); @@ -982,6 +1000,7 @@ void render_hud_attachments() gPipeline.renderGeom(hud_cam); LLSpatialGroup::sNoDelete = FALSE; + gPipeline.clearReferences(); render_hud_elements(); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index efe59744bc..c953fb23e3 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -71,6 +71,7 @@ #include "llimfloater.h" #include "llfloaterinspect.h" #include "llfloaterinventory.h" +#include "llfloaterimportcollada.h" #include "llfloaterjoystick.h" #include "llfloaterlagmeter.h" #include "llfloaterland.h" @@ -127,6 +128,8 @@ #include "llpreviewtexture.h" #include "llsyswellwindow.h" #include "llscriptfloater.h" +#include "llfloatermodelpreview.h" + // *NOTE: Please add files in alphabetical order to keep merges easy. @@ -174,6 +177,9 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>); LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>); +#if LL_MESH_ENABLED + LLFloaterReg::add("import_collada", "floater_import_collada.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImportCollada>); +#endif LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloaterContainer>); LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMWellWindow>); LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>); @@ -254,7 +260,10 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("upload_anim", "floater_animation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload"); LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload"); LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload"); - +#if LL_MESH_ENABLED + LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload"); +#endif + LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>); LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>); diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 6be7c442ef..9e35b5cc51 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -61,6 +61,7 @@ #include "v4math.h" #include "m3math.h" #include "m4math.h" +#include "llmatrix4a.h" #if !LL_DARWIN && !LL_LINUX && !LL_SOLARIS extern PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB; @@ -382,6 +383,7 @@ const S32 NUM_AXES = 3; // pivot parent 0-n -- child = n+1 static LLMatrix4 gJointMatUnaligned[32]; +static LLMatrix4a gJointMatAligned[32]; static LLMatrix3 gJointRotUnaligned[32]; static LLVector4 gJointPivot[32]; @@ -467,6 +469,14 @@ void LLViewerJointMesh::uploadJointMatrices() glUniform4fvARB(gAvatarMatrixParam, 45, mat); stop_glerror(); } + else + { + //load gJointMatUnaligned into gJointMatAligned + for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.count(); ++joint_num) + { + gJointMatAligned[joint_num].loadu(gJointMatUnaligned[joint_num]); + } + } } //-------------------------------------------------------------------- @@ -516,6 +526,8 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) U32 triangle_count = 0; + S32 diffuse_channel = LLDrawPoolAvatar::sDiffuseChannel; + stop_glerror(); //---------------------------------------------------------------- @@ -541,7 +553,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) LLTexUnit::eTextureAddressMode old_mode = LLTexUnit::TAM_WRAP; if (mTestImageName) { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName); + gGL.getTexUnit(diffuse_channel)->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName); if (mIsTransparent) { @@ -550,24 +562,18 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) else { glColor4f(0.7f, 0.6f, 0.3f, 1.f); - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); + gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); } } else if( !is_dummy && mLayerSet ) { if( mLayerSet->hasComposite() ) { - gGL.getTexUnit(0)->bind(mLayerSet->getComposite()); + gGL.getTexUnit(diffuse_channel)->bind(mLayerSet->getComposite()); } else { - // This warning will always trigger if you've hacked the avatar to show as incomplete. - // Ignore the warning if that's the case. - if (!gSavedSettings.getBOOL("RenderUnloadedAvatar")) - { - //llwarns << "Layerset without composite" << llendl; - } - gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); + gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); } } else @@ -577,25 +583,25 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) { old_mode = mTexture->getAddressMode(); } - gGL.getTexUnit(0)->bind(mTexture.get()); - gGL.getTexUnit(0)->bind(mTexture); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + gGL.getTexUnit(diffuse_channel)->bind(mTexture.get()); + gGL.getTexUnit(diffuse_channel)->bind(mTexture); + gGL.getTexUnit(diffuse_channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); } else { - gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); + gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); } if (gRenderForSelect) { if (isTransparent()) { - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_CONST_ALPHA); + gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); + gGL.getTexUnit(diffuse_channel)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_CONST_ALPHA); } else { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); } } @@ -632,13 +638,13 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) if (mTestImageName) { - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + gGL.getTexUnit(diffuse_channel)->setTextureBlendType(LLTexUnit::TB_MULT); } if (mTexture.notNull() && !is_dummy) { - gGL.getTexUnit(0)->bind(mTexture); - gGL.getTexUnit(0)->setTextureAddressMode(old_mode); + gGL.getTexUnit(diffuse_channel)->bind(mTexture); + gGL.getTexUnit(diffuse_channel)->setTextureAddressMode(old_mode); } return triangle_count; @@ -649,6 +655,9 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) //----------------------------------------------------------------------------- void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area) { + //bump num_vertices to next multiple of 4 + num_vertices = (num_vertices + 0x3) & ~0x3; + // Do a pre-alloc pass to determine sizes of data. if (mMesh && mValid) { @@ -671,6 +680,8 @@ static LLFastTimer::DeclareTimer FTM_AVATAR_FACE("Avatar Face"); void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update) { + //IF THIS FUNCTION BREAKS, SEE LLPOLYMESH CONSTRUCTOR AND CHECK ALIGNMENT OF INPUT ARRAYS + mFace = face; if (mFace->mVertexBuffer.isNull()) @@ -678,6 +689,16 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w return; } + LLDrawPool *poolp = mFace->getPool(); + BOOL hardware_skinning = (poolp && poolp->getVertexShaderLevel() > 0) ? TRUE : FALSE; + + if (!hardware_skinning && terse_update) + { //no need to do terse updates if we're doing software vertex skinning + // since mMesh is being copied into mVertexBuffer every frame + return; + } + + LLFastTimer t(FTM_AVATAR_FACE); LLStrider<LLVector3> verticesp; @@ -690,111 +711,59 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w // Copy data into the faces from the polymesh data. if (mMesh && mValid) { - if (mMesh->getNumVertices()) + const U32 num_verts = mMesh->getNumVertices(); + + if (num_verts) { - stop_glerror(); face->getGeometryAvatar(verticesp, normalsp, tex_coordsp, vertex_weightsp, clothing_weightsp); - stop_glerror(); face->mVertexBuffer->getIndexStrider(indicesp); - stop_glerror(); verticesp += mMesh->mFaceVertexOffset; - tex_coordsp += mMesh->mFaceVertexOffset; normalsp += mMesh->mFaceVertexOffset; - vertex_weightsp += mMesh->mFaceVertexOffset; - clothing_weightsp += mMesh->mFaceVertexOffset; - - const U32* __restrict coords = (U32*) mMesh->getCoords(); - const U32* __restrict tex_coords = (U32*) mMesh->getTexCoords(); - const U32* __restrict normals = (U32*) mMesh->getNormals(); - const U32* __restrict weights = (U32*) mMesh->getWeights(); - const U32* __restrict cloth_weights = (U32*) mMesh->getClothingWeights(); - - const U32 num_verts = mMesh->getNumVertices(); - - U32 i = 0; - - const U32 skip = verticesp.getSkip()/sizeof(U32); + + F32* v = (F32*) verticesp.get(); + F32* n = (F32*) normalsp.get(); + + U32 words = num_verts*4; - U32* __restrict v = (U32*) verticesp.get(); - U32* __restrict n = (U32*) normalsp.get(); + LLVector4a::memcpyNonAliased16(v, (F32*) mMesh->getCoords(), words); + LLVector4a::memcpyNonAliased16(n, (F32*) mMesh->getNormals(), words); + - if (terse_update) + if (!terse_update) { - for (S32 i = num_verts; i > 0; --i) - { - //morph target application only, only update positions and normals - v[0] = coords[0]; - v[1] = coords[1]; - v[2] = coords[2]; - coords += 3; - v += skip; - } + vertex_weightsp += mMesh->mFaceVertexOffset; + clothing_weightsp += mMesh->mFaceVertexOffset; + tex_coordsp += mMesh->mFaceVertexOffset; + + F32* tc = (F32*) tex_coordsp.get(); + F32* vw = (F32*) vertex_weightsp.get(); + F32* cw = (F32*) clothing_weightsp.get(); - for (S32 i = num_verts; i > 0; --i) - { - n[0] = normals[0]; - n[1] = normals[1]; - n[2] = normals[2]; - normals += 3; - n += skip; - } + LLVector4a::memcpyNonAliased16(tc, (F32*) mMesh->getTexCoords(), num_verts*2); + LLVector4a::memcpyNonAliased16(vw, (F32*) mMesh->getWeights(), num_verts); + LLVector4a::memcpyNonAliased16(cw, (F32*) mMesh->getClothingWeights(), num_verts*4); } - else - { - U32* __restrict tc = (U32*) tex_coordsp.get(); - U32* __restrict vw = (U32*) vertex_weightsp.get(); - U32* __restrict cw = (U32*) clothing_weightsp.get(); - - do - { - v[0] = *(coords++); - v[1] = *(coords++); - v[2] = *(coords++); - v += skip; - - tc[0] = *(tex_coords++); - tc[1] = *(tex_coords++); - tc += skip; - - n[0] = *(normals++); - n[1] = *(normals++); - n[2] = *(normals++); - n += skip; - - vw[0] = *(weights++); - vw += skip; - - cw[0] = *(cloth_weights++); - cw[1] = *(cloth_weights++); - cw[2] = *(cloth_weights++); - cw[3] = *(cloth_weights++); - cw += skip; - } - while (++i < num_verts); + const U32 idx_count = mMesh->getNumFaces()*3; - const U32 idx_count = mMesh->getNumFaces()*3; + indicesp += mMesh->mFaceIndexOffset; - indicesp += mMesh->mFaceIndexOffset; + U16* __restrict idx = indicesp.get(); + S32* __restrict src_idx = (S32*) mMesh->getFaces(); - U16* __restrict idx = indicesp.get(); - S32* __restrict src_idx = (S32*) mMesh->getFaces(); + const S32 offset = (S32) mMesh->mFaceVertexOffset; - i = 0; - - const S32 offset = (S32) mMesh->mFaceVertexOffset; - - do - { - *(idx++) = *(src_idx++)+offset; - } - while (++i < idx_count); + for (S32 i = 0; i < idx_count; ++i) + { + *(idx++) = *(src_idx++)+offset; } } } } + + //----------------------------------------------------------------------------- // updateLOD() //----------------------------------------------------------------------------- @@ -812,89 +781,49 @@ void LLViewerJointMesh::updateGeometryOriginal(LLFace *mFace, LLPolyMesh *mMesh) LLStrider<LLVector3> o_normals; //get vertex and normal striders - LLVertexBuffer *buffer = mFace->mVertexBuffer; + LLVertexBuffer* buffer = mFace->mVertexBuffer; buffer->getVertexStrider(o_vertices, 0); buffer->getNormalStrider(o_normals, 0); - F32 last_weight = F32_MAX; - LLMatrix4 gBlendMat; - LLMatrix3 gBlendRotMat; + F32* __restrict vert = o_vertices[0].mV; + F32* __restrict norm = o_normals[0].mV; + + const F32* __restrict weights = mMesh->getWeights(); + const LLVector4a* __restrict coords = (LLVector4a*) mMesh->getCoords(); + const LLVector4a* __restrict normals = (LLVector4a*) mMesh->getNormals(); + + U32 offset = mMesh->mFaceVertexOffset*4; + vert += offset; + norm += offset; - const F32* weights = mMesh->getWeights(); - const LLVector3* coords = mMesh->getCoords(); - const LLVector3* normals = mMesh->getNormals(); for (U32 index = 0; index < mMesh->getNumVertices(); index++) { - U32 bidx = index + mMesh->mFaceVertexOffset; - - // blend by first matrix - F32 w = weights[index]; - - // Maybe we don't have to change gBlendMat. - // Profiles of a single-avatar scene on a Mac show this to be a very - // common case. JC - if (w == last_weight) - { - o_vertices[bidx] = coords[index] * gBlendMat; - o_normals[bidx] = normals[index] * gBlendRotMat; - continue; - } - - last_weight = w; + // equivalent to joint = floorf(weights[index]); + S32 joint = _mm_cvtt_ss2si(_mm_load_ss(weights+index)); + F32 w = weights[index] - joint; - S32 joint = llfloor(w); - w -= joint; - - // No lerp required in this case. - if (w == 1.0f) + LLMatrix4a gBlendMat; + + if (w != 0.f) { - gBlendMat = gJointMatUnaligned[joint+1]; - o_vertices[bidx] = coords[index] * gBlendMat; - gBlendRotMat = gJointRotUnaligned[joint+1]; - o_normals[bidx] = normals[index] * gBlendRotMat; - continue; + // blend between matrices and apply + gBlendMat.setLerp(gJointMatAligned[joint+0], + gJointMatAligned[joint+1], w); + + LLVector4a res; + gBlendMat.affineTransform(coords[index], res); + res.store4a(vert+index*4); + gBlendMat.rotate(normals[index], res); + res.store4a(norm+index*4); + } + else + { // No lerp required in this case. + LLVector4a res; + gJointMatAligned[joint].affineTransform(coords[index], res); + res.store4a(vert+index*4); + gJointMatAligned[joint].rotate(normals[index], res); + res.store4a(norm+index*4); } - - // Try to keep all the accesses to the matrix data as close - // together as possible. This function is a hot spot on the - // Mac. JC - LLMatrix4 &m0 = gJointMatUnaligned[joint+1]; - LLMatrix4 &m1 = gJointMatUnaligned[joint+0]; - - gBlendMat.mMatrix[VX][VX] = lerp(m1.mMatrix[VX][VX], m0.mMatrix[VX][VX], w); - gBlendMat.mMatrix[VX][VY] = lerp(m1.mMatrix[VX][VY], m0.mMatrix[VX][VY], w); - gBlendMat.mMatrix[VX][VZ] = lerp(m1.mMatrix[VX][VZ], m0.mMatrix[VX][VZ], w); - - gBlendMat.mMatrix[VY][VX] = lerp(m1.mMatrix[VY][VX], m0.mMatrix[VY][VX], w); - gBlendMat.mMatrix[VY][VY] = lerp(m1.mMatrix[VY][VY], m0.mMatrix[VY][VY], w); - gBlendMat.mMatrix[VY][VZ] = lerp(m1.mMatrix[VY][VZ], m0.mMatrix[VY][VZ], w); - - gBlendMat.mMatrix[VZ][VX] = lerp(m1.mMatrix[VZ][VX], m0.mMatrix[VZ][VX], w); - gBlendMat.mMatrix[VZ][VY] = lerp(m1.mMatrix[VZ][VY], m0.mMatrix[VZ][VY], w); - gBlendMat.mMatrix[VZ][VZ] = lerp(m1.mMatrix[VZ][VZ], m0.mMatrix[VZ][VZ], w); - - gBlendMat.mMatrix[VW][VX] = lerp(m1.mMatrix[VW][VX], m0.mMatrix[VW][VX], w); - gBlendMat.mMatrix[VW][VY] = lerp(m1.mMatrix[VW][VY], m0.mMatrix[VW][VY], w); - gBlendMat.mMatrix[VW][VZ] = lerp(m1.mMatrix[VW][VZ], m0.mMatrix[VW][VZ], w); - - o_vertices[bidx] = coords[index] * gBlendMat; - - LLMatrix3 &n0 = gJointRotUnaligned[joint+1]; - LLMatrix3 &n1 = gJointRotUnaligned[joint+0]; - - gBlendRotMat.mMatrix[VX][VX] = lerp(n1.mMatrix[VX][VX], n0.mMatrix[VX][VX], w); - gBlendRotMat.mMatrix[VX][VY] = lerp(n1.mMatrix[VX][VY], n0.mMatrix[VX][VY], w); - gBlendRotMat.mMatrix[VX][VZ] = lerp(n1.mMatrix[VX][VZ], n0.mMatrix[VX][VZ], w); - - gBlendRotMat.mMatrix[VY][VX] = lerp(n1.mMatrix[VY][VX], n0.mMatrix[VY][VX], w); - gBlendRotMat.mMatrix[VY][VY] = lerp(n1.mMatrix[VY][VY], n0.mMatrix[VY][VY], w); - gBlendRotMat.mMatrix[VY][VZ] = lerp(n1.mMatrix[VY][VZ], n0.mMatrix[VY][VZ], w); - - gBlendRotMat.mMatrix[VZ][VX] = lerp(n1.mMatrix[VZ][VX], n0.mMatrix[VZ][VX], w); - gBlendRotMat.mMatrix[VZ][VY] = lerp(n1.mMatrix[VZ][VY], n0.mMatrix[VZ][VY], w); - gBlendRotMat.mMatrix[VZ][VZ] = lerp(n1.mMatrix[VZ][VZ], n0.mMatrix[VZ][VZ], w); - - o_normals[bidx] = normals[index] * gBlendRotMat; } buffer->setBuffer(0); diff --git a/indra/newview/llviewerjointmesh_sse.cpp b/indra/newview/llviewerjointmesh_sse.cpp index e586b910cd..4fb5fafad1 100644 --- a/indra/newview/llviewerjointmesh_sse.cpp +++ b/indra/newview/llviewerjointmesh_sse.cpp @@ -94,8 +94,8 @@ void LLViewerJointMesh::updateGeometrySSE(LLFace *face, LLPolyMesh *mesh) buffer->getNormalStrider(o_normals, mesh->mFaceVertexOffset); const F32* weights = mesh->getWeights(); - const LLVector3* coords = mesh->getCoords(); - const LLVector3* normals = mesh->getNormals(); + const LLVector3* coords = (const LLVector3*)mesh->getCoords(); + const LLVector3* normals = (const LLVector3*)mesh->getNormals(); for (U32 index = 0, index_end = mesh->getNumVertices(); index < index_end; ++index) { if( weight != weights[index]) diff --git a/indra/newview/llviewerjointmesh_sse2.cpp b/indra/newview/llviewerjointmesh_sse2.cpp index 550044c321..58cd75871d 100644 --- a/indra/newview/llviewerjointmesh_sse2.cpp +++ b/indra/newview/llviewerjointmesh_sse2.cpp @@ -101,8 +101,8 @@ void LLViewerJointMesh::updateGeometrySSE2(LLFace *face, LLPolyMesh *mesh) buffer->getNormalStrider(o_normals, mesh->mFaceVertexOffset); const F32* weights = mesh->getWeights(); - const LLVector3* coords = mesh->getCoords(); - const LLVector3* normals = mesh->getNormals(); + const LLVector3* coords = (const LLVector3*)mesh->getCoords(); + const LLVector3* normals = (const LLVector3*)mesh->getNormals(); for (U32 index = 0, index_end = mesh->getNumVertices(); index < index_end; ++index) { if( weight != weights[index]) diff --git a/indra/newview/llviewerjointmesh_vec.cpp b/indra/newview/llviewerjointmesh_vec.cpp index 8fb9d1cf68..a1225c9d1c 100644 --- a/indra/newview/llviewerjointmesh_vec.cpp +++ b/indra/newview/llviewerjointmesh_vec.cpp @@ -52,6 +52,7 @@ // static void LLViewerJointMesh::updateGeometryVectorized(LLFace *face, LLPolyMesh *mesh) { +#if 0 static LLV4Matrix4 sJointMat[32]; LLDynamicArray<LLJointRenderData*>& joint_data = mesh->getReferenceMesh()->mJointRenderData; S32 j, joint_num, joint_end = joint_data.count(); @@ -98,4 +99,5 @@ void LLViewerJointMesh::updateGeometryVectorized(LLFace *face, LLPolyMesh *mesh) } buffer->setBuffer(0); +#endif } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 1dc2a9eef7..c4a66499e6 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -168,7 +168,6 @@ LLMenuItemCallGL* gBusyMenu = NULL; // Local prototypes // File Menu -const char* upload_pick(void* data); void handle_compress_image(void*); @@ -455,7 +454,7 @@ void init_menus() gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost); gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost); gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost); - + gAFKMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Away", TRUE); gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE); gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); @@ -858,6 +857,10 @@ U32 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_BBOXES; } + else if ("normals" == info_display) + { + return LLPipeline::RENDER_DEBUG_NORMALS; + } else if ("points" == info_display) { return LLPipeline::RENDER_DEBUG_POINTS; @@ -870,6 +873,10 @@ U32 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; } + else if ("physics shapes" == info_display) + { + return LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES; + } else if ("occlusion" == info_display) { return LLPipeline::RENDER_DEBUG_OCCLUSION; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index f741e1bc10..20de01b78a 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -40,6 +40,8 @@ #include "llfilepicker.h" #include "llfloaterreg.h" #include "llbuycurrencyhtml.h" +#include "llfloaterimportcollada.h" +#include "llfloatermodelpreview.h" #include "llfloatersnapshot.h" #include "llimage.h" #include "llimagebmp.h" @@ -64,7 +66,8 @@ #include "llappviewer.h" #include "lluploaddialog.h" #include "lltrans.h" - +#include "llfloaterbuycurrency.h" +#include "llfloaterimportcollada.h" // linden libraries #include "llassetuploadresponders.h" @@ -72,6 +75,7 @@ #include "llhttpclient.h" #include "llnotificationsutil.h" #include "llsdserialize.h" +#include "llsdutil.h" #include "llstring.h" #include "lltransactiontypes.h" #include "lluuid.h" @@ -90,6 +94,89 @@ class LLFileEnableUpload : public view_listener_t } }; +class LLFileEnableUploadModel : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + return true; + } +}; + +class LLMeshEnabled : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + return gSavedSettings.getBOOL("MeshEnabled"); + } +}; + +LLMutex* LLFilePickerThread::sMutex = NULL; +std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ; + +void LLFilePickerThread::getFile() +{ +#if LL_WINDOWS + start(); +#else + run(); +#endif +} + +//virtual +void LLFilePickerThread::run() +{ + LLFilePicker picker; +#if LL_WINDOWS + if (picker.getOpenFile(mFilter, false)) + { + mFile = picker.getFirstFile(); + } +#else + if (picker.getOpenFile(mFilter, true)) + { + mFile = picker.getFirstFile(); + } +#endif + + { + LLMutexLock lock(sMutex); + sDeadQ.push(this); + } + +} + +//static +void LLFilePickerThread::initClass() +{ + sMutex = new LLMutex(NULL); +} + +//static +void LLFilePickerThread::cleanupClass() +{ + clearDead(); + + delete sMutex; + sMutex = NULL; +} + +//static +void LLFilePickerThread::clearDead() +{ + if (!sDeadQ.empty()) + { + LLMutexLock lock(sMutex); + while (!sDeadQ.empty()) + { + LLFilePickerThread* thread = sDeadQ.front(); + thread->notify(thread->mFile); + delete thread; + sDeadQ.pop(); + } + } +} + + //============================================================================ #if LL_WINDOWS @@ -103,6 +190,7 @@ static std::string XML_EXTENSIONS = "xml"; static std::string SLOBJECT_EXTENSIONS = "slobject"; #endif static std::string ALL_FILE_EXTENSIONS = "*.*"; +static std::string MODEL_EXTENSIONS = "dae"; std::string build_extensions_string(LLFilePicker::ELoadFilter filter) { @@ -117,6 +205,8 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter) return ANIM_EXTENSIONS; case LLFilePicker::FFLOAD_SLOBJECT: return SLOBJECT_EXTENSIONS; + case LLFilePicker::FFLOAD_MODEL: + return MODEL_EXTENSIONS; #ifdef _CORY_TESTING case LLFilePicker::FFLOAD_GEOMETRY: return GEOMETRY_EXTENSIONS; @@ -260,6 +350,35 @@ class LLFileUploadImage : public view_listener_t } }; +#if LL_MESH_ENABLED +class LLFileUploadScene : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_COLLADA); + if (!filename.empty()) + { + LLImportCollada::getInstance()->importFile(filename); + } + return TRUE; + } +}; + +class LLFileUploadModel : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model"); + if (fmp) + { + fmp->loadModel(3); + } + + return TRUE; + } +}; +#endif + class LLFileUploadSound : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -321,10 +440,21 @@ class LLFileUploadBulk : public view_listener_t LLAssetStorage::LLStoreAssetCallback callback = NULL; S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); void *userdata = NULL; - upload_new_resource(filename, asset_name, asset_name, 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), - display_name, - callback, expected_upload_cost, userdata); + + upload_new_resource( + filename, + asset_name, + asset_name, + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms(), + LLFloaterPerms::getGroupPerms(), + LLFloaterPerms::getEveryonePerms(), + display_name, + callback, + expected_upload_cost, + userdata); // *NOTE: Ew, we don't iterate over the file list here, // we handle the next files in upload_done_callback() @@ -479,17 +609,20 @@ void handle_compress_image(void*) } } -void upload_new_resource(const std::string& src_filename, std::string name, - std::string desc, S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) +LLUUID upload_new_resource( + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata) { // Generate the temporary UUID. std::string filename = gDirUtilp->getTempFilename(); @@ -514,7 +647,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, short_name.c_str()); args["FILE"] = short_name; upload_error(error_message, "NofileExtension", filename, args); - return; + return LLUUID(); } else if( exten == "bmp") { @@ -528,7 +661,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "tga") @@ -543,7 +676,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "jpg" || exten == "jpeg") @@ -558,7 +691,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if( exten == "png") @@ -573,7 +706,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, args["FILE"] = src_filename; args["ERROR"] = LLImage::getLastError(); upload_error(error_message, "ProblemWithFile", filename, args); - return; + return LLUUID(); } } else if(exten == "wav") @@ -601,7 +734,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); break; } - return; + return LLUUID(); } } else if(exten == "tmp") @@ -641,7 +774,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, error_message = llformat("corrupt resource file: %s", src_filename.c_str()); args["FILE"] = src_filename; upload_error(error_message, "CorruptResourceFile", filename, args); - return; + return LLUUID(); } if (2 == tokens_read) @@ -669,7 +802,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); args["FILE"] = src_filename; upload_error(error_message, "UnknownResourceFileVersion", filename, args); - return; + return LLUUID(); } } else @@ -711,7 +844,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, error_message = llformat( "Unable to create output file: %s", filename.c_str()); args["FILE"] = filename; upload_error(error_message, "UnableToCreateOutputFile", filename, args); - return; + return LLUUID(); } fclose(in); @@ -725,7 +858,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, { error_message = llformat("We do not currently support bulk upload of animation files\n"); upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args); - return; + return LLUUID(); } else { @@ -771,9 +904,21 @@ void upload_new_resource(const std::string& src_filename, std::string name, { t_disp_name = src_filename; } - upload_new_resource(tid, asset_type, name, desc, compression_info, // tid - destination_folder_type, inv_type, next_owner_perms, group_perms, everyone_perms, - display_name, callback, expected_upload_cost, userdata); + upload_new_resource( + tid, + asset_type, + name, + desc, + compression_info, // tid + destination_folder_type, + inv_type, + next_owner_perms, + group_perms, + everyone_perms, + display_name, + callback, + expected_upload_cost, + userdata); } else { @@ -787,9 +932,15 @@ void upload_new_resource(const std::string& src_filename, std::string name, } LLFilePicker::instance().reset(); } + + return uuid; } -void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed) +void upload_done_callback( + const LLUUID& uuid, + void* user_data, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (fixed) { LLResourceData* data = (LLResourceData*)user_data; S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; @@ -894,35 +1045,102 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt std::string display_name = LLStringUtil::null; LLAssetStorage::LLStoreAssetCallback callback = NULL; void *userdata = NULL; - upload_new_resource(next_file, asset_name, asset_name, // file - 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - PERM_NONE, PERM_NONE, PERM_NONE, - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); + upload_new_resource( + next_file, + asset_name, + asset_name, // file + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_NONE, + PERM_NONE, + PERM_NONE, + PERM_NONE, + display_name, + callback, + expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost + userdata); } } -void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type, - std::string name, - std::string desc, S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) +static LLAssetID upload_new_resource_prep( + const LLTransactionID& tid, + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description) +{ + LLAssetID uuid = generate_asset_id_for_new_upload(tid); + + increase_new_upload_stats(asset_type); + + assign_defaults_and_show_upload_message( + asset_type, + inventory_type, + name, + display_name, + description); + + return uuid; +} + +LLSD generate_new_resource_upload_capability_body( + LLAssetType::EType asset_type, + const std::string& name, + const std::string& desc, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms) +{ + LLSD body; + + body["folder_id"] = gInventory.findCategoryUUIDForType( + (destination_folder_type == LLFolderType::FT_NONE) ? + (LLFolderType::EType) asset_type : + destination_folder_type); + + body["asset_type"] = LLAssetType::lookup(asset_type); + body["inventory_type"] = LLInventoryType::lookup(inv_type); + body["name"] = name; + body["description"] = desc; + body["next_owner_mask"] = LLSD::Integer(next_owner_perms); + body["group_mask"] = LLSD::Integer(group_perms); + body["everyone_mask"] = LLSD::Integer(everyone_perms); + + return body; +} + +void upload_new_resource( + const LLTransactionID &tid, + LLAssetType::EType asset_type, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata) { if(gDisconnected) { return ; } - - LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); + + LLAssetID uuid = + upload_new_resource_prep( + tid, + asset_type, + inv_type, + name, + display_name, + desc); if( LLAssetType::AT_SOUND == asset_type ) { @@ -967,28 +1185,38 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl; lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl; lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl; - std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory"); - if (!url.empty()) + +#if LL_MESH_ENABLED + std::string url = gAgent.getRegion()->getCapability( + "NewFileAgentInventory"); + + if ( !url.empty() ) { llinfos << "New Agent Inventory via capability" << llendl; + LLSD body; - body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type); - body["asset_type"] = LLAssetType::lookup(asset_type); - body["inventory_type"] = LLInventoryType::lookup(inv_type); - body["name"] = name; - body["description"] = desc; - body["next_owner_mask"] = LLSD::Integer(next_owner_perms); - body["group_mask"] = LLSD::Integer(group_perms); - body["everyone_mask"] = LLSD::Integer(everyone_perms); - body["expected_upload_cost"] = LLSD::Integer(expected_upload_cost); - - //std::ostringstream llsdxml; - //LLSDSerialize::toPrettyXML(body, llsdxml); - //llinfos << "posting body to capability: " << llsdxml.str() << llendl; + body = generate_new_resource_upload_capability_body( + asset_type, + name, + desc, + destination_folder_type, + inv_type, + next_owner_perms, + group_perms, + everyone_perms); + + LLHTTPClient::post( + url, + body, + new LLNewAgentInventoryResponder( + body, + uuid, + asset_type)); LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type)); } else +#endif { llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl; // check for adequate funds @@ -1000,10 +1228,10 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty S32 balance = gStatusBar->getBalance(); if (balance < expected_upload_cost) { + // insufficient funds, bail on this upload LLStringUtil::format_map_t args; args["NAME"] = name; args["AMOUNT"] = llformat("%d", expected_upload_cost); - // insufficient funds, bail on this upload LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); return; } @@ -1027,18 +1255,162 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty { asset_callback = callback; } - gAssetStorage->storeAssetData(data->mAssetInfo.mTransactionID, data->mAssetInfo.mType, - asset_callback, - (void*)data, - FALSE); + gAssetStorage->storeAssetData( + data->mAssetInfo.mTransactionID, + data->mAssetInfo.mType, + asset_callback, + (void*)data, + FALSE); + } +} + +#if LL_MESH_ENABLED +BOOL upload_new_variable_price_resource( + const LLTransactionID &tid, + LLAssetType::EType asset_type, + std::string name, + std::string desc, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + const LLSD& asset_resources) +{ + LLAssetID uuid = + upload_new_resource_prep( + tid, + asset_type, + inv_type, + name, + display_name, + desc); + + llinfos << "*** Uploading: " << llendl; + llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl; + llinfos << "UUID: " << uuid << llendl; + llinfos << "Name: " << name << llendl; + llinfos << "Desc: " << desc << llendl; + lldebugs << "Folder: " + << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? (LLFolderType::EType)asset_type : destination_folder_type) << llendl; + lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl; + + std::string url = gAgent.getRegion()->getCapability( + "NewFileAgentInventoryVariablePrice"); + + if ( !url.empty() ) + { + lldebugs + << "New Agent Inventory variable price upload" << llendl; + + // Each of the two capabilities has similar data, so + // let's reuse that code + + LLSD body; + + body = generate_new_resource_upload_capability_body( + asset_type, + name, + desc, + destination_folder_type, + inv_type, + next_owner_perms, + group_perms, + everyone_perms); + + body["asset_resources"] = asset_resources; + + LLHTTPClient::post( + url, + body, + new LLNewAgentInventoryVariablePriceResponder( + uuid, + asset_type, + body)); + + return TRUE; + } + else + { + return FALSE; + } +} +#endif + +LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid) +{ + if ( gDisconnected ) + { + LLAssetID rv; + + rv.setNull(); + return rv; + } + + LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); + + return uuid; +} + +void increase_new_upload_stats(LLAssetType::EType asset_type) +{ + if ( LLAssetType::AT_SOUND == asset_type ) + { + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_SOUND_COUNT ); + } + else if ( LLAssetType::AT_TEXTURE == asset_type ) + { + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); + } + else if ( LLAssetType::AT_ANIMATION == asset_type ) + { + LLViewerStats::getInstance()->incStat( + LLViewerStats::ST_UPLOAD_ANIM_COUNT ); + } +} + +void assign_defaults_and_show_upload_message( + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description) +{ + if ( LLInventoryType::IT_NONE == inventory_type ) + { + inventory_type = LLInventoryType::defaultForAssetType(asset_type); + } + LLStringUtil::stripNonprintable(name); + LLStringUtil::stripNonprintable(description); + + if ( name.empty() ) + { + name = "(No Name)"; + } + if ( description.empty() ) + { + description = "(No Description)"; } + + // At this point, we're ready for the upload. + std::string upload_message = "Uploading...\n\n"; + upload_message.append(display_name); + LLUploadDialog::modalUploadDialog(upload_message); } + void init_menu_file() { view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); +#if LL_MESH_ENABLED + view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); + view_listener_t::addCommit(new LLFileUploadScene(), "File.UploadScene"); +#endif view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); @@ -1048,6 +1420,8 @@ void init_menu_file() view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); - + view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); + view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); + // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. } diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 1e6d13f1c6..bb7cfce862 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -36,39 +36,120 @@ #include "llfoldertype.h" #include "llassetstorage.h" #include "llinventorytype.h" +#include "llfilepicker.h" class LLTransactionID; void init_menu_file(); -void upload_new_resource(const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata); - -void upload_new_resource(const LLTransactionID &tid, - LLAssetType::EType type, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata); +LLUUID upload_new_resource( + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata); + +void upload_new_resource( + const LLTransactionID &tid, + LLAssetType::EType type, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata); + +#if LL_MESH_ENABLED +// TODO* : Move all uploads to use this new function +// since at some point, that upload path will be deprecated and no longer +// used + +// We make a new function here to ensure that previous code is not broken +BOOL upload_new_variable_price_resource( + const LLTransactionID& tid, + LLAssetType::EType type, + std::string name, + std::string desc, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + const LLSD& asset_resources); +#endif + +LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid); +void increase_new_upload_stats(LLAssetType::EType asset_type); +void assign_defaults_and_show_upload_message( + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description); + +LLSD generate_new_resource_upload_capability_body( + LLAssetType::EType asset_type, + const std::string& name, + const std::string& desc, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms); + +void on_new_single_inventory_upload_complete( + LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + const std::string inventory_type_string, + const LLUUID& item_folder_id, + const std::string& item_name, + const std::string& item_description, + const LLSD& server_response, + S32 upload_price); + +class LLFilePickerThread : public LLThread +{ //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) +public: + + static std::queue<LLFilePickerThread*> sDeadQ; + static LLMutex* sMutex; + + static void initClass(); + static void cleanupClass(); + static void clearDead(); + + std::string mFile; + + LLFilePicker::ELoadFilter mFilter; + + LLFilePickerThread(LLFilePicker::ELoadFilter filter) + : LLThread("file picker"), mFilter(filter) + { + + } + + void getFile(); + + virtual void run(); + + virtual void notify(const std::string& filename) = 0; +}; + #endif diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 15bdf126c5..862359005e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -53,6 +53,7 @@ #include "llprimitive.h" #include "llquantize.h" #include "llregionhandle.h" +#include "llsdserialize.h" #include "lltree_common.h" #include "llxfermanager.h" #include "message.h" @@ -200,6 +201,11 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mGLName(0), mbCanSelect(TRUE), mFlags(0), + mPhysicsShapeType(0), + mPhysicsGravity(0), + mPhysicsFriction(0), + mPhysicsDensity(0), + mPhysicsRestitution(0), mDrawable(), mCreateSelected(FALSE), mRenderMedia(FALSE), @@ -231,6 +237,9 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mState(0), mMedia(NULL), mClickAction(0), + mObjectCost(0.f), + mLinksetCost(0.f), + mCostStale(true), mAttachmentItemID(LLUUID::null) { if (!is_global) @@ -844,6 +853,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, #ifdef DEBUG_UPDATE_TYPE llinfos << "Full:" << getID() << llendl; #endif + //clear cost and linkset cost + mCostStale = true; + LLUUID audio_uuid; LLUUID owner_id; // only valid if audio_uuid or particle system is not null F32 gain; @@ -1409,6 +1421,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, #ifdef DEBUG_UPDATE_TYPE llinfos << "CompFull:" << getID() << llendl; #endif + mCostStale = true; + dp->unpackU32(crc, "CRC"); mTotalCRC = crc; dp->unpackU8(material, "Material"); @@ -2885,21 +2899,61 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped) } } -void LLViewerObject::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax) +void LLViewerObject::setObjectCost(F32 cost) +{ + mObjectCost = cost; + mCostStale = false; +} + +void LLViewerObject::setLinksetCost(F32 cost) +{ + mLinksetCost = cost; + mCostStale = false; +} + + +F32 LLViewerObject::getObjectCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mObjectCost; +} + +F32 LLViewerObject::getLinksetCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mLinksetCost; +} + + + +void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { - LLVector3 center = getRenderPosition(); - LLVector3 size = getScale(); - newMin.setVec(center-size); - newMax.setVec(center+size); - mDrawable->setPositionGroup((newMin + newMax) * 0.5f); + LLVector4a center; + center.load3(getRenderPosition().mV); + LLVector4a size; + size.load3(getScale().mV); + newMin.setSub(center, size); + newMax.setAdd(center, size); + + mDrawable->setPositionGroup(center); } F32 LLViewerObject::getBinRadius() { if (mDrawable.notNull()) { - const LLVector3* ext = mDrawable->getSpatialExtents(); - return (ext[1]-ext[0]).magVec(); + const LLVector4a* ext = mDrawable->getSpatialExtents(); + LLVector4a diff; + diff.setSub(ext[1], ext[0]); + return diff.length3(); } return getScale().magVec(); @@ -2965,7 +3019,7 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); } - if (isSculpted()) + if (isSculpted() && !isMesh()) { LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); LLUUID sculpt_id = sculpt_params->getSculptTexture(); @@ -3491,12 +3545,21 @@ BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVect return FALSE; } - const LLVector3* ext = mDrawable->getSpatialExtents(); + const LLVector4a* ext = mDrawable->getSpatialExtents(); - LLVector3 center = (ext[1]+ext[0])*0.5f; - LLVector3 size = (ext[1]-ext[0])*0.5f; + //VECTORIZE THIS + LLVector4a center; + center.setAdd(ext[1], ext[0]); + center.mul(0.5f); + LLVector4a size; + size.setSub(ext[1], ext[0]); + size.mul(0.5f); - return LLLineSegmentBoxIntersect(start, end, center, size); + LLVector4a starta, enda; + starta.load3(start.mV); + enda.load3(end.mV); + + return LLLineSegmentBoxIntersect(starta, enda, center, size); } U8 LLViewerObject::getMediaType() const @@ -4990,7 +5053,18 @@ void LLViewerObject::updateFlags() gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); + gMessageSystem->nextBlock("ExtraPhysics"); + gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() ); + gMessageSystem->addF32("Density", getPhysicsDensity() ); + gMessageSystem->addF32("Friction", getPhysicsFriction() ); + gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); + gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); gMessageSystem->sendReliable( regionp->getHost() ); + + if (getPhysicsShapeType() != 0) + { + llwarns << "sent non default physics rep " << (S32) getPhysicsShapeType() << llendl; + } } BOOL LLViewerObject::setFlags(U32 flags, BOOL state) @@ -5022,6 +5096,31 @@ BOOL LLViewerObject::setFlags(U32 flags, BOOL state) return setit; } +void LLViewerObject::setPhysicsShapeType(U8 type) +{ + mPhysicsShapeType = type; +} + +void LLViewerObject::setPhysicsGravity(F32 gravity) +{ + mPhysicsGravity = gravity; +} + +void LLViewerObject::setPhysicsFriction(F32 friction) +{ + mPhysicsFriction = friction; +} + +void LLViewerObject::setPhysicsDensity(F32 density) +{ + mPhysicsDensity = density; +} + +void LLViewerObject::setPhysicsRestitution(F32 restitution) +{ + mPhysicsRestitution = restitution; +} + void LLViewerObject::applyAngularVelocity(F32 dt) { //do target omega here @@ -5233,3 +5332,75 @@ void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplif return ; } +//virtual +LLVOAvatar* LLViewerObject::getAvatar() const +{ + if (isAttachment()) + { + LLViewerObject* vobj = (LLViewerObject*) getParent(); + + while (vobj && !vobj->asAvatar()) + { + vobj = (LLViewerObject*) vobj->getParent(); + } + + return (LLVOAvatar*) vobj; + } + + return NULL; +} + + +class ObjectPhysicsProperties : public LLHTTPNode +{ +public: + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + LLSD object_data = input["body"]["ObjectData"]; + S32 num_entries = object_data.size(); + + for ( S32 i = 0; i < num_entries; i++ ) + { + LLSD& curr_object_data = object_data[i]; + U32 local_id = curr_object_data["LocalID"].asInteger(); + + // Iterate through nodes at end, since it can be on both the regular AND hover list + struct f : public LLSelectedNodeFunctor + { + U32 mID; + f(const U32& id) : mID(id) {} + virtual bool apply(LLSelectNode* node) + { + return (node->getObject() && node->getObject()->mLocalID == mID ); + } + } func(local_id); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func); + + if (node) + { + // The LLSD message builder doesn't know how to handle U8, so we need to send as S8 and cast + U8 type = (U8)curr_object_data["PhysicsShapeType"].asInteger(); + F32 density = (F32)curr_object_data["Density"].asReal(); + F32 friction = (F32)curr_object_data["Friction"].asReal(); + F32 restitution = (F32)curr_object_data["Restitution"].asReal(); + F32 gravity = (F32)curr_object_data["GravityMultiplier"].asReal(); + + node->getObject()->setPhysicsShapeType(type); + node->getObject()->setPhysicsGravity(gravity); + node->getObject()->setPhysicsFriction(friction); + node->getObject()->setPhysicsDensity(density); + node->getObject()->setPhysicsRestitution(restitution); + } + } + + dialog_refresh_all(); + }; +}; + +LLHTTPRegistration<ObjectPhysicsProperties> + gHTTPRegistrationObjectPhysicsProperties("/message/ObjectPhysicsProperties"); + diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index be83fb7ef8..70bc916acb 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -181,6 +181,7 @@ public: void setOnActiveList(BOOL on_active) { mOnActiveList = on_active; } virtual BOOL isAttachment() const { return FALSE; } + virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment virtual BOOL isHUDAttachment() const { return FALSE; } virtual void updateRadius() {}; virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius() @@ -229,6 +230,7 @@ public: virtual BOOL isFlexible() const { return FALSE; } virtual BOOL isSculpted() const { return FALSE; } + virtual BOOL isMesh() const { return FALSE; } virtual BOOL hasLightTexture() const { return FALSE; } // This method returns true if the object is over land owned by @@ -332,6 +334,12 @@ public: virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); + void setObjectCost(F32 cost); + F32 getObjectCost(); + void setLinksetCost(F32 cost); + F32 getLinksetCost(); + + void sendShapeUpdate(); U8 getState() { return mState; } @@ -371,7 +379,7 @@ public: void markForUpdate(BOOL priority); void updateVolume(const LLVolumeParams& volume_params); - virtual void updateSpatialExtents(LLVector3& min, LLVector3& max); + virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); virtual F32 getBinRadius(); LLBBox getBoundingBoxAgent() const; @@ -384,7 +392,7 @@ public: void clearDrawableState(U32 state, BOOL recursive = TRUE); // Called when the drawable shifts - virtual void onShift(const LLVector3 &shift_vector) { } + virtual void onShift(const LLVector4a &shift_vector) { } ////////////////////////////////////// // @@ -459,6 +467,12 @@ public: inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); } inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); } + inline U8 getPhysicsShapeType() const { return mPhysicsShapeType; } + inline F32 getPhysicsGravity() const { return mPhysicsGravity; } + inline F32 getPhysicsFriction() const { return mPhysicsFriction; } + inline F32 getPhysicsDensity() const { return mPhysicsDensity; } + inline F32 getPhysicsRestitution() const { return mPhysicsRestitution; } + bool getIncludeInSearch() const; void setIncludeInSearch(bool include_in_search); @@ -474,6 +488,11 @@ public: void updateFlags(); BOOL setFlags(U32 flag, BOOL state); + void setPhysicsShapeType(U8 type); + void setPhysicsGravity(F32 gravity); + void setPhysicsFriction(F32 friction); + void setPhysicsDensity(F32 density); + void setPhysicsRestitution(F32 restitution); virtual void dump() const; static U32 getNumZombieObjects() { return sNumZombieObjects; } @@ -553,6 +572,14 @@ public: // Grabbed from UPDATE_FLAGS U32 mFlags; + // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties + U8 mPhysicsShapeType; + F32 mPhysicsGravity; + F32 mPhysicsFriction; + F32 mPhysicsDensity; + F32 mPhysicsRestitution; + + // Pipeline classes LLPointer<LLDrawable> mDrawable; @@ -660,6 +687,9 @@ protected: U8 mState; // legacy LLViewerObjectMedia* mMedia; // NULL if no media associated U8 mClickAction; + F32 mObjectCost; //resource cost of this object or -1 if unknown + F32 mLinksetCost; + bool mCostStale; static U32 sNumZombieObjects; // Objects which are dead, but not deleted diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index fc94fbafac..900aa3ce12 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -60,6 +60,7 @@ #include "llviewercamera.h" #include "llselectmgr.h" #include "llresmgr.h" +#include "llsdutil.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llvoavatarself.h" @@ -656,6 +657,21 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) LLVOAvatar::cullAvatarsByPixelArea(); } +class LLObjectCostResponder : public LLCurl::Responder +{ +public: + void result(const LLSD& content) + { + for (LLSD::map_const_iterator iter = content.beginMap(); iter != content.endMap(); ++iter) + { + LLUUID object_id = LLUUID(iter->first); + F32 link_cost = iter->second["LinksetResourceCost"].asReal(); + F32 prim_cost = iter->second["PrimResourceCost"].asReal(); + + gObjectList.updateObjectCost(object_id, prim_cost, link_cost); + } + } +}; void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) { @@ -753,6 +769,43 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) } } + //issue http request for stale object physics costs + if (!mStaleObjectCost.empty()) + { + LLViewerRegion* regionp = gAgent.getRegion(); + + if (regionp) + { + std::string url = regionp->getCapability("GetObjectCost"); + + if (!url.empty()) + { + LLSD id_list; + U32 idx = 0; + for (std::set<LLUUID>::iterator iter = mStaleObjectCost.begin(); iter != mStaleObjectCost.end(); ++iter) + { + if (mPendingObjectCost.find(*iter) == mPendingObjectCost.end()) + { + mPendingObjectCost.insert(*iter); + id_list[idx++] = *iter; + } + } + mPendingObjectCost = mStaleObjectCost; + mStaleObjectCost.clear(); + + if (id_list.size() > 0) + { + LLHTTPClient::post(url, id_list, new LLObjectCostResponder()); + } + } + else + { + mStaleObjectCost.clear(); + mPendingObjectCost.clear(); + } + } + } + mNumSizeCulled = 0; mNumVisCulled = 0; @@ -871,8 +924,12 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) mNumDeadObjects++; } +static LLFastTimer::DeclareTimer FTM_REMOVE_DRAWABLE("Remove Drawable"); + void LLViewerObjectList::removeDrawable(LLDrawable* drawablep) { + LLFastTimer t(FTM_REMOVE_DRAWABLE); + if (!drawablep) { return; @@ -1037,7 +1094,22 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp) } } +void LLViewerObjectList::updateObjectCost(LLViewerObject* object) +{ + mStaleObjectCost.insert(object->getID()); +} + +void LLViewerObjectList::updateObjectCost(LLUUID object_id, F32 prim_cost, F32 link_cost) +{ + mPendingObjectCost.erase(object_id); + LLViewerObject* object = findObject(object_id); + if (object) + { + object->setObjectCost(prim_cost); + object->setLinksetCost(link_cost); + } +} void LLViewerObjectList::shiftObjects(const LLVector3 &offset) { diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 706966deae..4064a68eb2 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -91,6 +91,9 @@ public: void updateApparentAngles(LLAgent &agent); void update(LLAgent &agent, LLWorld &world); + void updateObjectCost(LLViewerObject* object); + void updateObjectCost(LLUUID object_id, F32 prim_cost, F32 link_cost); + void shiftObjects(const LLVector3 &offset); void renderObjectsForMap(LLNetMap &netmap); @@ -192,6 +195,10 @@ protected: std::map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap; + //set of objects that need to update their cost + std::set<LLUUID> mStaleObjectCost; + std::set<LLUUID> mPendingObjectCost; + std::vector<LLDebugBeacon> mDebugBeacons; S32 mCurLazyUpdateIndex; diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index 6b480ccf8e..41848e8b7a 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -161,8 +161,8 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 ¢er_agent, const F32 bo if (group != NULL) { - LLVector3 center(group->mOctreeNode->getCenter()); - LLVector3 size(group->mOctreeNode->getSize()); + LLVector3 center(group->mOctreeNode->getCenter().getF32()); + LLVector3 size(group->mOctreeNode->getSize().getF32()); size += LLVector3(0.01f, 0.01f, 0.01f); mMinObjPos = center - size; mMaxObjPos = center + size; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index da240cedbb..ccec972c0d 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -174,7 +174,7 @@ public: mRegion->showReleaseNotes(); } } - + if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) { LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); @@ -1497,12 +1497,16 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("FetchLib"); capabilityNames.append("FetchLibDescendents"); capabilityNames.append("GetTexture"); + capabilityNames.append("GetMesh"); + capabilityNames.append("GetObjectCost"); capabilityNames.append("GroupProposalBallot"); capabilityNames.append("HomeLocation"); capabilityNames.append("LandResources"); capabilityNames.append("MapLayer"); capabilityNames.append("MapLayerGod"); capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("NewFileAgentInventoryVariablePrice"); + capabilityNames.append("ObjectAdd"); capabilityNames.append("ParcelPropertiesUpdate"); capabilityNames.append("ParcelMediaURLFilterList"); capabilityNames.append("ParcelNavigateMedia"); @@ -1517,6 +1521,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("SendUserReport"); capabilityNames.append("SendUserReportWithScreenshot"); capabilityNames.append("ServerReleaseNotes"); + capabilityNames.append("SimulatorFeatures"); capabilityNames.append("StartGroupProposal"); capabilityNames.append("TextureStats"); capabilityNames.append("UntrustedSimulatorMessage"); @@ -1529,6 +1534,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("UpdateNotecardTaskInventory"); capabilityNames.append("UpdateScriptTask"); capabilityNames.append("UploadBakedTexture"); + capabilityNames.append("UploadObjectAsset"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); capabilityNames.append("WebFetchInventoryDescendents"); @@ -1575,6 +1581,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const { return ""; } + return iter->second; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 0e29851778..49eeffe228 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -77,6 +77,12 @@ LLGLSLShader gObjectFullbrightShinyProgram; LLGLSLShader gObjectShinyProgram; LLGLSLShader gObjectShinyWaterProgram; +//object hardware skinning shaders +LLGLSLShader gSkinnedObjectSimpleProgram; +LLGLSLShader gSkinnedObjectFullbrightProgram; +LLGLSLShader gSkinnedObjectFullbrightShinyProgram; +LLGLSLShader gSkinnedObjectShinySimpleProgram; + //environment shaders LLGLSLShader gTerrainProgram; LLGLSLShader gTerrainWaterProgram; @@ -107,6 +113,9 @@ LLGLSLShader gDeferredImpostorProgram; LLGLSLShader gDeferredEdgeProgram; LLGLSLShader gDeferredWaterProgram; LLGLSLShader gDeferredDiffuseProgram; +LLGLSLShader gDeferredSkinnedDiffuseProgram; +LLGLSLShader gDeferredSkinnedBumpProgram; +LLGLSLShader gDeferredSkinnedAlphaProgram; LLGLSLShader gDeferredBumpProgram; LLGLSLShader gDeferredTerrainProgram; LLGLSLShader gDeferredTreeProgram; @@ -121,6 +130,7 @@ LLGLSLShader gDeferredBlurLightProgram; LLGLSLShader gDeferredSoftenProgram; LLGLSLShader gDeferredShadowProgram; LLGLSLShader gDeferredAvatarShadowProgram; +LLGLSLShader gDeferredAttachmentShadowProgram; LLGLSLShader gDeferredAlphaProgram; LLGLSLShader gDeferredFullbrightProgram; LLGLSLShader gDeferredGIProgram; @@ -148,6 +158,10 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gObjectSimpleProgram); mShaderList.push_back(&gObjectFullbrightProgram); mShaderList.push_back(&gObjectFullbrightShinyProgram); + mShaderList.push_back(&gSkinnedObjectSimpleProgram); + mShaderList.push_back(&gSkinnedObjectFullbrightProgram); + mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram); + mShaderList.push_back(&gSkinnedObjectShinySimpleProgram); mShaderList.push_back(&gTerrainProgram); mShaderList.push_back(&gTerrainWaterProgram); mShaderList.push_back(&gObjectSimpleWaterProgram); @@ -161,6 +175,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gDeferredLightProgram); mShaderList.push_back(&gDeferredMultiLightProgram); mShaderList.push_back(&gDeferredAlphaProgram); + mShaderList.push_back(&gDeferredSkinnedAlphaProgram); mShaderList.push_back(&gDeferredFullbrightProgram); mShaderList.push_back(&gDeferredPostGIProgram); mShaderList.push_back(&gDeferredEdgeProgram); @@ -195,6 +210,7 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void) mReservedAttribs.push_back("materialColor"); mReservedAttribs.push_back("specularColor"); mReservedAttribs.push_back("binormal"); + mReservedAttribs.push_back("object_weight"); mAvatarAttribs.reserve(5); mAvatarAttribs.push_back("weight"); @@ -499,6 +515,9 @@ void LLViewerShaderMgr::setShaders() if (!loadShadersDeferred()) { gSavedSettings.setBOOL("RenderDeferred", FALSE); + reentrance = false; + setShaders(); + return; } #endif } @@ -549,6 +568,13 @@ void LLViewerShaderMgr::unloadShaders() gObjectShinyProgram.unload(); gObjectFullbrightShinyProgram.unload(); gObjectShinyWaterProgram.unload(); + + gSkinnedObjectSimpleProgram.unload(); + gSkinnedObjectFullbrightProgram.unload(); + gSkinnedObjectFullbrightShinyProgram.unload(); + gSkinnedObjectShinySimpleProgram.unload(); + + gWaterProgram.unload(); gUnderWaterProgram.unload(); gTerrainProgram.unload(); @@ -568,6 +594,9 @@ void LLViewerShaderMgr::unloadShaders() gPostNightVisionProgram.unload(); gDeferredDiffuseProgram.unload(); + gDeferredSkinnedDiffuseProgram.unload(); + gDeferredSkinnedBumpProgram.unload(); + gDeferredSkinnedAlphaProgram.unload(); mVertexShaderLevel[SHADER_LIGHTING] = 0; mVertexShaderLevel[SHADER_OBJECT] = 0; @@ -626,6 +655,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders() shaders.push_back( make_pair( "lighting/lightSpecularV.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) ); shaders.push_back( make_pair( "windlight/atmosphericsV.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); shaders.push_back( make_pair( "avatar/avatarSkinV.glsl", 1 ) ); + shaders.push_back( make_pair( "avatar/objectSkinV.glsl", 1 ) ); // We no longer have to bind the shaders to global glhandles, they are automatically added to a map now. for (U32 i = 0; i < shaders.size(); i++) @@ -881,6 +911,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredTreeProgram.unload(); gDeferredDiffuseProgram.unload(); + gDeferredSkinnedDiffuseProgram.unload(); + gDeferredSkinnedBumpProgram.unload(); + gDeferredSkinnedAlphaProgram.unload(); gDeferredBumpProgram.unload(); gDeferredImpostorProgram.unload(); gDeferredTerrainProgram.unload(); @@ -893,6 +926,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenProgram.unload(); gDeferredShadowProgram.unload(); gDeferredAvatarShadowProgram.unload(); + gDeferredAttachmentShadowProgram.unload(); gDeferredAvatarProgram.unload(); gDeferredAvatarAlphaProgram.unload(); gDeferredAlphaProgram.unload(); @@ -904,7 +938,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredGIProgram.unload(); gDeferredGIFinalProgram.unload(); gDeferredWaterProgram.unload(); - return FALSE; + return TRUE; } mVertexShaderLevel[SHADER_AVATAR] = 1; @@ -923,6 +957,44 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { + gDeferredSkinnedDiffuseProgram.mName = "Deferred Skinned Diffuse Shader"; + gDeferredSkinnedDiffuseProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedDiffuseProgram.mShaderFiles.clear(); + gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSkinnedDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredSkinnedDiffuseProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredSkinnedBumpProgram.mName = "Deferred Skinned Bump Shader"; + gDeferredSkinnedBumpProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedBumpProgram.mShaderFiles.clear(); + gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSkinnedBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredSkinnedBumpProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader"; + gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = true; + gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true; + gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true; + gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true; + gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = true; + gDeferredSkinnedAlphaProgram.mShaderFiles.clear(); + gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSkinnedAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL); + } + + if (success) + { gDeferredBumpProgram.mName = "Deferred Bump Shader"; gDeferredBumpProgram.mShaderFiles.clear(); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER_ARB)); @@ -1098,6 +1170,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { + gDeferredAttachmentShadowProgram.mName = "Deferred Attachment Shadow Shader"; + gDeferredAttachmentShadowProgram.mFeatures.hasObjectSkinning = true; + gDeferredAttachmentShadowProgram.mShaderFiles.clear(); + gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredAttachmentShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredAttachmentShadowProgram.createShader(NULL, NULL); + } + + if (success) + { gTerrainProgram.mName = "Deferred Terrain Shader"; gDeferredTerrainProgram.mShaderFiles.clear(); gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER_ARB)); @@ -1128,7 +1211,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true; gDeferredAvatarAlphaProgram.mShaderFiles.clear(); gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredAvatarAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredAvatarAlphaProgram.createShader(&mAvatarAttribs, &mAvatarUniforms); } @@ -1215,6 +1298,11 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleWaterProgram.unload(); gObjectFullbrightProgram.unload(); gObjectFullbrightWaterProgram.unload(); + gSkinnedObjectSimpleProgram.unload(); + gSkinnedObjectFullbrightProgram.unload(); + gSkinnedObjectFullbrightShinyProgram.unload(); + gSkinnedObjectShinySimpleProgram.unload(); + return FALSE; } @@ -1324,6 +1412,68 @@ BOOL LLViewerShaderMgr::loadShadersObject() success = gObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms); } + if (success) + { + gSkinnedObjectSimpleProgram.mName = "Skinned Simple Shader"; + gSkinnedObjectSimpleProgram.mFeatures.calculatesLighting = true; + gSkinnedObjectSimpleProgram.mFeatures.calculatesAtmospherics = true; + gSkinnedObjectSimpleProgram.mFeatures.hasGamma = true; + gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true; + gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true; + gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true; + gSkinnedObjectSimpleProgram.mShaderFiles.clear(); + gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); + gSkinnedObjectSimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL); + } + + if (success) + { + gSkinnedObjectFullbrightProgram.mName = "Skinned Fullbright Shader"; + gSkinnedObjectFullbrightProgram.mFeatures.calculatesAtmospherics = true; + gSkinnedObjectFullbrightProgram.mFeatures.hasGamma = true; + gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true; + gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true; + gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true; + gSkinnedObjectFullbrightProgram.mShaderFiles.clear(); + gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gSkinnedObjectFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + success = gSkinnedObjectFullbrightProgram.createShader(NULL, NULL); + } + + if (success) + { + gSkinnedObjectFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader"; + gSkinnedObjectFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true; + gSkinnedObjectFullbrightShinyProgram.mFeatures.hasGamma = true; + gSkinnedObjectFullbrightShinyProgram.mFeatures.hasTransport = true; + gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true; + gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true; + gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true; + gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear(); + gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); + gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms); + } + + if (success) + { + gSkinnedObjectShinySimpleProgram.mName = "Skinned Shiny Simple Shader"; + gSkinnedObjectShinySimpleProgram.mFeatures.calculatesLighting = true; + gSkinnedObjectShinySimpleProgram.mFeatures.calculatesAtmospherics = true; + gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true; + gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true; + gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true; + gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true; + gSkinnedObjectShinySimpleProgram.mShaderFiles.clear(); + gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB)); + gSkinnedObjectShinySimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + success = gSkinnedObjectShinySimpleProgram.createShader(NULL, &mShinyUniforms); + } if( !success ) { diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index ac2b4624e0..da16a38427 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -82,6 +82,7 @@ public: MATERIAL_COLOR = 0, SPECULAR_COLOR, BINORMAL, + OBJECT_WEIGHT, END_RESERVED_ATTRIBS } eGLSLReservedAttribs; @@ -313,6 +314,11 @@ extern LLGLSLShader gObjectFullbrightShinyProgram; extern LLGLSLShader gObjectShinyProgram; extern LLGLSLShader gObjectShinyWaterProgram; +extern LLGLSLShader gSkinnedObjectSimpleProgram; +extern LLGLSLShader gSkinnedObjectFullbrightProgram; +extern LLGLSLShader gSkinnedObjectFullbrightShinyProgram; +extern LLGLSLShader gSkinnedObjectShinySimpleProgram; + //environment shaders extern LLGLSLShader gTerrainProgram; extern LLGLSLShader gTerrainWaterProgram; @@ -343,6 +349,9 @@ extern LLGLSLShader gDeferredImpostorProgram; extern LLGLSLShader gDeferredEdgeProgram; extern LLGLSLShader gDeferredWaterProgram; extern LLGLSLShader gDeferredDiffuseProgram; +extern LLGLSLShader gDeferredSkinnedDiffuseProgram; +extern LLGLSLShader gDeferredSkinnedBumpProgram; +extern LLGLSLShader gDeferredSkinnedAlphaProgram; extern LLGLSLShader gDeferredBumpProgram; extern LLGLSLShader gDeferredTerrainProgram; extern LLGLSLShader gDeferredTreeProgram; @@ -360,6 +369,7 @@ extern LLGLSLShader gDeferredShadowProgram; extern LLGLSLShader gDeferredPostGIProgram; extern LLGLSLShader gDeferredPostProgram; extern LLGLSLShader gDeferredAvatarShadowProgram; +extern LLGLSLShader gDeferredAttachmentShadowProgram; extern LLGLSLShader gDeferredAlphaProgram; extern LLGLSLShader gDeferredFullbrightProgram; extern LLGLSLShader gDeferredAvatarAlphaProgram; diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 59efae4cb2..697e8afa65 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -535,6 +535,9 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const case LLAssetType::AT_BODYPART: img_name = "Inv_Skin"; break; case LLAssetType::AT_ANIMATION: img_name = "Inv_Animation"; break; case LLAssetType::AT_GESTURE: img_name = "Inv_Gesture"; break; +#if LL_MESH_ENABLED + case LLAssetType::AT_MESH: img_name = "Inv_Mesh"; break; +#endif default: llassert(0); } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 75bb9f84e2..719c5b0da5 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -835,7 +835,7 @@ BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* image llassert(mGLTexturep.notNull()) ; BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ; - + if(ret) { mFullWidth = mGLTexturep->getCurrentWidth() ; @@ -1420,8 +1420,15 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) mOrigWidth = mRawImage->getWidth(); mOrigHeight = mRawImage->getHeight(); - // leave black border, do not scale image content - mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); + + if (mBoostLevel == BOOST_PREVIEW) + { + mRawImage->biasedScaleToPowerOfTwo(1024); + } + else + { // leave black border, do not scale image content + mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); + } mFullWidth = mRawImage->getWidth(); mFullHeight = mRawImage->getHeight(); @@ -2800,7 +2807,7 @@ BOOL LLViewerFetchedTexture::insertToAtlas() } //process the waiting_list - for(ll_face_list_t::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter) + for(std::vector<LLFace*>::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter) { facep = (LLFace*)*iter ; groupp = facep->getDrawable()->getSpatialGroup() ; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 2f63e7ef01..67dbe3e52b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -31,7 +31,6 @@ */ #include "llviewerprecompiledheaders.h" - #include "llviewerwindow.h" #if LL_WINDOWS @@ -47,6 +46,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llfloaterreg.h" +#include "llmeshrepository.h" #include "llpanellogin.h" #include "llviewerkeyboard.h" #include "llviewermenu.h" @@ -230,6 +230,8 @@ LLVector2 gDebugRaycastTexCoord; LLVector3 gDebugRaycastNormal; LLVector3 gDebugRaycastBinormal; S32 gDebugRaycastFaceHit; +LLVector3 gDebugRaycastStart; +LLVector3 gDebugRaycastEnd; // HUD display lines in lower right BOOL gDisplayWindInfo = FALSE; @@ -320,7 +322,7 @@ public: mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f ); // Draw stuff growing up from right lower corner of screen - U32 xpos = mWindow->getWindowWidthScaled() - 350; + U32 xpos = mWindow->getWorldViewWidthScaled() - 350; U32 ypos = 64; const U32 y_inc = 20; @@ -585,6 +587,54 @@ public: ypos += y_inc; } } + + + if (gSavedSettings.getBOOL("DebugShowUploadCost")) + { +#if LL_MESH_ENABLED + addText(xpos, ypos, llformat(" Meshes: L$%d", gPipeline.mDebugMeshUploadCost)); + ypos += y_inc/2; +#endif + addText(xpos, ypos, llformat(" Sculpties: L$%d", gPipeline.mDebugSculptUploadCost)); + ypos += y_inc/2; + addText(xpos, ypos, llformat(" Textures: L$%d", gPipeline.mDebugTextureUploadCost)); + ypos += y_inc/2; + addText(xpos, ypos, "Upload Cost: "); + + ypos += y_inc; + } + +#if LL_MESH_ENABLED + //temporary hack to give feedback on mesh upload progress + if (!gMeshRepo.mUploads.empty()) + { + for (std::vector<LLMeshUploadThread*>::iterator iter = gMeshRepo.mUploads.begin(); + iter != gMeshRepo.mUploads.end(); ++iter) + { + LLMeshUploadThread* thread = *iter; + + addText(xpos, ypos, llformat("Mesh Upload -- price quote: %d:%d | upload: %d:%d | create: %d", + thread->mPendingConfirmations, thread->mUploadQ.size()+thread->mTextureQ.size(), + thread->mPendingUploads, thread->mConfirmedQ.size()+thread->mConfirmedTextureQ.size(), + thread->mInstanceQ.size())); + ypos += y_inc; + } + } + + S32 pending = (S32) gMeshRepo.mPendingRequests.size(); + S32 header = (S32) gMeshRepo.mThread->mHeaderReqQ.size(); + S32 lod = (S32) gMeshRepo.mThread->mLODReqQ.size(); + + if (pending + header + lod + LLMeshRepoThread::sActiveHeaderRequests + LLMeshRepoThread::sActiveLODRequests != 0) + { + addText(xpos, ypos, llformat ("Mesh Queue - %d pending (%d:%d header | %d:%d LOD)", + pending, + LLMeshRepoThread::sActiveHeaderRequests, header, + LLMeshRepoThread::sActiveLODRequests, lod)); + + ypos += y_inc; + } +#endif } void draw() @@ -2450,7 +2500,9 @@ void LLViewerWindow::updateUI() &gDebugRaycastIntersection, &gDebugRaycastTexCoord, &gDebugRaycastNormal, - &gDebugRaycastBinormal); + &gDebugRaycastBinormal, + &gDebugRaycastStart, + &gDebugRaycastEnd); } updateMouseDelta(); @@ -3395,7 +3447,9 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de LLVector3 *intersection, LLVector2 *uv, LLVector3 *normal, - LLVector3 *binormal) + LLVector3 *binormal, + LLVector3* start, + LLVector3* end) { S32 x = mouse_x; S32 y = mouse_y; @@ -3427,7 +3481,16 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de LLVector3 mouse_world_start = mouse_point_global; LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth; - + if (start) + { + *start = mouse_world_start; + } + + if (end) + { + *end = mouse_world_end; + } + LLViewerObject* found = NULL; if (this_object) // check only this object @@ -4466,6 +4529,7 @@ BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsyn //gResizeScreenTexture = TRUE; + //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples"); //U32 old_fsaa = mWindow->getFSAASamples(); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 1e0200a075..61038e2366 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -357,7 +357,9 @@ public: LLVector3 *intersection = NULL, LLVector2 *uv = NULL, LLVector3 *normal = NULL, - LLVector3 *binormal = NULL); + LLVector3 *binormal = NULL, + LLVector3* start = NULL, + LLVector3* end = NULL); // Returns a pointer to the last object hit @@ -495,6 +497,8 @@ extern LLVector2 gDebugRaycastTexCoord; extern LLVector3 gDebugRaycastNormal; extern LLVector3 gDebugRaycastBinormal; extern S32 gDebugRaycastFaceHit; +extern LLVector3 gDebugRaycastStart; +extern LLVector3 gDebugRaycastEnd; extern S32 CHAT_BAR_HEIGHT; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index d596b96d81..abf22b5e5a 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -64,6 +64,7 @@ #include "llkeyframefallmotion.h" #include "llkeyframestandmotion.h" #include "llkeyframewalkmotion.h" +#include "llmeshrepository.h" #include "llmutelist.h" #include "llmoveview.h" #include "llnotificationsutil.h" @@ -81,6 +82,7 @@ #include "llviewermenu.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" +#include "llviewershadermgr.h" #include "llviewerstats.h" #include "llvoavatarself.h" #include "llvovolume.h" @@ -682,7 +684,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, { LLMemType mt(LLMemType::MTYPE_AVATAR); //VTResume(); // VTune - + mImpostorExtents = (LLVector4a*) ll_aligned_malloc_16(32); + // mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim ); @@ -828,6 +831,9 @@ LLVOAvatar::~LLVOAvatar() mAnimationSources.clear(); + ll_aligned_free_16(mImpostorExtents); + mImpostorExtents = NULL; + lldebugs << "LLVOAvatar Destructor end" << llendl; } @@ -1336,41 +1342,46 @@ void LLVOAvatar::updateDrawable(BOOL force_damped) clearChanged(SHIFTED); } -void LLVOAvatar::onShift(const LLVector3& shift_vector) +void LLVOAvatar::onShift(const LLVector4a& shift_vector) { - mLastAnimExtents[0] += shift_vector; - mLastAnimExtents[1] += shift_vector; + const LLVector3& shift = reinterpret_cast<const LLVector3&>(shift_vector); + mLastAnimExtents[0] += shift; + mLastAnimExtents[1] += shift; mNeedsImpostorUpdate = TRUE; mNeedsAnimUpdate = TRUE; } -void LLVOAvatar::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax) +void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { if (isImpostor() && !needsImpostorUpdate()) { LLVector3 delta = getRenderPosition() - - ((LLVector3(mDrawable->getPositionGroup())-mImpostorOffset)); + ((LLVector3(mDrawable->getPositionGroup().getF32())-mImpostorOffset)); - newMin = mLastAnimExtents[0] + delta; - newMax = mLastAnimExtents[1] + delta; + newMin.load3( (mLastAnimExtents[0] + delta).mV); + newMax.load3( (mLastAnimExtents[1] + delta).mV); } else { getSpatialExtents(newMin,newMax); - mLastAnimExtents[0] = newMin; - mLastAnimExtents[1] = newMax; - LLVector3 pos_group = (newMin+newMax)*0.5f; - mImpostorOffset = pos_group-getRenderPosition(); + mLastAnimExtents[0].set(newMin.getF32()); + mLastAnimExtents[1].set(newMax.getF32()); + LLVector4a pos_group; + pos_group.setAdd(newMin,newMax); + pos_group.mul(0.5f); + mImpostorOffset = LLVector3(pos_group.getF32())-getRenderPosition(); mDrawable->setPositionGroup(pos_group); } } -void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax) +void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { - LLVector3 buffer(0.25f, 0.25f, 0.25f); - LLVector3 pos = getRenderPosition(); - newMin = pos - buffer; - newMax = pos + buffer; + LLVector4a buffer(0.25f); + LLVector4a pos; + pos.load3(getRenderPosition().mV); + newMin.setSub(pos, buffer); + newMax.setAdd(pos, buffer); + float max_attachment_span = DEFAULT_MAX_PRIM_SCALE * 5.0f; //stretch bounding box by joint positions @@ -1379,12 +1390,20 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax) LLPolyMesh* mesh = i->second; for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++) { - update_min_max(newMin, newMax, - mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation()); + LLVector4a trans; + trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV); + update_min_max(newMin, newMax, trans); } } - mPixelArea = LLPipeline::calcPixelArea((newMin+newMax)*0.5f, (newMax-newMin)*0.5f, *LLViewerCamera::getInstance()); + LLVector4a center, size; + center.setAdd(newMin, newMax); + center.mul(0.5f); + + size.setSub(newMax,newMin); + size.mul(0.5f); + + mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); //stretch bounding box by attachments for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); @@ -1411,15 +1430,17 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax) LLSpatialBridge* bridge = drawable->getSpatialBridge(); if (bridge) { - const LLVector3* ext = bridge->getSpatialExtents(); - LLVector3 distance = (ext[1] - ext[0]); + const LLVector4a* ext = bridge->getSpatialExtents(); + LLVector4a distance; + distance.setSub(ext[1], ext[0]); + LLVector4a max_span(max_attachment_span); + + S32 lt = distance.lessThan4(max_span).getComparisonMask() & 0x7; // Only add the prim to spatial extents calculations if it isn't a megaprim. // max_attachment_span calculated at the start of the function // (currently 5 times our max prim size) - if (distance.mV[0] < max_attachment_span - && distance.mV[1] < max_attachment_span - && distance.mV[2] < max_attachment_span) + if (lt == 0x7) { update_min_max(newMin,newMax,ext[0]); update_min_max(newMin,newMax,ext[1]); @@ -1431,8 +1452,9 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax) } //pad bounding box - newMin -= buffer; - newMax += buffer; + + newMin.sub(buffer); + newMax.add(buffer); } //----------------------------------------------------------------------------- @@ -2478,7 +2500,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) if (isImpostor() && !mNeedsImpostorUpdate) { - LLVector3 ext[2]; + LLVector4a ext[2]; F32 distance; LLVector3 angle; @@ -2507,12 +2529,22 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) } else { + //VECTORIZE THIS getSpatialExtents(ext[0], ext[1]); - if ((ext[1]-mImpostorExtents[1]).length() > 0.05f || - (ext[0]-mImpostorExtents[0]).length() > 0.05f) + LLVector4a diff; + diff.setSub(ext[1], mImpostorExtents[1]); + if (diff.length3() > 0.05f) { mNeedsImpostorUpdate = TRUE; } + else + { + diff.setSub(ext[0], mImpostorExtents[0]); + if (diff.length3() > 0.05f) + { + mNeedsImpostorUpdate = TRUE; + } + } } } } @@ -3768,6 +3800,46 @@ bool LLVOAvatar::shouldAlphaMask() } +U32 LLVOAvatar::renderSkinnedAttachments() +{ + /*U32 num_indices = 0; + + const U32 data_mask = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4; + + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + const LLViewerObject* attached_object = (*attachment_iter); + if (attached_object && !attached_object->isHUDAttachment()) + { + const LLDrawable* drawable = attached_object->mDrawable; + if (drawable) + { + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* face = drawable->getFace(i); + if (face->isState(LLFace::RIGGED)) + { + + } + } + } + } + + return num_indices;*/ + return 0; +} + //----------------------------------------------------------------------------- // renderSkinned() //----------------------------------------------------------------------------- @@ -5353,9 +5425,13 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) return; } - const LLVector3* ext = mDrawable->getSpatialExtents(); - LLVector3 center = (ext[1] + ext[0]) * 0.5f; - LLVector3 size = (ext[1]-ext[0])*0.5f; + const LLVector4a* ext = mDrawable->getSpatialExtents(); + LLVector4a center; + center.setAdd(ext[1], ext[0]); + center.mul(0.5f); + LLVector4a size; + size.setSub(ext[1], ext[0]); + size.mul(0.5f); mImpostorPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); @@ -5367,7 +5443,7 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) } else { - F32 radius = size.length(); + F32 radius = size.length3(); mAppAngle = (F32) atan2( radius, range) * RAD_TO_DEG; } @@ -5563,8 +5639,7 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi // correctly, but putting this check in here to be safe. if (attachmentID & ATTACHMENT_ADD) { - llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl; - attachmentID &= ~ATTACHMENT_ADD; + llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl; attachmentID &= ~ATTACHMENT_ADD; } LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); @@ -5686,6 +5761,14 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) return TRUE; } } + + std::vector<LLPointer<LLViewerObject> >::iterator iter = std::find(mPendingAttachment.begin(), mPendingAttachment.end(), viewer_object); + if (iter != mPendingAttachment.end()) + { + mPendingAttachment.erase(iter); + return TRUE; + } + return FALSE; } @@ -7839,9 +7922,9 @@ void LLVOAvatar::cacheImpostorValues() getImpostorValues(mImpostorExtents, mImpostorAngle, mImpostorDistance); } -void LLVOAvatar::getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance) const +void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const { - const LLVector3* ext = mDrawable->getSpatialExtents(); + const LLVector4a* ext = mDrawable->getSpatialExtents(); extents[0] = ext[0]; extents[1] = ext[1]; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index f12dbb8801..95b0665f7d 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -128,7 +128,7 @@ public: virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate. virtual void updateTextures(); virtual S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim. - virtual void onShift(const LLVector3& shift_vector); + virtual void onShift(const LLVector4a& shift_vector); virtual U32 getPartitionType() const; virtual const LLVector3 getRenderPosition() const; virtual void updateDrawable(BOOL force_damped); @@ -136,8 +136,8 @@ public: virtual BOOL updateGeometry(LLDrawable *drawable); virtual void setPixelAreaAndAngle(LLAgent &agent); virtual void updateRegion(LLViewerRegion *regionp); - virtual void updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax); - virtual void getSpatialExtents(LLVector3& newMin, LLVector3& newMax); + virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax); + virtual void getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, @@ -345,6 +345,7 @@ public: U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0); U32 renderRigid(); U32 renderSkinned(EAvatarRenderPass pass); + U32 renderSkinnedAttachments(); U32 renderTransparent(BOOL first_pass); void renderCollisionVolumes(); static void deleteCachedImages(bool clearAll=true); @@ -395,7 +396,7 @@ public: BOOL needsImpostorUpdate() const; const LLVector3& getImpostorOffset() const; const LLVector2& getImpostorDim() const; - void getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance) const; + void getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const; void cacheImpostorValues(); void setImpostorDim(const LLVector2& dim); static void resetImpostors(); @@ -406,7 +407,7 @@ private: LLVector3 mImpostorOffset; LLVector2 mImpostorDim; BOOL mNeedsAnimUpdate; - LLVector3 mImpostorExtents[2]; + LLVector4a* mImpostorExtents; LLVector3 mImpostorAngle; F32 mImpostorDistance; F32 mImpostorPixelArea; diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index a82afbeb76..fe1e36cbe8 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -594,7 +594,7 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en LLVector2 tc[4]; LLVector3 v[4]; - // LLVector3 n[4]; // unused! + //LLVector3 n[4]; F32 closest_t = 1.f; @@ -640,7 +640,6 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en position.mV[2] += blade_height; v[3] = v1 = position + mRegionp->getOriginAgent(); - F32 a,b,t; BOOL hit = FALSE; @@ -648,23 +647,23 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en U32 idx0 = 0,idx1 = 0,idx2 = 0; - if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, &a, &b, &t, FALSE)) + if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE)) { hit = TRUE; idx0 = 0; idx1 = 1; idx2 = 2; } - else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, &a, &b, &t, FALSE)) + else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, a, b, t, FALSE)) { hit = TRUE; idx0 = 1; idx1 = 3; idx2 = 2; } - else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, &a, &b, &t, FALSE)) + else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, a, b, t, FALSE)) { normal1 = -normal1; hit = TRUE; idx0 = 2; idx1 = 1; idx2 = 0; } - else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, &a, &b, &t, FALSE)) + else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, a, b, t, FALSE)) { normal1 = -normal1; hit = TRUE; diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 3ba4ecad0c..b5fd8182c6 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -79,12 +79,14 @@ F32 LLVOPartGroup::getBinRadius() return mScale.mV[0]*2.f; } -void LLVOPartGroup::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) +void LLVOPartGroup::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { const LLVector3& pos_agent = getPositionAgent(); - newMin = pos_agent - mScale; - newMax = pos_agent + mScale; - mDrawable->setPositionGroup(pos_agent); + newMin.load3( (pos_agent - mScale).mV); + newMax.load3( (pos_agent + mScale).mV); + LLVector4a pos; + pos.load3(pos_agent.mV); + mDrawable->setPositionGroup(pos); } BOOL LLVOPartGroup::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h index 18583b4be9..771ae1c1eb 100644 --- a/indra/newview/llvopartgroup.h +++ b/indra/newview/llvopartgroup.h @@ -57,7 +57,7 @@ public: BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); virtual F32 getBinRadius(); - virtual void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax); + virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); virtual U32 getPartitionType() const; /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index ef7b161003..02e7e7e60f 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -60,27 +60,77 @@ public: LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0 | MAP_TEXCOORD1 | MAP_COLOR, GL_DYNAMIC_DRAW_ARB) { //texture coordinates 2 and 3 exist, but use the same data as texture coordinate 1 - mOffsets[TYPE_TEXCOORD3] = mOffsets[TYPE_TEXCOORD2] = mOffsets[TYPE_TEXCOORD1]; - mTypeMask |= MAP_TEXCOORD2 | MAP_TEXCOORD3; }; - /*// virtual + // virtual void setupVertexBuffer(U32 data_mask) const - { - if (LLDrawPoolTerrain::getDetailMode() == 0 || LLPipeline::sShadowRender) + { + U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; + + //assume tex coords 2 and 3 are present + U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3; + + if ((data_mask & type_mask) != data_mask) { - LLVertexBuffer::setupVertexBuffer(data_mask); + llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; + } + + if (data_mask & MAP_NORMAL) + { + glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); + } + if (data_mask & MAP_TEXCOORD3) + { //substitute tex coord 0 for tex coord 3 + glClientActiveTextureARB(GL_TEXTURE3_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + } + if (data_mask & MAP_TEXCOORD2) + { //substitute tex coord 0 for tex coord 2 + glClientActiveTextureARB(GL_TEXTURE2_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); } - else if (data_mask & LLVertexBuffer::MAP_TEXCOORD1) + if (data_mask & MAP_TEXCOORD1) { - LLVertexBuffer::setupVertexBuffer(data_mask); + glClientActiveTextureARB(GL_TEXTURE1_ARB); + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); } - else + if (data_mask & MAP_BINORMAL) { - LLVertexBuffer::setupVertexBuffer(data_mask); + glClientActiveTextureARB(GL_TEXTURE2_ARB); + glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); + glClientActiveTextureARB(GL_TEXTURE0_ARB); } - llglassertok(); - }*/ + if (data_mask & MAP_TEXCOORD0) + { + glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); + } + if (data_mask & MAP_COLOR) + { + glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeOffsets[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); + } + + if (data_mask & MAP_WEIGHT) + { + glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT])); + } + + if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1) + { + glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4])); + } + + if (data_mask & MAP_CLOTHWEIGHT) + { + glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeOffsets[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT])); + } + if (data_mask & MAP_VERTEX) + { + glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_VERTEX], (void*)(base + 0)); + } + } }; //============================================================================ @@ -945,7 +995,13 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect //step one meter at a time until intersection point found - const LLVector3* ext = mDrawable->getSpatialExtents(); + //VECTORIZE THIS + const LLVector4a* exta = mDrawable->getSpatialExtents(); + + LLVector3 ext[2]; + ext[0].set(exta[0].getF32()); + ext[1].set(exta[1].getF32()); + F32 rad = (delta*tdelta).magVecSquared(); F32 t = 0.f; @@ -1007,13 +1063,16 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect return FALSE; } -void LLVOSurfacePatch::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax) +void LLVOSurfacePatch::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { LLVector3 posAgent = getPositionAgent(); LLVector3 scale = getScale(); - newMin = posAgent-scale*0.5f; // Changing to 2.f makes the culling a -little- better, but still wrong - newMax = posAgent+scale*0.5f; - mDrawable->setPositionGroup((newMin+newMax)*0.5f); + newMin.load3( (posAgent-scale*0.5f).mV); // Changing to 2.f makes the culling a -little- better, but still wrong + newMax.load3( (posAgent+scale*0.5f).mV); + LLVector4a pos; + pos.setAdd(newMin,newMax); + pos.mul(0.5f); + mDrawable->setPositionGroup(pos); } U32 LLVOSurfacePatch::getPartitionType() const diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h index 10a5888526..15442e1947 100644 --- a/indra/newview/llvosurfacepatch.h +++ b/indra/newview/llvosurfacepatch.h @@ -78,7 +78,7 @@ public: /*virtual*/ void updateTextures(); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area - /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax); + /*virtual*/ void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. void setPatch(LLSurfacePatch *patchp); diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp index 428ef20006..339da3c0bf 100644 --- a/indra/newview/llvotextbubble.cpp +++ b/indra/newview/llvotextbubble.cpp @@ -45,6 +45,7 @@ #include "llviewertexturelist.h" #include "llvolume.h" #include "pipeline.h" +#include "llvector4a.h" #include "llviewerregion.h" LLVOTextBubble::LLVOTextBubble(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) @@ -217,7 +218,7 @@ void LLVOTextBubble::updateFaceSize(S32 idx) else { const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); - face->setSize(vol_face.mVertices.size(), vol_face.mIndices.size()); + face->setSize(vol_face.mNumVertices, vol_face.mNumIndices); } } @@ -235,19 +236,37 @@ void LLVOTextBubble::getGeometry(S32 idx, const LLVolumeFace& face = getVolume()->getVolumeFace(idx); - LLVector3 pos = getPositionAgent(); + LLVector4a pos; + pos.load3(getPositionAgent().mV); + + LLVector4a scale; + scale.load3(getScale().mV); + LLColor4U color = LLColor4U(getTE(idx)->getColor()); U32 offset = mDrawable->getFace(idx)->getGeomIndex(); - for (U32 i = 0; i < face.mVertices.size(); i++) + LLVector4a* dst_pos = (LLVector4a*) verticesp.get(); + LLVector4a* src_pos = (LLVector4a*) face.mPositions; + + LLVector4a* dst_norm = (LLVector4a*) normalsp.get(); + LLVector4a* src_norm = (LLVector4a*) face.mNormals; + + LLVector2* dst_tc = (LLVector2*) texcoordsp.get(); + LLVector2* src_tc = (LLVector2*) face.mTexCoords; + + LLVector4a::memcpyNonAliased16((F32*) dst_norm, (F32*) src_norm, face.mNumVertices*4); + LLVector4a::memcpyNonAliased16((F32*) dst_tc, (F32*) src_tc, face.mNumVertices*2); + + + for (U32 i = 0; i < face.mNumVertices; i++) { - *verticesp++ = face.mVertices[i].mPosition.scaledVec(getScale()) + pos; - *normalsp++ = face.mVertices[i].mNormal; - *texcoordsp++ = face.mVertices[i].mTexCoord; + LLVector4a t; + t.setMul(src_pos[i], scale); + dst_pos[i].setAdd(t, pos); *colorsp++ = color; } - for (U32 i = 0; i < face.mIndices.size(); i++) + for (U32 i = 0; i < face.mNumIndices; i++) { *indicesp++ = face.mIndices[i] + offset; } diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 5431aec07c..eb790b04cc 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -1247,7 +1247,7 @@ void LLVOTree::updateRadius() mDrawable->setRadius(32.0f); } -void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) +void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { F32 radius = getScale().length()*0.05f; LLVector3 center = getRenderPosition(); @@ -1257,9 +1257,11 @@ void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) center += LLVector3(0, 0, size.mV[2]) * getRotation(); - newMin.set(center-size); - newMax.set(center+size); - mDrawable->setPositionGroup(center); + newMin.load3((center-size).mV); + newMax.load3((center+size).mV); + LLVector4a pos; + pos.load3(center.mV); + mDrawable->setPositionGroup(pos); } BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp, @@ -1272,8 +1274,13 @@ BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end return FALSE; } - const LLVector3* ext = mDrawable->getSpatialExtents(); + const LLVector4a* exta = mDrawable->getSpatialExtents(); + //VECTORIZE THIS + LLVector3 ext[2]; + ext[0].set(exta[0].getF32()); + ext[1].set(exta[1].getF32()); + LLVector3 center = (ext[1]+ext[0])*0.5f; LLVector3 size = (ext[1]-ext[0]); diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h index 036ad692b1..104226fcb6 100644 --- a/indra/newview/llvotree.h +++ b/indra/newview/llvotree.h @@ -73,7 +73,7 @@ public: /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); - /*virtual*/ void updateSpatialExtents(LLVector3 &min, LLVector3 &max); + /*virtual*/ void updateSpatialExtents(LLVector4a &min, LLVector4a &max); virtual U32 getPartitionType() const; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 5644e02134..4faef57074 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -36,6 +36,8 @@ #include "llvovolume.h" +#include <sstream> + #include "llviewercontrol.h" #include "lldir.h" #include "llflexibleobject.h" @@ -50,6 +52,7 @@ #include "object_flags.h" #include "llagentconstants.h" #include "lldrawable.h" +#include "lldrawpoolavatar.h" #include "lldrawpoolbump.h" #include "llface.h" #include "llspatialpartition.h" @@ -57,8 +60,10 @@ #include "llflexibleobject.h" #include "llsky.h" #include "lltexturefetch.h" +#include "llvector4a.h" #include "llviewercamera.h" #include "llviewertexturelist.h" +#include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewertextureanim.h" #include "llworld.h" @@ -67,8 +72,11 @@ #include "llsdutil.h" #include "llmediaentry.h" #include "llmediadataclient.h" +#include "llmeshrepository.h" #include "llagent.h" #include "llviewermediafocus.h" +#include "llvoavatar.h" + const S32 MIN_QUIET_FRAMES_COALESCE = 30; const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; @@ -88,6 +96,12 @@ LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles"); static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes"); +static LLFastTimer::DeclareTimer FTM_BUILD_MESH("Mesh"); +static LLFastTimer::DeclareTimer FTM_MESH_VFS("VFS"); +static LLFastTimer::DeclareTimer FTM_MESH_STREAM("Stream"); +static LLFastTimer::DeclareTimer FTM_MESH_FACES("Faces"); +static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures"); + // Implementation class of LLMediaDataClientObject. See llmediadataclient.h class LLMediaDataClientObjectImpl : public LLMediaDataClientObject @@ -653,6 +667,7 @@ void LLVOVolume::updateTextures() void LLVOVolume::updateTextureVirtualSize() { + LLFastTimer ftm(FTM_VOLUME_TEXTURES); // Update the pixel area of all faces if(mDrawable.isNull() || !mDrawable->isVisible()) @@ -686,7 +701,7 @@ void LLVOVolume::updateTextureVirtualSize() const LLTextureEntry *te = face->getTextureEntry(); LLViewerTexture *imagep = face->getTexture(); if (!imagep || !te || - face->mExtents[0] == face->mExtents[1]) + face->mExtents[0].equal3(face->mExtents[1])) { continue; } @@ -745,10 +760,12 @@ void LLVOVolume::updateTextureVirtualSize() if (isSculpted()) { LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID id = sculpt_params->getSculptTexture(); + LLUUID id = sculpt_params->getSculptTexture(); updateSculptTexture(); + + if (mSculptTexture.notNull()) { mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), @@ -789,6 +806,7 @@ void LLVOVolume::updateTextureVirtualSize() mSculptTexture->getHeight(), mSculptTexture->getWidth())); } } + } if (getLightTextureID().notNull()) @@ -804,7 +822,7 @@ void LLVOVolume::updateTextureVirtualSize() *camera)); } } - + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) { setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); @@ -900,8 +918,36 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) return mDrawable; } -BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume) +BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms, const S32 detail, bool unique_volume) { + LLVolumeParams volume_params = params; + + S32 lod = mLOD; + + BOOL is404 = FALSE; + +#if LL_MESH_ENABLED + if (isSculpted()) + { + // if it's a mesh + if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + { //meshes might not have all LODs, get the force detail to best existing LOD + + LLUUID mesh_id = params.getSculptID(); + + //profile and path params don't matter for meshes + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + lod = gMeshRepo.getActualMeshLOD(volume_params, lod); + if (lod == -1) + { + is404 = TRUE; + lod = 0; + } + } + } +#endif + // Check if we need to change implementations bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE); if (is_flexible) @@ -929,24 +975,48 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail } } - if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged) + if (is404) + { + setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI)); + } + + if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged) { mFaceMappingChanged = TRUE; if (mVolumeImpl) { - mVolumeImpl->onSetVolume(volume_params, detail); + mVolumeImpl->onSetVolume(volume_params, mLOD); } updateSculptTexture(); + if (isSculpted()) { updateSculptTexture(); - - if (mSculptTexture.notNull()) +#if LL_MESH_ENABLED + // if it's a mesh + if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { - sculpt(); + if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron()) + { + //load request not yet issued, request pipeline load this mesh + LLUUID asset_id = volume_params.getSculptID(); + S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod); + if (available_lod != lod) + { + LLPrimitive::setVolume(volume_params, available_lod); + } + } + } + else // otherwise is sculptie +#endif + { + if (mSculptTexture.notNull()) + { + sculpt(); + } } } @@ -959,7 +1029,7 @@ void LLVOVolume::updateSculptTexture() { LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture; - if (isSculpted()) + if (isSculpted() && !isMesh()) { LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); LLUUID id = sculpt_params->getSculptTexture(); @@ -987,6 +1057,15 @@ void LLVOVolume::updateSculptTexture() } + + +void LLVOVolume::notifyMeshLoaded() +{ + mSculptChanged = TRUE; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); + dirtySpatialGroup(TRUE); +} + // sculpt replaces generate() for sculpted surfaces void LLVOVolume::sculpt() { @@ -1173,6 +1252,11 @@ void LLVOVolume::updateFaceFlags() for (S32 i = 0; i < getVolume()->getNumFaces(); i++) { LLFace *face = mDrawable->getFace(i); + if (!face) + { + return; + } + BOOL fullbright = getTE(i)->getFullbright(); face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); @@ -1252,13 +1336,17 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) { BOOL res = TRUE; - LLVector3 min,max; + LLVector4a min,max; BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION); - for (S32 i = 0; i < getVolume()->getNumFaces(); i++) + for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++) { LLFace *face = mDrawable->getFace(i); + if (!face) + { + continue; + } res &= face->genVolumeBBoxes(*getVolume(), i, mRelativeXform, mRelativeXformInvTrans, (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); @@ -1272,17 +1360,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) } else { - for (U32 i = 0; i < 3; i++) - { - if (face->mExtents[0].mV[i] < min.mV[i]) - { - min.mV[i] = face->mExtents[0].mV[i]; - } - if (face->mExtents[1].mV[i] > max.mV[i]) - { - max.mV[i] = face->mExtents[1].mV[i]; - } - } + min.setMin(face->mExtents[0]); + max.setMax(face->mExtents[1]); } } } @@ -1290,7 +1369,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) if (rebuild) { mDrawable->setSpatialExtents(min,max); - mDrawable->setPositionGroup((min+max)*0.5f); + min.add(max); + min.mul(0.5f); + mDrawable->setPositionGroup(min); } updateRadius(); @@ -1513,19 +1594,14 @@ void LLVOVolume::updateFaceSize(S32 idx) LLFace* facep = mDrawable->getFace(idx); if (idx >= getVolume()->getNumVolumeFaces()) { - facep->setSize(0,0); + facep->setSize(0,0, true); } else { const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); - if (LLPipeline::sUseTriStrips) - { - facep->setSize(vol_face.mVertices.size(), vol_face.mTriStrip.size()); - } - else - { - facep->setSize(vol_face.mVertices.size(), vol_face.mIndices.size()); - } + facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, + true); // <--- volume faces should be padded for 16-byte alignment + } } @@ -1780,21 +1856,25 @@ bool LLVOVolume::hasMedia() const LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id) { LLVolume* volume = getVolume(); - LLVector3 result; + LLVector4a result; + result.clear(); + + LLVector3 ret; if (volume && face_id < volume->getNumVolumeFaces()) { const LLVolumeFace& face = volume->getVolumeFace(face_id); - for (S32 i = 0; i < (S32)face.mVertices.size(); ++i) + for (S32 i = 0; i < (S32)face.mNumVertices; ++i) { - result += face.mVertices[i].mNormal; + result.add(face.mNormals[i]); } - result = volumeDirectionToAgent(result); - result.normVec(); + LLVector3 ret((F32*) &result.mQ); + ret = volumeDirectionToAgent(ret); + ret.normVec(); } - return result; + return ret; } void LLVOVolume::requestMediaDataUpdate(bool isNew) @@ -2581,6 +2661,26 @@ BOOL LLVOVolume::isSculpted() const return FALSE; } +BOOL LLVOVolume::isMesh() const +{ +#if LL_MESH_ENABLED + if (isSculpted()) + { + LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + U8 sculpt_type = sculpt_params->getSculptType(); + + if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + // mesh is a mesh + { + return TRUE; + } + } +#endif + + + return FALSE; +} + BOOL LLVOVolume::hasLightTexture() const { if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) @@ -2911,7 +3011,7 @@ void LLVOVolume::setSelected(BOOL sel) } } -void LLVOVolume::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) +void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { } @@ -2919,7 +3019,33 @@ F32 LLVOVolume::getBinRadius() { F32 radius; - const LLVector3* ext = mDrawable->getSpatialExtents(); + F32 scale = 1.f; + +#if LL_MESH_ENABLED + if (isSculpted()) + { + LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLUUID id = sculpt_params->getSculptTexture(); + U8 sculpt_type = sculpt_params->getSculptType(); + + if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + // mesh is a mesh + { + LLVolume* volume = getVolume(); + U32 vert_count = 0; + + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + vert_count += face.mNumVertices; + } + + scale = 1.f/llmax(vert_count/1024.f, 1.f); + } + } +#endif + + const LLVector4a* ext = mDrawable->getSpatialExtents(); BOOL shrink_wrap = mDrawable->isAnimating(); BOOL alpha_wrap = FALSE; @@ -2951,7 +3077,10 @@ F32 LLVOVolume::getBinRadius() } else if (shrink_wrap) { - radius = (ext[1]-ext[0]).length()*0.5f; + LLVector4a rad; + rad.setSub(ext[1], ext[0]); + + radius = rad.length3()*0.5f; } else if (mDrawable->isStatic()) { @@ -2975,7 +3104,7 @@ F32 LLVOVolume::getBinRadius() radius = 8.f; } - return llclamp(radius, 0.5f, 256.f); + return llclamp(radius*scale, 0.5f, 256.f); } const LLVector3 LLVOVolume::getPivotPositionAgent() const @@ -2987,7 +3116,7 @@ const LLVector3 LLVOVolume::getPivotPositionAgent() const return LLViewerObject::getPivotPositionAgent(); } -void LLVOVolume::onShift(const LLVector3 &shift_vector) +void LLVOVolume::onShift(const LLVector4a &shift_vector) { if (mVolumeImpl) { @@ -3234,7 +3363,6 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, model_mat = &(drawable->getRegion()->mRenderMatrix); } - U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0; LLViewerTexture* tex = facep->getTexture(); @@ -3263,7 +3391,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec[idx]->mCount += facep->getIndicesCount(); draw_vec[idx]->mEnd += facep->getGeomCount(); draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize()); - validate_draw_info(*draw_vec[idx]); + draw_vec[idx]->validate(); update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]); update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]); } @@ -3287,12 +3415,13 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } draw_info->mExtents[0] = facep->mExtents[0]; draw_info->mExtents[1] = facep->mExtents[1]; - validate_draw_info(*draw_info); if (LLPipeline::sUseTriStrips) { draw_info->mDrawMode = LLRender::TRIANGLE_STRIP; } + + draw_info->validate(); } } @@ -3304,6 +3433,34 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume"); static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); +#if LL_MESH_ENABLED +static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) +{ + LLVOAvatar* avatar = vobj->getAvatar(); + + if (avatar) + { + LLDrawable* drawable = avatar->mDrawable; + if (drawable && drawable->getNumFaces() > 0) + { + LLFace* face = drawable->getFace(0); + if (face) + { + LLDrawPool* drawpool = face->getPool(); + if (drawpool) + { + if (drawpool->getType() == LLDrawPool::POOL_AVATAR) + { + return (LLDrawPoolAvatar*) drawpool; + } + } + } + } + } + + return NULL; +} +#endif void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { @@ -3370,6 +3527,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) drawablep->clearState(LLDrawable::HAS_ALPHA); +#if LL_MESH_ENABLED + bool rigged = vobj->isAttachment() && + vobj->isMesh() && + gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID()); +#endif + + bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); + //for each face for (S32 i = 0; i < drawablep->getNumFaces(); i++) { @@ -3377,6 +3542,105 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) drawablep->updateFaceSize(i); LLFace* facep = drawablep->getFace(i); +#if LL_MESH_ENABLED + if (rigged) + { + if (!facep->isState(LLFace::RIGGED)) + { + facep->mVertexBuffer = NULL; + facep->mLastVertexBuffer = NULL; + facep->setState(LLFace::RIGGED); + + //get drawpool of avatar with rigged face + LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); + + if (pool) + { + const LLTextureEntry* te = facep->getTextureEntry(); + + //remove face from old pool if it exists + LLDrawPool* old_pool = facep->getPool(); + if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR) + { + ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); + } + + //add face to new pool + LLViewerTexture* tex = facep->getTexture(); + U32 type = gPipeline.getPoolTypeFromTE(te, tex); + + if (type == LLDrawPool::POOL_ALPHA) + { + if (te->getFullbright()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); + } + } + else if (te->getShiny()) + { + if (te->getFullbright()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); + } + } + else + { + if (te->getFullbright()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + } + } + + if (te->getGlow()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); + } + + if (LLPipeline::sRenderDeferred) + { + if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) + { + if (te->getBumpmap()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); + } + } + } + } + } + + continue; + } + else + { + if (facep->isState(LLFace::RIGGED)) + { //face is not rigged but used to be, remove from rigged face pool + LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); + if (pool) + { + pool->removeRiggedFace(facep); + } + facep->clearState(LLFace::RIGGED); + } + } +#endif + if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) { facep->mVertexBuffer = NULL; @@ -3471,7 +3735,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bump_faces.push_back(facep); } else if ((te->getShiny() && LLPipeline::sRenderBump) || - !te->getFullbright()) + !(te->getFullbright() || bake_sunlight)) { //needs normal simple_faces.push_back(facep); } @@ -3567,6 +3831,11 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) face->getGeometryVolume(*volume, face->getTEOffset(), vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()); } + + if (!face) + { + llerrs << "WTF?" << llendl; + } } drawablep->clearState(LLDrawable::REBUILD_ALL); @@ -3676,6 +3945,8 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: buffer_index = 0; } + bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic(); + U32 index_count = facep->getIndicesCount(); U32 geom_count = facep->getGeomCount(); @@ -3781,7 +4052,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: // can we safely treat this as an alpha mask? if (facep->canRenderAsMask()) { - if (te->getFullbright()) + if (te->getFullbright() || LLPipeline::sNoAlpha) { registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); } @@ -3845,7 +4116,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: { //invisiprim registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); } - else if (fullbright) + else if (fullbright || bake_sunlight) { //fullbright registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap()) @@ -3959,7 +4230,7 @@ LLHUDPartition::LLHUDPartition() mLODPeriod = 1; } -void LLHUDPartition::shift(const LLVector3 &offset) +void LLHUDPartition::shift(const LLVector4a &offset) { //HUD objects don't shift with region crossing. That would be silly. } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index fbae011ffc..d5606034d0 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -66,7 +66,7 @@ public: virtual void onSetVolume(const LLVolumeParams &volume_params, const S32 detail) = 0; virtual void onSetScale(const LLVector3 &scale, BOOL damped) = 0; virtual void onParameterChanged(U16 param_type, LLNetworkData *data, BOOL in_use, bool local_origin) = 0; - virtual void onShift(const LLVector3 &shift_vector) = 0; + virtual void onShift(const LLVector4a &shift_vector) = 0; virtual bool isVolumeUnique() const = 0; // Do we need a unique LLVolume instance? virtual bool isVolumeGlobal() const = 0; // Are we in global space? virtual bool isActive() const = 0; // Is this object currently active? @@ -145,7 +145,7 @@ public: void markForUpdate(BOOL priority) { LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; } - /*virtual*/ void onShift(const LLVector3 &shift_vector); // Called when the drawable shifts + /*virtual*/ void onShift(const LLVector4a &shift_vector); // Called when the drawable shifts /*virtual*/ void parameterChanged(U16 param_type, bool local_origin); /*virtual*/ void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin); @@ -184,6 +184,11 @@ public: void updateSculptTexture(); void setIndexInTex(S32 index) { mIndexInTex = index ;} void sculpt(); + static void rebuildMeshAssetCallback(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status); + void updateRelativeXform(); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); /*virtual*/ void updateFaceSize(S32 idx); @@ -196,7 +201,7 @@ public: void regenFaces(); BOOL genBBoxes(BOOL force_global); void preRebuild(); - virtual void updateSpatialExtents(LLVector3& min, LLVector3& max); + virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); virtual F32 getBinRadius(); virtual U32 getPartitionType() const; @@ -230,6 +235,7 @@ public: U32 getVolumeInterfaceID() const; virtual BOOL isFlexible() const; virtual BOOL isSculpted() const; + virtual BOOL isMesh() const; virtual BOOL hasLightTexture() const; BOOL isVolumeGlobal() const; @@ -254,6 +260,7 @@ public: void mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location); void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event); + // Sync the given media data with the impl and the given te void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent); @@ -269,9 +276,11 @@ public: LLVector3 getApproximateFaceNormal(U8 face_id); + void notifyMeshLoaded(); + // Returns 'true' iff the media data for this object is in flight bool isMediaDataBeingFetched() const; - + // Returns the "last fetched" media version, or -1 if not fetched yet S32 getLastFetchedMediaVersion() const { return mLastFetchedMediaVersion; } diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index a8c4625f6e..7c1b22d432 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -258,15 +258,21 @@ void LLVOWater::setIsEdgePatch(const BOOL edge_patch) mIsEdgePatch = edge_patch; } -void LLVOWater::updateSpatialExtents(LLVector3 &newMin, LLVector3& newMax) +void LLVOWater::updateSpatialExtents(LLVector4a &newMin, LLVector4a& newMax) { - LLVector3 pos = getPositionAgent(); - LLVector3 scale = getScale(); - - newMin = pos - scale * 0.5f; - newMax = pos + scale * 0.5f; + LLVector4a pos; + pos.load3(getPositionAgent().mV); + LLVector4a scale; + scale.load3(getScale().mV); + scale.mul(0.5f); + + newMin.setSub(pos, scale); + newMax.setAdd(pos, scale); + + pos.setAdd(newMin,newMax); + pos.mul(0.5f); - mDrawable->setPositionGroup((newMin + newMax) * 0.5f); + mDrawable->setPositionGroup(pos); } U32 LLVOWater::getPartitionType() const diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h index 3cc031e589..a868afe58b 100644 --- a/indra/newview/llvowater.h +++ b/indra/newview/llvowater.h @@ -66,7 +66,7 @@ public: /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); - /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax); + /*virtual*/ void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); /*virtual*/ void updateTextures(); /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 1dc46a4012..fec7da1dd0 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -71,6 +71,7 @@ #include "llgldbg.h" #include "llhudmanager.h" #include "lllightconstants.h" +#include "llmeshrepository.h" #include "llresmgr.h" #include "llselectmgr.h" #include "llsky.h" @@ -104,6 +105,7 @@ #include "llspatialpartition.h" #include "llmutelist.h" #include "lltoolpie.h" +#include "llcurl.h" #ifdef _DEBUG @@ -273,6 +275,8 @@ BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE; BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE; BOOL LLPipeline::sDisableShaders = FALSE; BOOL LLPipeline::sRenderBump = TRUE; +BOOL LLPipeline::sBakeSunlight = FALSE; +BOOL LLPipeline::sNoAlpha = FALSE; BOOL LLPipeline::sUseTriStrips = TRUE; BOOL LLPipeline::sUseFarClip = TRUE; BOOL LLPipeline::sShadowRender = FALSE; @@ -1159,9 +1163,15 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj) } +static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set"); +static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); + void LLPipeline::unlinkDrawable(LLDrawable *drawable) { - LLFastTimer t(FTM_PIPELINE); + LLFastTimer t(FTM_UNLINK); assertInitialized(); @@ -1170,6 +1180,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) // Based on flags, remove the drawable from the queues that it's on. if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) { + LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST); LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); if (iter != mMovedList.end()) { @@ -1179,6 +1190,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) if (drawablep->getSpatialGroup()) { + LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION); if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup())) { #ifdef LL_RELEASE_FOR_DOWNLOAD @@ -1189,18 +1201,23 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) } } - mLights.erase(drawablep); - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); iter++) { - if (iter->drawable == drawablep) + LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET); + mLights.erase(drawablep); + + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); iter++) { - mNearbyLights.erase(iter); - break; + if (iter->drawable == drawablep) + { + mNearbyLights.erase(iter); + break; + } } } { + LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET); HighlightItem item(drawablep); mHighlightSet.erase(item); @@ -1497,11 +1514,214 @@ F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera return radius*radius * F_PI; } +//static +F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera) +{ + LLVector4a origin; + origin.load3(camera.getOrigin().mV); + + LLVector4a lookAt; + lookAt.setSub(center, origin); + F32 dist = lookAt.length3(); + + //ramp down distance for nearby objects + //shrink dist by dist/16. + if (dist < 16.f) + { + dist /= 16.f; + dist *= dist; + dist *= 16.f; + } + + //get area of circle around node + F32 app_angle = atanf(size.length3()/dist); + F32 radius = app_angle*LLDrawable::sCurPixelAngle; + return radius*radius * F_PI; +} + void LLPipeline::grabReferences(LLCullResult& result) { sCull = &result; } +void LLPipeline::clearReferences() +{ + sCull = NULL; +} + +void check_references(LLSpatialGroup* group, LLDrawable* drawable) +{ + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + if (drawable == *i) + { + llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl; + } + } +} + +void check_references(LLDrawable* drawable, LLFace* face) +{ + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + if (drawable->getFace(i) == face) + { + llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl; + } + } +} + +void check_references(LLSpatialGroup* group, LLFace* face) +{ + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawable = *i; + check_references(drawable, face); + } +} + +void LLPipeline::checkReferences(LLFace* face) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, face); + } + + for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) + { + LLDrawable* drawable = *iter; + check_references(drawable, face); + } + } +#endif +} + +void LLPipeline::checkReferences(LLDrawable* drawable) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, drawable); + } + + for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) + { + if (drawable == *iter) + { + llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl; + } + } + } +#endif +} + +void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info) +{ + for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) + { + LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; + for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) + { + LLDrawInfo* params = *j; + if (params == draw_info) + { + llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl; + } + } + } +} + + +void LLPipeline::checkReferences(LLDrawInfo* draw_info) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + check_references(group, draw_info); + } + } +#endif +} + +void LLPipeline::checkReferences(LLSpatialGroup* group) +{ +#if 0 + if (sCull) + { + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + { + if (group == *iter) + { + llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + } + } + } +#endif +} + + BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera) { for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); @@ -1703,7 +1923,7 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) } if (sMinRenderSize > 0.f && - llmax(llmax(group->mBounds[1].mV[0], group->mBounds[1].mV[1]), group->mBounds[1].mV[2]) < sMinRenderSize) + llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize) { return; } @@ -1811,6 +2031,10 @@ void LLPipeline::rebuildPriorityGroups() assertInitialized(); +#if LL_MESH_ENABLED + gMeshRepo.notifyLoadedMeshes(); +#endif + // Iterate through all drawables on the priority build queue, for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin(); iter != mGroupQ1.end(); ++iter) @@ -1821,6 +2045,7 @@ void LLPipeline::rebuildPriorityGroups() } mGroupQ1.clear(); + } void LLPipeline::rebuildGroups() @@ -2086,6 +2311,9 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) glClear(GL_DEPTH_BUFFER_BIT); gDepthDirty = TRUE; + LLVector4a offseta; + offseta.load3(offset.mV); + for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); iter != mShiftList.end(); iter++) { @@ -2094,7 +2322,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) { continue; } - drawablep->shiftPos(offset); + drawablep->shiftPos(offseta); drawablep->clearState(LLDrawable::ON_SHIFT_LIST); } mShiftList.resize(0); @@ -2108,7 +2336,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) LLSpatialPartition* part = region->getSpatialPartition(i); if (part) { - part->shift(offset); + part->shift(offseta); } } } @@ -2641,8 +2869,10 @@ void LLPipeline::postSort(LLCamera& camera) { if (sMinRenderSize > 0.f) { - LLVector3 bounds = (*k)->mExtents[1]-(*k)->mExtents[0]; - if (llmax(llmax(bounds.mV[0], bounds.mV[1]), bounds.mV[2]) > sMinRenderSize) + LLVector4a bounds; + bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]); + + if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize) { sCull->pushDrawInfo(j->first, *k); } @@ -3573,6 +3803,65 @@ void LLPipeline::renderDebug() } } + if (gSavedSettings.getBOOL("DebugShowUploadCost")) + { + std::set<LLUUID> textures; + std::set<LLUUID> sculpts; + std::set<LLUUID> meshes; + + BOOL selected = TRUE; + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + selected = FALSE; + } + + for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + { + LLSpatialGroup* group = *iter; + LLSpatialGroup::OctreeNode* node = group->mOctreeNode; + for (LLSpatialGroup::OctreeNode::element_iter elem = node->getData().begin(); elem != node->getData().end(); ++elem) + { + LLDrawable* drawable = *elem; + LLVOVolume* volume = drawable->getVOVolume(); + if (volume && volume->isSelected() == selected) + { + for (U32 i = 0; i < volume->getNumTEs(); ++i) + { + LLTextureEntry* te = volume->getTE(i); + textures.insert(te->getID()); + } + + if (volume->isSculpted()) + { + LLUUID sculpt_id = volume->getVolume()->getParams().getSculptID(); + if (volume->isMesh()) + { + meshes.insert(sculpt_id); + } + else + { + sculpts.insert(sculpt_id); + } + } + } + } + } + + gPipeline.mDebugTextureUploadCost = textures.size() * 10; + gPipeline.mDebugSculptUploadCost = sculpts.size()*10; + +#if LL_MESH_ENABLED + U32 mesh_cost = 0; + + for (std::set<LLUUID>::iterator iter = meshes.begin(); iter != meshes.end(); ++iter) + { + mesh_cost += gMeshRepo.getResourceCost(*iter)*10; + } + + gPipeline.mDebugMeshUploadCost = mesh_cost; +#endif + } + for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) { LLSpatialBridge* bridge = *i; @@ -3587,6 +3876,8 @@ void LLPipeline::renderDebug() if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) { + LLVertexBuffer::unbind(); + LLGLEnable blend(GL_BLEND); LLGLDepthTest depth(TRUE, FALSE); LLGLDisable cull(GL_CULL_FACE); @@ -3650,7 +3941,7 @@ void LLPipeline::renderDebug() if (i < 4) { - if (i == 0 || !mShadowFrustPoints[i].empty()) + //if (i == 0 || !mShadowFrustPoints[i].empty()) { //render visible point cloud gGL.flush(); @@ -4409,7 +4700,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) // mNearbyLight (and all light_set_t's) are sorted such that // begin() == the closest light and rbegin() == the farthest light const S32 MAX_LOCAL_LIGHTS = 6; -// LLVector3 cam_pos = gAgentCamera.getCameraPositionAgent(); +// LLVector3 cam_pos = gAgent.getCameraPositionAgent(); LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ? camera.getOrigin() : gAgent.getPositionAgent(); @@ -4654,8 +4945,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV); glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV); } - - if (isAgentAvatarValid() && + if (gAgentAvatarp && gAgentAvatarp->mSpecialRenderMode == 3) { LLColor4 light_color = LLColor4::white; @@ -5410,6 +5700,8 @@ void LLPipeline::resetVertexBuffers() sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); + sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight"); + sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha"); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -6686,8 +6978,9 @@ void LLPipeline::renderDeferredLighting() } - LLVector3 center = drawablep->getPositionAgent(); - F32* c = center.mV; + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32* c = center.getF32(); F32 s = volume->getLightRadius()*1.5f; LLColor3 col = volume->getLightColor(); @@ -6703,7 +6996,9 @@ void LLPipeline::renderDeferredLighting() continue; } - if (camera->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0) + LLVector4a sa; + sa.splat(s); + if (camera->AABBInFrustumNoFarClip(center, sa) == 0) { continue; } @@ -6781,8 +7076,9 @@ void LLPipeline::renderDeferredLighting() LLVOVolume* volume = drawablep->getVOVolume(); - LLVector3 center = drawablep->getPositionAgent(); - F32* c = center.mV; + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32* c = center.getF32(); F32 s = volume->getLightRadius()*1.5f; sVisibleLightCount++; @@ -7349,7 +7645,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) LLGLDisable cull(GL_CULL_FACE); updateCull(camera, ref_result, 1); stateSort(camera, ref_result); - } + } if (LLDrawPoolWater::sNeedsDistortionUpdate) { @@ -7710,7 +8006,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector 0,1, 1,2, 2,3, - 3,1, + 3,0, 4,5, 5,6, @@ -8110,6 +8406,14 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist"); //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; + //put together a universal "near clip" plane for shadow frusta + LLPlane shadow_near_clip; + { + LLVector3 p = gAgent.getPositionAgent(); + p += mSunDir * gSavedSettings.getF32("RenderFarClip")*2.f; + shadow_near_clip.setVec(p, mSunDir); + } + LLVector3 lightDir = -mSunDir; lightDir.normVec(); @@ -8544,7 +8848,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); - shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); + //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); + shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip); //translate and scale to from [-1, 1] to [0, 1] glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, @@ -8855,7 +9160,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) stateSort(*LLViewerCamera::getInstance(), result); - const LLVector3* ext = avatar->mDrawable->getSpatialExtents(); + const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); LLCamera camera = *viewer_camera; @@ -8864,18 +9169,23 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) LLVector2 tdim; - LLVector3 half_height = (ext[1]-ext[0])*0.5f; - LLVector3 left = camera.getLeftAxis(); - left *= left; - left.normalize(); + LLVector4a half_height; + half_height.setSub(ext[1], ext[0]); + half_height.mul(0.5f); + + LLVector4a left; + left.load3(camera.getLeftAxis().mV); + left.mul(left); + left.normalize3fast(); - LLVector3 up = camera.getUpAxis(); - up *= up; - up.normalize(); + LLVector4a up; + up.load3(camera.getUpAxis().mV); + up.mul(up); + up.normalize3fast(); - tdim.mV[0] = fabsf(half_height * left); - tdim.mV[1] = fabsf(half_height * up); + tdim.mV[0] = fabsf(half_height.dot3(left)); + tdim.mV[1] = fabsf(half_height.dot3(up)); glMatrixMode(GL_PROJECTION); glPushMatrix(); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 8e6390012a..56c64b190b 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -45,6 +45,9 @@ #include "llgl.h" #include "lldrawable.h" #include "llrendertarget.h" +#include "llmodel.h" //for LL_MESH_ENaBLED + +#include <stack> #include <stack> @@ -60,6 +63,11 @@ class LLCubeMap; class LLCullResult; class LLVOAvatar; class LLGLSLShader; +class LLCurlRequest; + +#if LL_MESH_ENABLED +class LLMeshResponder; +#endif typedef enum e_avatar_skinning_method { @@ -215,6 +223,7 @@ public: //calculate pixel area of given box from vantage point of given camera static F32 calcPixelArea(LLVector3 center, LLVector3 size, LLCamera& camera); + static F32 calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera); void stateSort(LLCamera& camera, LLCullResult& result); void stateSort(LLSpatialGroup* group, LLCamera& camera); @@ -227,6 +236,14 @@ public: void renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture); void grabReferences(LLCullResult& result); + void clearReferences(); + + //check references will assert that there are no references in sCullResult to the provided data + void checkReferences(LLFace* face); + void checkReferences(LLDrawable* drawable); + void checkReferences(LLDrawInfo* draw_info); + void checkReferences(LLSpatialGroup* group); + void renderGeom(LLCamera& camera, BOOL forceVBOUpdate = FALSE); void renderGeomDeferred(LLCamera& camera); @@ -429,6 +446,8 @@ public: RENDER_DEBUG_AVATAR_VOLUME = 0x0100000, RENDER_DEBUG_BUILD_QUEUE = 0x0200000, RENDER_DEBUG_AGENT_TARGET = 0x0400000, + RENDER_DEBUG_PHYSICS_SHAPES = 0x0800000, + RENDER_DEBUG_NORMALS = 0x1000000, }; public: @@ -451,6 +470,12 @@ public: S32 mNumVisibleNodes; S32 mVerticesRelit; + S32 mDebugTextureUploadCost; + S32 mDebugSculptUploadCost; +#if LL_MESH_ENABLED + S32 mDebugMeshUploadCost; +#endif + S32 mLightingChanges; S32 mGeometryChanges; @@ -466,6 +491,8 @@ public: static BOOL sAutoMaskAlphaNonDeferred; static BOOL sDisableShaders; // if TRUE, rendering will be done without shaders static BOOL sRenderBump; + static BOOL sBakeSunlight; + static BOOL sNoAlpha; static BOOL sUseTriStrips; static BOOL sUseFarClip; static BOOL sShadowRender; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 082b37d80b..9ebb7dc76c 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -208,6 +208,7 @@ with the same filename but different name <texture name="Inv_LostClosed" file_name="icons/Inv_LostClosed.png" preload="false" /> <texture name="Inv_LostOpen" file_name="icons/Inv_LostOpen.png" preload="false" /> <texture name="Inv_Landmark" file_name="icons/Inv_Landmark.png" preload="false" /> + <texture name="Inv_Mesh" file_name="icons/Inv_Mesh.png" preload="false" /> <texture name="Inv_Notecard" file_name="icons/Inv_Notecard.png" preload="false" /> <texture name="Inv_Object" file_name="icons/Inv_Object.png" preload="false" /> <texture name="Inv_Object_Multi" file_name="icons/Inv_Object_Multi.png" preload="false" /> @@ -607,6 +608,8 @@ with the same filename but different name <texture name="icon_for_sale.tga" file_name="icons/Icon_For_Sale.png" /> <texture name="icon_top_pick.tga" /> + <texture name="inv_folder_mesh.tga"/> + <texture name="inv_item_mesh.tga"/> <texture name="lag_status_critical.tga" /> <texture name="lag_status_good.tga" /> <texture name="lag_status_warning.tga" /> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index b5be03346e..860cff6664 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -139,17 +139,20 @@ Thank you to the following Residents for helping to ensure that this is the best word_wrap="true"> 3Dconnexion SDK Copyright (C) 1992-2007 3Dconnexion APR Copyright (C) 2000-2004 The Apache Software Foundation + Collada DOM Copyright 2005 Sony Computer Entertainment Inc. cURL Copyright (C) 1996-2002, Daniel Stenberg, (daniel@haxx.se) DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc. expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org). GL Copyright (C) 1999-2004 Brian Paul. + GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) jpeglib Copyright (C) 1991-1998, Thomas G. Lane. ogg/vorbis Copyright (C) 2001, Xiphophorus OpenSSL Copyright (C) 1998-2002 The OpenSSL Project. + PCRE Copyright (c) 1997-2008 University of Cambridge Pth Copyright (C) 1999-2006 Ralf S. Engelschall <rse@gnu.org> SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) @@ -157,10 +160,12 @@ xmlrpc-epi Copyright (C) 2000 Epinions, Inc. zlib Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler. google-perftools Copyright (c) 2005, Google Inc. +Second Life Viewer uses Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (and its Licensors). All Rights Reserved. See www.havok.com for details. + All rights reserved. See licenses.txt for details. Voice chat Audio coding: Polycom(R) Siren14(TM) (ITU-T Rec. G.722.1 Annex C) - </text_editor> + </text_editor> </panel> </tab_container> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml index 90fee857fb..388825d31a 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml @@ -104,6 +104,23 @@ width="16" /> <check_box height="16" + label="Meshes" + layout="topleft" + left_pad="2" + name="check_mesh" + top_delta="0" + width="126" /> + <icon + height="16" + image_name="Inv_Mesh" + layout="topleft" + left="8" + mouse_opaque="true" + name="icon_mesh" + top="142" + width="16" /> + <check_box + height="16" label="Notecards" layout="topleft" left_pad="2" @@ -117,7 +134,7 @@ left="8" mouse_opaque="true" name="icon_object" - top="142" + top="162" width="16" /> <check_box height="16" @@ -134,7 +151,7 @@ left="8" mouse_opaque="true" name="icon_script" - top="162" + top="182" width="16" /> <check_box height="16" @@ -151,7 +168,7 @@ left="8" mouse_opaque="true" name="icon_sound" - top="182" + top="202" width="16" /> <check_box height="16" @@ -168,7 +185,7 @@ left="8" mouse_opaque="true" name="icon_texture" - top="202" + top="222" width="16" /> <check_box height="16" @@ -185,7 +202,7 @@ left="8" mouse_opaque="true" name="icon_snapshot" - top="222" + top="242" width="16" /> <check_box height="16" @@ -203,7 +220,7 @@ layout="topleft" left="8" name="All" - top="242" + top="262" width="100" /> <button follows="left|top" diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index a96dbe3553..8a6cae9bb1 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2,7 +2,7 @@ <floater legacy_header_height="18" follows="left|top|right" - height="580" + height="780" layout="topleft" bg_opaque_image="Window_NoTitle_Foreground" bg_alpha_image="Window_NoTitle_Background" @@ -750,7 +750,7 @@ </text> <tab_container follows="left|top" - height="410" + height="610" halign="center" left="0" name="Object Info Tabs" @@ -1211,7 +1211,7 @@ even though the user gets a free copy. <panel border="false" follows="all" - height="367" + height="567" label="Object" layout="topleft" left_delta="0" @@ -1426,6 +1426,111 @@ even though the user gets a free copy. text_enabled_color="1 1 1 1" top_pad="3" width="87" /> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left_delta="0" + name="label physicsshapetype" + top_pad="10" + width="121"> + Physics Shape Type: + </text> + <combo_box + height="23" + layout="topleft" + follows="left|top" + name="Physics Shape Type Combo Ctrl" + tool_tip="Choose the physics shape type" + left_pad="0" + width="108"> + <combo_box.item + label="Prim" + name="Prim" + value="Prim" /> + <combo_box.item + label="None" + name="None" + value="None" /> + <combo_box.item + label="Convex Hull" + name="Convex Hull" + value="Convex Hull" /> + </combo_box> + + <spinner + follows="left|top" + height="19" + increment="1" + initial_value="1" + label="Gravity" + label_width="70" + layout="topleft" + left="10" + min_val="-1" + max_val="10" + name="Physics Gravity" + top_pad="10" + width="128" /> + + <check_box + height="19" + label="Override material" + layout="topleft" + left_delta="0" + name="Physics Material Override" + tool_tip="Override Material" + top_pad="10" + width="121" /> + + <spinner + follows="left|top" + height="19" + increment="0.1" + initial_value="0" + label="Friction" + label_width="70" + layout="topleft" + left_delta="0" + max_val="255" + min_val="0" + name="Physics Friction" + top_pad="4" + width="128" /> + + <spinner + follows="left|top" + height="19" + increment="0.1" + initial_value="0" + label="Density" + label_width="70" + layout="topleft" + left_delta="0" + max_val="10" + min_val="0" + name="Physics Density" + top_pad="4" + width="128" /> + + <spinner + follows="left|top" + height="19" + increment="0.01" + initial_value="0" + label="Restitution" + label_width="70" + layout="topleft" + left_delta="0" + max_val="1" + min_val="0" + name="Physics Restitution" + top_pad="4" + width="128" /> + + <!-- <text type="string" diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index ae98abf4fb..e0e6567872 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -42,6 +42,18 @@ <menu_item_call.on_enable function="File.EnableUpload" /> </menu_item_call> + <menu_item_call + label="Model..." + layout="topleft" + name="Upload Model"> + <menu_item_call.on_click + function="File.UploadModel" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUploadModel" /> + <menu_item_call.on_visible + function="File.MeshEnabled"/> + </menu_item_call> <menu_item_call label="Bulk (L$[COST] per file)..." layout="topleft" @@ -231,4 +243,4 @@ parameter="eyes" /> </menu_item_call> </menu> -</menu>
\ No newline at end of file +</menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 67b8c81a01..c95e27155a 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1878,6 +1878,17 @@ function="ToggleControl" parameter="DebugShowTime" /> </menu_item_check> + <menu_item_check + label="Show Upload Cost" + layout="topleft" + name="Show Upload Cost"> + <menu_item_check.on_check + function="CheckControl" + parameter="DebugShowUploadCost" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="DebugShowUploadCost" /> + </menu_item_check> <menu_item_check label="Show Render Info" name="Show Render Info"> @@ -2041,6 +2052,16 @@ parameter="bboxes" /> </menu_item_check> <menu_item_check + label="Normals" + name="Normals"> + <menu_item_check.on_check + function="Advanced.CheckInfoDisplay" + parameter="normals" /> + <menu_item_check.on_click + function="Advanced.ToggleInfoDisplay" + parameter="normals" /> + </menu_item_check> + <menu_item_check label="Octree" name="Octree"> <menu_item_check.on_check @@ -2061,6 +2082,16 @@ parameter="shadow frusta" /> </menu_item_check> <menu_item_check + label="Physics Shapes" + name="Physics Shapes"> + <menu_item_check.on_check + function="Advanced.CheckInfoDisplay" + parameter="physics shapes" /> + <menu_item_check.on_click + function="Advanced.ToggleInfoDisplay" + parameter="physics shapes" /> + </menu_item_check> + <menu_item_check label="Occlusion" name="Occlusion"> <menu_item_check.on_check @@ -3048,6 +3079,16 @@ <menu_item_call.on_click function="Advanced.LeaveAdminStatus" /> </menu_item_call> + <menu_item_call + label="HACK Upload Model..." + layout="topleft" + name="Upload Model"> + <menu_item_call.on_click + function="File.UploadModel" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUploadModel" /> + </menu_item_call> </menu> <menu create_jump_keys="true" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 04bdb4302c..844ad41332 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6145,7 +6145,7 @@ Attachment has been saved. Unable to find the help topic for this element. </notification> - <notification + <notification icon="alertmodal.tga" name="ObjectMediaFailure" type="alertmodal"> @@ -6175,6 +6175,17 @@ Your voice has been muted by moderator. name="okbutton" yestext="OK"/> </notification> + + <notification + icon="alertmodal.tga" + name="UploadCostConfirmation" + type="alertmodal"> +This upload will cost L$[PRICE], do you wish to continue with the upload? + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Upload"/> + </notification> <notification icon="alertmodal.tga" @@ -6201,6 +6212,14 @@ The button will be shown when there is enough space for it. type="notifytip"> Select residents to share with. </notification> + + <notification + name="MeshUploadError" + icon="alert.tga" + type="alert"> + [LABEL] failed to upload: [MESSAGE] [IDENTIFIER] [INVALIDITY_IDENTIFIER] + </notification> + <notification icon="notifytip.tga" name="ShareItemsConfirmation" @@ -6375,7 +6394,6 @@ Mute everyone? notext="Cancel"/> <unique/> </notification> - <global name="UnsupportedCPU"> - Your CPU speed does not meet the minimum requirements. </global> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 113d5fb6dc..eb9c12be4f 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -211,7 +211,6 @@ <check_box.commit_callback function="Pref.VertexShaderEnable" /> </check_box> -<!-- DISABLED UNTIL WE REALLY WANT TO SUPPORT THIS <check_box control_name="RenderDeferred" height="16" @@ -273,7 +272,7 @@ name="2" value="2"/> </combo_box> ---> + <text type="string" length="1" @@ -614,9 +613,9 @@ follows="left|top" height="12" layout="topleft" - left_delta="-260" + left="200" name="AvatarRenderingText" - top_pad="18" + top_pad="8" width="128"> Avatar rendering: </text> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index b91acbe27d..d2cf25d7bc 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1962,6 +1962,7 @@ Clears (deletes) the media and all params from the given face. <string name="InvFolder Current Outfit">Current Outfit</string> <string name="InvFolder My Outfits">My Outfits</string> <string name="InvFolder Accessories">Accessories</string> + <string name="InvFolder Meshes">Meshes</string> <!-- are used for Friends and Friends/All folders in Inventory "Calling cards" folder. See EXT-694--> <string name="InvFolder Friends">Friends</string> diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 0b30128ff3..03d0310222 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -271,12 +271,21 @@ class WindowsManifest(ViewerManifest): self.path('libapr-1.dll') self.path('libaprutil-1.dll') self.path('libapriconv-1.dll') + except RuntimeError, err: print err.message print "Skipping llcommon.dll (assuming llcommon was linked statically)" self.disable_manifest_check() + # Mesh 3rd party libs needed for auto LOD and collada reading + try: + self.path("libcollada14dom21.dll") + self.path("glod.dll") + except RuntimeError, err: + print err.message + print "Skipping COLLADA and GLOD libraries (assumming linked statically)" + # For textures if self.args['configuration'].lower() == 'debug': self.path("openjpegd.dll") @@ -322,9 +331,9 @@ class WindowsManifest(ViewerManifest): # For using FMOD for sound... DJS self.path("fmod.dll") - + self.enable_no_crt_manifest_check() - + # Media plugins - QuickTime if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"): self.path("media_plugin_quicktime.dll") |