diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 7ce670a36..d01c74eaa 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -281,6 +281,10 @@ endif (STANDALONE) if(1 EQUAL 1) add_definitions(-DOPENSIM_RULES=1) add_definitions(-DMESH_ENABLED=1) + add_definitions(-DENABLE_CLASSIC_CLOUDS=1) + if (NOT "$ENV{SHY_MOD}" STREQUAL "") + add_definitions(-DSHY_MOD=1) + endif (NOT "$ENV{SHY_MOD}" STREQUAL "") endif(1 EQUAL 1) SET( CMAKE_EXE_LINKER_FLAGS_RELEASESSE2 diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 36e3d99f1..85291530c 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -56,8 +56,7 @@ LLCharacter::LLCharacter() mPreferredPelvisHeight( 0.f ), mSex( SEX_FEMALE ), mAppearanceSerialNum( 0 ), - mSkeletonSerialNum( 0 ), - mInAppearance( false ) + mSkeletonSerialNum( 0 ) { llassert_always(sAllowInstancesChange) ; sInstances.push_back(this); diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index b92805045..5fad36b1c 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -268,10 +268,6 @@ public: ESex getSex() const { return mSex; } void setSex( ESex sex ) { mSex = sex; } - // set appearance flag - void setAppearanceFlag( bool flag ) { mInAppearance = flag; } - bool getAppearanceFlag() { return mInAppearance; } - U32 getAppearanceSerialNum() const { return mAppearanceSerialNum; } void setAppearanceSerialNum( U32 num ) { mAppearanceSerialNum = num; } @@ -293,8 +289,6 @@ protected: U32 mSkeletonSerialNum; LLAnimPauseRequest mPauseRequest; - BOOL mInAppearance; - private: // visual parameter stuff typedef std::map visual_param_index_map_t; diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp index 80274e886..9d12ee98d 100644 --- a/indra/llcharacter/llheadrotmotion.cpp +++ b/indra/llcharacter/llheadrotmotion.cpp @@ -510,20 +510,6 @@ BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) vergence_quat.transQuat(); right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot; - //if in appearance, set the eyes straight forward - if(mCharacter->getAppearanceFlag()) // no idea why this variable is reversed - { - LLVector3 forward(1.f, 0.0, 0.0); - LLVector3 left; - LLVector3 up; - left.setVec(forward % forward); - up.setVec(forward % left); - target_eye_rot = LLQuaternion(forward, left, up); - mLeftEyeState->setRotation( target_eye_rot ); - mRightEyeState->setRotation( target_eye_rot ); - return TRUE; - } - mLeftEyeState->setRotation( left_eye_rot ); mRightEyeState->setRotation( right_eye_rot ); diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index b7e7e1dca..7d1b80710 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -50,6 +50,16 @@ public: const LLStrider& operator = (Object *first) { mObjectp = first; return *this;} void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));} + + LLStrider operator+(const S32& index) + { + LLStrider ret; + ret.mBytep = mBytep + mSkip*index; + ret.mSkip = mSkip; + + return ret; + } + //void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); } //bool isStrided() const { return mTypeSize != mSkip; } diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index c81126812..34c679352 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -1,37 +1,32 @@ /** * @file llimagedxt.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llimagedxt.h" +#include "llmemory.h" //static void LLImageDXT::checkMinWidthHeight(EFileFormat format, S32& width, S32& height) diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index 33b1ab181..34f553ffc 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -2,31 +2,25 @@ * @file llimagepng.cpp * @brief LLImageFormatted glue to encode / decode PNG files. * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -66,6 +60,12 @@ BOOL LLImagePNG::updateData() // Decode the PNG data and extract sizing information LLPngWrapper pngWrapper; + if (!pngWrapper.isValidPng(getData())) + { + setLastError("LLImagePNG data does not have a valid PNG header!"); + return FALSE; + } + LLPngWrapper::ImageInfo infop; if (! pngWrapper.readPng(getData(), NULL, &infop)) { @@ -96,6 +96,12 @@ BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time) // Decode the PNG data into the raw image LLPngWrapper pngWrapper; + if (!pngWrapper.isValidPng(getData())) + { + setLastError("LLImagePNG data does not have a valid PNG header!"); + return FALSE; + } + if (! pngWrapper.readPng(getData(), raw_image)) { setLastError(pngWrapper.getErrorMessage()); diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index a6721bfa0..58426d31f 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -1,40 +1,36 @@ /** * @file llimagetga.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" -#include "lldir.h" #include "llimagetga.h" + +#include "lldir.h" #include "llerror.h" #include "llmath.h" +#include "llpointer.h" // For expanding 5-bit pixel values to 8-bit with best rounding // static diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index cde11493f..743c7a347 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -2,31 +2,25 @@ * @file llimagej2coj.cpp * @brief This is an implementation of JPEG2000 encode/decode using OpenJPEG. * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,7 +31,7 @@ #include "openjpeg.h" #include "lltimer.h" -#include "llmemory.h" +//#include "llmemory.h" const char* fallbackEngineInfoLLImageJ2CImpl() { @@ -96,8 +90,15 @@ void info_callback(const char* msg, void*) lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl; } +// Divide a by 2 to the power of b and round upwards +int ceildivpow2(int a, int b) +{ + return (a + (1 << b) - 1) >> b; +} -LLImageJ2COJ::LLImageJ2COJ() : LLImageJ2CImpl() + +LLImageJ2COJ::LLImageJ2COJ() + : LLImageJ2CImpl() { } @@ -180,7 +181,7 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod // dereference the array. if(!image || !image->numcomps) { - llwarns << "failed to decode image!" << llendl; + LL_WARNS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; if (image) { opj_image_destroy(image); @@ -195,7 +196,7 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod { if (image->comps[i].factor != base.getRawDiscardLevel()) { - llwarns << "Expected discard level not reached!" << llendl; + LL_WARNS("Texture") << "Expected discard level not reached!" << llendl; // if we didn't get the discard level we're expecting, fail opj_image_destroy(image); base.decodeFailed(); @@ -256,7 +257,7 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod } else // Some rare OpenJPEG versions have this bug. { - llwarns << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << llendl; + LL_WARNS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << llendl; opj_image_destroy(image); base.decodeFailed(); @@ -391,7 +392,7 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con if (!bSuccess) { opj_cio_close(cio); - llinfos << "Failed to encode image." << llendl; + LL_WARNS("Texture") << "Failed to encode image." << llendl; return FALSE; } codestream_length = cio_tell(cio); diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 1bcef4401..9999c236d 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -60,6 +60,7 @@ class LLVolumeTriangle; #include "llstrider.h" #include "v4coloru.h" #include "llrefcount.h" +#include "llpointer.h" #include "llfile.h" //============================================================================ @@ -926,6 +927,10 @@ public: LLVector2* mTexCoords; U16* mIndices; + //vertex buffer filled in by LLFace to cache this volume face geometry in vram + // (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer) + mutable LLPointer mVertexBuffer; + std::vector mEdge; //list of skin weights for rigged volumes diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 45a3b1817..362452d83 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -81,7 +81,7 @@ void LLCubeMap::initGL() { U32 texname = 0; - LLImageGL::generateTextures(1, &texname); + LLImageGL::generateTextures(LLTexUnit::TT_CUBE_MAP, GL_RGB8, 1, &texname); for (int i = 0; i < 6; i++) { diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 3937184d2..92d095b80 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -2,31 +2,25 @@ * @file llgl.cpp * @brief LLGL implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -263,6 +257,12 @@ PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL; PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL; PFNGLSAMPLEMASKIPROC glSampleMaski = NULL; +//transform feedback (4.0 core) +PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL; +PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL; + //GL_ARB_debug_output PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL; PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL; @@ -436,6 +436,7 @@ LLGLManager::LLGLManager() : mHasDrawBuffers(FALSE), mHasTextureRectangle(FALSE), mHasTextureMultisample(FALSE), + mHasTransformFeedback(FALSE), mMaxSampleMaskWords(0), mMaxColorTextureSamples(0), mMaxDepthTextureSamples(0), @@ -573,7 +574,8 @@ bool LLGLManager::initGL() parse_gl_version( &mDriverVersionMajor, &mDriverVersionMinor, &mDriverVersionRelease, - &mDriverVersionVendorString ); + &mDriverVersionVendorString, + &mGLVersionString); mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f; @@ -591,7 +593,7 @@ bool LLGLManager::initGL() #endif } - if (mGLVersion >= 3.f && LLImageGL::sCompressTextures) + if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures) { //use texture compression glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); } @@ -620,11 +622,8 @@ bool LLGLManager::initGL() #endif // LL_WINDOWS #if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS - // release 7277 is a point at which we verify that ATI OpenGL - // drivers get pretty stable with SL, ~Catalyst 8.2, - // for both Win32 and Linux. - if (mDriverVersionRelease < 7277 && - mDriverVersionRelease != 0) // 0 == Undetectable driver version - these get to pretend to be new ATI drivers, though that decision may be revisited. + // count any pre OpenGL 3.0 implementation as an old driver + if (mGLVersion < 3.f) { mATIOldDriver = TRUE; } @@ -931,7 +930,6 @@ void LLGLManager::initExtensions() mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); - mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); glh_init_extensions("GL_ARB_texture_cube_map"); @@ -956,11 +954,15 @@ void LLGLManager::initExtensions() ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); #endif mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts); + + mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f; + mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts); mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts); + mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE; #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); #endif @@ -1202,7 +1204,14 @@ void LLGLManager::initExtensions() glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample"); glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv"); glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski"); - } + } + if (mHasTransformFeedback) + { + glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback"); + glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback"); + glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings"); + glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange"); + } if (mHasDebugOutput) { glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB"); @@ -2040,7 +2049,7 @@ void LLGLManager::initGLStates() //////////////////////////////////////////////////////////////////////////////// -void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ) +void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ) { // GL_VERSION returns a null-terminated string with the format: // .[.] [] @@ -2056,6 +2065,8 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor return; } + version_string->assign(version); + std::string ver_copy( version ); S32 len = (S32)strlen( version ); /* Flawfinder: ignore */ S32 i = 0; @@ -2417,3 +2428,63 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip() gGL.matrixMode(LLRender::MM_MODELVIEW); } + + +LLGLSyncFence::LLGLSyncFence() +{ +#ifdef GL_ARB_sync + mSync = 0; +#endif +} + +LLGLSyncFence::~LLGLSyncFence() +{ +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } +#endif +} + +void LLGLSyncFence::placeFence() +{ +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } + mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +#endif +} + +bool LLGLSyncFence::isCompleted() +{ + bool ret = true; +#ifdef GL_ARB_sync + if (mSync) + { + GLenum status = glClientWaitSync(mSync, 0, 1); + if (status == GL_TIMEOUT_EXPIRED) + { + ret = false; + } + } +#endif + return ret; +} + +void LLGLSyncFence::wait() +{ +#ifdef GL_ARB_sync + if (mSync) + { + while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) + { //track the number of times we've waited here + static S32 waits = 0; + waits++; + } + } +#endif +} + diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 6817ec0f0..06f6155c9 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -2,31 +2,25 @@ * @file llgl.h * @brief LLGL definition * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -111,6 +105,7 @@ public: BOOL mHasDepthClamp; BOOL mHasTextureRectangle; BOOL mHasTextureMultisample; + BOOL mHasTransformFeedback; S32 mMaxSampleMaskWords; S32 mMaxColorTextureSamples; S32 mMaxDepthTextureSamples; @@ -148,6 +143,7 @@ public: S32 mGLSLVersionMajor; S32 mGLSLVersionMinor; std::string mDriverVersionVendorString; + std::string mGLVersionString; S32 mVRAM; // VRAM in MB S32 mGLMaxVertexRange; @@ -425,13 +421,39 @@ public: virtual void updateGL() = 0; }; +const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000; //1 ms + +class LLGLFence +{ +public: + virtual void placeFence() = 0; + virtual bool isCompleted() = 0; + virtual void wait() = 0; + virtual ~LLGLFence() {} +}; + +class LLGLSyncFence : public LLGLFence +{ +public: +#ifdef GL_ARB_sync + GLsync mSync; +#endif + + LLGLSyncFence(); + virtual ~LLGLSyncFence(); + + void placeFence(); + bool isCompleted(); + void wait(); +}; + extern LLMatrix4 gGLObliqueProjectionInverse; #include "llglstates.h" void init_glstates(); -void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ); +void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ); extern BOOL gClothRipple; extern BOOL gNoRender; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 7ccc0d819..9e3d9b96f 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -534,6 +534,13 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//transform feedback (4.0 core) +extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + + #elif LL_WINDOWS //---------------------------------------------------------------------------- // LL_WINDOWS @@ -765,6 +772,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//transform feedback (4.0 core) +extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + //GL_ARB_debug_output extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 6da17d2fd..1c90d7658 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -134,7 +134,9 @@ void LLGLSLShader::unload() } BOOL LLGLSLShader::createShader(vector * attributes, - vector * uniforms) + vector * uniforms, + U32 varying_count, + const char** varyings) { //reloading, reset matrix hash values for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) @@ -142,6 +144,7 @@ BOOL LLGLSLShader::createShader(vector * attributes, mMatHash[i] = 0xFFFFFFFF; } mLightHash = 0xFFFFFFFF; + llassert_always(!mShaderFiles.empty()); BOOL success = TRUE; @@ -181,6 +184,13 @@ BOOL LLGLSLShader::createShader(vector * attributes, mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1); } +#ifdef GL_INTERLEAVED_ATTRIBS + if (varying_count > 0 && varyings) + { + glTransformFeedbackVaryings(mProgramObject, varying_count, varyings, GL_INTERLEAVED_ATTRIBS); + } +#endif + // Map attributes and uniforms if (success) { @@ -228,13 +238,13 @@ BOOL LLGLSLShader::createShader(vector * attributes, } unbind(); } + return success; } BOOL LLGLSLShader::attachObject(std::string object) { - std::map &ShaderObjects = LLShaderMgr::instance()->mShaderObjects; - if (ShaderObjects.find(object) != ShaderObjects.end()) + if (LLShaderMgr::instance()->mShaderObjects.count(object) > 0) { stop_glerror(); glAttachObjectARB(mProgramObject, LLShaderMgr::instance()->mShaderObjects[object]); diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 6311d8410..2f64b0c9f 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -82,7 +82,9 @@ public: void unload(); BOOL createShader(std::vector * attributes, - std::vector * uniforms); + std::vector * uniforms, + U32 varying_count = 0, + const char** varyings = NULL); BOOL attachObject(std::string object); void attachObject(GLhandleARB object); void attachObjects(GLhandleARB* objects = NULL, S32 count = 0); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 7064a2c85..061fb48e7 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -42,13 +42,17 @@ #include "llmath.h" #include "llgl.h" +#include "llglslshader.h" #include "llrender.h" -//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- const F32 MIN_TEXTURE_LIFETIME = 10.f; +//which power of 2 is i? +//assumes i is a power of 2 > 0 +U32 wpo2(U32 i); + //statics -LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 }; U32 LLImageGL::sUniqueCount = 0; U32 LLImageGL::sBindCount = 0; @@ -56,7 +60,8 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0; S32 LLImageGL::sBoundTextureMemoryInBytes = 0; S32 LLImageGL::sCurBoundTextureMemory = 0; S32 LLImageGL::sCount = 0; -std::list LLImageGL::sDeadTextureList; +LLImageGL::dead_texturelist_t LLImageGL::sDeadTextureList[LLTexUnit::TT_NONE]; +U32 LLImageGL::sCurTexName = 1; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; @@ -79,7 +84,7 @@ std::vector LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; S32 LLImageGL::sCurTexSizeBar = -1 ; S32 LLImageGL::sCurTexPickSize = -1 ; LLPointer LLImageGL::sHighlightTexturep = NULL; -S32 LLImageGL::sMaxCatagories = 1 ; +S32 LLImageGL::sMaxCategories = 1 ; std::vector LLImageGL::sTextureMemByCategory; std::vector LLImageGL::sTextureMemByCategoryBound ; @@ -181,11 +186,11 @@ BOOL is_little_endian() //static void LLImageGL::initClass(S32 num_catagories) { - sMaxCatagories = num_catagories ; + sMaxCategories = num_catagories ; - sTextureMemByCategory.resize(sMaxCatagories); - sTextureMemByCategoryBound.resize(sMaxCatagories) ; - sTextureCurMemByCategoryBound.resize(sMaxCatagories) ; + sTextureMemByCategory.resize(sMaxCategories); + sTextureMemByCategoryBound.resize(sMaxCategories) ; + sTextureCurMemByCategoryBound.resize(sMaxCategories) ; } //static @@ -493,8 +498,9 @@ void LLImageGL::init(BOOL usemipmaps) mAllowCompression = true; mTarget = GL_TEXTURE_2D; - mBindTarget = LLTexUnit::TT_TEXTURE; - mHasMipMaps = false; + mBindTarget = LLTexUnit::TT_TEXTURE; + mHasMipMaps = false; + mMipLevels = -1; mIsResident = 0; @@ -679,19 +685,32 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { -// LLFastTimer t1(FTM_TEMP1); bool is_compressed = false; if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) { is_compressed = true; } -// LLFastTimer t2(FTM_TEMP2); - llverify(gGL.getTexUnit(0)->bind(this)); + + + if (mUseMipMaps) + { + //set has mip maps to true before binding image so tex parameters get set properly + gGL.getTexUnit(0)->unbind(mBindTarget); + mHasMipMaps = true; + mTexOptionsDirty = true; + setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + } + else + { + mHasMipMaps = false; + } + + llverify(gGL.getTexUnit(0)->bind(this)); + if (mUseMipMaps) { -// LLFastTimer t2(FTM_TEMP3); if (data_hasmips) { // NOTE: data_in points to largest image; smaller images @@ -702,6 +721,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 w = getWidth(d); S32 h = getHeight(d); S32 gl_level = d-mCurrentDiscardLevel; + + mMipLevels = llmax(mMipLevels, gl_level); + if (d > mCurrentDiscardLevel) { data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment @@ -745,10 +767,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { if (mAutoGenMips) { - if (!gGLManager.mHasFramebufferObject) - { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE); - } stop_glerror(); { // LLFastTimer t2(FTM_TEMP4); @@ -762,6 +780,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 w = getWidth(mCurrentDiscardLevel); S32 h = getHeight(mCurrentDiscardLevel); + mMipLevels = wpo2(llmax(w, h)); + + //use legacy mipmap generation mode + glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, mFormatPrimary, mFormatType, @@ -777,17 +800,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } } - - if (gGLManager.mHasFramebufferObject) - { - //GL_EXT_framebuffer_object implies glGenerateMipmap - glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget)); - } } else { // Create mips by hand - // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800 // ~4x faster than gluBuild2DMipmaps S32 width = getWidth(mCurrentDiscardLevel); S32 height = getHeight(mCurrentDiscardLevel); @@ -797,6 +813,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) const U8* cur_mip_data = 0; S32 prev_mip_size = 0; S32 cur_mip_size = 0; + + mMipLevels = nummips; + for (int m=0; msecond.empty(); + } + + for (S32 i = 0; i < numTextures; ++i) + { + if (!empty) + { + textures[i] = iter->second.front(); + iter->second.pop_front(); + empty = iter->second.empty(); + } + else + { + textures[i] = sCurTexName++; + } + } } // static -void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate) +void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate) { - for (S32 i = 0; i < numTextures; i++) + if (gGLManager.mInited) { - sDeadTextureList.push_back(textures[i]); - } + if (format == 0 || type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1) + { //unknown internal format or unknown number of mip levels, not safe to reuse + glDeleteTextures(numTextures, textures); + } + else + { + for (S32 i = 0; i < numTextures; ++i) + { //remove texture from VRAM by setting its size to zero + for (S32 j = 0; j <= mip_levels; j++) + { + gGL.getTexUnit(0)->bindManual(type, textures[i]); - if (immediate) + glTexImage2D(LLTexUnit::getInternalType(type), j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + + llassert(std::find(sDeadTextureList[type][format].begin(), + sDeadTextureList[type][format].end(), textures[i]) == + sDeadTextureList[type][format].end()); + + sDeadTextureList[type][format].push_back(textures[i]); + } + } + } + + /*if (immediate) { LLImageGL::deleteDeadTextures(); - } + }*/ } // static @@ -1162,10 +1221,11 @@ BOOL LLImageGL::createGLTexture() if(mTexName) { - glDeleteTextures(1, (reinterpret_cast(&mTexName))) ; + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, (reinterpret_cast(&mTexName))) ; } - glGenTextures(1, (GLuint*)&mTexName); + + LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName); stop_glerror(); if (!mTexName) { @@ -1279,7 +1339,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } else { - LLImageGL::generateTextures(1, &mTexName); + LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName); stop_glerror(); { llverify(gGL.getTexUnit(0)->bind(this)); @@ -1329,7 +1389,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ decTextureCounter(mTextureMemory, mComponents, mCategory) ; } - LLImageGL::deleteTextures(1, &old_name); + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &old_name); stop_glerror(); } @@ -1345,59 +1405,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ mLastBindTime = sLastFrameTime; return TRUE; } -#if 0 -BOOL LLImageGL::setDiscardLevel(S32 discard_level) -{ - llassert(discard_level >= 0); - llassert(mCurrentDiscardLevel >= 0); - - discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); - - if (mDontDiscard) - { - // don't discard! - return FALSE; - } - else if (discard_level == mCurrentDiscardLevel) - { - // nothing to do - return FALSE; - } - else if (discard_level < mCurrentDiscardLevel) - { - // larger image - dump(); - llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl; - return FALSE; - } - else if (mUseMipMaps) - { - LLPointer imageraw = new LLImageRaw; - while(discard_level > mCurrentDiscardLevel) - { - if (readBackRaw(discard_level, imageraw, false)) - { - break; - } - discard_level--; - } - if (discard_level == mCurrentDiscardLevel) - { - // unable to increase the discard level - return FALSE; - } - return createGLTexture(discard_level, imageraw); - } - else - { -#if !LL_LINUX && !LL_SOLARIS - // *FIX: This should not be skipped for the linux client. - llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl; -#endif - return FALSE; - } -} -#endif BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) { @@ -1515,28 +1522,32 @@ void LLImageGL::deleteDeadTextures() { bool reset = false; - while (!sDeadTextureList.empty()) + for(U32 i=0;igetCurrTexture() == tex) + while(!it->second.empty()) { - tex_unit->unbind(tex_unit->getCurrType()); - stop_glerror(); - - if (i > 0) + GLuint tex = it->second.front(); + it->second.pop_front(); + for (int j = 0; j < gGLManager.mNumTextureImageUnits; j++) { - reset = true; + LLTexUnit* tex_unit = gGL.getTexUnit(j); + if (tex_unit && tex_unit->getCurrTexture() == tex) + { + tex_unit->unbind(tex_unit->getCurrType()); + stop_glerror(); + + if (i > 0) + { + reset = true; + } + } } + glDeleteTextures(1, &tex); + stop_glerror(); } } - - glDeleteTextures(1, &tex); - stop_glerror(); } if (reset) @@ -1559,9 +1570,9 @@ void LLImageGL::destroyGLTexture() mTextureMemory = 0; } - LLImageGL::deleteTextures(1, &mTexName); - mTexName = 0; + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &mTexName); mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. + mTexName = 0; mGLTextureCreated = FALSE ; } } @@ -1997,7 +2008,7 @@ void LLImageGL::setCategory(S32 category) { sTextureMemByCategory[mCategory] -= mTextureMemory ; } - if(category > -1 && category < sMaxCatagories) + if(category > -1 && category < sMaxCategories) { sTextureMemByCategory[category] += mTextureMemory ; mCategory = category; diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 37b997199..e90b242e1 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -2,31 +2,25 @@ * @file llimagegl.h * @brief Object for managing images and their textures * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,8 +45,16 @@ class LLImageGL : public LLRefCount { friend class LLTexUnit; public: - static std::list sDeadTextureList; + static U32 sCurTexName; + //previously used but now available texture names + // sDeadTextureList[][] + typedef std::map > dead_texturelist_t; + static dead_texturelist_t sDeadTextureList[LLTexUnit::TT_NONE]; + + // These 2 functions replace glGenTextures() and glDeleteTextures() + static void generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures); + static void deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate = false); static void deleteDeadTextures(); // Size calculation @@ -102,15 +104,11 @@ public: void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} void setAllowCompression(bool allow) { mAllowCompression = allow; } - // These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() - // for tracking purposes and will be deprecated in the future - static void generateTextures(S32 numTextures, U32 *textures); - static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false); static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); BOOL createGLTexture() ; - BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, - S32 category = sMaxCatagories - 1); + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, + S32 category = sMaxCategories-1); BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); void setImage(const LLImageRaw* imageraw); void setImage(const U8* data_in, BOOL data_hasmips = FALSE); @@ -209,7 +207,8 @@ protected: LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps) LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps) bool mHasMipMaps; - + S32 mMipLevels; + LLGLboolean mIsResident; S8 mComponents; @@ -232,8 +231,6 @@ public: static F32 sLastFrameTime; - static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID - // Global memory statistics static S32 sGlobalTextureMemoryInBytes; // Tracks main memory texmem static S32 sBoundTextureMemoryInBytes; // Tracks bound texmem for last completed frame @@ -255,7 +252,7 @@ public: static void initClass(S32 num_catagories) ; static void cleanupClass() ; private: - static S32 sMaxCatagories ; + static S32 sMaxCategories ; //the flag to allow to call readBackRaw(...). //can be removed if we do not use that function at all. diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index f8a8db2b4..d73b17a51 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -422,12 +422,14 @@ void LLTexUnit::unbind(eTextureType type) if (mIndex < 0) return; + //always flush and activate for consistency + // some code paths assume unbind always flushes and sets the active texture + gGL.flush(); + activate(); + // Disabled caching of binding state. if (mCurrTexType == type) { - gGL.flush(); - - activate(); mCurrTexture = 0; if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE) { @@ -478,11 +480,25 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio } else if (option >= TFO_BILINEAR) { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } } else { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } } if (gGLManager.mHasAnisotropic) diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index ff7689058..6ea20e977 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -61,7 +61,6 @@ bool LLRenderTarget::sUseFBO = false; LLRenderTarget::LLRenderTarget() : mResX(0), mResY(0), - mTex(0), mFBO(0), mDepth(0), mStencil(0), @@ -149,7 +148,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) } U32 tex; - LLImageGL::generateTextures(1, &tex); + LLImageGL::generateTextures(mUsage, color_fmt, 1, &tex); gGL.getTexUnit(0)->bindManual(mUsage, tex); stop_glerror(); @@ -207,6 +206,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) } mTex.push_back(tex); + mInternalFormat.push_back(color_fmt); if (gDebugGL) { //bind and unbind to validate target @@ -231,7 +231,7 @@ bool LLRenderTarget::allocateDepth() } else { - LLImageGL::generateTextures(1, &mDepth); + LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth); gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); @@ -308,7 +308,7 @@ void LLRenderTarget::release() } else { - LLImageGL::deleteTextures(1, &mDepth, true); + LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true); stop_glerror(); } mDepth = 0; @@ -340,8 +340,9 @@ void LLRenderTarget::release() if (mTex.size() > 0) { sBytesAllocated -= mResX*mResY*4*mTex.size(); - LLImageGL::deleteTextures(mTex.size(), &mTex[0], true); + LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true); mTex.clear(); + mInternalFormat.clear(); } mResX = mResY = 0; diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 4051b3e9b..9ed95770e 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -152,6 +152,7 @@ protected: U32 mResX; U32 mResY; std::vector mTex; + std::vector mInternalFormat; U32 mFBO; U32 mDepth; bool mStencil; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index a9265e5ff..63e0d3e83 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1069,6 +1069,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("size"); mReservedUniforms.push_back("falloff"); + mReservedUniforms.push_back("box_center"); + mReservedUniforms.push_back("box_size"); + mReservedUniforms.push_back("minLuminance"); mReservedUniforms.push_back("maxExtractAlpha"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index f56b1db7b..b06d61b3e 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -97,6 +97,8 @@ public: LIGHT_CENTER, LIGHT_SIZE, LIGHT_FALLOFF, + BOX_CENTER, + BOX_SIZE, GLOW_MIN_LUMINANCE, GLOW_MAX_EXTRACT_ALPHA, diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 10c3eccaa..696730924 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -39,8 +39,10 @@ #include "llmemory.h" #include "llfasttimer.h" -#define LL_VBO_POOLING 0 - +#if LL_DARWIN +#define LL_VBO_POOLING 1 +#else +#endif //Next Highest Power Of Two //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 U32 nhpo2(U32 v) @@ -68,6 +70,7 @@ U32 wpo2(U32 i) const U32 LL_VBO_BLOCK_SIZE = 2048; +const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024; U32 vbo_block_size(U32 size) { //what block size will fit size? @@ -80,6 +83,7 @@ U32 vbo_block_index(U32 size) return vbo_block_size(size)/LL_VBO_BLOCK_SIZE; } +const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE); //============================================================================ @@ -92,6 +96,11 @@ LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_ U32 LLVBOPool::sBytesPooled = 0; U32 LLVBOPool::sIndexBytesPooled = 0; +U32 LLVBOPool::sCurGLName = 1; + +std::list LLVertexBuffer::sAvailableVAOName; +U32 LLVertexBuffer::sCurVAOName = 1; + U32 LLVertexBuffer::sAllocatedIndexBytes = 0; U32 LLVertexBuffer::sIndexCount = 0; @@ -116,69 +125,55 @@ bool LLVertexBuffer::sUseStreamDraw = true; bool LLVertexBuffer::sUseVAO = false; bool LLVertexBuffer::sPreferStreamDraw = false; -const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms -class LLGLSyncFence : public LLGLFence +U32 LLVBOPool::genBuffer() { -public: -#ifdef GL_ARB_sync - GLsync mSync; -#endif - - LLGLSyncFence() + U32 ret = 0; + + if (mGLNamePool.empty()) { -#ifdef GL_ARB_sync - mSync = 0; -#endif + ret = sCurGLName++; + } + else + { + ret = mGLNamePool.front(); + mGLNamePool.pop_front(); } - virtual ~LLGLSyncFence() + return ret; +} + +void LLVBOPool::deleteBuffer(U32 name) +{ + if (gGLManager.mInited) { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } -#endif - } - - void placeFence() - { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } - mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -#endif - } - - void wait() - { -#ifdef GL_ARB_sync - if (mSync) - { - while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) - { //track the number of times we've waited here - static S32 waits = 0; - waits++; - } - } -#endif + LLVertexBuffer::unbind(); + + glBindBufferARB(mType, name); + glBufferDataARB(mType, 0, NULL, mUsage); + + llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end()); + + mGLNamePool.push_back(name); + + glBindBufferARB(mType, 0); } +} -}; +LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType) +: mUsage(vboUsage), mType(vboType) +{ + mMissCount.resize(LL_VBO_POOL_SEED_COUNT); + std::fill(mMissCount.begin(), mMissCount.end(), 0); +} - -volatile U8* LLVBOPool::allocate(U32& name, U32 size) +volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) { llassert(vbo_block_size(size) == size); volatile U8* ret = NULL; -#if LL_VBO_POOLING - U32 i = vbo_block_index(size); if (mFreeList.size() <= i) @@ -186,25 +181,31 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) mFreeList.resize(i+1); } - if (mFreeList[i].empty()) + if (mFreeList[i].empty() || for_seed) { //make a new buffer - glGenBuffersARB(1, &name); + name = genBuffer(); + glBindBufferARB(mType, name); + if (!for_seed && i < LL_VBO_POOL_SEED_COUNT) + { //record this miss + mMissCount[i]++; + } + if (mType == GL_ARRAY_BUFFER_ARB) { LLVertexBuffer::sAllocatedBytes += size; } else - { - LLVertexBuffer::sAllocatedIndexBytes += size; - } + { + LLVertexBuffer::sAllocatedIndexBytes += size; + } - if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) - { - glBufferDataARB(mType, size, 0, mUsage); - ret = (U8*) ll_aligned_malloc_16(size); + if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) + { + glBufferDataARB(mType, size, 0, mUsage); + ret = (U8*) ll_aligned_malloc_16(size); } else { //always use a true hint of static draw when allocating non-client-backed buffers @@ -212,6 +213,25 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) } glBindBufferARB(mType, 0); + + if (for_seed) + { //put into pool for future use + llassert(mFreeList.size() > i); + + Record rec; + rec.mGLName = name; + rec.mClientData = ret; + + if (mType == GL_ARRAY_BUFFER_ARB) + { + sBytesPooled += size; + } + else + { + sIndexBytesPooled += size; + } + mFreeList[i].push_back(rec); + } } else { @@ -229,33 +249,6 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) mFreeList[i].pop_front(); } -#else //no pooling - - glGenBuffersARB(1, &name); - glBindBufferARB(mType, name); - - if (mType == GL_ARRAY_BUFFER_ARB) - { - LLVertexBuffer::sAllocatedBytes += size; - } - else - { - LLVertexBuffer::sAllocatedIndexBytes += size; - } - - if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) - { - glBufferDataARB(mType, size, 0, mUsage); - ret = (U8*) ll_aligned_malloc_16(size); - } - else - { //always use a true hint of static draw when allocating non-client-backed buffers - glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB); - } - - glBindBufferARB(mType, 0); - -#endif return ret; } @@ -264,34 +257,7 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) { llassert(vbo_block_size(size) == size); -#if LL_VBO_POOLING - - U32 i = vbo_block_index(size); - - llassert(mFreeList.size() > i); - - Record rec; - rec.mGLName = name; - rec.mClientData = buffer; - - if (buffer == NULL) - { - glDeleteBuffersARB(1, &rec.mGLName); - } - else - { - if (mType == GL_ARRAY_BUFFER_ARB) - { - sBytesPooled += size; - } - else - { - sIndexBytesPooled += size; - } - mFreeList[i].push_back(rec); - } -#else //no pooling - glDeleteBuffersARB(1, &name); + deleteBuffer(name); ll_aligned_free_16((U8*) buffer); if (mType == GL_ARRAY_BUFFER_ARB) @@ -302,12 +268,36 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) { LLVertexBuffer::sAllocatedIndexBytes -= size; } -#endif } +void LLVBOPool::seedPool() +{ + U32 dummy_name = 0; + + if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT) + { + mFreeList.resize(LL_VBO_POOL_SEED_COUNT); + } + + for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++) + { + if (mMissCount[i] > mFreeList[i].size()) + { + U32 size = i*LL_VBO_BLOCK_SIZE; + + S32 count = mMissCount[i] - mFreeList[i].size(); + for (S32 j = 0; j < count; ++j) + { + allocate(dummy_name, size, true); + } + } + } +} + + void LLVBOPool::cleanup() { - U32 size = 1; + U32 size = LL_VBO_BLOCK_SIZE; for (U32 i = 0; i < mFreeList.size(); ++i) { @@ -317,8 +307,8 @@ void LLVBOPool::cleanup() { Record& r = l.front(); - glDeleteBuffersARB(1, &r.mGLName); - + deleteBuffer(r.mGLName); + if (r.mClientData) { ll_aligned_free_16((void*) r.mClientData); @@ -338,8 +328,11 @@ void LLVBOPool::cleanup() } } - size *= 2; + size += LL_VBO_BLOCK_SIZE; } + + //reset miss counts + std::fill(mMissCount.begin(), mMissCount.end(), 0); } @@ -373,6 +366,41 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = GL_LINE_LOOP, }; +//static +U32 LLVertexBuffer::getVAOName() +{ + U32 ret = 0; + + if (!sAvailableVAOName.empty()) + { + ret = sAvailableVAOName.front(); + sAvailableVAOName.pop_front(); + } + else + { +#ifdef GL_ARB_vertex_array_object + glGenVertexArrays(1, &ret); +#endif + } + + return ret; +} + +//static +void LLVertexBuffer::releaseVAOName(U32 name) +{ + sAvailableVAOName.push_back(name); +} + + +//static +void LLVertexBuffer::seedPools() +{ + sStreamVBOPool.seedPool(); + sDynamicVBOPool.seedPool(); + sStreamIBOPool.seedPool(); + sDynamicIBOPool.seedPool(); +} //static void LLVertexBuffer::setupClientArrays(U32 data_mask) @@ -982,7 +1010,7 @@ LLVertexBuffer::~LLVertexBuffer() if (mGLArray) { #if GL_ARB_vertex_array_object - glDeleteVertexArrays(1, &mGLArray); + releaseVAOName(mGLArray); #endif } @@ -1267,7 +1295,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) { #if GL_ARB_vertex_array_object - glGenVertexArrays(1, &mGLArray); + mGLArray = getVAOName(); #endif setupVertexArray(); } @@ -2137,6 +2165,16 @@ void LLVertexBuffer::flush() } } +// bind for transform feedback (quick 'n dirty) +void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count) +{ +#ifdef GL_TRANSFORM_FEEDBACK_BUFFER + U32 offset = mOffsets[type] + sTypeSize[type]*index; + U32 size= (sTypeSize[type]*count); + glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size); +#endif +} + // Set for rendering void LLVertexBuffer::setBuffer(U32 data_mask) { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 0ab73af1d..14438a95e 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -56,24 +56,29 @@ class LLVBOPool public: static U32 sBytesPooled; static U32 sIndexBytesPooled; + + static U32 sCurGLName; - LLVBOPool(U32 vboUsage, U32 vboType) - : mUsage(vboUsage) - , mType(vboType) - {} - + LLVBOPool(U32 vboUsage, U32 vboType); + const U32 mUsage; const U32 mType; //size MUST be a power of 2 - volatile U8* allocate(U32& name, U32 size); + volatile U8* allocate(U32& name, U32 size, bool for_seed = false); //size MUST be the size provided to allocate that returned the given name void release(U32 name, volatile U8* buffer, U32 size); + //batch allocate buffers to be provided to the application on demand + void seedPool(); + //destroy all records in mFreeList void cleanup(); + U32 genBuffer(); + void deleteBuffer(U32 name); + class Record { public: @@ -81,16 +86,11 @@ public: volatile U8* mClientData; }; + std::list mGLNamePool; + typedef std::list record_list_t; std::vector mFreeList; -}; - -class LLGLFence -{ -public: - virtual void placeFence() = 0; - virtual void wait() = 0; - virtual ~LLGLFence() {} + std::vector mMissCount; }; //============================================================================ @@ -126,13 +126,22 @@ public: static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; + static std::list sAvailableVAOName; + static U32 sCurVAOName; + static bool sUseStreamDraw; static bool sUseVAO; static bool sPreferStreamDraw; + static void seedPools(); + + static U32 getVAOName(); + static void releaseVAOName(U32 name); + static void initClass(bool use_vbo, bool no_vbo_mapping); static void cleanupClass(); static void setupClientArrays(U32 data_mask); + static void pushPositions(U32 mode, const LLVector4a* pos, U32 count); static void drawArrays(U32 mode, const std::vector& pos, const std::vector& norm); static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp); @@ -209,7 +218,6 @@ protected: void destroyGLIndices(); void updateNumVerts(S32 nverts); void updateNumIndices(S32 nindices); - bool useVBOs() const; void unmapBuffer(); public: @@ -219,6 +227,8 @@ public: volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range); + void bindForFeedback(U32 channel, U32 type, U32 index, U32 count); + // set for rendering virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 void flush(); //flush pending data to GL memory @@ -241,12 +251,14 @@ public: bool getNormalStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getBinormalStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getColorStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTextureIndexStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getEmissiveStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeightStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeight4Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getClothWeightStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool useVBOs() const; bool isEmpty() const { return mEmpty; } bool isLocked() const { return mVertexLocked || mIndexLocked; } S32 getNumVerts() const { return mNumVerts; } diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 7c2fd3a81..f10e211f1 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -297,8 +297,7 @@ boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackPa boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) { - if (!mCommitSignal) mCommitSignal = new commit_signal_t(); - return mCommitSignal->connect(cb); + return LLUICtrl::setCommitCallback(cb); } boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb ) { diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index 29ea32816..377c9a12b 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -280,7 +280,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, } //add the panel, add it to proper maps - mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); + mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, 0, FALSE, insertion_point); mFloaterDataMap[floaterp->getHandle()] = floater_data; updateResizeLimits(); @@ -366,10 +366,10 @@ void LLMultiFloater::removeFloater(LLFloater* floaterp) updateResizeLimits(); - tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); + tabOpen((LLFloater*)mTabContainer->getCurrentPanel()); } -void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click) +void LLMultiFloater::tabOpen(LLFloater* opened_floater) { // default implementation does nothing } @@ -464,12 +464,9 @@ void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing) mTabContainer->setTabPanelFlashing(floaterp, flashing); } -//static -void LLMultiFloater::onTabSelected(void* userdata, bool from_click) +void LLMultiFloater::onTabSelected() { - LLMultiFloater* floaterp = (LLMultiFloater*)userdata; - - floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(), from_click); + tabOpen((LLFloater*)mTabContainer->getCurrentPanel()); } void LLMultiFloater::setCanResize(BOOL can_resize) @@ -499,6 +496,7 @@ BOOL LLMultiFloater::postBuild() if (checkRequirements()) { mTabContainer = getChild("Preview Tabs"); + mTabContainer->setCommitCallback(boost::bind(&LLMultiFloater::onTabSelected, this)); return TRUE; } diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h index 29c03b3c4..0ac9ee856 100644 --- a/indra/llui/llmultifloater.h +++ b/indra/llui/llmultifloater.h @@ -60,7 +60,7 @@ public: virtual void showFloater(LLFloater* floaterp); virtual void removeFloater(LLFloater* floaterp); - virtual void tabOpen(LLFloater* opened_floater, bool from_click); + virtual void tabOpen(LLFloater* opened_floater); virtual void tabClose(); virtual BOOL selectFloater(LLFloater* floaterp); @@ -74,7 +74,7 @@ public: virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing); virtual BOOL closeAllFloaters(); //Returns FALSE if the floater could not be closed due to pending confirmation dialogs void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } - static void onTabSelected(void* userdata, bool); + void onTabSelected(); virtual void updateResizeLimits(); diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 627f06c80..136dcf524 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -931,24 +931,6 @@ LLPanel *LLPanel::childGetVisibleTab(const std::string& id) const return NULL; } -void LLPanel::childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata, void (*on_precommit)(void*,bool)) -{ - LLTabContainer* child = getChild(id); - if (child) - { - LLPanel *panel = child->getPanelByName(tabname); - if (panel) - { - child->setTabChangeCallback(panel, on_tab_clicked); - child->setTabUserData(panel, userdata); - if (on_precommit) - { - child->setTabPrecommitChangeCallback(panel, on_precommit); - } - } - } -} - void LLPanel::childSetKeystrokeCallback(const std::string& id, void (*keystroke_callback)(LLLineEditor* caller, void* user_data), void *user_data) { LLLineEditor* child = getChild(id); diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index bb16b6e02..ad721cbf5 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -198,7 +198,6 @@ public: // LLTabContainer void childShowTab(const std::string& id, const std::string& tabname, bool visible = true); LLPanel *childGetVisibleTab(const std::string& id) const; - void childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata, void (*on_precommit)(void*,bool) = NULL); // LLTextBox void childSetWrappedText(const std::string& id, const std::string& text, bool visible = true); diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index 96604270d..946073b97 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -29,6 +29,9 @@ * $/LicenseInfo$ */ +#ifndef LL_LLSCROLLINGPANELLIST_H +#define LL_LLSCROLLINGPANELLIST_H + #include #include "llui.h" @@ -56,6 +59,8 @@ public: LLScrollingPanelList(const std::string& name, const LLRect& rect) : LLUICtrl(name, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_BOTTOM ) {} + typedef std::deque panel_list_t; + virtual void setValue(const LLSD& value) {}; virtual void draw(); @@ -64,11 +69,16 @@ public: void addPanel( LLScrollingPanel* panel ); void updatePanels(BOOL allow_modify); + const panel_list_t& getPanelList() { return mPanelList; } + virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); private: void updatePanelVisiblilty(); - std::deque mPanelList; + + panel_list_t mPanelList; }; + +#endif //LL_LLSCROLLINGPANELLIST_H diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 0f08f2c58..7d3bb20c4 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -69,19 +69,38 @@ const S32 TABCNTRV_PAD = 0; static LLRegisterWidget r("tab_container"); +// Structure used to map tab buttons to and from tab panels +class LLTabTuple +{ +public: + LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, LLTextBox* placeholder = NULL) + : + mTabContainer(c), + mTabPanel(p), + mButton(b), + mOldState(FALSE), + mPlaceholderText(placeholder), + mPadding(0) + {} + + LLTabContainer* mTabContainer; + LLPanel* mTabPanel; + LLButton* mButton; + BOOL mOldState; + LLTextBox* mPlaceholderText; + S32 mPadding; +}; + LLTabContainer::LLTabContainer(const std::string& name, const LLRect& rect, TabPosition pos, BOOL bordered, BOOL is_vertical ) : LLPanel(name, rect, bordered), mCurrentTabIdx(-1), - mNextTabIdx(-1), mTabsHidden(FALSE), mScrolled(FALSE), mScrollPos(0), mScrollPosPixels(0), mMaxScrollPos(0), - mCloseCallback( NULL ), - mCallbackUserdata( NULL ), mTitleBox(NULL), mTopBorderHeight(LLPANEL_BORDER_WIDTH), mTabPosition(pos), @@ -196,9 +215,9 @@ void LLTabContainer::draw() } } - setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f))); + setScrollPosPixels(mIsVertical ? target_pixel_scroll : lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f))); - BOOL has_scroll_arrows = (mMaxScrollPos > 0) || (mScrollPosPixels > 0); + BOOL has_scroll_arrows = !getTabsHidden() && ((mMaxScrollPos > 0) || (mScrollPosPixels > 0)); if (!mIsVertical) { mJumpPrevArrowBtn->setVisible( has_scroll_arrows ); @@ -221,13 +240,22 @@ void LLTabContainer::draw() } // Hide all the buttons - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + if (getTabsHidden() || mIsVertical) { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( FALSE ); + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + tuple->mButton->setVisible( FALSE ); + } } - LLPanel::draw(); + { + LLRect clip_rect = getLocalRect(); + clip_rect.mLeft+=(LLPANEL_BORDER_WIDTH + 2); + clip_rect.mRight-=(LLPANEL_BORDER_WIDTH + 2); + LLLocalClipRect clip(clip_rect); + LLPanel::draw(); + } // if tabs are hidden, don't draw them and leave them in the invisible state if (!getTabsHidden()) @@ -241,19 +269,10 @@ void LLTabContainer::draw() // Draw some of the buttons... LLRect clip_rect = getLocalRect(); - if (has_scroll_arrows) + if (has_scroll_arrows && mIsVertical) { - // ...but clip them. - if (mIsVertical) - { - clip_rect.mBottom = mNextArrowBtn->getRect().mTop + 3*TABCNTRV_PAD; - clip_rect.mTop = mPrevArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD; - } - else - { - clip_rect.mLeft = mPrevArrowBtn->getRect().mRight; - clip_rect.mRight = mNextArrowBtn->getRect().mLeft; - } + clip_rect.mTop = top - getScrollPosPixels(); + clip_rect.mBottom = TABCNTR_ARROW_BTN_SIZE+1; } LLLocalClipRect clip(clip_rect); @@ -285,12 +304,13 @@ void LLTabContainer::draw() } } } - LLUI::pushMatrix(); + else { + LLUI::pushMatrix(); LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); tuple->mButton->draw(); + LLUI::popMatrix(); } - LLUI::popMatrix(); idx++; } @@ -320,7 +340,7 @@ void LLTabContainer::draw() BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -355,7 +375,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) } S32 tab_count = getTabCount(); - if (tab_count > 0) + if (tab_count > 0 && !getTabsHidden()) { LLTabTuple* firsttuple = getTab(0); LLRect tab_rect; @@ -379,6 +399,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) index = llclamp(index, 0, tab_count-1); LLButton* tab_button = getTab(index)->mButton; gFocusMgr.setMouseCapture(this); + tab_button->setFocus(TRUE); gFocusMgr.setKeyboardFocus(tab_button); } } @@ -389,7 +410,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -431,7 +452,7 @@ BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -487,7 +508,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect ) { BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect ); - if (!handled && getTabCount() > 0) + if (!handled && getTabCount() > 0 && !getTabsHidden()) { LLTabTuple* firsttuple = getTab(0); @@ -523,12 +544,6 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* stic } } } - - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( FALSE ); - } } return handled; } @@ -552,7 +567,7 @@ BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask) { if (getCurrentPanel()) { - getCurrentPanel()->setFocus(TRUE); + getCurrentPanel()->setFocus(TRUE); } } @@ -633,59 +648,63 @@ LLXMLNodePtr LLTabContainer::getXML(bool save_children) const // virtual BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType type, void* cargo_data, EAcceptance *accept, std::string &tooltip) { - bool const has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0); - LLButton* button = NULL; - if (has_scroll_arrows) + if(!getTabsHidden()) { - // We're dragging an inventory item. Check if we're hovering over scroll arrows of this tab container. - if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) + // In that case, we'll open the hovered tab while dragging and dropping items. + // This allows for drilling through tabs. + if (mDragAndDropDelayTimer.getStarted()) { - button = mJumpPrevArrowBtn; - } - else if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) - { - button = mJumpNextArrowBtn; - } - else if (mPrevArrowBtn->getRect().pointInRect(x, y)) - { - button = mPrevArrowBtn; - } - else if (mNextArrowBtn->getRect().pointInRect(x, y)) - { - button = mNextArrowBtn; - } - if (button) - { - if (mDragAndDropDelayTimer.getStarted() && mDragAndDropDelayTimer.hasExpired()) + if (mDragAndDropDelayTimer.getElapsedTimeF32() > SCROLL_DELAY_TIME) { - // We've been hovering (another) SCROLL_DELAY_TIME seconds. Emulate a button press. - button->onCommit(); - // Reset the timer. - mDragAndDropDelayTimer.start(SCROLL_DELAY_TIME); - } - else if (!mDragAndDropDelayTimer.getStarted()) - { - // We just entered the arrow. Start the timer. - mDragAndDropDelayTimer.start(SCROLL_DELAY_TIME); + if (has_scroll_arrows) + { + if (mJumpPrevArrowBtn && mJumpPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpPrevArrowBtn->getRect().mBottom; + mJumpPrevArrowBtn->handleHover(local_x, local_y, mask); + } + if (mJumpNextArrowBtn && mJumpNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mJumpNextArrowBtn->getRect().mLeft; + S32 local_y = y - mJumpNextArrowBtn->getRect().mBottom; + mJumpNextArrowBtn->handleHover(local_x, local_y, mask); + } + if (mPrevArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mPrevArrowBtn->getRect().mLeft; + S32 local_y = y - mPrevArrowBtn->getRect().mBottom; + mPrevArrowBtn->handleHover(local_x, local_y, mask); + } + else if (mNextArrowBtn->getRect().pointInRect(x, y)) + { + S32 local_x = x - mNextArrowBtn->getRect().mLeft; + S32 local_y = y - mNextArrowBtn->getRect().mBottom; + mNextArrowBtn->handleHover(local_x, local_y, mask); + } + } + + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + tuple->mButton->setVisible( TRUE ); + S32 local_x = x - tuple->mButton->getRect().mLeft; + S32 local_y = y - tuple->mButton->getRect().mBottom; + if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) + { + tuple->mButton->onCommit(); + } + } + // Stop the timer whether successful or not. Don't let it run forever. + mDragAndDropDelayTimer.stop(); } } - else + else { - // We're not on an arrow or just left it. Stop the time (in case it was running). - mDragAndDropDelayTimer.stop(); - } - } - - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( TRUE ); - S32 local_x = x - tuple->mButton->getRect().mLeft; - S32 local_y = y - tuple->mButton->getRect().mBottom; - if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) - { - tuple->mButton->onCommit(); + // Start a timer so we don't open tabs as soon as we hover on them + mDragAndDropDelayTimer.start(); } } @@ -695,12 +714,11 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag void LLTabContainer::addTabPanel(LLPanel* child, const std::string& label, BOOL select, - void (*on_tab_clicked)(void*, bool), - void* userdata, S32 indent, BOOL placeholder, eInsertionPoint insertion_point) { + if (child->getParent() == this) { // already a child of mine @@ -722,22 +740,30 @@ void LLTabContainer::addTabPanel(LLPanel* child, // Tab panel S32 tab_panel_top; S32 tab_panel_bottom; - if( getTabPosition() == LLTabContainer::TOP ) + if (!getTabsHidden()) { - S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT; - tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP); - tab_panel_bottom = LLPANEL_BORDER_WIDTH; + if( getTabPosition() == LLTabContainer::TOP ) + { + S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT; + tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP); + tab_panel_bottom = LLPANEL_BORDER_WIDTH; + } + else + { + tab_panel_top = getRect().getHeight() - getTopBorderHeight(); + tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP); // Run to the edge, covering up the border + } } else { - tab_panel_top = getRect().getHeight() - getTopBorderHeight(); - tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP); // Run to the edge, covering up the border + //Scip tab button space if they are invisible(EXT - 576) + tab_panel_top = getRect().getHeight(); + tab_panel_bottom = LLPANEL_BORDER_WIDTH; } - LLRect tab_panel_rect; - if (mIsVertical) + if (!getTabsHidden() && mIsVertical) { - tab_panel_rect = LLRect(mMinTabWidth + (LLPANEL_BORDER_WIDTH * 2) + TABCNTRV_PAD, + tab_panel_rect = LLRect(mMinTabWidth + mRightTabBtnOffset + (LLPANEL_BORDER_WIDTH * 2) + TABCNTRV_PAD, getRect().getHeight() - LLPANEL_BORDER_WIDTH, getRect().getWidth() - LLPANEL_BORDER_WIDTH, LLPANEL_BORDER_WIDTH); @@ -854,24 +880,33 @@ void LLTabContainer::addTabPanel(LLPanel* child, } } - LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, textbox ); + LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox ); insertTuple( tuple, insertion_point ); - if (textbox) + //Don't add button and textbox if tab buttons are invisible(EXT - 576) + if (!getTabsHidden()) { - textbox->setSaveToXML(false); - addChild( textbox, 0 ); + if (textbox) + { + textbox->setSaveToXML(false); + addChild( textbox, 0 ); + } } if (btn) { btn->setSaveToXML(false); - btn->setClickedCallback(&LLTabContainer::onTabBtn, tuple); + btn->setClickedCallback(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); addChild( btn, 0 ); } if (child) { addChild(child, 1); } + + sendChildToFront(mPrevArrowBtn); + sendChildToFront(mNextArrowBtn); + sendChildToFront(mJumpPrevArrowBtn); + sendChildToFront(mJumpNextArrowBtn); if( select ) { @@ -883,7 +918,7 @@ void LLTabContainer::addTabPanel(LLPanel* child, void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label) { - addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE); + addTabPanel(child, label, FALSE, 0, TRUE); } void LLTabContainer::removeTabPanel(LLPanel* child) @@ -984,6 +1019,10 @@ void LLTabContainer::enableTabButton(S32 which, BOOL enable) { mTabList[which]->mButton->setEnabled(enable); } + // Stop the DaD timer as it might run forever + // enableTabButton() is typically called on refresh and draw when anything changed + // in the tab container so it's a good time to reset that. + mDragAndDropDelayTimer.stop(); } void LLTabContainer::deleteAllTabs() @@ -1154,8 +1193,8 @@ BOOL LLTabContainer::selectTabPanel(LLPanel* child) BOOL LLTabContainer::selectTab(S32 which) { - if (which >= getTabCount()) return FALSE; - if (which < 0) return FALSE; + if (which >= getTabCount() || which < 0) + return FALSE; //if( gFocusMgr.childHasKeyboardFocus( this ) ) //{ @@ -1167,28 +1206,26 @@ BOOL LLTabContainer::selectTab(S32 which) { return FALSE; } + + LLSD cbdata; + if (selected_tuple->mTabPanel) + cbdata = selected_tuple->mTabPanel->getName(); - if (!selected_tuple->mPrecommitChangeCallback) + BOOL res = FALSE; + if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) ) { - return setTab(which); + res = setTab(which); + if (res && mCommitSignal) + { + (*mCommitSignal)(this, cbdata); + } } - - mNextTabIdx = which; - selected_tuple->mPrecommitChangeCallback(selected_tuple->mUserData, false); - return TRUE; + + return res; } BOOL LLTabContainer::setTab(S32 which) { - if (which == -1) - { - if (mNextTabIdx == -1) - { - return FALSE; - } - which = mNextTabIdx; - mNextTabIdx = -1; - } LLTabTuple* selected_tuple = getTab(which); if (!selected_tuple) @@ -1212,12 +1249,12 @@ BOOL LLTabContainer::setTab(S32 which) // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs tuple->mButton->setTabStop( is_selected ); - if( is_selected && (mIsVertical || (getMaxScrollPos() > 0))) + if (is_selected) { // Make sure selected tab is within scroll region if (mIsVertical) { - S32 num_visible = getTabCount() - getMaxScrollPos(); + /*S32 num_visible = getTabCount() - getMaxScrollPos(); if( i >= getScrollPos() && i <= getScrollPos() + num_visible) { setCurrentPanelIndex(which); @@ -1226,9 +1263,28 @@ BOOL LLTabContainer::setTab(S32 which) else { is_visible = FALSE; + }*/ + if (getMaxScrollPos() > 0) + { + if( i < getScrollPos() ) + { + setScrollPos(i); + } + else + { + S32 available_height_with_arrows = getRect().getHeight() - getTopBorderHeight() - (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1); + S32 min_scroll_pos = llmax(i-llfloor(((F32)available_height_with_arrows)/((F32)BTN_HEIGHT))+1,0); + setScrollPos(llclamp(getScrollPos(), min_scroll_pos, i)); + setScrollPos(llmin(getScrollPos(), getMaxScrollPos())); + } + is_visible = TRUE; + } + else + { + is_visible = TRUE; } } - else + else if (getMaxScrollPos() > 0) { if( i < getScrollPos() ) { @@ -1259,20 +1315,20 @@ BOOL LLTabContainer::setTab(S32 which) } is_visible = TRUE; } + else + { + is_visible = TRUE; + } } i++; } - if( selected_tuple->mOnChangeCallback ) - { - selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false ); - } } - if (mIsVertical && getCurrentPanelIndex() >= 0) + /*if (mIsVertical && getCurrentPanelIndex() >= 0) { LLTabTuple* tuple = getTab(getCurrentPanelIndex()); tuple->mTabPanel->setVisible( TRUE ); tuple->mButton->setToggleState( TRUE ); - } + }*/ return is_visible; } @@ -1315,28 +1371,44 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L if( tuple ) { tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT, color); + reshapeTuple(tuple); + } +} - if (!mIsVertical) - { - const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); - // remove current width from total tab strip width - mTotalTabWidth -= tuple->mButton->getRect().getWidth(); +void LLTabContainer::setTabImage(LLPanel* child, const LLUUID& image_id, const LLColor4& color) +{ + LLTabTuple* tuple = getTabByPanel(child); + if( tuple ) + { + tuple->mButton->setImageOverlay(image_id, LLFontGL::LEFT, color); + reshapeTuple(tuple); + } +} - S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? - tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : - 0; +void LLTabContainer::reshapeTuple(LLTabTuple* tuple) +{ - tuple->mPadding = image_overlay_width; + if (!mIsVertical) + { + const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); + S32 image_overlay_width = 0; + image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? + tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : 0; + // remove current width from total tab strip width + mTotalTabWidth -= tuple->mButton->getRect().getWidth(); - tuple->mButton->setRightHPad(6); - tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), + + + tuple->mPadding = image_overlay_width; + + tuple->mButton->setRightHPad(6); + tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tuple->mButton->getRect().getHeight()); - // add back in button width to total tab strip width - mTotalTabWidth += tuple->mButton->getRect().getWidth(); + // add back in button width to total tab strip width + mTotalTabWidth += tuple->mButton->getRect().getWidth(); - // tabs have changed size, might need to scroll to see current tab - updateMaxScrollPos(); - } + // tabs have changed size, might need to scroll to see current tab + updateMaxScrollPos(); } } @@ -1368,33 +1440,6 @@ S32 LLTabContainer::getTopBorderHeight() const return mTopBorderHeight; } -void LLTabContainer::setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*, bool)) -{ - LLTabTuple* tuplep = getTabByPanel(tab); - if (tuplep) - { - tuplep->mOnChangeCallback = on_tab_clicked; - } -} - -void LLTabContainer::setTabPrecommitChangeCallback(LLPanel* tab, void (*on_precommit)(void*, bool)) -{ - LLTabTuple* tuplep = getTabByPanel(tab); - if (tuplep) - { - tuplep->mPrecommitChangeCallback = on_precommit; - } -} - -void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata) -{ - LLTabTuple* tuplep = getTabByPanel(tab); - if (tuplep) - { - tuplep->mUserData = userdata; - } -} - void LLTabContainer::setRightTabBtnOffset(S32 offset) { mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 ); @@ -1408,7 +1453,7 @@ void LLTabContainer::setPanelTitle(S32 index, const std::string& title) { LLTabTuple* tuple = getTab(index); LLButton* tab_button = tuple->mButton; - const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); + const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall(); mTotalTabWidth -= tab_button->getRect().getWidth(); tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); mTotalTabWidth += tab_button->getRect().getWidth(); @@ -1419,84 +1464,62 @@ void LLTabContainer::setPanelTitle(S32 index, const std::string& title) } -// static -void LLTabContainer::onTabBtn( void* userdata ) +void LLTabContainer::onTabBtn( const LLSD& data, LLPanel* panel ) { - LLTabTuple* tuple = (LLTabTuple*) userdata; - LLTabContainer* self = tuple->mTabContainer; - self->selectTabPanel( tuple->mTabPanel ); + LLTabTuple* tuple = getTabByPanel(panel); + selectTabPanel( panel ); - tuple->mTabPanel->setFocus(TRUE); -} - -// static -void LLTabContainer::onCloseBtn( void* userdata ) -{ - LLTabContainer* self = (LLTabContainer*) userdata; - if( self->mCloseCallback ) + if (tuple) { - self->mCloseCallback( self->mCallbackUserdata ); + tuple->mTabPanel->setFocus(TRUE); } } -// static -void LLTabContainer::onNextBtn( void* userdata ) +void LLTabContainer::onNextBtn( const LLSD& data ) { - // Scroll tabs to the left - LLTabContainer* self = (LLTabContainer*) userdata; - if (!self->mScrolled) + if (!mScrolled) { - self->scrollNext(); + scrollNext(); } - self->mScrolled = FALSE; + mScrolled = FALSE; } -// static -void LLTabContainer::onNextBtnHeld( void* userdata ) +void LLTabContainer::onNextBtnHeld( const LLSD& data ) { - LLTabContainer* self = (LLTabContainer*) userdata; - if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) + if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) { - self->mScrollTimer.reset(); - self->scrollNext(); - self->mScrolled = TRUE; + mScrollTimer.reset(); + scrollNext(); + mScrolled = TRUE; } } -// static -void LLTabContainer::onPrevBtn( void* userdata ) +void LLTabContainer::onPrevBtn( const LLSD& data ) { - LLTabContainer* self = (LLTabContainer*) userdata; - if (!self->mScrolled) + if (!mScrolled) { - self->scrollPrev(); + scrollPrev(); } - self->mScrolled = FALSE; + mScrolled = FALSE; } -// static -void LLTabContainer::onJumpFirstBtn( void* userdata ) +void LLTabContainer::onJumpFirstBtn( const LLSD& data ) { - LLTabContainer* self = (LLTabContainer*) userdata; - self->mScrollPos = 0; + mScrollPos = 0; } -// static -void LLTabContainer::onJumpLastBtn( void* userdata ) +void LLTabContainer::onJumpLastBtn( const LLSD& data ) { - LLTabContainer* self = (LLTabContainer*) userdata; - self->mScrollPos = self->mMaxScrollPos; + mScrollPos = mMaxScrollPos; } -// static -void LLTabContainer::onPrevBtnHeld( void* userdata ) +void LLTabContainer::onPrevBtnHeld( const LLSD& data ) { - LLTabContainer* self = (LLTabContainer*) userdata; - if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) + if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME) { - self->mScrollTimer.reset(); - self->scrollPrev(); - self->mScrolled = TRUE; + mScrollTimer.reset(); + scrollPrev(); + mScrolled = TRUE; } } @@ -1583,8 +1606,7 @@ LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto } BOOL placeholder = FALSE; child->getAttributeBOOL("placeholder", placeholder); - tab_container->addTabPanel(panelp, label, false, - NULL, NULL, 0, placeholder); + tab_container->addTabPanel(panelp, label, false, 0, placeholder); } } @@ -1614,7 +1636,7 @@ void LLTabContainer::initButtons() { // Left and right scroll arrows (for when there are too many tabs to show all at once). S32 btn_top = getRect().getHeight(); - S32 btn_top_lower = getRect().mBottom+TABCNTRV_ARROW_BTN_SIZE; + S32 btn_top_lower = TABCNTRV_ARROW_BTN_SIZE; LLRect up_arrow_btn_rect; up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE ); @@ -1625,18 +1647,20 @@ void LLTabContainer::initButtons() out_id = "UIImgBtnScrollUpOutUUID"; in_id = "UIImgBtnScrollUpInUUID"; mPrevArrowBtn = new LLButton(std::string("Up Arrow"), up_arrow_btn_rect, - out_id, in_id, LLStringUtil::null, - &onPrevBtn, this, NULL ); + out_id, in_id, LLStringUtil::null, NULL ); mPrevArrowBtn->setFollowsTop(); mPrevArrowBtn->setFollowsLeft(); - + mPrevArrowBtn->setCommitCallback(boost::bind(&LLTabContainer::onPrevBtn,this,_2)); + mPrevArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2)); + out_id = "UIImgBtnScrollDownOutUUID"; in_id = "UIImgBtnScrollDownInUUID"; mNextArrowBtn = new LLButton(std::string("Down Arrow"), down_arrow_btn_rect, - out_id, in_id, LLStringUtil::null, - &onNextBtn, this, NULL ); + out_id, in_id, LLStringUtil::null, NULL ); mNextArrowBtn->setFollowsBottom(); mNextArrowBtn->setFollowsLeft(); + mNextArrowBtn->setCommitCallback(boost::bind(&LLTabContainer::onNextBtn,this,_2)); + mNextArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onNextBtnHeld, this, _2)); } else // Horizontal { @@ -1674,31 +1698,35 @@ void LLTabContainer::initButtons() in_id = "UIImgBtnJumpLeftInUUID"; mJumpPrevArrowBtn = new LLButton(std::string("Jump Left Arrow"), jump_left_arrow_btn_rect, out_id, in_id, LLStringUtil::null, - &LLTabContainer::onJumpFirstBtn, this, LLFontGL::getFontSansSerif() ); + NULL, NULL, LLFontGL::getFontSansSerif() ); + mJumpPrevArrowBtn->setCommitCallback(boost::bind(&LLTabContainer::onJumpFirstBtn, this, _2)); mJumpPrevArrowBtn->setFollowsLeft(); out_id = "UIImgBtnScrollLeftOutUUID"; in_id = "UIImgBtnScrollLeftInUUID"; mPrevArrowBtn = new LLButton(std::string("Left Arrow"), left_arrow_btn_rect, out_id, in_id, LLStringUtil::null, - &LLTabContainer::onPrevBtn, this, LLFontGL::getFontSansSerif() ); - mPrevArrowBtn->setHeldDownCallback(boost::bind(LLTabContainer::onPrevBtnHeld, this)); + NULL, NULL, LLFontGL::getFontSansSerif() ); + + mPrevArrowBtn->setCommitCallback(boost::bind(&LLTabContainer::onPrevBtn, this, _2)); + mPrevArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2)); mPrevArrowBtn->setFollowsLeft(); out_id = "UIImgBtnJumpRightOutUUID"; in_id = "UIImgBtnJumpRightInUUID"; mJumpNextArrowBtn = new LLButton(std::string("Jump Right Arrow"), jump_right_arrow_btn_rect, out_id, in_id, LLStringUtil::null, - &LLTabContainer::onJumpLastBtn, this, - LLFontGL::getFontSansSerif()); + NULL, NULL, LLFontGL::getFontSansSerif()); + mJumpNextArrowBtn->setCommitCallback(boost::bind(&LLTabContainer::onJumpLastBtn, this, _2)); mJumpNextArrowBtn->setFollowsRight(); out_id = "UIImgBtnScrollRightOutUUID"; in_id = "UIImgBtnScrollRightInUUID"; mNextArrowBtn = new LLButton(std::string("Right Arrow"), right_arrow_btn_rect, out_id, in_id, LLStringUtil::null, - &LLTabContainer::onNextBtn, this, - LLFontGL::getFontSansSerif()); + NULL, NULL, LLFontGL::getFontSansSerif()); + mNextArrowBtn->setCommitCallback(boost::bind(&LLTabContainer::onNextBtn, this, _2)); + mNextArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onNextBtnHeld, this, _2)); mNextArrowBtn->setFollowsRight(); if( getTabPosition() == TOP ) @@ -1717,12 +1745,10 @@ void LLTabContainer::initButtons() } } - mPrevArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onPrevBtnHeld, this)); mPrevArrowBtn->setSaveToXML(false); mPrevArrowBtn->setTabStop(FALSE); addChild(mPrevArrowBtn); - - mNextArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onNextBtnHeld, this)); + mNextArrowBtn->setSaveToXML(false); mNextArrowBtn->setTabStop(FALSE); addChild(mNextArrowBtn); @@ -1745,7 +1771,7 @@ void LLTabContainer::initButtons() setDefaultTabGroup(1); } -LLTabContainer::LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child) +LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child) { for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { @@ -1794,11 +1820,11 @@ void LLTabContainer::updateMaxScrollPos() BOOL no_scroll = TRUE; if (mIsVertical) { - S32 tab_total_height = (BTN_HEIGHT + TABCNTRV_PAD) * getTabCount(); - S32 available_height = getRect().getHeight() - getTopBorderHeight(); + S32 tab_total_height = (BTN_HEIGHT + TABCNTRV_PAD) * getTabCount() + TABCNTRV_PAD; + S32 available_height = getRect().getHeight() - getTopBorderHeight() - 2 * LLPANEL_BORDER_WIDTH; if( tab_total_height > available_height ) { - S32 available_height_with_arrows = getRect().getHeight() - 2*(TABCNTRV_ARROW_BTN_SIZE + 3*TABCNTRV_PAD); + S32 available_height_with_arrows = getRect().getHeight() - getTopBorderHeight() - (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1); S32 additional_needed = tab_total_height - available_height_with_arrows; setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) ); no_scroll = FALSE; @@ -1846,12 +1872,12 @@ void LLTabContainer::updateMaxScrollPos() void LLTabContainer::commitHoveredButton(S32 x, S32 y) { - if (hasMouseCapture()) + if (!getTabsHidden() && hasMouseCapture()) { for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( TRUE ); + //tuple->mButton->setVisible( TRUE ); S32 local_x = x - tuple->mButton->getRect().mLeft; S32 local_y = y - tuple->mButton->getRect().mBottom; if (tuple->mButton->pointInView(local_x, local_y) && tuple->mButton->getEnabled() && !tuple->mTabPanel->getVisible()) diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 8117cdee9..de5a51639 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -36,6 +36,7 @@ #include "llpanel.h" #include "lltextbox.h" #include "llframetimer.h" +class LLTabTuple; extern const S32 TABCNTR_HEADER_HEIGHT; @@ -79,9 +80,7 @@ public: void addTabPanel(LLPanel* child, const std::string& label, - BOOL select = FALSE, - void (*on_tab_clicked)(void*, bool) = NULL, - void* userdata = NULL, + BOOL select = FALSE, S32 indent = 0, BOOL placeholder = FALSE, eInsertionPoint insertion_point = END); @@ -108,20 +107,16 @@ public: BOOL selectTabPanel( LLPanel* child ); BOOL selectTab(S32 which); BOOL selectTabByName(const std::string& title); - BOOL setTab(S32 which); BOOL getTabPanelFlashing(LLPanel* child); void setTabPanelFlashing(LLPanel* child, BOOL state); void setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white); + void setTabImage(LLPanel* child, const LLUUID& img_id, const LLColor4& color = LLColor4::white); void setTitle( const std::string& title ); const std::string getPanelTitle(S32 index); void setTopBorderHeight(S32 height); S32 getTopBorderHeight() const; - - void setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*,bool)); - void setTabPrecommitChangeCallback(LLPanel* tab, void (*on_precommit)(void*, bool)); - void setTabUserData(LLPanel* tab, void* userdata); void setRightTabBtnOffset( S32 offset ); void setPanelTitle(S32 index, const std::string& title); @@ -134,51 +129,22 @@ public: void startDragAndDropDelayTimer() { mDragAndDropDelayTimer.start(); } - static void onCloseBtn(void* userdata); - static void onTabBtn(void* userdata); - static void onNextBtn(void* userdata); - static void onNextBtnHeld(void* userdata); - static void onPrevBtn(void* userdata); - static void onPrevBtnHeld(void* userdata); - static void onJumpFirstBtn( void* userdata ); - static void onJumpLastBtn( void* userdata ); + void onTabBtn( const LLSD& data, LLPanel* panel ); + void onNextBtn(const LLSD& data); + void onNextBtnHeld(const LLSD& data); + void onPrevBtn(const LLSD& data); + void onPrevBtnHeld(const LLSD& data); + void onJumpFirstBtn( const LLSD& data ); + void onJumpLastBtn( const LLSD& data ); static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); private: - // Structure used to map tab buttons to and from tab panels - struct LLTabTuple - { - LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, - void (*cb)(void*,bool), void* userdata, LLTextBox* placeholder = NULL, - void (*pcb)(void*,bool) = NULL) - : - mTabContainer(c), - mTabPanel(p), - mButton(b), - mOnChangeCallback( cb ), - mPrecommitChangeCallback( pcb ), - mUserData( userdata ), - mOldState(FALSE), - mPlaceholderText(placeholder), - mPadding(0) - {} - - LLTabContainer* mTabContainer; - LLPanel* mTabPanel; - LLButton* mButton; - void (*mOnChangeCallback)(void*, bool); - void (*mPrecommitChangeCallback)(void*,bool); // Precommit callback gets called before tab is changed and - // can prevent it from being changed. onChangeCallback is called - // immediately after tab is actually changed - Nyx - void* mUserData; - BOOL mOldState; - LLTextBox* mPlaceholderText; - S32 mPadding; - }; void initButtons(); + BOOL setTab(S32 which); + LLTabTuple* getTab(S32 index) { return mTabList[index]; } LLTabTuple* getTabByPanel(LLPanel* child); void insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point); @@ -201,13 +167,13 @@ private: void updateMaxScrollPos(); void commitHoveredButton(S32 x, S32 y); + void reshapeTuple(LLTabTuple* tuple); // Variables typedef std::vector tuple_list_t; tuple_list_t mTabList; S32 mCurrentTabIdx; - S32 mNextTabIdx; BOOL mTabsHidden; BOOL mScrolled; @@ -216,9 +182,6 @@ private: S32 mScrollPosPixels; S32 mMaxScrollPos; - void (*mCloseCallback)(void*); - void* mCallbackUserdata; - LLTextBox* mTitleBox; S32 mTopBorderHeight; diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 4472a9a07..24a13d36e 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -228,7 +228,7 @@ bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNo bool LLUICtrlFactory::getLayeredXMLNodeFromBuffer(const std::string &buffer, LLXMLNodePtr& root) { - if (!LLXMLNode::parseBuffer(buffer.data(), buffer.size(), root, 0)) { + if (!LLXMLNode::parseBuffer((U8*)buffer.data(), buffer.size(), root, 0)) { llwarns << "Error reading UI description from buffer." << llendl; return false; } diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index db9caf8c0..b35585527 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -64,6 +64,7 @@ LLXMLNode::LLXMLNode() : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -85,6 +86,7 @@ LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -106,6 +108,7 @@ LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -127,6 +130,8 @@ LLXMLNode::LLXMLNode(const LLXMLNode& rhs) : mPrecision(rhs.mPrecision), mType(rhs.mType), mEncoding(rhs.mEncoding), + mLineNumber(0), + mParser(NULL), mParent(NULL), mChildren(NULL), mAttributes(), @@ -226,6 +231,10 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) { mChildren->head = target_child->mNext; } + if (target_child == mChildren->tail) + { + mChildren->tail = target_child->mPrev; + } LLXMLNodePtr prev = target_child->mPrev; LLXMLNodePtr next = target_child->mNext; @@ -294,6 +303,22 @@ void LLXMLNode::addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child) mChildren->tail = new_child; } } + // if after_child == parent, then put new_child at beginning + else if (after_child == this) + { + // add to front of list + new_child->mNext = mChildren->head; + if (mChildren->head) + { + mChildren->head->mPrev = new_child; + mChildren->head = new_child; + } + else // no children + { + mChildren->head = new_child; + mChildren->tail = new_child; + } + } else { if (after_child->mNext.notNull()) @@ -401,7 +426,8 @@ void XMLCALL StartXMLNode(void *userData, } new_node_ptr->mParser = parent->mParser; - + new_node_ptr->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); + // Set the current active node to the new node XML_Parser *parser = parent->mParser; XML_SetUserData(*parser, (void *)new_node_ptr); @@ -492,6 +518,7 @@ void XMLCALL StartXMLNode(void *userData, if (!new_node->getAttribute(attr_name.c_str(), attr_node, FALSE)) { attr_node = new LLXMLNode(attr_name.c_str(), TRUE); + attr_node->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); } attr_node->setValue(attr_value); new_node->addChild(attr_node); @@ -608,13 +635,14 @@ bool LLXMLNode::updateNode( } //update all of node's children with updateNodes children that match name - LLXMLNodePtr child; + LLXMLNodePtr child = node->getFirstChild(); + LLXMLNodePtr last_child = child; LLXMLNodePtr updateChild; for (updateChild = update_node->getFirstChild(); updateChild.notNull(); updateChild = updateChild->getNextSibling()) { - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) + while(child.notNull()) { std::string nodeName; std::string updateName; @@ -633,6 +661,22 @@ bool LLXMLNode::updateNode( if ((nodeName != "") && (updateName == nodeName)) { updateNode(child, updateChild); + last_child = child; + child = child->getNextSibling(); + if (child.isNull()) + { + child = node->getFirstChild(); + } + break; + } + + child = child->getNextSibling(); + if (child.isNull()) + { + child = node->getFirstChild(); + } + if (child == last_child) + { break; } } @@ -670,14 +714,14 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ if (fp == NULL) { - node = new LLXMLNode(); + node = NULL ; return false; } fseek(fp, 0, SEEK_END); U32 length = ftell(fp); fseek(fp, 0, SEEK_SET); - char *buffer = new char[length+1]; + U8* buffer = new U8[length+1]; size_t nread = fread(buffer, 1, length, fp); buffer[nread] = 0; fclose(fp); @@ -689,7 +733,7 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML // static bool LLXMLNode::parseBuffer( - const char *buffer, + U8* buffer, U32 length, LLXMLNodePtr& node, LLXMLNode* defaults) @@ -708,7 +752,7 @@ bool LLXMLNode::parseBuffer( XML_SetUserData(my_parser, (void *)file_node_ptr); // Do the parsing - if (XML_Parse(my_parser, buffer, length, TRUE) != XML_STATUS_OK) + if (XML_Parse(my_parser, (const char *)buffer, length, TRUE) != XML_STATUS_OK) { llwarns << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) @@ -723,7 +767,7 @@ bool LLXMLNode::parseBuffer( { llwarns << "Parse failure - wrong number of top-level nodes xml." << llendl; - node = new LLXMLNode(); + node = NULL ; return false; } @@ -761,7 +805,7 @@ bool LLXMLNode::parseStream( while(str.good()) { str.read((char*)buffer, BUFSIZE); - int count = str.gcount(); + int count = (int)str.gcount(); if (XML_Parse(my_parser, (const char *)buffer, count, !str.good()) != XML_STATUS_OK) { @@ -782,7 +826,7 @@ bool LLXMLNode::parseStream( { llwarns << "Parse failure - wrong number of top-level nodes xml." << llendl; - node = new LLXMLNode(); + node = NULL; return false; } @@ -836,12 +880,64 @@ BOOL LLXMLNode::isFullyDefault() } // static -void LLXMLNode::writeHeaderToFile(LLFILE *fOut) +bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, + const std::vector& paths) { - fprintf(fOut, "\n"); + if (paths.empty()) return false; + + std::string filename = paths.front(); + if (filename.empty()) + { + return false; + } + + if (!LLXMLNode::parseFile(filename, root, NULL)) + { + llwarns << "Problem reading UI description file: " << filename << llendl; + return false; + } + + LLXMLNodePtr updateRoot; + + std::vector::const_iterator itor; + + for (itor = paths.begin(), ++itor; itor != paths.end(); ++itor) + { + std::string layer_filename = *itor; + if(layer_filename.empty() || layer_filename == filename) + { + // no localized version of this file, that's ok, keep looking + continue; + } + + if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL)) + { + llwarns << "Problem reading localized UI description file: " << layer_filename << llendl; + return false; + } + + std::string nodeName; + std::string updateName; + + updateRoot->getAttributeString("name", updateName); + root->getAttributeString("name", nodeName); + + if (updateName == nodeName) + { + LLXMLNode::updateNode(root, updateRoot); + } + } + + return true; } -void LLXMLNode::writeToFile(LLFILE *fOut, const std::string& indent) +// static +void LLXMLNode::writeHeaderToFile(LLFILE *out_file) +{ + fprintf(out_file, "\n"); +} + +void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations) { if (isFullyDefault()) { @@ -850,15 +946,16 @@ void LLXMLNode::writeToFile(LLFILE *fOut, const std::string& indent) } std::ostringstream ostream; - writeToOstream(ostream, indent); + writeToOstream(ostream, indent, use_type_decorations); std::string outstring = ostream.str(); - if (fwrite(outstring.c_str(), 1, outstring.length(), fOut) != outstring.length()) + size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file); + if (written != outstring.length()) { llwarns << "Short write" << llendl; } } -void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent) +void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent, bool use_type_decorations) { if (isFullyDefault()) { @@ -872,84 +969,86 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i BOOL has_default_length = mDefault.isNull()?FALSE:(mLength == mDefault->mLength); // stream the name - output_stream << indent << "<" << mName->mString; + output_stream << indent << "<" << mName->mString << "\n"; - // ID - if (mID != "") + if (use_type_decorations) { - output_stream << " id=\"" << mID << "\""; - } - - // Type - if (!has_default_type) - { - switch (mType) + // ID + if (mID != "") { - case TYPE_BOOLEAN: - output_stream << " type=\"boolean\""; - break; - case TYPE_INTEGER: - output_stream << " type=\"integer\""; - break; - case TYPE_FLOAT: - output_stream << " type=\"float\""; - break; - case TYPE_STRING: - output_stream << " type=\"string\""; - break; - case TYPE_UUID: - output_stream << " type=\"uuid\""; - break; - case TYPE_NODEREF: - output_stream << " type=\"noderef\""; - break; - default: - // default on switch(enum) eliminates a warning on linux - break; - }; - } + output_stream << indent << " id=\"" << mID << "\"\n"; + } - // Encoding - if (!has_default_encoding) - { - switch (mEncoding) + // Type + if (!has_default_type) { - case ENCODING_DECIMAL: - output_stream << " encoding=\"decimal\""; - break; - case ENCODING_HEX: - output_stream << " encoding=\"hex\""; - break; - /*case ENCODING_BASE32: - output_stream << " encoding=\"base32\""; - break;*/ - default: - // default on switch(enum) eliminates a warning on linux - break; - }; - } + switch (mType) + { + case TYPE_BOOLEAN: + output_stream << indent << " type=\"boolean\"\n"; + break; + case TYPE_INTEGER: + output_stream << indent << " type=\"integer\"\n"; + break; + case TYPE_FLOAT: + output_stream << indent << " type=\"float\"\n"; + break; + case TYPE_STRING: + output_stream << indent << " type=\"string\"\n"; + break; + case TYPE_UUID: + output_stream << indent << " type=\"uuid\"\n"; + break; + case TYPE_NODEREF: + output_stream << indent << " type=\"noderef\"\n"; + break; + default: + // default on switch(enum) eliminates a warning on linux + break; + }; + } - // Precision - if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT)) - { - output_stream << " precision=\"" << mPrecision << "\""; - } + // Encoding + if (!has_default_encoding) + { + switch (mEncoding) + { + case ENCODING_DECIMAL: + output_stream << indent << " encoding=\"decimal\"\n"; + break; + case ENCODING_HEX: + output_stream << indent << " encoding=\"hex\"\n"; + break; + /*case ENCODING_BASE32: + output_stream << indent << " encoding=\"base32\"\n"; + break;*/ + default: + // default on switch(enum) eliminates a warning on linux + break; + }; + } - // Version - if (mVersionMajor > 0 || mVersionMinor > 0) - { - output_stream << " version=\"" << mVersionMajor << "." << mVersionMinor << "\""; - } + // Precision + if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT)) + { + output_stream << indent << " precision=\"" << mPrecision << "\"\n"; + } - // Array length - if (!has_default_length && mLength > 0) - { - output_stream << " length=\"" << mLength << "\""; + // Version + if (mVersionMajor > 0 || mVersionMinor > 0) + { + output_stream << indent << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"\n"; + } + + // Array length + if (!has_default_length && mLength > 0) + { + output_stream << indent << " length=\"" << mLength << "\"\n"; + } } { // Write out attributes - S32 col_pos = 0; LLXMLAttribList::const_iterator attr_itr; LLXMLAttribList::const_iterator attr_end = mAttributes.end(); for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr) @@ -958,12 +1057,13 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue) { std::string attr = child->mName->mString; - if (attr == "id" || - attr == "type" || - attr == "encoding" || - attr == "precision" || - attr == "version" || - attr == "length") + if (use_type_decorations + && (attr == "id" || + attr == "type" || + attr == "encoding" || + attr == "precision" || + attr == "version" || + attr == "length")) { continue; // skip built-in attributes } @@ -971,17 +1071,14 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i std::string attr_str = llformat(" %s=\"%s\"", attr.c_str(), escapeXML(child->mValue).c_str()); - if (col_pos + (S32)attr_str.length() > MAX_COLUMN_WIDTH) - { - output_stream << "\n" << indent << " "; - col_pos = 4; - } - col_pos += attr_str.length(); - output_stream << attr_str; + output_stream << indent << attr_str << "\n"; } } } + // erase last \n before attaching final > or /> + output_stream.seekp(-1, std::ios::cur); + if (mChildren.isNull() && mValue == "") { output_stream << " />\n"; @@ -993,16 +1090,16 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i if (mChildren.notNull()) { // stream non-attributes - std::string next_indent = indent + "\t"; + std::string next_indent = indent + " "; for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling()) { - child->writeToOstream(output_stream, next_indent); + child->writeToOstream(output_stream, next_indent, use_type_decorations); } } if (!mValue.empty()) { std::string contents = getTextContents(); - output_stream << indent << "\t" << escapeXML(contents) << "\n"; + output_stream << indent << " " << escapeXML(contents) << "\n"; } output_stream << indent << "mString << ">\n"; } @@ -1130,7 +1227,7 @@ bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOO { return mDefault->getChild(name, node, FALSE); } - node = new LLXMLNode(); + node = NULL; return false; } @@ -1201,7 +1298,7 @@ bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, { return mDefault->getAttribute(name, node, FALSE); } - node = new LLXMLNode(); + return false; } @@ -2475,14 +2572,15 @@ std::string LLXMLNode::escapeXML(const std::string& xml) return out; } -void LLXMLNode::setStringValue(U32 length, const std::string *array) +void LLXMLNode::setStringValue(U32 length, const std::string *strings) { if (length == 0) return; std::string new_value; for (U32 pos=0; pos @@ -44,10 +44,11 @@ #include #include "indra_constants.h" -#include "llmemory.h" -#include "llthread.h" +#include "llpointer.h" +#include "llthread.h" // LLThreadSafeRefCount #include "llstring.h" #include "llstringtable.h" +#include "llfile.h" class LLVector3; @@ -141,7 +142,7 @@ public: LLXMLNodePtr& node, LLXMLNode* defaults_tree); static bool parseBuffer( - const char *buffer, + U8* buffer, U32 length, LLXMLNodePtr& node, LLXMLNode* defaults); @@ -153,9 +154,18 @@ public: LLXMLNodePtr& node, LLXMLNodePtr& update_node); static LLXMLNodePtr replaceNode(LLXMLNodePtr node, LLXMLNodePtr replacement_node); - static void writeHeaderToFile(LLFILE *fOut); - void writeToFile(LLFILE *fOut, const std::string& indent = std::string()); - void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string()); + + static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector& paths); + + + // Write standard XML file header: + // + static void writeHeaderToFile(LLFILE *out_file); + + // Write XML to file with one attribute per line. + // XML escapes values as they are written. + void writeToFile(LLFILE *out_file, const std::string& indent = std::string(), bool use_type_decorations=true); + void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string(), bool use_type_decorations=true); // Utility void findName(const std::string& name, LLXMLNodeList &results); @@ -207,6 +217,7 @@ public: U32 getLength() const { return mLength; } U32 getPrecision() const { return mPrecision; } const std::string& getValue() const { return mValue; } + std::string getSanitizedValue() const; std::string getTextContents() const; const LLStringTableEntry* getName() const { return mName; } BOOL hasName(const char* name) const { return mName == gStringTable.checkStringEntry(name); } @@ -227,6 +238,8 @@ public: bool getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); + S32 getLineNumber(); + // The following skip over attributes LLXMLNodePtr getFirstChild() const; LLXMLNodePtr getNextSibling() const; @@ -262,6 +275,8 @@ public: void setName(const std::string& name); void setName(LLStringTableEntry* name); + void setLineNumber(S32 line_number); + // Escapes " (quot) ' (apos) & (amp) < (lt) > (gt) static std::string escapeXML(const std::string& xml); @@ -300,6 +315,7 @@ public: U32 mPrecision; // The number of BITS per array item ValueType mType; // The value type Encoding mEncoding; // The value encoding + S32 mLineNumber; // line number in source file, if applicable LLXMLNode* mParent; // The parent node LLXMLChildrenPtr mChildren; // The child nodes diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b3661472b..83125c7fd 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -341,6 +341,7 @@ set(viewer_SOURCE_FILES llpanelavatar.cpp llpanelclassified.cpp llpanelcontents.cpp + llpaneleditwearable.cpp llpaneldebug.cpp llpaneldirbrowser.cpp llpaneldirclassified.cpp @@ -404,6 +405,8 @@ set(viewer_SOURCE_FILES llregionposition.cpp llremoteparcelrequest.cpp llsavedsettingsglue.cpp + llscrollingpanelparam.cpp + llscrollingpanelparambase.cpp llselectmgr.cpp llsky.cpp llspatialpartition.cpp @@ -833,6 +836,7 @@ set(viewer_HEADER_FILES llpanelavatar.h llpanelclassified.h llpanelcontents.h + llpaneleditwearable.h llpaneldebug.h llpaneldirbrowser.h llpaneldirclassified.h @@ -898,6 +902,8 @@ set(viewer_HEADER_FILES llremoteparcelrequest.h llresourcedata.h llsavedsettingsglue.h + llscrollingpanelparam.h + llscrollingpanelparambase.h llselectmgr.h llsky.h llspatialpartition.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 4e8aac711..22e357a2d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -783,17 +783,6 @@ Value 0 - EmeraldUseProperArc - - Comment - Enables/Disables a fixed ARC counter - Persist - 1 - Type - Boolean - Value - 0 - EmeraldBoobMass Comment @@ -825,17 +814,6 @@ Type Boolean Value - 1 - - EmeraldBreastSportsBra - - Comment - allows disabling the physics for 1 av, in case their outfit looks wrong with it on - Persist - 1 - Type - Boolean - Value 0 EmeraldBoobVelMax @@ -7245,6 +7223,39 @@ Value 1.0 + InventoryDisplayInbox + + Comment + Override received items inventory inbox display + Persist + 0 + Type + Boolean + Value + 0 + + InventoryDisplayOutbox + + Comment + Override merchant inventory outbox display + Persist + 0 + Type + Boolean + Value + 0 + + InventoryOutboxLogging + + Comment + Enable debug output associated with the Merchant Outbox. + Persist + 1 + Type + Boolean + Value + 0 + InventoryOutboxMaxFolderCount Comment @@ -11172,7 +11183,7 @@ Comment Maximum size of a single node's vertex data (in KB). Persist - 0 + 1 Type S32 Value @@ -11553,28 +11564,19 @@ Value 0 - RenderUseShaderLOD + + RenderAutoHideSurfaceAreaLimit Comment - Whether we want to have different shaders for LOD + Maximum surface area of a set of proximal objects inworld before automatically hiding geometry to prevent system overload. Persist 1 Type - Boolean - Value - 1 - - RenderUseShaderNearParticles - - Comment - Whether we want to use shaders on near particles - Persist - 1 - Type - Boolean + F32 Value 0 + RenderVBOEnable Comment @@ -13243,6 +13245,39 @@ Value 20.0 + TexelPixelRatio + + Comment + texel pixel ratio = texel / pixel + Persist + 1 + Type + F32 + Value + 1.0 + + TextureCameraMotionThreshold + + Comment + If the overall motion is lower than this value, textures will be loaded faster + Persist + 1 + Type + F32 + Value + 0.2 + + TextureCameraMotionBoost + + Comment + Progressive discard level decrement when the camera is still + Persist + 1 + Type + S32 + Value + 3 + TextureDecodeDisabled Comment diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl index cb87b754b..1113a9845 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl @@ -31,6 +31,8 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif +uniform float minimum_alpha; + uniform sampler2DRect depthMap; uniform sampler2D diffuseMap; @@ -70,9 +72,15 @@ void main() vec4 diff= texture2D(diffuseMap,vary_texcoord0.xy); + if (diff.a < minimum_alpha) + { + discard; + } + vec4 col = vec4(vary_ambient + vary_directional.rgb, 1.0); vec4 color = diff * col; + color.rgb = atmosLighting(color.rgb); color.rgb = scaleSoftClip(color.rgb); diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl index 75de47614..bff87cb6a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl @@ -55,8 +55,6 @@ uniform float far_clip; uniform vec3 proj_origin; //origin of projection to be used for angular attenuation uniform float sun_wash; -uniform int proj_shadow_idx; -uniform float shadow_fade; uniform vec3 center; uniform vec3 color; @@ -143,7 +141,8 @@ void main() discard; } - vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0; + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0, norm.z); norm = normalize(norm); float l_dist = -dot(lv, proj_n); diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl index 19800a8b8..f671d5b75 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl @@ -42,12 +42,13 @@ uniform sampler2DRect depthMap; uniform vec3 env_mat[3]; uniform float sun_wash; -uniform vec3 center; uniform vec3 color; uniform float falloff; uniform float size; VARYING vec4 vary_fragcoord; +VARYING vec3 trans_center; + uniform vec2 screen_res; uniform mat4 inv_proj; @@ -74,7 +75,7 @@ void main() frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = center.xyz-pos; + vec3 lv = trans_center.xyz-pos; float dist2 = dot(lv,lv); dist2 /= size; if (dist2 > 1.0) diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl index cb14e6d4e..949142123 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl @@ -24,16 +24,22 @@ */ uniform mat4 modelview_projection_matrix; +uniform mat4 modelview_matrix; ATTRIBUTE vec3 position; +uniform vec3 center; +uniform float size; + VARYING vec4 vary_fragcoord; +VARYING vec3 trans_center; void main() { //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); + vec3 p = position*sqrt(size)+center; + vec4 pos = modelview_projection_matrix * vec4(p.xyz, 1.0); vary_fragcoord = pos; - + trans_center = (modelview_matrix*vec4(center.xyz, 1.0)).xyz; gl_Position = pos; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl new file mode 100644 index 000000000..6195e2f1e --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl @@ -0,0 +1,44 @@ +/** + * @file shadowCubeV.glsl + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; + +VARYING vec4 post_pos; + +uniform vec3 box_center; +uniform vec3 box_size; + +void main() +{ + //transform vertex + vec3 p = position*box_size+box_center; + vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0); + + post_pos = pos; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl index 7ed8ed337..cca63872d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl @@ -24,18 +24,21 @@ */ -#extension GL_ARB_texture_rectangle : enable - #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else #define frag_color gl_FragColor #endif +//class 1 -- no shadows + +#extension GL_ARB_texture_rectangle : enable + uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; +uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D projectionMap; @@ -46,6 +49,7 @@ uniform vec3 proj_n; uniform float proj_focus; //distance from plane to begin blurring uniform float proj_lod; //(number of mips in proj map) uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambient_lod; uniform float proj_ambiance; uniform float near_clip; uniform float far_clip; @@ -53,19 +57,66 @@ uniform float far_clip; uniform vec3 proj_origin; //origin of projection to be used for angular attenuation uniform float sun_wash; -uniform vec3 center; uniform vec3 color; uniform float falloff; uniform float size; VARYING vec4 vary_fragcoord; +VARYING vec3 trans_center; + uniform vec2 screen_res; uniform mat4 inv_proj; +vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float det = max(1.0-lod/(proj_lod*0.5), 0.0); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); + + return ret; +} + +vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + + float det = min(lod/(proj_lod*0.5), 1.0); + + float d = min(dist.x, dist.y); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + + vec4 getPosition(vec2 pos_screen) { - float depth = texture2DRect(depthMap, pos_screen.xy).a; + float depth = texture2DRect(depthMap, pos_screen.xy).r; vec2 sc = pos_screen.xy*2.0; sc /= screen_res; sc -= vec2(1.0,1.0); @@ -84,16 +135,16 @@ void main() frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = center.xyz-pos.xyz; + vec3 lv = trans_center.xyz-pos.xyz; float dist2 = dot(lv,lv); dist2 /= size; if (dist2 > 1.0) { discard; } - + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; - norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + norm = vec3((norm.xy-0.5)*2.0, norm.z); norm = normalize(norm); float l_dist = -dot(lv, proj_n); @@ -107,7 +158,11 @@ void main() proj_tc.xyz /= proj_tc.w; float fa = falloff+1.0; - float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + if (dist_atten <= 0.0) + { + discard; + } lv = proj_origin-pos.xyz; lv = normalize(lv); @@ -125,32 +180,32 @@ void main() proj_tc.y > 0.0) { float lit = 0.0; + float amb_da = proj_ambiance; + if (da > 0.0) { float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); float lod = diff * proj_lod; - vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod); + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); vec3 lcol = color.rgb * plcol.rgb * plcol.a; lit = da * dist_atten * noise; col = lcol*lit*diff_tex; + amb_da += (da*0.5)*proj_ambiance; } - float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); - float lod = diff * proj_lod; - vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod); - //float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0)); - float amb_da = proj_ambiance; - + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); + vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); + amb_da += (da*da*0.5+0.5)*proj_ambiance; - + amb_da *= dist_atten * noise; - + amb_da = min(amb_da, 1.0-lit); - + col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; } @@ -168,18 +223,22 @@ void main() { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz; + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { - stc.xy /= stc.z+proj_near; - + stc.xy /= stc.w; + + float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); + + stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); + if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && stc.y > 0.0) { - vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); + vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb; } } diff --git a/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl b/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl new file mode 100644 index 000000000..5c479d27a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl @@ -0,0 +1,38 @@ +/** + * @file occlusionCubeV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; + +uniform vec3 box_center; +uniform vec3 box_size; + +void main() +{ + vec3 p = position*box_size+box_center; + gl_Position = modelview_projection_matrix * vec4(p.xyz, 1.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl new file mode 100644 index 000000000..44f1aa34a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl @@ -0,0 +1,36 @@ +/** + * @file binormalV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat3 normal_matrix; + +ATTRIBUTE vec3 binormal; + +VARYING vec4 binormal_out; + +void main() +{ + binormal_out = vec4(normal_matrix * binormal, 0.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/colorV.glsl b/indra/newview/app_settings/shaders/class1/transform/colorV.glsl new file mode 100644 index 000000000..59c4a7d89 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/colorV.glsl @@ -0,0 +1,36 @@ +/** + * @file colorV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform int color_in; + +ATTRIBUTE vec3 position; + +VARYING int color_out; + +void main() +{ + color_out = color_in; +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/normalV.glsl b/indra/newview/app_settings/shaders/class1/transform/normalV.glsl new file mode 100644 index 000000000..a213aa0ae --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/normalV.glsl @@ -0,0 +1,36 @@ +/** + * @file normalV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat3 normal_matrix; + +ATTRIBUTE vec3 normal; + +VARYING vec4 normal_out; + +void main() +{ + normal_out = vec4(normalize(normal_matrix * normal), 0.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/positionV.glsl b/indra/newview/app_settings/shaders/class1/transform/positionV.glsl new file mode 100644 index 000000000..01eed18de --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/positionV.glsl @@ -0,0 +1,40 @@ +/** + * @file positionV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_matrix; + +uniform int texture_index_in; + +ATTRIBUTE vec3 position; + +VARYING vec3 position_out; +VARYING int texture_index_out; + +void main() +{ + texture_index_out = texture_index_in; + position_out = (modelview_matrix*vec4(position, 1.0)).xyz; +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl b/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl new file mode 100644 index 000000000..0e074f3ce --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl @@ -0,0 +1,35 @@ +/** + * @file texcoordV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 texcoord_out; + +void main() +{ + texcoord_out = texcoord0; +} + diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 08f6ec63f..8db4cb58c 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -58,20 +58,22 @@ uniform float shadow_bias; uniform mat4 inv_proj; -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc) { stc.xyz /= stc.w; stc.z += shadow_bias; + + stc.x = floor(stc.x + fract(stc.y*12345)); // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here float cs = shadow2DRect(shadowMap, stc.xyz).x; float shadow = cs; - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, -scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, -scl, 0.0)).x, cs); - - return shadow/5.0; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, -1.5, 0.0)).x; + + return shadow*0.2; } @@ -101,7 +103,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap3, lpos, 0.25)*w; + shadow += pcfShadow(shadowMap3, lpos)*w; weight += w; shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); } @@ -114,7 +116,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap2, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap2, lpos)*w; weight += w; } @@ -126,7 +128,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; - shadow += pcfShadow(shadowMap1, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap1, lpos)*w; weight += w; } @@ -138,7 +140,7 @@ void main() float w = 1.0; w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; - shadow += pcfShadow(shadowMap0, lpos, 1.0)*w; + shadow += pcfShadow(shadowMap0, lpos)*w; weight += w; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl index aae6a070e..33958a501 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl @@ -71,20 +71,22 @@ vec4 getPosition(vec2 pos_screen) return pos; } -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc) { stc.xyz /= stc.w; stc.z += shadow_bias; + + stc.x = floor(stc.x + fract(stc.y*12345)); // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here float cs = shadow2DRect(shadowMap, stc.xyz).x; float shadow = cs; - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, -scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, -scl, 0.0)).x, cs); - - return shadow/5.0; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, -1.5, 0.0)).x; + + return shadow*0.2; } @@ -114,7 +116,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap3, lpos, 0.25)*w; + shadow += pcfShadow(shadowMap3, lpos)*w; weight += w; shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); } @@ -127,7 +129,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap2, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap2, lpos)*w; weight += w; } @@ -139,7 +141,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; - shadow += pcfShadow(shadowMap1, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap1, lpos)*w; weight += w; } @@ -151,7 +153,7 @@ void main() float w = 1.0; w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; - shadow += pcfShadow(shadowMap0, lpos, 1.0)*w; + shadow += pcfShadow(shadowMap0, lpos)*w; weight += w; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl index 931577359..2093fc37d 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl @@ -31,6 +31,8 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif +uniform float minimum_alpha; + uniform sampler2DRectShadow shadowMap0; uniform sampler2DRectShadow shadowMap1; uniform sampler2DRectShadow shadowMap2; @@ -70,20 +72,22 @@ vec4 getPosition(vec2 pos_screen) return pos; } -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc) { stc.xyz /= stc.w; stc.z += shadow_bias; + + stc.x = floor(stc.x + fract(stc.y*12345)); // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here float cs = shadow2DRect(shadowMap, stc.xyz).x; float shadow = cs; - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, -scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, scl, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, -scl, 0.0)).x, cs); - - return shadow/5.0; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, -1.5, 0.0)).x; + + return shadow*0.2; } @@ -95,6 +99,13 @@ void main() float shadow = 0.0; vec4 pos = vec4(vary_position, 1.0); + vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy); + + if (diff.a < minimum_alpha) + { + discard; + } + vec4 spos = pos; if (spos.z > -shadow_clip.w) @@ -113,7 +124,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap3, lpos, 0.25)*w; + shadow += pcfShadow(shadowMap3, lpos)*w; weight += w; shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); } @@ -126,7 +137,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap2, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap2, lpos)*w; weight += w; } @@ -138,7 +149,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; - shadow += pcfShadow(shadowMap1, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap1, lpos)*w; weight += w; } @@ -150,7 +161,7 @@ void main() float w = 1.0; w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; - shadow += pcfShadow(shadowMap0, lpos, 1.0)*w; + shadow += pcfShadow(shadowMap0, lpos)*w; weight += w; } @@ -162,8 +173,6 @@ void main() shadow = 1.0; } - vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy); - vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, 1.0); vec4 color = diff * col; diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl index 61a7f1e32..a137bea30 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl @@ -309,11 +309,11 @@ void main() // vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); float sa = dot(refnormpersp, sun_dir.xyz); - vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).r; + vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*(6 * texture2D(lightFunc, vec2(sa, spec.a)).r); // add the two types of shiny together vec3 spec_contrib = dumbshiny * spec.rgb; - bloom = dot(spec_contrib, spec_contrib); + bloom = dot(spec_contrib, spec_contrib) / 4; col += spec_contrib; //add environmentmap diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl index 99a277fbf..ab077d9e0 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl @@ -31,8 +31,6 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -VARYING vec4 vertex_color; - uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect depthMap; @@ -49,6 +47,7 @@ uniform vec3 proj_n; uniform float proj_focus; //distance from plane to begin blurring uniform float proj_lod; //(number of mips in proj map) uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambient_lod; uniform float proj_ambiance; uniform float near_clip; uniform float far_clip; @@ -58,16 +57,65 @@ uniform float sun_wash; uniform int proj_shadow_idx; uniform float shadow_fade; -VARYING vec4 vary_light; +uniform float size; +uniform vec3 color; +uniform float falloff; +VARYING vec3 trans_center; VARYING vec4 vary_fragcoord; uniform vec2 screen_res; uniform mat4 inv_proj; +vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float det = max(1.0-lod/(proj_lod*0.5), 0.0); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); + + return ret; +} + +vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + + float det = min(lod/(proj_lod*0.5), 1.0); + + float d = min(dist.x, dist.y); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + + vec4 getPosition(vec2 pos_screen) { - float depth = texture2DRect(depthMap, pos_screen.xy).a; + float depth = texture2DRect(depthMap, pos_screen.xy).r; vec2 sc = pos_screen.xy*2.0; sc /= screen_res; sc -= vec2(1.0,1.0); @@ -85,6 +133,15 @@ void main() frag.xyz = frag.xyz*0.5+0.5; frag.xy *= screen_res; + vec3 pos = getPosition(frag.xy).xyz; + vec3 lv = trans_center.xyz-pos.xyz; + float dist2 = dot(lv,lv); + dist2 /= size; + if (dist2 > 1.0) + { + discard; + } + float shadow = 1.0; if (proj_shadow_idx >= 0) @@ -96,15 +153,6 @@ void main() shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0); } - vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = vary_light.xyz-pos.xyz; - float dist2 = dot(lv,lv); - dist2 /= vary_light.w; - if (dist2 > 1.0) - { - discard; - } - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm @@ -119,8 +167,12 @@ void main() proj_tc.xyz /= proj_tc.w; - float fa = vertex_color.a+1.0; - float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + float fa = falloff+1.0; + float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + if (dist_atten <= 0.0) + { + discard; + } lv = proj_origin-pos.xyz; lv = normalize(lv); @@ -138,37 +190,33 @@ void main() proj_tc.y > 0.0) { float lit = 0.0; + float amb_da = proj_ambiance; + if (da > 0.0) { float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); float lod = diff * proj_lod; - vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod); + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); - vec3 lcol = vertex_color.rgb * plcol.rgb * plcol.a; + vec3 lcol = color.rgb * plcol.rgb * plcol.a; lit = da * dist_atten * noise; col = lcol*lit*diff_tex*shadow; - } - - float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); - float lod = diff * proj_lod; - vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod); - //float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0)); - float amb_da = proj_ambiance; - if (da > 0.0) - { amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; } + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); + vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); + amb_da += (da*da*0.5+0.5)*proj_ambiance; - + amb_da *= dist_atten * noise; - + amb_da = min(amb_da, 1.0-lit); - - col += amb_da*vertex_color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + + col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; } @@ -185,19 +233,23 @@ void main() { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz; + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { - stc.xy /= stc.z+proj_near; - + stc.xy /= stc.w; + + float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); + + stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); + if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && stc.y > 0.0) { - vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); - col += dist_atten*scol.rgb*vertex_color.rgb*scol.a*spec.rgb*shadow; + vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); + col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb*shadow; } } } diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl index 8c4ccf9cb..db3d76035 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl @@ -78,42 +78,42 @@ vec4 getPosition(vec2 pos_screen) return pos; } -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; stc.z += shadow_bias*scl; - + + stc.x = floor(stc.x + fract(pos_screen.y*0.666666666)); // add some jitter to X sample pos according to Y to disguise the snapping going on here + float cs = shadow2DRect(shadowMap, stc.xyz).x; float shadow = cs; - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, 1.5, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, -1.5, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, 1.5, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, -1.5, 0.0)).x, cs); + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, -1.5, 0.0)).x; - return shadow/5.0; - - //return shadow; + return shadow*0.2; } -float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl) +float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; stc.z += spot_shadow_bias*scl; + stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap float cs = shadow2D(shadowMap, stc.xyz).x; float shadow = cs; - vec2 off = 1.5/proj_shadow_res; + vec2 off = 1.0/proj_shadow_res; + off.y *= 1.5; - shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, off.y, 0.0)).x, cs); - shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x, cs); - shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x, cs); - shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x, cs); - - return shadow/5.0; - - //return shadow; + shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x; + + return shadow*0.2; } void main() @@ -166,7 +166,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap3, lpos, 0.25)*w; + shadow += pcfShadow(shadowMap3, lpos, 0.25, pos_screen)*w; weight += w; shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); } @@ -179,7 +179,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap2, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap2, lpos, 0.5, pos_screen)*w; weight += w; } @@ -191,7 +191,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; - shadow += pcfShadow(shadowMap1, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap1, lpos, 0.75, pos_screen)*w; weight += w; } @@ -203,7 +203,7 @@ void main() float w = 1.0; w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; - shadow += pcfShadow(shadowMap0, lpos, 1.0)*w; + shadow += pcfShadow(shadowMap0, lpos, 1.0, pos_screen)*w; weight += w; } @@ -237,11 +237,11 @@ void main() //spotlight shadow 1 vec4 lpos = shadow_matrix[4]*spos; - frag_color[2] = pcfShadow(shadowMap4, lpos, 0.8); + frag_color[2] = pcfShadow(shadowMap4, lpos, 0.8, pos_screen); //spotlight shadow 2 lpos = shadow_matrix[5]*spos; - frag_color[3] = pcfShadow(shadowMap5, lpos, 0.8); + frag_color[3] = pcfShadow(shadowMap5, lpos, 0.8, pos_screen); //frag_color.rgb = pos.xyz; //frag_color.b = shadow; diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl index 02075a768..32b206e63 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -139,42 +139,42 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm) return min(ret, 1.0); } -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl) +float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; stc.z += shadow_bias*scl; + + stc.x = floor(stc.x + fract(pos_screen.y*0.666666666)); float cs = shadow2DRect(shadowMap, stc.xyz).x; float shadow = cs; - - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, 1.5, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, -1.5, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, 1.5, 0.0)).x, cs); - shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, -1.5, 0.0)).x, cs); - - return shadow/5.0; - //return shadow; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, 1.5, 0.0)).x; + shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, -1.5, 0.0)).x; + + return shadow*0.2; } -float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl) +float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; stc.z += spot_shadow_bias*scl; + stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap float cs = shadow2D(shadowMap, stc.xyz).x; float shadow = cs; - vec2 off = 1.5/proj_shadow_res; + vec2 off = 1.0/proj_shadow_res; + off.y *= 1.5; - shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, off.y, 0.0)).x, cs); - shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x, cs); - shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x, cs); - shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x, cs); - - return shadow/5.0; - - //return shadow; + shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x; + + return shadow*0.2; } void main() @@ -227,7 +227,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap3, lpos, 0.25)*w; + shadow += pcfShadow(shadowMap3, lpos, 0.25, pos_screen)*w; weight += w; shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); } @@ -240,7 +240,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap2, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap2, lpos, 0.5, pos_screen)*w; weight += w; } @@ -252,7 +252,7 @@ void main() float w = 1.0; w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; - shadow += pcfShadow(shadowMap1, lpos, 0.75)*w; + shadow += pcfShadow(shadowMap1, lpos, 0.75, pos_screen)*w; weight += w; } @@ -264,7 +264,7 @@ void main() float w = 1.0; w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; - shadow += pcfShadow(shadowMap0, lpos, 1.0)*w; + shadow += pcfShadow(shadowMap0, lpos, 1.0, pos_screen)*w; weight += w; } @@ -298,11 +298,11 @@ void main() //spotlight shadow 1 vec4 lpos = shadow_matrix[4]*spos; - frag_color[2] = pcfShadow(shadowMap4, lpos, 0.8); + frag_color[2] = pcfShadow(shadowMap4, lpos, 0.8, pos_screen); //spotlight shadow 2 lpos = shadow_matrix[5]*spos; - frag_color[3] = pcfShadow(shadowMap5, lpos, 0.8); + frag_color[3] = pcfShadow(shadowMap5, lpos, 0.8, pos_screen); //frag_color.rgb = pos.xyz; //frag_color.b = shadow; diff --git a/indra/newview/emeraldboobutils.cpp b/indra/newview/emeraldboobutils.cpp index 6d1238976..084d666a3 100644 --- a/indra/newview/emeraldboobutils.cpp +++ b/indra/newview/emeraldboobutils.cpp @@ -33,8 +33,6 @@ std::ostream &operator<<(std::ostream &os, const EmeraldBoobState &v) os << "frameDuration: " << v.frameDuration << std::endl; os << "chestDisplacement: " << v.chestDisplacement << std::endl; os << "localChestDisplacement: " << v.localChestDisplacement << std::endl; - os << "displacementForce: " << v.displacementForce << std::endl; - os << "mysteryValue: " << v.mysteryValue << std::endl; os << "Number of bounceStates: " << v.bounceStates.size() << std::endl; return os; } @@ -45,8 +43,6 @@ std::ostream &operator<<(std::ostream &os, const EmeraldBoobInputs &v) os << "chestPosition: " << v.chestPosition << std::endl; os << "chestRotation: " << v.chestRotation << std::endl; os << "elapsedTime: " << v.elapsedTime << std::endl; - os << "appearanceFlag: " << v.appearanceFlag << std::endl; - os << "appearanceAnimating: " << v.appearanceAnimating << std::endl; return os; } @@ -80,27 +76,11 @@ EmeraldBoobState EmeraldBoobUtils::idleUpdate(const EmeraldGlobalBoobConfig &con F32 avatarLocalMass = 0.0f; F32 partMod = 1.f; - if(!config.enabled || inputs.appearanceFlag || inputs.appearanceAnimating) + if(!config.enabled) return newState; - if(inputs.type == 0) - { - newState.boobGrav = localConfig.actualBoobGrav; - avatarLocalMass = (llclamp(localConfig.boobSize, 0.0f, 0.5f) / 0.5f); - } - if(inputs.type == 1) - { - newState.boobGrav = localConfig.actualButtGrav; - partMod = 1.5f; - avatarLocalMass = llclamp(localConfig.actualButtGrav, 0.0f, 0.5f) / 0.5f; - } - if(inputs.type == 2) - { - newState.boobGrav = localConfig.actualFatGrav; - partMod = 1.3f; - avatarLocalMass = localConfig.actualFatGrav; - } - + newState.boobGrav = localConfig.actualBoobGrav; + avatarLocalMass = (llclamp(localConfig.boobSize, 0.0f, 0.5f) / 0.5f); newState.elapsedTime = inputs.elapsedTime; // seemed to create incorrect amounts of velocity when FPS varied @@ -119,9 +99,10 @@ EmeraldBoobState EmeraldBoobUtils::idleUpdate(const EmeraldGlobalBoobConfig &con boobVel = newState.localChestDisplacement.mV[VZ]; boobVel += newState.localChestDisplacement[VX] * config.XYInfluence; boobVel += newState.localChestDisplacement.mV[VY] * config.XYInfluence; - boobVel *= newState.frameDuration * 0.3f * 100.f; boobVel = llclamp(boobVel, -config.velMax, config.velMax); - if(fabs(boobVel) <= config.velMax * config.velMin * newState.frameDuration * 100.f) + boobVel *= newState.frameDuration * 0.3f * 100.f; + + if(fabs(boobVel) <= config.velMin * newState.frameDuration * 100.f) boobVel = 0.0f; else { @@ -135,26 +116,6 @@ EmeraldBoobState EmeraldBoobUtils::idleUpdate(const EmeraldGlobalBoobConfig &con } } - /*if(fabs(newState.localChestDisplacement.length()) >= 0.f) { - LLVector3 displacementInfluence = newState.localChestDisplacement; - displacementInfluence *= LLVector3(0.3f, 0.3f, 1.0f); - F32 clampedDisplacementInfluenceLength = llclamp(displacementInfluence.length(), 0.0f, config.velMax); - if(displacementInfluence[VZ]<0.f) - clampedDisplacementInfluenceLength= -clampedDisplacementInfluenceLength; - EmeraldBoobBounceState bounceState; - bounceState.bounceStart = inputs.elapsedTime; - bounceState.bounceStartFrameDuration = newState.frameDuration; - bounceState.bounceStartAmplitude = clampedDisplacementInfluenceLength; - if(fabs(bounceState.bounceStartAmplitude) < config.velMin * config.velMax) - bounceState.bounceStartAmplitude = 0.0f; - else - { - bounceState.bounceStartAmplitude *= config.mass; - bounceStates.push_front(bounceState); - } - } - */ - F32 totalNewAmplitude = 0.0f; //std::cout << "Beginning bounce State processing at time " << inputs.elapsedTime << std::endl; while(!bounceStates.empty()) { @@ -170,15 +131,6 @@ EmeraldBoobState EmeraldBoobUtils::idleUpdate(const EmeraldGlobalBoobConfig &con } totalNewAmplitude+=newAmplitude; } - //std::cout << "Total new amplitude: " << totalNewAmplitude << std::endl; - /* - if(inputs.type == 0) - newState.boobGrav = localConfig.actualBoobGrav + totalNewAmplitude; - if(inputs.type == 1) - newState.boobGrav = localConfig.actualButtGrav + totalNewAmplitude; - if(inputs.type == 2) - newState.boobGrav = localConfig.actualFatGrav + totalNewAmplitude; - */ newState.boobGrav = totalNewAmplitude; diff --git a/indra/newview/emeraldboobutils.h b/indra/newview/emeraldboobutils.h index 26008f9de..a9cdf3abc 100644 --- a/indra/newview/emeraldboobutils.h +++ b/indra/newview/emeraldboobutils.h @@ -32,19 +32,6 @@ struct EmeraldGlobalBoobConfig XYInfluence(0.3f) { } - - bool operator==(const EmeraldGlobalBoobConfig &other) const - { - return - enabled == other.enabled && - mass == other.mass && - zMax == other.zMax && - velMax == other.velMax && - velMin == other.velMin && - zInfluence == other.zInfluence && - XYInfluence == other.XYInfluence && - friction == other.friction; - } }; std::ostream &operator<<(std::ostream &os, const EmeraldGlobalBoobConfig &v); @@ -52,14 +39,10 @@ std::ostream &operator<<(std::ostream &os, const EmeraldGlobalBoobConfig &v); struct EmeraldAvatarLocalBoobConfig { F32 actualBoobGrav; - F32 actualButtGrav; - F32 actualFatGrav; F32 boobSize; EmeraldAvatarLocalBoobConfig() : actualBoobGrav(0.0f), - actualButtGrav(0.0f), - actualFatGrav(0.0f), boobSize(0.0f) { } @@ -68,8 +51,6 @@ struct EmeraldAvatarLocalBoobConfig { return actualBoobGrav == other.actualBoobGrav && - actualButtGrav == other.actualButtGrav && - actualFatGrav == other.actualFatGrav && boobSize == other.boobSize; } @@ -88,8 +69,6 @@ struct EmeraldBoobState F32 frameDuration; LLVector3 chestDisplacement; LLVector3 localChestDisplacement; - LLVector3 displacementForce; - F32 mysteryValue; std::list bounceStates; EmeraldBoobState() @@ -99,9 +78,7 @@ struct EmeraldBoobState elapsedTime(0.0f), frameDuration(0.0f), chestDisplacement(0.0f,0.0f,0.0f), - localChestDisplacement(0.0f,0.0f,0.0f), - displacementForce(0.0f,0.0f,0.0f), - mysteryValue(0.0f) + localChestDisplacement(0.0f,0.0f,0.0f) { } @@ -115,8 +92,6 @@ struct EmeraldBoobState frameDuration == other.frameDuration && chestDisplacement == other.chestDisplacement && localChestDisplacement == other.localChestDisplacement && - displacementForce == other.displacementForce && - mysteryValue == other.mysteryValue && bounceStates == other.bounceStates; } }; @@ -128,17 +103,11 @@ struct EmeraldBoobInputs LLVector3 chestPosition; LLQuaternion chestRotation; F32 elapsedTime; - bool appearanceFlag; - bool appearanceAnimating; - S32 type; EmeraldBoobInputs() : chestPosition(0.0f,0.0f,0.0f), chestRotation(0.0f,0.0f,0.0f,1.0f), - elapsedTime(0.0f), - appearanceFlag(false), - appearanceAnimating(false), - type(0) + elapsedTime(0.0f) { } @@ -147,10 +116,7 @@ struct EmeraldBoobInputs return chestPosition == other.chestPosition && chestRotation == other.chestRotation && - elapsedTime == other.elapsedTime && - appearanceFlag == other.appearanceFlag && - appearanceAnimating == other.appearanceAnimating && - type == other.type; + elapsedTime == other.elapsedTime; } }; diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 4c961b02d..d0ba0a140 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3344,13 +3344,12 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * else { // no cache of this bake. request upload. - gAgentAvatarp->requestLayerSetUpload(baked_index); + gAgentAvatarp->invalidateComposite(gAgentAvatarp->getLayerSet(baked_index),TRUE); } } } } } - llinfos << "Received cached texture response for " << num_results << " textures." << llendl; gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them"); @@ -3885,7 +3884,7 @@ void LLAgent::sendAgentSetAppearance() return; } - llinfos << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << llendl; + LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL; //dumpAvatarTEs( "sendAgentSetAppearance()" ); LLMessageSystem* msg = gMessageSystem; @@ -3943,14 +3942,14 @@ void LLAgent::sendAgentSetAppearance() // only update cache entries if we have all our baked textures if (textures_current) { - llinfos << "TAT: Sending cached texture data" << llendl; + LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { BOOL generate_valid_hash = TRUE; if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLVOAvatarDefines::EBakedTextureIndex)baked_index)) { generate_valid_hash = FALSE; - llinfos << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << llendl; + LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << LL_ENDL; } const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index ccd53a187..ab33da86c 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -281,8 +281,6 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy const LLUUID& item_id, LLWearable* wearable) { - //llassert_always(index == 0); - llinfos << "type " << type << " index " << index << " item " << item_id.asString() << llendl; if (item_id.isNull()) @@ -472,29 +470,28 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 } } -void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, +LLWearable* LLAgentWearables::saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found) { - //llassert_always(index == 0); if (!isWearableCopyable(type, index)) { llwarns << "LLAgent::saveWearableAs() not copyable." << llendl; - return; + return NULL; } LLWearable* old_wearable = getWearable(type, index); if (!old_wearable) { llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl; - return; + return NULL; } LLInventoryItem* item = gInventory.getItem(getWearableItemID(type,index)); if (!item) { llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl; - return; + return NULL; } std::string trunc_name(new_name); LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN); @@ -532,6 +529,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, // unsaved changes so other inventory items aren't affected by the changes // that were just saved. old_wearable->revertValues(); + return new_wearable; } void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index) @@ -755,7 +753,7 @@ void LLAgentWearables::setWearable(const LLWearableType::EType type, U32 index, pushWearable(type,wearable); return; } - + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { @@ -831,6 +829,13 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable) saveWearable(wearable->getType(),index,TRUE); } + //Needed as wearable 'save' process is a mess and fires superfluous updateScrollingPanelList calls + //while the wearable being created has not yet been stuffed into the wearable list. + //This results in the param hints being buggered and screwing up the current wearable during LLVisualParamHint::preRender, + //thus making the wearable 'dirty'. The code below basically 'forces' a refresh of the panel to fix this. + if(gFloaterCustomize) + gFloaterCustomize->wearablesChanged(wearable->getType()); + } void LLAgentWearables::popWearable(LLWearable *wearable) @@ -1607,7 +1612,16 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it { gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); gAgentAvatarp->updateVisualParams(); - gAgentAvatarp->invalidateAll(); + + // If we have not yet declouded, we may want to use + // baked texture UUIDs sent from the first objectUpdate message + // don't overwrite these. If we have already declouded, we've saved + // these ids as the last known good textures and can invalidate without + // re-clouding. + if (!gAgentAvatarp->getIsCloud()) + { + gAgentAvatarp->invalidateAll(); + } } // Start rendering & update the server @@ -1695,21 +1709,21 @@ bool LLAgentWearables::onSetWearableDialog( const LLSD& notification, const LLSD switch( option ) { - case 0: // "Save" + case 0: // "Save" gAgentWearables.saveWearable(wearable->getType(),index); - gAgentWearables.setWearableFinal( new_item, wearable ); - break; + gAgentWearables.setWearableFinal( new_item, wearable ); + break; - case 1: // "Don't Save" - gAgentWearables.setWearableFinal( new_item, wearable ); - break; + case 1: // "Don't Save" + gAgentWearables.setWearableFinal( new_item, wearable ); + break; - case 2: // "Cancel" - break; + case 2: // "Cancel" + break; - default: - llassert(0); - break; + default: + llassert(0); + break; } delete wearable; @@ -1725,10 +1739,11 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* n if (do_append && getWearableItemID(type,0).notNull()) { new_wearable->setItemID(new_item->getUUID()); - mWearableDatas[type].push_back(new_wearable); + /*mWearableDatas[type].push_back(new_wearable); llinfos << "Added additional wearable for type " << type << " size is now " << mWearableDatas[type].size() << llendl; - checkWearableAgainstInventory(new_wearable); + checkWearableAgainstInventory(new_wearable);*/ + pushWearable(type,new_wearable); //To call LLAgentWearables::wearableUpdated } else { @@ -1808,7 +1823,8 @@ void LLAgentWearables::queryWearableCache() { gAgentAvatarp->outputRezTiming("Fetching textures from cache"); } - llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl; + + LL_INFOS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL; gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); gAgentQueryManager.mNumPendingQueries++; gAgentQueryManager.mWearablesCacheQueryID++; @@ -2210,6 +2226,12 @@ bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool clos U32 swap_i = closer_to_body ? i-1 : i+1; wearable_vec[i] = wearable_vec[swap_i]; wearable_vec[swap_i] = wearable; + + if(gFloaterCustomize) + { + gFloaterCustomize->wearablesChanged(item->getWearableType()); + } + return true; } @@ -2337,6 +2359,11 @@ boost::signals2::connection LLAgentWearables::addInitialWearablesLoadedCallback( } // [/SL:KB] +bool LLAgentWearables::changeInProgress() const +{ + return mCOFChangeInProgress; +} + void LLAgentWearables::notifyLoadingStarted() { mCOFChangeInProgress = true; diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 36ec572eb..c3aad9500 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -205,7 +205,7 @@ private: // Save Wearables //-------------------------------------------------------------------- public: - void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found); + LLWearable* saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found); void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, const std::string new_name = ""); void saveAllWearables(); @@ -247,6 +247,7 @@ public: boost::signals2::connection addInitialWearablesLoadedCallback(loaded_callback_t cb); // [/SL:KB] + bool changeInProgress() const; void notifyLoadingStarted(); void notifyLoadingFinished(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 1cd4eceb9..60ebf402e 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -54,6 +54,11 @@ #include "rlvlocks.h" // [/RLVa:KB] +std::string self_av_string() +{ + return gAgentAvatarp->avString(); +} + // RAII thingy to guarantee that a variable gets reset when the Setter // goes out of scope. More general utility would be handy - TODO: // check boost. @@ -160,6 +165,8 @@ public: { mCatID = cat_id; mAppend = append; + + LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; } void fire(const LLUUID& item_id) { @@ -171,12 +178,13 @@ public: * after the last item has fired the event and dereferenced it -- if all * the events actually fire! */ + LL_DEBUGS("Avatar") << self_av_string() << " fired on copied item, id " << item_id << LL_ENDL; } protected: ~LLWearInventoryCategoryCallback() { - llinfos << "done all inventory callbacks" << llendl; + LL_INFOS("Avatar") << self_av_string() << "done all inventory callbacks" << LL_ENDL; // Is the destructor called by ordinary dereference, or because the app's shutting down? // If the inventory callback manager goes away, we're shutting down, no longer want the callback. @@ -186,7 +194,7 @@ protected: } else { - llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl; + llwarns << self_av_string() << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl; } } @@ -220,6 +228,7 @@ LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() { + LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL; llinfos << "done update appearance on destroy" << llendl; if (!LLApp::isExiting()) @@ -233,7 +242,7 @@ void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; #endif mFireCount++; } @@ -399,7 +408,8 @@ void LLWearableHoldingPattern::checkMissingWearables() { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway why don't we actually skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } std::vector found_by_type(LLWearableType::WT_COUNT,0); @@ -417,7 +427,7 @@ void LLWearableHoldingPattern::checkMissingWearables() { if (requested_by_type[type] > found_by_type[type]) { - llwarns << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl; + llwarns << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl; } if (found_by_type[type] > 0) continue; @@ -434,7 +444,7 @@ void LLWearableHoldingPattern::checkMissingWearables() mTypesToRecover.insert(type); mTypesToLink.insert(type); recoverMissingWearable((LLWearableType::EType)type); - llwarns << "need to replace " << type << llendl; + llwarns << self_av_string() << "need to replace " << type << llendl; } } @@ -454,13 +464,14 @@ void LLWearableHoldingPattern::onAllComplete() if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway need to skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } // Activate all gestures in this folder if (mGestItems.count() > 0) { - llinfos << "Activating " << mGestItems.count() << " gestures" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.count() << " gestures" << LL_ENDL; LLGestureMgr::instance().activateGestures(mGestItems); @@ -477,7 +488,7 @@ void LLWearableHoldingPattern::onAllComplete() } // Update wearables. - llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl; + LL_INFOS("Avatar") << self_av_string() << "Updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; LLAppearanceMgr::instance().updateAgentWearables(this, false); // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-03-22 (Catznip-3.0.0a) | Added: Catznip-2.1.2a @@ -504,7 +515,8 @@ void LLWearableHoldingPattern::onFetchCompletion() { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } checkMissingWearables(); @@ -515,7 +527,8 @@ bool LLWearableHoldingPattern::pollFetchCompletion() { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; // [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves @@ -530,14 +543,14 @@ bool LLWearableHoldingPattern::pollFetchCompletion() if (done) { - llinfos << "polling, done status: " << completed << " timed out " << timed_out - << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl; + LL_INFOS("Avatar") << self_av_string() << "polling, done status: " << completed << " timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; mFired = true; if (timed_out) { - llwarns << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; + llwarns << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; } onFetchCompletion(); @@ -585,12 +598,12 @@ public: } else { - llwarns << "inventory item not found for recovered wearable" << llendl; + llwarns << self_av_string() << "inventory item not found for recovered wearable" << llendl; } } else { - llwarns << "inventory link not found for recovered wearable" << llendl; + llwarns << self_av_string() << "inventory link not found for recovered wearable" << llendl; } } private: @@ -612,7 +625,8 @@ public: { if (!mHolder->isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; // [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves @@ -620,7 +634,7 @@ public: // [/SL:KB] } - llinfos << "Recovered item for type " << mType << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << mType << LL_ENDL; LLViewerInventoryItem *itemp = gInventory.getItem(item_id); mWearable->setItemID(item_id); LLPointer cb = new RecoveredItemLinkCB(mType,mWearable,mHolder); @@ -647,7 +661,8 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } // Try to recover by replacing missing wearable with a new one. @@ -686,7 +701,7 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) { // Wearable link that was never resolved; remove links to it from COF - llinfos << "removing link for unresolved item " << data.mItemID.asString() << llendl; + LL_INFOS("Avatar") << self_av_string() << "removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID,false); } } @@ -709,7 +724,8 @@ bool LLWearableHoldingPattern::pollMissingWearables() { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; // [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves @@ -724,11 +740,11 @@ bool LLWearableHoldingPattern::pollMissingWearables() if (!done) { - llinfos << "polling missing wearables, waiting for items " << mTypesToRecover.size() + LL_INFOS("Avatar") << self_av_string() << "polling missing wearables, waiting for items " << mTypesToRecover.size() << " links " << mTypesToLink.size() << " wearables, timed out " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() - << " done " << done << llendl; + << " done " << done << LL_ENDL; } if (done) @@ -762,14 +778,14 @@ void LLWearableHoldingPattern::handleLateArrivals() } if (!isMostRecent()) { - llwarns << "Late arrivals not handled - outfit change no longer valid" << llendl; + llwarns << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << llendl; } if (!mIsAllComplete) { - llwarns << "Late arrivals not handled - in middle of missing wearables processing" << llendl; + llwarns << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << llendl; } - llinfos << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << llendl; + LL_INFOS("Avatar") << self_av_string() << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; // Update mFoundList using late-arriving wearables. std::set replaced_types; @@ -845,19 +861,19 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable) { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } mResolved += 1; // just counting callbacks, not successes. - llinfos << "resolved " << mResolved << "/" << getFoundList().size() << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; if (!wearable) { - llwarns << "no wearable found" << llendl; + llwarns << self_av_string() << "no wearable found" << llendl; } if (mFired) { - llwarns << "called after holder fired" << llendl; + llwarns << self_av_string() << "called after holder fired" << llendl; if (wearable) { mLateArrivals.insert(wearable); @@ -883,7 +899,7 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable) // Failing this means inventory or asset server are corrupted in a way we don't handle. if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) { - llwarns << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl; + llwarns << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl; break; } @@ -1554,7 +1570,7 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << LL_ENDL; #endif } } @@ -1685,7 +1701,7 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, removeDuplicateItems(gest_items); // Create links to new COF contents. - llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "creating LLUpdateAppearanceOnDestroy" << LL_ENDL; LLPointer link_waiter = new LLUpdateAppearanceOnDestroy(!append); // [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f @@ -1696,24 +1712,24 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, bool keep_outfit_links = append; purgeCategory(cof, keep_outfit_links); gInventory.notifyObservers(); - #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking body items" << llendl; - #endif - linkAll(cof, body_items, link_waiter); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "Linking body items" << LL_ENDL; +#endif + linkAll(cof, body_items, link_waiter); - #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking wear items" << llendl; - #endif - linkAll(cof, wear_items, link_waiter); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "Linking wear items" << LL_ENDL; +#endif + linkAll(cof, wear_items, link_waiter); - #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking obj items" << llendl; - #endif - linkAll(cof, obj_items, link_waiter); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "Linking obj items" << LL_ENDL; +#endif + linkAll(cof, obj_items, link_waiter); - #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking gesture items" << llendl; - #endif +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "Linking gesture items" << LL_ENDL; +#endif linkAll(cof, gest_items, link_waiter); // [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f } @@ -1741,7 +1757,7 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, // createBaseOutfitLink(category, link_waiter); // } - llinfos << "waiting for LLUpdateAppearanceOnDestroy" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; } void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) @@ -1954,7 +1970,7 @@ void LLAppearanceMgr::enforceItemRestrictions() ++it) { LLViewerInventoryItem *item = *it; - llinfos << "purging duplicate or excess item " << item->getName() << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL; gInventory.purgeObject(item->getUUID()); } gInventory.notifyObservers(); @@ -1971,7 +1987,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); - llinfos << "starting" << llendl; + LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; //checking integrity of the COF in terms of ordering of wearables, //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) @@ -2125,7 +2141,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) { LLFoundData& found = *it; - lldebugs << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; + lldebugs << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; // Fetch the wearables about to be worn. LLWearableList::instance().getAsset(found.mAssetID, @@ -2214,8 +2230,8 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool gAgentWearables.notifyLoadingStarted(); - llinfos << "wearInventoryCategory( " << category->getName() - << " )" << llendl; + LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() + << " )" << LL_ENDL; callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, &LLAppearanceMgr::instance(), @@ -2224,7 +2240,7 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) { - llinfos << "starting" << llendl; + LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; // We now have an outfit ready to be copied to agent inventory. Do // it, and wear that outfit normally. @@ -2307,8 +2323,8 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego // wearables being dirty. if(!category) return; - llinfos << "wearInventoryCategoryOnAvatar( " << category->getName() - << " )" << llendl; + LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName() + << "'" << LL_ENDL; if (gAgentCamera.cameraCustomizeAvatar()) { @@ -2321,7 +2337,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego void LLAppearanceMgr::wearOutfitByName(const std::string& name) { - llinfos << "Wearing category " << name << llendl; + LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; //inc_busy_count(); LLInventoryModel::cat_array_t cat_array; @@ -2492,7 +2508,21 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update { cb = new ModifiedCOFCallback; } - const std::string description = vitem->getIsLinkType() ? vitem->getDescription() : ""; + std::string description = vitem->getIsLinkType() ? vitem->getDescription() : ""; + if(description.empty()) + { + LLWearable* wearable = gAgentWearables.getWearableFromItemID(vitem->getLinkedUUID()); + if(wearable) + { + U32 index = gAgentWearables.getWearableIndex(wearable); + if(index < LLAgentWearables::MAX_CLOTHING_PER_TYPE) + { + std::ostringstream order_num; + order_num << ORDER_NUMBER_SEPARATOR << wearable->getType() * 100 + index; + description = order_num.str(); + } + } + } link_inventory_item( gAgent.getID(), vitem->getLinkedUUID(), getCOF(), @@ -2651,7 +2681,7 @@ const std::string OTHER_GESTURES_FOLDER = "Other Gestures"; void LLAppearanceMgr::copyLibraryGestures() { - llinfos << "Copying library gestures" << llendl; + LL_INFOS("Avatar") << self_av_string() << "Copying library gestures" << LL_ENDL; // Copy gestures LLUUID lib_gesture_cat_id = @@ -2707,11 +2737,11 @@ void LLAppearanceMgr::copyLibraryGestures() LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); if (cat_id.isNull()) { - llwarns << "failed to find gesture folder for " << folder_name << llendl; + llwarns << self_av_string() << "failed to find gesture folder for " << folder_name << llendl; } else { - llinfos << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << LL_ENDL; callAfterCategoryFetch(cat_id, boost::bind(&LLAppearanceMgr::shallowCopyCategory, &LLAppearanceMgr::instance(), @@ -2725,7 +2755,7 @@ void LLAppearanceMgr::autopopulateOutfits() // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) // then auto-populate outfits from the library into the My Outfits folder. - llinfos << "avatar fully visible" << llendl; + LL_INFOS("Avatar") << self_av_string() << "avatar fully visible" << LL_ENDL; static bool check_populate_my_outfits = true; if (check_populate_my_outfits && @@ -3454,9 +3484,8 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items, { asset_id = linked_item->getAssetUUID(); } - llinfos << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << llendl; + LL_DEBUGS("Avatar") << self_av_string() << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << LL_ENDL; } - llinfos << llendl; } LLAppearanceMgr::LLAppearanceMgr(): diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ad9b7d8ed..c0bb21085 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4040,7 +4040,9 @@ void LLAppViewer::idle() // if (!gNoRender) { +#if ENABLE_CLASSIC_CLOUDS LLWorld::getInstance()->updateClouds(gFrameDTClamped); +#endif gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets // Update wind vector @@ -4056,9 +4058,10 @@ void LLAppViewer::idle() // Compute average wind and use to drive motion of water average_wind = regionp->mWind.getAverage(); +#if ENABLE_CLASSIC_CLOUDS F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region); - gSky.setCloudDensityAtAgent(cloud_density); +#endif gSky.setWind(average_wind); //LLVOWater::setWind(average_wind); } diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index aa7d391a1..9ec769f9f 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -31,6 +31,7 @@ // Viewer includes #include "llagent.h" #include "llviewergenericmessage.h" +#include "llstartup.h" // Linden library includes #include "llavatarconstants.h" // AVATAR_TRANSACTED, etc. @@ -111,6 +112,14 @@ void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EA void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id) { + // this is the startup state when send_complete_agent_movement() message is sent. + // Before this, the AvatarPropertiesRequest message + // won't work so don't bother trying + if (LLStartUp::getStartupState() <= STATE_AGENT_SEND) + { + return; + } + if (isPendingRequest(avatar_id, APT_PROPERTIES)) { // waiting for a response, don't re-request diff --git a/indra/newview/llcloud.cpp b/indra/newview/llcloud.cpp index 2165f4238..fcdfbecd4 100644 --- a/indra/newview/llcloud.cpp +++ b/indra/newview/llcloud.cpp @@ -54,6 +54,7 @@ #include "lldrawpool.h" #include "llworld.h" +#if ENABLE_CLASSIC_CLOUDS extern LLPipeline gPipeline; const F32 CLOUD_UPDATE_RATE = 1.0f; // Global time dilation for clouds @@ -544,3 +545,4 @@ void LLCloudLayer::disconnectAllNeighbors() disconnectNeighbor(i); } } +#endif diff --git a/indra/newview/llcloud.h b/indra/newview/llcloud.h index f4ae03b68..b3fd6f681 100644 --- a/indra/newview/llcloud.h +++ b/indra/newview/llcloud.h @@ -89,6 +89,7 @@ class LLCloudLayer; class LLBitPack; class LLGroupHeader; +#if ENABLE_CLASSIC_CLOUDS const S32 CLOUD_GROUPS_PER_EDGE = 4; class LLCloudPuff @@ -201,5 +202,5 @@ protected: LLCloudGroup mCloudGroups[CLOUD_GROUPS_PER_EDGE][CLOUD_GROUPS_PER_EDGE]; }; - +#endif #endif diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 745c2f41f..cb57169a5 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -390,7 +390,9 @@ void LLDrawable::makeActive() pcode == LLViewerObject::LL_VO_SURFACE_PATCH || pcode == LLViewerObject::LL_VO_PART_GROUP || pcode == LLViewerObject::LL_VO_HUD_PART_GROUP || +#if ENABLE_CLASSIC_CLOUDS pcode == LLViewerObject::LL_VO_CLOUDS || +#endif pcode == LLViewerObject::LL_VO_GROUND || pcode == LLViewerObject::LL_VO_SKY) { @@ -454,7 +456,7 @@ void LLDrawable::makeStatic(BOOL warning_enabled) { if (isState(ACTIVE)) { - clearState(ACTIVE); + clearState(ACTIVE | ANIMATED_CHILD); if (mParent.notNull() && mParent->isActive() && warning_enabled) { @@ -542,9 +544,9 @@ F32 LLDrawable::updateXform(BOOL undamped) target_rot = new_rot; target_scale = new_scale; } - else + else if (mVObjp->getAngularVelocity().isExactlyZero()) { - // snap to final position + // snap to final position (only if no target omega is applied) dist_squared = 0.0f; if (getVOVolume() && !isRoot()) { //child prim snapping to some position, needs a rebuild @@ -553,15 +555,25 @@ F32 LLDrawable::updateXform(BOOL undamped) } } - if ((mCurrentScale != target_scale) || - (!isRoot() && - (dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED || - !mVObjp->getAngularVelocity().isExactlyZero() || - target_pos != mXform.getPosition() || - target_rot != mXform.getRotation()))) - { //child prim moving or scale change requires immediate rebuild + LLVector3 vec = mCurrentScale-target_scale; + + if (vec*vec > MIN_INTERPOLATE_DISTANCE_SQUARED) + { //scale change requires immediate rebuild + mCurrentScale = target_scale; gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); } + else if (!isRoot() && + (!mVObjp->getAngularVelocity().isExactlyZero() || + dist_squared > 0.f)) + { //child prim moving relative to parent, tag as needing to be rendered atomically and rebuild + dist_squared = 1.f; //keep this object on the move list + if (!isState(LLDrawable::ANIMATED_CHILD)) + { + setState(LLDrawable::ANIMATED_CHILD); + gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE); + mVObjp->dirtySpatialGroup(); + } + } else if (!getVOVolume() && !isAvatar()) { movePartition(); @@ -572,9 +584,7 @@ F32 LLDrawable::updateXform(BOOL undamped) mXform.setRotation(target_rot); mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!) mXform.updateMatrix(); - - mCurrentScale = target_scale; - + if (mSpatialBridge) { gPipeline.markMoved(mSpatialBridge, FALSE); @@ -600,7 +610,11 @@ void LLDrawable::moveUpdatePipeline(BOOL moved) // Update the face centers. for (S32 i = 0; i < getNumFaces(); i++) { - getFace(i)->updateCenterAgent(); + LLFace* face = getFace(i); + if (face) + { + face->updateCenterAgent(); + } } } @@ -731,7 +745,8 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) for (S32 i = 0; i < getNumFaces(); i++) { LLFace* facep = getFace(i); - if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA) + if (facep && + (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)) { LLVector4a box; box.setSub(facep->mExtents[1], facep->mExtents[0]); @@ -830,13 +845,16 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector) for (S32 i = 0; i < getNumFaces(); i++) { LLFace *facep = getFace(i); - facep->mCenterAgent += LLVector3(shift_vector.getF32ptr()); - facep->mExtents[0].add(shift_vector); - facep->mExtents[1].add(shift_vector); - - if (!volume && facep->hasGeometry()) + if (facep) { - facep->clearVertexBuffer(); + facep->mCenterAgent += LLVector3(shift_vector.getF32ptr()); + facep->mExtents[0].add(shift_vector); + facep->mExtents[1].add(shift_vector); + + if (!volume && facep->hasGeometry()) + { + facep->clearVertexBuffer(); + } } } @@ -958,7 +976,10 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp) for (S32 i = 0; i < getNumFaces(); ++i) { LLFace* facep = getFace(i); - facep->clearVertexBuffer(); + if (facep) + { + facep->clearVertexBuffer(); + } } } @@ -1544,15 +1565,17 @@ BOOL LLDrawable::isAnimating() const { return TRUE; } +#if ENABLE_CLASSIC_CLOUDS if (mVObjp->getPCode() == LLViewerObject::LL_VO_CLOUDS) { return TRUE; } +#endif - if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero()) - { + /*if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero()) + { //target omega return TRUE; - } + }*/ return FALSE; } diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 66ef4b7c4..6f07c82be 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -283,6 +283,7 @@ public: HAS_ALPHA = 0x04000000, RIGGED = 0x08000000, PARTITION_MOVE = 0x10000000, + ANIMATED_CHILD = 0x20000000, } EDrawableFlags; private: //aligned members @@ -339,12 +340,14 @@ inline LLFace* LLDrawable::getFace(const S32 i) const if ((U32) i >= mFaces.size()) { - llerrs << "Invalid face index." << llendl; + llwarns << "Invalid face index." << llendl; + return NULL; } if (!mFaces[i]) { - llerrs << "Null face found." << llendl; + llwarns << "Null face found." << llendl; + return NULL; } return mFaces[i]; diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 4d4864470..500f8b67a 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -404,7 +404,9 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) bool draw_glow_for_this_partition = mVertexShaderLevel > 0 && // no shaders = no glow. // All particle systems seem to come off the wire with texture entries which claim that they glow. This is probably a bug in the data. Suppress. group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_PARTICLE && +#if ENABLE_CLASSIC_CLOUDS group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_CLOUD && +#endif group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD_PARTICLE; LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; @@ -413,13 +415,20 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) { LLDrawInfo& params = **k; + if ((params.mVertexBuffer->getTypeMask() & mask) != mask) + { //FIXME! + llwarns << "Missing required components, skipping render batch." << llendl; + continue; + } + LLRenderPass::applyModelMatrix(params); - if (params.mFullbright) + + if (params.mFullbright) + { + // Turn off lighting if it hasn't already been so. + if (light_enabled || !initialized_lighting) { - // Turn off lighting if it hasn't already been so. - if (light_enabled || !initialized_lighting) - { initialized_lighting = TRUE; if (use_shaders) { diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index a91c2b3c5..56c372655 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -265,7 +265,9 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha() sRenderingSkinned = TRUE; gPipeline.bindDeferredShader(*sVertexProgram); - + + sVertexProgram->setMinimumAlpha(0.2f); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index cd3c7812a..6a299deda 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -50,11 +50,13 @@ #include "llsky.h" #include "llviewercamera.h" #include "llviewertexturelist.h" +#include "llvopartgroup.h" #include "llvosky.h" #include "llvovolume.h" #include "pipeline.h" #include "llviewerregion.h" #include "llviewerwindow.h" +#include "llviewershadermgr.h" #define LL_MAX_INDICES_COUNT 1000000 @@ -167,7 +169,19 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mGeomCount = 0; mGeomIndex = 0; mIndicesCount = 0; - mIndicesIndex = 0; + if (drawablep->getRenderType() == LLPipeline::RENDER_TYPE_PARTICLES || + drawablep->getRenderType() == LLPipeline::RENDER_TYPE_HUD_PARTICLES +#if ENABLE_CLASSIC_CLOUDS + || drawablep->getRenderType() == LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS +#endif + ) + { //indicate to LLParticlePartition that this particle is uninitialized + mIndicesIndex = 0xFFFFFFFF; + } + else + { + mIndicesIndex = 0; + } mIndexInTex = 0; mTexture = NULL; mTEOffset = -1; @@ -183,12 +197,6 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mFaceColor = LLColor4(1,0,0,1); - mLastVertexBuffer = mVertexBuffer; - mLastGeomCount = mGeomCount; - mLastGeomIndex = mGeomIndex; - mLastIndicesCount = mIndicesCount; - mLastIndicesIndex = mIndicesIndex; - mImportanceToCamera = 0.f ; mBoundingSphereRadius = 0.0f ; } @@ -206,6 +214,19 @@ void LLFace::destroy() mTexture->removeFace(this) ; } + if (mDrawablep.notNull() && + (mDrawablep->getRenderType() == LLPipeline::RENDER_TYPE_PARTICLES || + mDrawablep->getRenderType() == LLPipeline::RENDER_TYPE_HUD_PARTICLES +#if ENABLE_CLASSIC_CLOUDS + || mDrawablep->getRenderType() == LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS +#endif + ) && + mIndicesIndex != 0xFFFFFFFF) + { + LLVOPartGroup::freeVBSlot(getGeomIndex()/4); + mIndicesIndex = 0xFFFFFFFF; + } + if (mDrawPoolp) { if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR) @@ -372,7 +393,6 @@ void LLFace::setSize(S32 num_vertices, const S32 num_indices, bool align) mGeomCount = num_vertices; mIndicesCount = num_indices; mVertexBuffer = NULL; - mLastVertexBuffer = NULL; } llassert(verify()); @@ -1034,30 +1054,13 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offs void LLFace::updateRebuildFlags() { - if (!mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) - { - BOOL moved = TRUE; - if (mLastVertexBuffer == mVertexBuffer && - !mVertexBuffer->isEmpty()) - { //this face really doesn't need to be regenerated, try real hard not to do so - if (mLastGeomCount == mGeomCount && - mLastGeomIndex == mGeomIndex && - mLastIndicesCount == mIndicesCount && - mLastIndicesIndex == mIndicesIndex) - { //data is in same location in vertex buffer - moved = FALSE; - } - } - mLastMoveTime = gFrameTimeSeconds; - - if (moved) - { - mDrawablep->setState(LLDrawable::REBUILD_VOLUME); - } + if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) + { //this rebuild is zero overhead (direct consequence of some change that affects this face) + mLastUpdateTime = gFrameTimeSeconds; } else - { - mLastUpdateTime = gFrameTimeSeconds; + { //this rebuild is overhead (side effect of some change that does not affect this face) + mLastMoveTime = gFrameTimeSeconds; } } @@ -1096,6 +1099,72 @@ bool LLFace::canRenderAsMask() } +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_VOLUME("Volume VB Cache"); + +//static +void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf) +{ + LLFastTimer t(FTM_FACE_GEOM_VOLUME); + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL; + + if (vf.mWeights) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + LLVertexBuffer* buff = new LLVertexBuffer(mask, GL_STATIC_DRAW_ARB); + vf.mVertexBuffer = buff; + + buff->allocateBuffer(vf.mNumVertices, 0, true); + + LLStrider f_vert; + LLStrider f_binorm; + LLStrider f_norm; + LLStrider f_tc; + + buff->getBinormalStrider(f_binorm); + buff->getVertexStrider(f_vert); + buff->getNormalStrider(f_norm); + buff->getTexCoord0Strider(f_tc); + + for (U32 i = 0; i < (U32)vf.mNumVertices; ++i) + { + *f_vert++ = vf.mPositions[i]; + (*f_binorm++).set(vf.mBinormals[i].getF32ptr()); + *f_tc++ = vf.mTexCoords[i]; + (*f_norm++).set(vf.mNormals[i].getF32ptr()); + } + + if (vf.mWeights) + { + LLStrider f_wght; + buff->getWeight4Strider(f_wght); + for (U32 i = 0; i < (U32)vf.mNumVertices; ++i) + { + (*f_wght++).set(vf.mWeights[i].getF32ptr()); + } + } + + buff->flush(); +} + +//helper function for pushing primitives for transform shaders and cleaning up +//uninitialized data on the tail, plus tracking number of expected primitives +void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count) +{ + if (source_count > 0 && dest_count >= source_count) //protect against possible U32 wrapping + { + //push source primitives + buff->drawArrays(LLRender::POINTS, 0, source_count); + U32 tail = dest_count-source_count; + for (U32 i = 0; i < tail; ++i) + { //copy last source primitive into each element in tail + buff->drawArrays(LLRender::POINTS, source_count-1, 1); + } + gPipeline.mTransformFeedbackPrimitives += dest_count; + } +} static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom"); static LLFastTimer::DeclareTimer FTM_FACE_GEOM_POSITION("Position"); static LLFastTimer::DeclareTimer FTM_FACE_GEOM_NORMAL("Normal"); @@ -1113,8 +1182,8 @@ static LLFastTimer::DeclareTimer FTM_FACE_TEX_DEFAULT("Default"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK("Quick"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_NO_XFORM("No Xform"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_XFORM("Xform"); - static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_PLANAR("Quick Planar"); + BOOL LLFace::getGeometryVolume(const LLVolume& volume, const S32 &f, const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in, @@ -1145,9 +1214,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, << " VF Num Indices: " << num_indices << " Indices Index: " << mIndicesIndex << " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl; - llwarns << "Last Indices Count: " << mLastIndicesCount - << " Last Indices Index: " << mLastIndicesIndex - << " Face Index: " << f + llwarns << " Face Index: " << f << " Pool Type: " << mPoolType << llendl; return FALSE; } @@ -1264,17 +1331,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLMatrix4a mat_normal; mat_normal.loadu(mat_norm_in); - //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); - F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; - + bool do_xform = false; if (rebuild_tcoord) { - LLFastTimer t(FTM_FACE_GEOM_TEXTURE); - bool do_xform; - if (tep) { r = tep->getRotation(); @@ -1303,310 +1363,368 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { do_xform = false; } - - //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); - - LLQuaternion bump_quat; - if (mDrawablep->isActive()) - { - bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); - } - - if (bump_code) - { - mVObjp->getVolume()->genBinormals(f); - F32 offset_multiple; - switch( bump_code ) - { - case BE_NO_BUMP: - offset_multiple = 0.f; - break; - case BE_BRIGHTNESS: - case BE_DARKNESS: - if( mTexture.notNull() && mTexture->hasGLTexture()) - { - // 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); - } - - U8 tex_mode = 0; + } - if (isState(TEXTURE_ANIM)) + static LLCachedControl use_transform_feedback("RenderUseTransformFeedback", false); + +#ifdef GL_TRANSFORM_FEEDBACK_BUFFER + if (use_transform_feedback && + gTransformPositionProgram.mProgramObject && //transform shaders are loaded + mVertexBuffer->useVBOs() && //target buffer is in VRAM + !rebuild_weights && //TODO: add support for weights + !volume.isUnique()) //source volume is NOT flexi + { //use transform feedback to pack vertex buffer + + LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); + + if (vf.mVertexBuffer.isNull() || buff->getNumVerts() != vf.mNumVertices) { - LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; - tex_mode = vobj->mTexAnimMode; + mVObjp->getVolume()->genBinormals(f); + LLFace::cacheFaceInVRAM(vf); + buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); + } - 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; + LLGLSLShader* cur_shader = LLGLSLShader::sCurBoundShaderPtr; + + gGL.pushMatrix(); + gGL.loadMatrix((GLfloat*) mat_vert_in.mMatrix); - do_xform = false; - } + if (rebuild_pos) + { + LLFastTimer t(FTM_FACE_GEOM_POSITION); + gTransformPositionProgram.bind(); - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) - { //don't override texture transform during tc bake - tex_mode = 0; - } + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount); + + U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + + S32 val = 0; + U8* vp = (U8*) &val; + vp[0] = index; + vp[1] = 0; + vp[2] = 0; + vp[3] = 0; + + gTransformPositionProgram.uniform1i("texture_index_in", val); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + + push_for_transform(buff, vf.mNumVertices, mGeomCount); + + glEndTransformFeedback(); } - LLVector4a scalea; - scalea.load3(scale.mV); + if (rebuild_color) + { + LLFastTimer t(FTM_FACE_GEOM_COLOR); + gTransformColorProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount); - bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - bool do_tex_mat = tex_mode && mTextureMatrix; + S32 val = *((S32*) color.mV); - if (!do_bump) - { //not in atlas or not bump mapped, might be able to do a cheap update - mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount); + gTransformColorProgram.uniform1i("color_in", val); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } - if (texgen != LLTextureEntry::TEX_GEN_PLANAR) + if (rebuild_emissive) + { + LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); + gTransformColorProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount); + + U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); + + S32 glow32 = glow | + (glow << 8) | + (glow << 16) | + (glow << 24); + + gTransformColorProgram.uniform1i("color_in", glow32); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } + + if (rebuild_normal) + { + LLFastTimer t(FTM_FACE_GEOM_NORMAL); + gTransformNormalProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_NORMAL); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } + + if (rebuild_binormal) + { + LLFastTimer t(FTM_FACE_GEOM_BINORMAL); + gTransformBinormalProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_BINORMAL, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_BINORMAL); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } + + if (rebuild_tcoord) + { + LLFastTimer t(FTM_FACE_GEOM_TEXTURE); + gTransformTexCoordProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); + + if (do_bump) { - LLFastTimer t(FTM_FACE_TEX_QUICK); - if (!do_tex_mat) + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD1, mGeomIndex, mGeomCount); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } + } + + glBindBufferARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0); + + gGL.popMatrix(); + + if (cur_shader) + { + cur_shader->bind(); + } + } + else +#endif + { + //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); + + if (rebuild_tcoord) + { + LLFastTimer t(FTM_FACE_GEOM_TEXTURE); + + //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); + + LLQuaternion bump_quat; + if (mDrawablep->isActive()) + { + bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); + } + + if (bump_code) + { + mVObjp->getVolume()->genBinormals(f); + F32 offset_multiple; + switch( bump_code ) { - if (!do_xform) + case BE_NO_BUMP: + offset_multiple = 0.f; + break; + case BE_BRIGHTNESS: + case BE_DARKNESS: + if( mTexture.notNull() && mTexture->hasGLTexture()) { - LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); - LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + // 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 { - LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM); - F32* dst = (F32*) tex_coords.get(); - LLVector4a* src = (LLVector4a*) vf.mTexCoords; + offset_multiple = 1.f/256; + } + break; - LLVector4a trans; - trans.splat(-0.5f); + default: // Standard bumpmap textures. Assumed to be 256x256 + offset_multiple = 1.f / 256; + break; + } - LLVector4a rot0; - rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); + 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; - LLVector4a rot1; - rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); + 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); + } - LLVector4a scale; - scale.set(ms, mt, ms, mt); + U8 texgen = getTextureEntry()->getTexGen(); + if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { //planar texgen needs binormals + mVObjp->getVolume()->genBinormals(f); + } - LLVector4a offset; - offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); + U8 tex_mode = 0; + + if (isState(TEXTURE_ANIM)) + { + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + tex_mode = vobj->mTexAnimMode; - LLVector4Logical mask; - mask.clear(); - mask.setElement<2>(); - mask.setElement<3>(); + 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; - U32 count = num_vertices/2 + num_vertices%2; + do_xform = false; + } - for (U32 i = 0; i < count; i++) + if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) + { //don't override texture transform during tc bake + tex_mode = 0; + } + } + + LLVector4a scalea; + scalea.load3(scale.mV); + + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); + bool do_tex_mat = tex_mode && mTextureMatrix; + + if (!do_bump) + { //not in atlas or not bump mapped, might be able to do a cheap update + mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount); + + if (texgen != LLTextureEntry::TEX_GEN_PLANAR) + { + LLFastTimer t(FTM_FACE_TEX_QUICK); + if (!do_tex_mat) + { + if (!do_xform) + { + LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); + LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + } + else + { + LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM); + F32* dst = (F32*) tex_coords.get(); + LLVector4a* src = (LLVector4a*) vf.mTexCoords; + + LLVector4a trans; + trans.splat(-0.5f); + + LLVector4a rot0; + rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); + + LLVector4a rot1; + rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); + + LLVector4a scale; + scale.set(ms, mt, ms, mt); + + LLVector4a offset; + offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); + + LLVector4Logical mask; + mask.clear(); + mask.setElement<2>(); + mask.setElement<3>(); + + U32 count = num_vertices/2 + num_vertices%2; + + for (U32 i = 0; i < count; i++) + { + LLVector4a res = *src++; + xform4a(res, trans, mask, rot0, rot1, offset, scale); + res.store4a(dst); + dst += 4; + } + } + } + else + { //do tex mat, no texgen, no atlas, no bump + for (S32 i = 0; i < num_vertices; i++) { - LLVector4a res = *src++; - xform4a(res, trans, mask, rot0, rot1, offset, scale); - res.store4a(dst); - dst += 4; + 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; } } } 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; - } - } - } - else - { //no bump, no atlas, tex gen planar - LLFastTimer t(FTM_FACE_TEX_QUICK_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; - } - } - 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; - } - } - } - - if (map_range) - { - mVertexBuffer->flush(); - } - } - else - { //either bump mapped or in atlas, just do the whole expensive loop - LLFastTimer t(FTM_FACE_TEX_DEFAULT); - mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range); - - std::vector bump_tc; - - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - - LLVector4a& norm = vf.mNormals[i]; - - LLVector4a& center = *(vf.mCenter); - - if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { - LLVector4a vec = vf.mPositions[i]; - - vec.mul(scalea); - - switch (texgen) + { //no bump, no atlas, tex gen planar + LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR); + if (do_tex_mat) { - case LLTextureEntry::TEX_GEN_PLANAR: + 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); - 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 - { - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - } - - - *tex_coords++ = tc; - if (do_bump) - { - bump_tc.push_back(tc); - } - } - - if (map_range) - { - mVertexBuffer->flush(); - } - - if (do_bump) - { - mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range); - - for (S32 i = 0; i < num_vertices; i++) - { - 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.getF32ptr()); - t *= bump_quat; - binormal.load3(t.mV); + 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; + } } + 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); - binormal.normalize3fast(); - LLVector2 tc = bump_tc[i]; - tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); - - *tex_coords2++ = tc; + *tex_coords++ = tc; + } + } } if (map_range) @@ -1614,205 +1732,304 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mVertexBuffer->flush(); } } - } - } + else + { //either bump mapped or in atlas, just do the whole expensive loop + LLFastTimer t(FTM_FACE_TEX_DEFAULT); + mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range); - if (rebuild_pos) - { - LLFastTimer t(FTM_FACE_GEOM_POSITION); - llassert(num_vertices > 0); + std::vector bump_tc; - mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + + LLVector4a& norm = vf.mNormals[i]; + + LLVector4a& center = *(vf.mCenter); + + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { + LLVector4a vec = vf.mPositions[i]; + + 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 + { + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + } + + + *tex_coords++ = tc; + if (do_bump) + { + bump_tc.push_back(tc); + } + } + + if (map_range) + { + mVertexBuffer->flush(); + } + + if (do_bump) + { + mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range); + + for (S32 i = 0; i < num_vertices; i++) + { + 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.getF32ptr()); + t *= bump_quat; + binormal.load3(t.mV); + } + + binormal.normalize3fast(); + LLVector2 tc = bump_tc[i]; + tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); + + *tex_coords2++ = tc; + } + + if (map_range) + { + mVertexBuffer->flush(); + } + } + } + } + + if (rebuild_pos) + { + LLFastTimer t(FTM_FACE_GEOM_POSITION); + llassert(num_vertices > 0); + + mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); - LLMatrix4a mat_vert; - mat_vert.loadu(mat_vert_in); + LLMatrix4a mat_vert; + mat_vert.loadu(mat_vert_in); - LLVector4a* src = vf.mPositions; - volatile F32* dst = (volatile F32*) vert.get(); + LLVector4a* src = vf.mPositions; + volatile F32* dst = (volatile F32*) vert.get(); - volatile F32* end = dst+num_vertices*4; - LLVector4a res; + volatile F32* end = dst+num_vertices*4; + LLVector4a res; - LLVector4a texIdx; + LLVector4a texIdx; - U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + U8 index = mTextureIndex < 255 ? mTextureIndex : 0; - F32 val = 0.f; - U8* vp = (U8*) &val; - vp[0] = index; - vp[1] = 0; - vp[2] = 0; - vp[3] = 0; + F32 val = 0.f; + U8* vp = (U8*) &val; + vp[0] = index; + vp[1] = 0; + vp[2] = 0; + vp[3] = 0; - llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); + llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); - LLVector4Logical mask; - mask.clear(); - mask.setElement<3>(); + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); - texIdx.set(0,0,0,val); + texIdx.set(0,0,0,val); - { - LLFastTimer t(FTM_FACE_POSITION_STORE); - LLVector4a tmp; - - do - { - mat_vert.affineTransform(*src++, res); - tmp.setSelectWithMask(mask, texIdx, res); - tmp.store4a((F32*) dst); - dst += 4; - } - while(dst < end); - } - - { - LLFastTimer t(FTM_FACE_POSITION_PAD); - S32 aligned_pad_vertices = mGeomCount - num_vertices; - res.set(res[0], res[1], res[2], 0.f); - - while (aligned_pad_vertices > 0) { - --aligned_pad_vertices; - res.store4a((F32*) dst); - dst += 4; + LLFastTimer t(FTM_FACE_POSITION_STORE); + LLVector4a tmp; + + do + { + mat_vert.affineTransform(*src++, res); + tmp.setSelectWithMask(mask, texIdx, res); + tmp.store4a((F32*) dst); + dst += 4; + } + while(dst < end); + } + + { + LLFastTimer t(FTM_FACE_POSITION_PAD); + S32 aligned_pad_vertices = mGeomCount - num_vertices; + res.set(res[0], res[1], res[2], 0.f); + + while (aligned_pad_vertices > 0) + { + --aligned_pad_vertices; + res.store4a((F32*) dst); + dst += 4; + } + } + + if (map_range) + { + mVertexBuffer->flush(); } } - if (map_range) - { - mVertexBuffer->flush(); - } - } - if (rebuild_normal) - { - LLFastTimer t(FTM_FACE_GEOM_NORMAL); - mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); - F32* normals = (F32*) norm.get(); + if (rebuild_normal) + { + LLFastTimer t(FTM_FACE_GEOM_NORMAL); + mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); + F32* normals = (F32*) norm.get(); - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a normal; - mat_normal.rotate(vf.mNormals[i], normal); - normal.normalize3fast(); - normal.store4a(normals); - normals += 4; - } + for (S32 i = 0; i < num_vertices; i++) + { + LLVector4a normal; + mat_normal.rotate(vf.mNormals[i], normal); + normal.normalize3fast(); + normal.store4a(normals); + normals += 4; + } - if (map_range) + if (map_range) + { + mVertexBuffer->flush(); + } + } + + if (rebuild_binormal) { - mVertexBuffer->flush(); - } - } + LLFastTimer t(FTM_FACE_GEOM_BINORMAL); + mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); + F32* binormals = (F32*) binorm.get(); - if (rebuild_binormal) - { - LLFastTimer t(FTM_FACE_GEOM_BINORMAL); - mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); - F32* binormals = (F32*) binorm.get(); - - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a binormal; - mat_normal.rotate(vf.mBinormals[i], binormal); - binormal.normalize3fast(); - binormal.store4a(binormals); - binormals += 4; - } + for (S32 i = 0; i < num_vertices; i++) + { + LLVector4a binormal; + mat_normal.rotate(vf.mBinormals[i], binormal); + binormal.normalize3fast(); + binormal.store4a(binormals); + binormals += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_weights && vf.mWeights) - { - LLFastTimer t(FTM_FACE_GEOM_WEIGHTS); - mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); - F32* weights = (F32*) wght.get(); - LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); - if (map_range) + if (rebuild_weights && vf.mWeights) { - mVertexBuffer->flush(); + LLFastTimer t(FTM_FACE_GEOM_WEIGHTS); + mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); + F32* weights = (F32*) wght.get(); + LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); + if (map_range) + { + mVertexBuffer->flush(); + } + } + + if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) + { + LLFastTimer t(FTM_FACE_GEOM_COLOR); + mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); + + LLVector4a src; + + U32 vec[4]; + vec[0] = vec[1] = vec[2] = vec[3] = color.mAll; + + src.loadua((F32*) vec); + + F32* dst = (F32*) colors.get(); + S32 num_vecs = num_vertices/4; + if (num_vertices%4 > 0) + { + ++num_vecs; + } + + for (S32 i = 0; i < num_vecs; i++) + { + src.store4a(dst); + dst += 4; + } + + if (map_range) + { + mVertexBuffer->flush(); + } + } + + if (rebuild_emissive) + { + LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); + LLStrider emissive; + mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); + + U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); + + LLVector4a src; + + + U32 glow32 = glow | + (glow << 8) | + (glow << 16) | + (glow << 24); + + U32 vec[4]; + std::fill_n(vec,4,glow32); // for clang + + src.loadua((F32*) vec); + + F32* dst = (F32*) emissive.get(); + S32 num_vecs = num_vertices/4; + if (num_vertices%4 > 0) + { + ++num_vecs; + } + + for (S32 i = 0; i < num_vecs; i++) + { + src.store4a(dst); + dst += 4; + } + + if (map_range) + { + mVertexBuffer->flush(); + } } } - // FS-5132 Only use color strider if face has colors. - // if (rebuild_color) - if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) - // - { - LLFastTimer t(FTM_FACE_GEOM_COLOR); - mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); - - LLVector4a src; - - U32 vec[4]; - vec[0] = vec[1] = vec[2] = vec[3] = color.mAll; - - src.loadua((F32*) vec); - - F32* dst = (F32*) colors.get(); - S32 num_vecs = num_vertices/4; - if (num_vertices%4 > 0) - { - ++num_vecs; - } - - for (S32 i = 0; i < num_vecs; i++) - { - src.store4a(dst); - dst += 4; - } - - if (map_range) - { - mVertexBuffer->flush(); - } - } - - if (rebuild_emissive) - { - LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); - LLStrider emissive; - mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); - - U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); - - LLVector4a src; - - - U32 glow32 = glow | - (glow << 8) | - (glow << 16) | - (glow << 24); - - U32 vec[4]; - std::fill_n(vec,4,glow32); - - src.loadua((F32*) vec); - - F32* dst = (F32*) emissive.get(); - S32 num_vecs = num_vertices/4; - if (num_vertices%4 > 0) - { - ++num_vecs; - } - - for (S32 i = 0; i < num_vecs; i++) - { - src.store4a(dst); - dst += 4; - } - - if (map_range) - { - mVertexBuffer->flush(); - } - } if (rebuild_tcoord) { mTexExtents[0].setVec(0,0); @@ -1828,11 +2045,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mTexExtents[1][1] *= et ; } - mLastVertexBuffer = mVertexBuffer; - mLastGeomCount = mGeomCount; - mLastGeomIndex = mGeomIndex; - mLastIndicesCount = mIndicesCount; - mLastIndicesIndex = mIndicesIndex; return TRUE; } @@ -2233,7 +2445,6 @@ void LLFace::setVertexBuffer(LLVertexBuffer* buffer) void LLFace::clearVertexBuffer() { mVertexBuffer = NULL; - mLastVertexBuffer = NULL; } //static diff --git a/indra/newview/llface.h b/indra/newview/llface.h index f6d514760..5513ecd41 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -88,6 +88,8 @@ public: static void initClass(); + static void cacheFaceInVRAM(const LLVolumeFace& vf); + public: LLFace(LLDrawable* drawablep, LLViewerObject* objp) { init(drawablep, objp); } ~LLFace() { destroy(); } @@ -245,7 +247,6 @@ public: private: LLPointer mVertexBuffer; - LLPointer mLastVertexBuffer; U32 mState; LLFacePool* mDrawPoolp; @@ -259,12 +260,6 @@ private: U32 mIndicesIndex; // index into draw pool for indices (yeah, I know!) S32 mIndexInTex ; - //previous rebuild's geometry info - U16 mLastGeomCount; - U16 mLastGeomIndex; - U32 mLastIndicesCount; - U32 mLastIndicesIndex; - LLXformMatrix* mXform; LLPointer mTexture; LLPointer mDrawablep; diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 32a533570..11edb6071 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -368,7 +368,7 @@ void LLVolumeImplFlexible::doFlexibleUpdate() LLPath *path = &volume->getPath(); if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) { - mVO->markForUpdate(TRUE); + //mVO->markForUpdate(TRUE); if (!doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0)) { return; // we did not get updated or initialized, proceeding without can be dangerous @@ -729,7 +729,11 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) else if (!mUpdated || rotated) { volume->mDrawable->setState(LLDrawable::REBUILD_POSITION); - volume->dirtyMesh(); + LLSpatialGroup* group = volume->mDrawable->getSpatialGroup(); + if (group) + { + group->dirtyMesh(); + } volume->genBBoxes(isVolumeGlobal()); } @@ -814,15 +818,17 @@ LLQuaternion LLVolumeImplFlexible::getEndRotation() }//------------------------------------------------------------------ -void LLVolumeImplFlexible::updateRelativeXform() +void LLVolumeImplFlexible::updateRelativeXform(bool force_identity) { LLQuaternion delta_rot; LLVector3 delta_pos, delta_scale; LLVOVolume* vo = (LLVOVolume*) mVO; + bool use_identity = vo->mDrawable->isSpatialRoot() || force_identity; + //matrix from local space to parent relative/global space - delta_rot = vo->mDrawable->isSpatialRoot() ? LLQuaternion() : vo->mDrawable->getRotation(); - delta_pos = vo->mDrawable->isSpatialRoot() ? LLVector3(0,0,0) : vo->mDrawable->getPosition(); + delta_rot = use_identity ? LLQuaternion() : vo->mDrawable->getRotation(); + delta_pos = use_identity ? LLVector3(0,0,0) : vo->mDrawable->getPosition(); delta_scale = LLVector3(1,1,1); // Vertex transform (4x4) diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h index bdfbded82..faed3801b 100644 --- a/indra/newview/llflexibleobject.h +++ b/indra/newview/llflexibleobject.h @@ -95,7 +95,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface bool isVolumeGlobal() const { return true; } bool isActive() const { return true; } const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; - void updateRelativeXform(); + void updateRelativeXform(bool force_identity); void doFlexibleUpdate(); // Called to update the simulation void doFlexibleRebuild(); // Called to rebuild the geometry void preRebuild(); diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 02db1cc7b..b93812506 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -142,24 +142,16 @@ BOOL LLFloaterAvatarPicker::postBuild() inventory_panel->openDefaultFolderForType(LLAssetType::AT_CALLINGCARD); inventory_panel->setSelectCallback(boost::bind(&LLFloaterAvatarPicker::onCallingCardSelectionChange, _1, _2, (void*)this)); - childSetTabChangeCallback("ResidentChooserTabs", "SearchPanel", onTabChanged, this); - childSetTabChangeCallback("ResidentChooserTabs", "CallingCardsPanel", onTabChanged, this); - childSetTabChangeCallback("ResidentChooserTabs", "NearMePanel", onTabChanged, this); - childSetTabChangeCallback("ResidentChooserTabs", "KeyPanel", onTabChanged, this); + getChild("ResidentChooserTabs")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onTabChanged,this)); + setAllowMultiple(FALSE); return TRUE; } -void LLFloaterAvatarPicker::onTabChanged(void* userdata, bool from_click) +void LLFloaterAvatarPicker::onTabChanged() { - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)userdata; - if (!self) - { - return; - } - - self->childSetEnabled("Select", self->visibleItemsSelected()); + childSetEnabled("Select", visibleItemsSelected()); } // Destroys the object diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index 56bc387bc..17b928f40 100644 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -62,7 +62,7 @@ private: static void onRangeAdjust(LLUICtrl* source, void* data); static void onBtnClose(void* userdata); static void onList(class LLUICtrl* ctrl, void* userdata); - static void onTabChanged(void* userdata, bool from_click); + void onTabChanged(); void doCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data); static void onCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 61d1671e9..890d80829 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -49,7 +49,7 @@ #include "lltoolmgr.h" #include "llviewermenu.h" #include "llscrollcontainer.h" -#include "llscrollingpanellist.h" +#include "llscrollingpanelparam.h" #include "llsliderctrl.h" #include "lltabcontainervertical.h" #include "llviewerwindow.h" @@ -78,6 +78,7 @@ #include "llviewercontrol.h" #include "lluictrlfactory.h" #include "llnotificationsutil.h" +#include "llpaneleditwearable.h" #include "statemachine/aifilepicker.h" #include "hippogridmanager.h" @@ -89,8 +90,6 @@ using namespace LLVOAvatarDefines; // Globals LLFloaterCustomize* gFloaterCustomize = NULL; -const F32 PARAM_STEP_TIME_THRESHOLD = 0.25f; - ///////////////////////////////////////////////////////////////////// // LLFloaterCustomizeObserver @@ -99,7 +98,7 @@ class LLFloaterCustomizeObserver : public LLInventoryObserver public: LLFloaterCustomizeObserver(LLFloaterCustomize* fc) : mFC(fc) {} virtual ~LLFloaterCustomizeObserver() {} - virtual void changed(U32 mask) { mFC->updateScrollingPanelUI(); } + virtual void changed(U32 mask) { mFC->getCurrentWearablePanel()->updateScrollingPanelUI(); } protected: LLFloaterCustomize* mFC; }; @@ -108,62 +107,6 @@ protected: // Local Constants -class LLWearableSaveAsDialog : public LLModalDialog -{ -private: - std::string mItemName; - void (*mCommitCallback)(LLWearableSaveAsDialog*,void*); - void* mCallbackUserData; - -public: - LLWearableSaveAsDialog( const std::string& desc, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata ) - : LLModalDialog( LLStringUtil::null, 240, 100 ), - mCommitCallback( commit_cb ), - mCallbackUserData( userdata ) - { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml"); - - childSetAction("Save", LLWearableSaveAsDialog::onSave, this ); - childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this ); - - childSetTextArg("name ed", "[DESC]", desc); - } - - virtual void startModal() - { - LLModalDialog::startModal(); - LLLineEditor* edit = getChild("name ed"); - if (!edit) return; - edit->setFocus(TRUE); - edit->selectAll(); - } - - const std::string& getItemName() { return mItemName; } - - static void onSave( void* userdata ) - { - LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; - self->mItemName = self->childGetValue("name ed").asString(); - LLStringUtil::trim(self->mItemName); - if( !self->mItemName.empty() ) - { - if( self->mCommitCallback ) - { - self->mCommitCallback( self, self->mCallbackUserData ); - } - self->close(); // destroys this object - } - } - - static void onCancel( void* userdata ) - { - LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; - self->close(); // destroys this object - } -}; - -//////////////////////////////////////////////////////////////////////////// - BOOL edit_wearable_for_teens(LLWearableType::EType type) { switch(type) @@ -390,1331 +333,20 @@ public: } }; -///////////////////////////////////////////////////////////////////// -// LLPanelEditWearable - -enum ESubpart { - SUBPART_SHAPE_HEAD = 1, // avoid 0 - SUBPART_SHAPE_EYES, - SUBPART_SHAPE_EARS, - SUBPART_SHAPE_NOSE, - SUBPART_SHAPE_MOUTH, - SUBPART_SHAPE_CHIN, - SUBPART_SHAPE_TORSO, - SUBPART_SHAPE_LEGS, - SUBPART_SHAPE_WHOLE, - SUBPART_SHAPE_DETAIL, - SUBPART_SKIN_COLOR, - SUBPART_SKIN_FACEDETAIL, - SUBPART_SKIN_MAKEUP, - SUBPART_SKIN_BODYDETAIL, - SUBPART_HAIR_COLOR, - SUBPART_HAIR_STYLE, - SUBPART_HAIR_EYEBROWS, - SUBPART_HAIR_FACIAL, - SUBPART_EYES, - SUBPART_SHIRT, - SUBPART_PANTS, - SUBPART_SHOES, - SUBPART_SOCKS, - SUBPART_JACKET, - SUBPART_GLOVES, - SUBPART_UNDERSHIRT, - SUBPART_UNDERPANTS, - SUBPART_SKIRT, - SUBPART_ALPHA, - SUBPART_TATTOO, - SUBPART_PHYSICS_BREASTS_UPDOWN, - SUBPART_PHYSICS_BREASTS_INOUT, - SUBPART_PHYSICS_BREASTS_LEFTRIGHT, - SUBPART_PHYSICS_BELLY_UPDOWN, - SUBPART_PHYSICS_BUTT_UPDOWN, - SUBPART_PHYSICS_BUTT_LEFTRIGHT, - SUBPART_PHYSICS_ADVANCED - }; - -struct LLSubpart -{ - LLSubpart(const char* pJoint, const char* pGroup, const LLVector3d &target_offs, const LLVector3d &cam_offs, const ESex sex=SEX_BOTH, bool visual_hint=true ) - : mSex( sex ), mVisualHint(visual_hint), mTargetJoint(pJoint), mEditGroup(pGroup), mTargetOffset(target_offs), mCameraOffset(cam_offs) - {} - LLSubpart(const char* pJoint, const char* pGroup, const LLVector3d &target_offs, const LLVector3d &cam_offs, bool visual_hint) - : mSex( SEX_BOTH ), mVisualHint(visual_hint), mTargetJoint(pJoint), mEditGroup(pGroup), mTargetOffset(target_offs), mCameraOffset(cam_offs) - {} - std::string mButtonName; - std::string mTargetJoint; - std::string mEditGroup; - LLVector3d mTargetOffset; - LLVector3d mCameraOffset; - ESex mSex; - - bool mVisualHint; -}; - //////////////////////////////////////////////////////////////////////////// -class LLPanelEditWearable : public LLPanel -{ -public: - LLPanelEditWearable( LLWearableType::EType type ); - virtual ~LLPanelEditWearable(); - - virtual BOOL postBuild(); - virtual void draw(); - virtual BOOL isDirty() const; // LLUICtrl - - void addSubpart(const std::string& name, ESubpart id, LLSubpart* part ); - void addTextureDropTarget( ETextureIndex te, const std::string& name, const LLUUID& default_image_id, BOOL allow_no_texture ); - void addInvisibilityCheckbox(ETextureIndex te, const std::string& name); - void addColorSwatch( ETextureIndex te, const std::string& name ); - - const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); } - LLWearableType::EType getType() { return mType; } - - LLSubpart* getCurrentSubpart() { return mSubpartList[mCurrentSubpart]; } - ESubpart getDefaultSubpart(); - void setSubpart( ESubpart subpart ); - void switchToDefaultSubpart(); - - void setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete); - - void setUIPermissions(U32 perm_mask, BOOL is_complete); - - void hideTextureControls(); - bool textureIsInvisible(ETextureIndex te); - void initPreviousTextureList(); - void initPreviousTextureListEntry(ETextureIndex te); - - virtual void setVisible( BOOL visible ); - - // Callbacks - static void onBtnSubpart( void* userdata ); - static void onBtnTakeOff( void* userdata ); - static void onBtnSave( void* userdata ); - - static void onBtnSaveAs( void* userdata ); - static void onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ); - - static void onBtnRevert( void* userdata ); - static void onBtnTakeOffDialog( S32 option, void* userdata ); - static void onBtnCreateNew( void* userdata ); - static void onTextureCommit( LLUICtrl* ctrl, void* userdata ); - static void onInvisibilityCommit( LLUICtrl* ctrl, void* userdata ); - static void onColorCommit( LLUICtrl* ctrl, void* userdata ); - static void onCommitSexChange( LLUICtrl*, void* userdata ); - static bool onSelectAutoWearOption(const LLSD& notification, const LLSD& response); - - - -private: - LLWearableType::EType mType; - BOOL mCanTakeOff; - std::map mTextureList; - std::map mInvisibilityList; - std::map mColorList; - std::map mSubpartList; - std::map mPreviousTextureList; - ESubpart mCurrentSubpart; -}; - -//////////////////////////////////////////////////////////////////////////// - -LLPanelEditWearable::LLPanelEditWearable( LLWearableType::EType type ) - : LLPanel( LLWearableType::getTypeLabel( type ) ), - mType( type ) -{ -} - -BOOL LLPanelEditWearable::postBuild() -{ - LLAssetType::EType asset_type = LLWearableType::getAssetType( mType ); - /*std::string icon_name = (asset_type == LLAssetType::AT_CLOTHING ? - "inv_item_clothing.tga" : - "inv_item_skin.tga" );*/ - std::string icon_name = LLInventoryIcon::getIconName(asset_type,LLInventoryType::IT_WEARABLE,mType,FALSE); - - childSetValue("icon", icon_name); - - childSetAction("Create New", LLPanelEditWearable::onBtnCreateNew, this ); - - // If PG, can't take off underclothing or shirt - mCanTakeOff = - LLWearableType::getAssetType( mType ) == LLAssetType::AT_CLOTHING && - !( gAgent.isTeen() && (mType == LLWearableType::WT_UNDERSHIRT || mType == LLWearableType::WT_UNDERPANTS) ); - childSetVisible("Take Off", mCanTakeOff); - childSetAction("Take Off", LLPanelEditWearable::onBtnTakeOff, this ); - - childSetAction("Save", &LLPanelEditWearable::onBtnSave, (void*)this ); - - childSetAction("Save As", &LLPanelEditWearable::onBtnSaveAs, (void*)this ); - - childSetAction("Revert", &LLPanelEditWearable::onBtnRevert, (void*)this ); - - return TRUE; -} - -LLPanelEditWearable::~LLPanelEditWearable() -{ - std::for_each(mSubpartList.begin(), mSubpartList.end(), DeletePairedPointer()); - - // Clear colorswatch commit callbacks that point to this object. - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - childSetCommitCallback(iter->first, NULL, NULL); - } -} - -void LLPanelEditWearable::addSubpart( const std::string& name, ESubpart id, LLSubpart* part ) -{ - if (!name.empty()) - { - childSetAction(name, &LLPanelEditWearable::onBtnSubpart, (void*)id); - part->mButtonName = name; - } - mSubpartList[id] = part; - -} - -// static -void LLPanelEditWearable::onBtnSubpart(void* userdata) -{ - LLFloaterCustomize* floater_customize = gFloaterCustomize; - if (!floater_customize) return; - LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel(); - if (!self) return; - ESubpart subpart = (ESubpart) (intptr_t)userdata; - self->setSubpart( subpart ); -} - -void LLPanelEditWearable::setSubpart( ESubpart subpart ) -{ - mCurrentSubpart = subpart; - - for (std::map::iterator iter = mSubpartList.begin(); - iter != mSubpartList.end(); ++iter) - { - LLButton* btn = getChild(iter->second->mButtonName); - if (btn) - { - btn->setToggleState( subpart == iter->first ); - } - } - - LLSubpart* part = get_if_there(mSubpartList, (ESubpart)subpart, (LLSubpart*)NULL); - if( part ) - { - // Update the thumbnails we display - LLFloaterCustomize::param_map sorted_params; - LLVOAvatar* avatar = gAgentAvatarp; - ESex avatar_sex = avatar->getSex(); - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType,0); // TODO: MULTI-WEARABLE - U32 perm_mask = 0x0; - BOOL is_complete = FALSE; - bool can_export = false; - bool can_import = false; - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - - if (subpart <= 18) // body parts only - { - can_import = true; - - if (is_complete && - gAgent.getID() == item->getPermissions().getOwner() && - gAgent.getID() == item->getPermissions().getCreator() && - (PERM_ITEM_UNRESTRICTED & - perm_mask) == PERM_ITEM_UNRESTRICTED) - { - can_export = true; - } - } - } - setUIPermissions(perm_mask, is_complete); - BOOL editable = ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE; - - for(LLViewerVisualParam* param = (LLViewerVisualParam *)avatar->getFirstVisualParam(); - param; - param = (LLViewerVisualParam *)avatar->getNextVisualParam()) - { - if (param->getID() == -1 - || !param->isTweakable() - || param->getEditGroup() != part->mEditGroup - || !(param->getSex() & avatar_sex)) - { - continue; - } - - // negative getDisplayOrder() to make lowest order the highest priority - LLFloaterCustomize::param_map::value_type vt(-param->getDisplayOrder(), LLFloaterCustomize::editable_param(editable, param)); - llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates - sorted_params.insert(vt); - } - gFloaterCustomize->generateVisualParamHints(NULL, sorted_params, part->mVisualHint); - gFloaterCustomize->updateScrollingPanelUI(); - gFloaterCustomize->childSetEnabled("Export", can_export); - gFloaterCustomize->childSetEnabled("Import", can_import); - - // Update the camera - gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( part->mTargetJoint ) ); - gMorphView->setCameraTargetOffset( part->mTargetOffset ); - gMorphView->setCameraOffset( part->mCameraOffset ); - gMorphView->setCameraDistToDefault(); - if (gSavedSettings.getBOOL("AppearanceCameraMovement")) - { - gMorphView->updateCamera(); - } - } -} - -// static -void LLPanelEditWearable::onBtnTakeOff( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - - LLWearable* wearable = gAgentWearables.getWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE - if( !wearable ) - { - return; - } - - gAgentWearables.removeWearable( self->mType, false, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnSave( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.saveWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnSaveAs( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->getType(), 0 ); // TODO: MULTI-WEARABLE - if( wearable ) - { - LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self ); - save_as_dialog->startModal(); - // LLWearableSaveAsDialog deletes itself. - } -} - -// static -void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar ) - { - gAgentWearables.saveWearableAs( self->getType(), 0, save_as_dialog->getItemName(), FALSE ); // TODO: MULTI-WEARABLE - } -} - - -// static -void LLPanelEditWearable::onBtnRevert( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.revertWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnCreateNew( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLSD payload; - payload["wearable_type"] = (S32)self->getType(); - LLNotificationsUtil::add("AutoWearNewClothing", LLSD(), payload, &onSelectAutoWearOption); -} - -bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLVOAvatar* avatar = gAgentAvatarp; - if(avatar) - { - // Create a new wearable in the default folder for the wearable's asset type. - LLWearable* wearable = LLWearableList::instance().createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger() ); - LLAssetType::EType asset_type = wearable->getAssetType(); - - LLUUID folder_id; - // regular UI, items get created in normal folder - folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); - - // Only auto wear the new item if the AutoWearNewClothing checkbox is selected. - LLPointer cb = option == 0 ? - new WearOnAvatarCallback : NULL; - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), - asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), cb); - } - return false; -} - -bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) -{ - const LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if(wearable) - { - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - return (lto && lto->getID() == IMG_INVISIBLE); - } - return false; -} - -void LLPanelEditWearable::addInvisibilityCheckbox(ETextureIndex te, const std::string& name) -{ - childSetCommitCallback(name, LLPanelEditWearable::onInvisibilityCommit, this); - - mInvisibilityList[name] = te; -} - -// static -void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLCheckBoxCtrl* checkbox_ctrl = (LLCheckBoxCtrl*) ctrl; - if (!gAgentAvatarp) - { - return; - } - - ETextureIndex te = (ETextureIndex)(self->mInvisibilityList[ctrl->getName()]); - - bool new_invis_state = checkbox_ctrl->get(); - if (new_invis_state) - { - - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); - - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - const LLLocalTextureObject* lto = wearable ? wearable->getLocalTextureObject(te) : NULL; - - if(lto) - { - self->mPreviousTextureList[(S32)te] = lto->getID(); - } - if(wearable) - { - LLLocalTextureObject new_lto(image, IMG_INVISIBLE); - wearable->setLocalTextureObject(te, new_lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - - } - else - { - // Try to restore previous texture, if any. - LLUUID prev_id = self->mPreviousTextureList[(S32)te]; - if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) - { - prev_id = LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")); - } - if (prev_id.notNull()) - { - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - if(wearable) - { - LLLocalTextureObject new_lto(image, prev_id); - wearable->setLocalTextureObject(te, new_lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - } - - } -} - -void LLPanelEditWearable::addColorSwatch( ETextureIndex te, const std::string& name ) -{ - childSetCommitCallback(name, LLPanelEditWearable::onColorCommit, this); - mColorList[name] = te; -} - -// static -void LLPanelEditWearable::onColorCommit( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLColorSwatchCtrl* color_ctrl = (LLColorSwatchCtrl*) ctrl; - - if( self && color_ctrl && gAgentAvatarp ) - { - std::map::const_iterator cl_itr = self->mColorList.find(ctrl->getName()); - if(cl_itr != self->mColorList.end()) - { - ETextureIndex te = (ETextureIndex)cl_itr->second; - - LLWearable* wearable = gAgentWearables.getWearable(self->mType, 0); // TODO: MULTI-WEARABLE - if(!wearable) - return; - - LLColor4 old_color = wearable->getClothesColor( te ); - const LLColor4& new_color = color_ctrl->get(); - if( old_color != new_color ) - { - // Set the new version - wearable->setClothesColor(te, new_color, TRUE); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - LLVisualParamHint::requestHintUpdates(); - } - } - } -} - -void LLPanelEditWearable::initPreviousTextureList() -{ - initPreviousTextureListEntry(TEX_LOWER_ALPHA); - initPreviousTextureListEntry(TEX_UPPER_ALPHA); - initPreviousTextureListEntry(TEX_HEAD_ALPHA); - initPreviousTextureListEntry(TEX_EYES_ALPHA); - initPreviousTextureListEntry(TEX_LOWER_ALPHA); -} - -void LLPanelEditWearable::initPreviousTextureListEntry(ETextureIndex te) -{ - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if(!wearable) - return; - - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - if (lto) - { - mPreviousTextureList[te] = lto->getID(); - } -} - -void LLPanelEditWearable::addTextureDropTarget( ETextureIndex te, const std::string& name, - const LLUUID& default_image_id, BOOL allow_no_texture ) -{ - childSetCommitCallback(name, LLPanelEditWearable::onTextureCommit, this); - LLTextureCtrl* texture_ctrl = getChild(name); - if (texture_ctrl) - { - texture_ctrl->setDefaultImageAssetID(default_image_id); - texture_ctrl->setAllowNoTexture( allow_no_texture ); - // Don't allow (no copy) or (no transfer) textures to be selected. - texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); - texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); - } - mTextureList[name] = te; - LLVOAvatar* avatar = gAgentAvatarp; - if (avatar) - { - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if (wearable && mType == LLWearableType::WT_ALPHA) - { - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - if (lto) - { - mPreviousTextureList[te] = lto->getID(); - } - } - } -} - -// static -void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLTextureCtrl* texture_ctrl = (LLTextureCtrl*) ctrl; - - if( gAgentAvatarp ) - { - ETextureIndex te = (ETextureIndex)(self->mTextureList[ctrl->getName()]); - - // Set the new version - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( texture_ctrl->getImageAssetID() ); - if (image->getID().isNull()) - { - image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); - } - self->mTextureList[ctrl->getName()] = te; - - LLWearable* wearable = gAgentWearables.getWearable(self->mType, 0); // TODO: MULTI-WEARABLE - if (wearable) - { - LLLocalTextureObject lto(image, texture_ctrl->getImageAssetID()); - wearable->setLocalTextureObject(te, lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - if (self->mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) - { - self->mPreviousTextureList[te] = image->getID(); - } - } -} - - -ESubpart LLPanelEditWearable::getDefaultSubpart() -{ - switch( mType ) - { - case LLWearableType::WT_SHAPE: return SUBPART_SHAPE_WHOLE; - case LLWearableType::WT_SKIN: return SUBPART_SKIN_COLOR; - case LLWearableType::WT_HAIR: return SUBPART_HAIR_COLOR; - case LLWearableType::WT_EYES: return SUBPART_EYES; - case LLWearableType::WT_SHIRT: return SUBPART_SHIRT; - case LLWearableType::WT_PANTS: return SUBPART_PANTS; - case LLWearableType::WT_SHOES: return SUBPART_SHOES; - case LLWearableType::WT_SOCKS: return SUBPART_SOCKS; - case LLWearableType::WT_JACKET: return SUBPART_JACKET; - case LLWearableType::WT_GLOVES: return SUBPART_GLOVES; - case LLWearableType::WT_UNDERSHIRT: return SUBPART_UNDERSHIRT; - case LLWearableType::WT_UNDERPANTS: return SUBPART_UNDERPANTS; - case LLWearableType::WT_SKIRT: return SUBPART_SKIRT; - case LLWearableType::WT_ALPHA: return SUBPART_ALPHA; - case LLWearableType::WT_TATTOO: return SUBPART_TATTOO; - case LLWearableType::WT_PHYSICS: return SUBPART_PHYSICS_BELLY_UPDOWN; - - default: llassert(0); return SUBPART_SHAPE_WHOLE; - } -} - - -void LLPanelEditWearable::draw() -{ - if( gFloaterCustomize->isMinimized() ) - { - return; - } - - LLVOAvatar* avatar = gAgentAvatarp; - if( !avatar ) - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE - BOOL has_wearable = (wearable != NULL ); - BOOL is_dirty = isDirty(); - BOOL is_modifiable = FALSE; - BOOL is_copyable = FALSE; - BOOL is_complete = FALSE; - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType, 0); // TODO: MULTI-WEARABLE - if(item) - { - const LLPermissions& perm = item->getPermissions(); - is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); - is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()); - is_complete = item->isComplete(); - } - - childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty); - childSetEnabled("Save As", is_copyable && is_complete && has_wearable); - childSetEnabled("Revert", has_wearable && is_dirty ); - childSetEnabled("Take Off", has_wearable ); - childSetVisible("Take Off", mCanTakeOff && has_wearable ); - childSetVisible("Create New", !has_wearable ); - - childSetVisible("not worn instructions", !has_wearable ); - childSetVisible("no modify instructions", has_wearable && !is_modifiable); - - for (std::map::iterator iter = mSubpartList.begin(); - iter != mSubpartList.end(); ++iter) - { - childSetVisible(iter->second->mButtonName,has_wearable); - if( has_wearable && is_complete && is_modifiable ) - { - childSetEnabled(iter->second->mButtonName, iter->second->mSex & avatar->getSex() ); - } - else - { - childSetEnabled(iter->second->mButtonName, FALSE ); - } - } - - childSetVisible("square", !is_modifiable); - - childSetVisible("title", FALSE); - childSetVisible("title_no_modify", FALSE); - childSetVisible("title_not_worn", FALSE); - childSetVisible("title_loading", FALSE); - - childSetVisible("path", FALSE); - - LLTextBox *av_height = getChild("avheight",FALSE,FALSE); - if(av_height) //Only display this if the element exists - { - // Display the shape's nominal height. - // - // The value for avsize is the best available estimate from - // measuring against prims. - float avsize = avatar->mBodySize.mV[VZ] + .195; - int inches = (int)(avsize / .0254f); - int feet = inches / 12; - inches %= 12; - - std::ostringstream avheight(std::ostringstream::trunc); - avheight << std::fixed << std::setprecision(2) << avsize << " m (" - << feet << "' " << inches << "\")"; - av_height->setVisible(TRUE); - av_height->setTextArg("[AVHEIGHT]",avheight.str()); - } - - if(has_wearable && !is_modifiable) - { - // *TODO:Translate - childSetVisible("title_no_modify", TRUE); - childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - hideTextureControls(); - } - else if(has_wearable && !is_complete) - { - // *TODO:Translate - childSetVisible("title_loading", TRUE); - childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE - append_path(item_id, path); - childSetVisible("path", TRUE); - childSetTextArg("path", "[PATH]", path); - - hideTextureControls(); - } - else if(has_wearable && is_modifiable) - { - childSetVisible("title", TRUE); - childSetTextArg("title", "[DESC]", wearable->getName() ); - - std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE - append_path(item_id, path); - childSetVisible("path", TRUE); - childSetTextArg("path", "[PATH]", path); - - for( std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter ) - { - std::string name = iter->first; - LLTextureCtrl* texture_ctrl = getChild(name); - S32 te_index = iter->second; - childSetVisible(name, is_copyable && is_modifiable && is_complete ); - if (texture_ctrl) - { - - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te_index); - - LLUUID new_id; - - if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) - { - new_id = lto->getID(); - } - else - { - new_id = LLUUID::null; - } - - LLUUID old_id = texture_ctrl->getImageAssetID(); - - if (old_id != new_id) - { - // texture has changed, close the floater to avoid DEV-22461 - texture_ctrl->closeFloater(); - } - - texture_ctrl->setImageAssetID(new_id); - } - } - - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - - if(wearable) - { - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - std::string name = iter->first; - S32 te_index = iter->second; - childSetVisible(name, is_modifiable && is_complete ); - childSetEnabled(name, is_modifiable && is_complete ); - LLColorSwatchCtrl* ctrl = getChild(name); - if (ctrl) - { - ctrl->set( wearable->getClothesColor(te_index ) ); - } - } - } - - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - std::string name = iter->first; - ETextureIndex te = (ETextureIndex)iter->second; - childSetVisible(name, is_copyable && is_modifiable && is_complete); - childSetEnabled(name, is_copyable && is_modifiable && is_complete); - LLCheckBoxCtrl* ctrl = getChild(name); - if (ctrl) - { - ctrl->set(textureIsInvisible(te)); - } - } - } - else - { - // *TODO:Translate - childSetVisible("title_not_worn", TRUE); - childSetTextArg("title_not_worn", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - hideTextureControls(); - } - - childSetVisible("icon", has_wearable && is_modifiable); - - LLPanel::draw(); -} - -void LLPanelEditWearable::hideTextureControls() -{ - for (std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } - for (std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } -} - -void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete) -{ - if( wearable ) - { - setUIPermissions(perm_mask, is_complete); - if (mType == LLWearableType::WT_ALPHA) - { - initPreviousTextureList(); - } - } -} - -void LLPanelEditWearable::switchToDefaultSubpart() -{ - setSubpart( getDefaultSubpart() ); -} - -void LLPanelEditWearable::setVisible(BOOL visible) -{ - LLPanel::setVisible( visible ); - if( !visible ) - { - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - // this forces any open color pickers to cancel their selection - childSetEnabled(iter->first, FALSE ); - } - } -} - -BOOL LLPanelEditWearable::isDirty() const -{ - LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE - if( !wearable ) - { - return FALSE; - } - - if( wearable->isDirty() ) - { - return TRUE; - } - - return FALSE; -} - -// static -void LLPanelEditWearable::onCommitSexChange( LLUICtrl*, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) - { - return; - } - - if( !gAgentWearables.isWearableModifiable(self->mType, 0)) // TODO: MULTI-WEARABLE - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - if(!wearable) - { - return; - } - - ESex new_sex = gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE; - - LLVisualParam* param = avatar->getVisualParam( "male" ); - if( !param ) - { - return; - } - - wearable->setVisualParamWeight(param->getID(), (new_sex == SEX_MALE), TRUE); - wearable->writeToAvatar(); - avatar->updateVisualParams(); - - /*param->setWeight( (new_sex == SEX_MALE), TRUE ); - - avatar->updateSexDependentLayerSets( TRUE ); - - avatar->updateVisualParams();*/ - - gFloaterCustomize->clearScrollingPanelList(); - - // Assumes that we're in the "Shape" Panel. - self->setSubpart( SUBPART_SHAPE_WHOLE ); -} - -void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) -{ - BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE; - BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE; - - childSetEnabled("Save", is_modifiable && is_complete); - childSetEnabled("Save As", is_copyable && is_complete); - childSetEnabled("sex radio", is_modifiable && is_complete); - for( std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter ) - { - childSetVisible(iter->first, is_copyable && is_modifiable && is_complete ); - } - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - childSetVisible(iter->first, is_modifiable && is_complete ); - } - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - childSetVisible(iter->first, is_copyable && is_modifiable && is_complete); - } -} - -///////////////////////////////////////////////////////////////////// -// LLScrollingPanelParam - -class LLScrollingPanelParam : public LLScrollingPanel -{ -public: - LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ); - virtual ~LLScrollingPanelParam(); - - virtual void draw(); - virtual void setVisible( BOOL visible ); - virtual void updatePanel(BOOL allow_modify); - - static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata); - static void onSliderMoved(LLUICtrl* ctrl, void* userdata); - static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata); - - void onHintMouseUp( bool max ); - void onHintMouseDown( bool max ); - void onHintHeldDown( bool max ); - - F32 weightToPercent( F32 weight ); - F32 percentToWeight( F32 percent ); - -public: - LLViewerVisualParam* mParam; - LLPointer mHintMin; - LLPointer mHintMax; - LLButton* mLess; - LLButton* mMore; - - static S32 sUpdateDelayFrames; - -protected: - LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. - F32 mLastHeldTime; - - BOOL mAllowModify; -}; - -//static -S32 LLScrollingPanelParam::sUpdateDelayFrames = 0; - -const S32 BTN_BORDER = 2; -const S32 PARAM_HINT_WIDTH = 128; -const S32 PARAM_HINT_HEIGHT = 128; -const S32 PARAM_HINT_LABEL_HEIGHT = 16; -const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH); -const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; - -LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, - LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ) - : LLScrollingPanel( name, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 ) ), - mParam(param), - mAllowModify(allow_modify), - mLess(NULL), - mMore(NULL) -{ - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); - - //Set up the slider - LLSliderCtrl *slider = getChild("param slider"); - slider->setValue(weightToPercent(param->getWeight())); - slider->setLabelArg("[DESC]", param->getDisplayName()); - slider->setEnabled(mAllowModify); - slider->setCommitCallback(LLScrollingPanelParam::onSliderMoved); - slider->setCallbackUserData(this); - - if(bVisualHint) - { - S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; - S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT; - F32 min_weight = param->getMinWeight(); - F32 max_weight = param->getMaxWeight(); - - mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight); - pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; - mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight ); - - mHintMin->setAllowsUpdates( FALSE ); - mHintMax->setAllowsUpdates( FALSE ); - - // *TODO::translate - std::string min_name = param->getMinDisplayName(); - std::string max_name = param->getMaxDisplayName(); - childSetValue("min param text", min_name); - childSetValue("max param text", max_name); - mLess = getChild("less"); - mLess->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, false) ); - mLess->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, false) ); - mLess->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, false) ); - mLess->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); - - mMore = getChild("more"); - mMore->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, true) ); - mMore->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, true) ); - mMore->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, true) ); - mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); - } - else - { - //Kill everything that isn't the slider... - child_list_t to_remove; - child_list_t::const_iterator it; - for (it = getChildList()->begin(); it != getChildList()->end(); it++) - { - if ((*it) != slider && (*it)->getName() != "panel border") - { - to_remove.push_back(*it); - } - } - for (it = to_remove.begin(); it != to_remove.end(); it++) - { - removeChild(*it); - delete (*it); - } - slider->translate(0,PARAM_HINT_HEIGHT); - reshape(getRect().getWidth(),getRect().getHeight()-PARAM_HINT_HEIGHT); - } - - setVisible(FALSE); - setBorderVisible( FALSE ); -} - -LLScrollingPanelParam::~LLScrollingPanelParam() -{ - mHintMin = NULL; - mHintMax = NULL; -} - -void LLScrollingPanelParam::updatePanel(BOOL allow_modify) -{ - childSetValue("param slider", weightToPercent( mParam->getWeight() ) ); - if(mHintMin) - mHintMin->requestUpdate( sUpdateDelayFrames++ ); - if(mHintMax) - mHintMax->requestUpdate( sUpdateDelayFrames++ ); - - mAllowModify = allow_modify; - childSetEnabled("param slider", mAllowModify); - - if(mLess) - mLess->setEnabled(mAllowModify); - if(mMore) - mMore->setEnabled(mAllowModify); -} - -void LLScrollingPanelParam::setVisible( BOOL visible ) -{ - if( getVisible() != visible ) - { - LLPanel::setVisible( visible ); - if(mHintMin) - mHintMin->setAllowsUpdates( visible ); - if(mHintMax) - mHintMax->setAllowsUpdates( visible ); - - if( visible ) - { - if(mHintMin) - mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ ); - if(mHintMax) - mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ ); - } - } -} - -void LLScrollingPanelParam::draw() -{ - if( gFloaterCustomize->isMinimized() ) - { - return; - } - - if(mLess) - mLess->setVisible(mHintMin ? mHintMin->getVisible() : false); - if(mMore) - mMore->setVisible(mHintMax ? mHintMax->getVisible() : false); - - // Draw all the children except for the labels - childSetVisible( "min param text", FALSE ); - childSetVisible( "max param text", FALSE ); - LLPanel::draw(); - - // Draw the hints over the "less" and "more" buttons. - if(mHintMin) - { - gGL.pushMatrix(); - { - const LLRect& r = mHintMin->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - gGL.translatef(left, bot, 0.f); - mHintMin->draw(); - } - gGL.popMatrix(); - } - - if(mHintMax) - { - gGL.pushMatrix(); - { - const LLRect& r = mHintMax->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - gGL.translatef(left, bot, 0.f); - mHintMax->draw(); - } - gGL.popMatrix(); - } - - - // Draw labels on top of the buttons - childSetVisible( "min param text", TRUE ); - drawChild(getChild("min param text"), BTN_BORDER, BTN_BORDER); - - childSetVisible( "max param text", TRUE ); - drawChild(getChild("max param text"), BTN_BORDER, BTN_BORDER); -} - void updateAvatarHeightDisplay() { - if (gFloaterCustomize) - { - LLVOAvatar* avatar = gAgentAvatarp; - F32 avatar_size = (avatar->mBodySize.mV[VZ]) + (F32)0.17; //mBodySize is actually quite a bit off. - gFloaterCustomize->getChild("HeightTextM")->setValue(llformat("%.2f", avatar_size) + "m"); - F32 feet = avatar_size / 0.3048; - F32 inches = (feet - (F32)((U32)feet)) * 12.0; - gFloaterCustomize->getChild("HeightTextI")->setValue(llformat("%d'%d\"", (U32)feet, (U32)inches)); - } + if (gFloaterCustomize && isAgentAvatarValid()) + { + F32 avatar_size = (gAgentAvatarp->mBodySize.mV[VZ]) + (F32)0.17; //mBodySize is actually quite a bit off. + gFloaterCustomize->getChild("HeightTextM")->setValue(llformat("%.2f", avatar_size) + "m"); + F32 feet = avatar_size / 0.3048; + F32 inches = (feet - (F32)((U32)feet)) * 12.0; + gFloaterCustomize->getChild("HeightTextI")->setValue(llformat("%d'%d\"", (U32)feet, (U32)inches)); + } } -// static -void LLScrollingPanelParam::onSliderMoved(LLUICtrl* ctrl, void* userdata) -{ - LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; - LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; - LLViewerVisualParam* param = self->mParam; - - if(!param) - return; - - LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)param->getWearableType(), 0 ); // TODO: MULTI-WEARABLE - - if(!wearable) - return; - - F32 current_weight = wearable->getVisualParamWeight(param->getID()); - F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); - if (current_weight != new_weight ) - { - updateAvatarHeightDisplay(); - wearable->setVisualParamWeight( param->getID(), new_weight, FALSE); - wearable->writeToAvatar(); - gAgentAvatarp->updateVisualParams(); - } -} - -// static -void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata) -{ -} - -// static -void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata) -{ - LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; - - LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); -} - -void LLScrollingPanelParam::onHintMouseDown( bool max ) -{ - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - // morph towards this result - F32 current_weight = gAgentAvatarp->getVisualParamWeight( hint->getVisualParam() ); - - // if we have maxed out on this morph, we shouldn't be able to click it - if( hint->getVisualParamWeight() != current_weight ) - { - mMouseDownTimer.reset(); - mLastHeldTime = 0.f; - } -} - -void LLScrollingPanelParam::onHintHeldDown( bool max ) -{ - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - LLViewerVisualParam* param = hint->getVisualParam(); - - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE - - if(!wearable) - return; - - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); - - if (current_weight != hint->getVisualParamWeight() ) - { - const F32 FULL_BLEND_TIME = 2.f; - F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime; - mLastHeldTime += elapsed_time; - - F32 new_weight; - if (current_weight > hint->getVisualParamWeight() ) - { - new_weight = current_weight - (elapsed_time / FULL_BLEND_TIME); - } - else - { - new_weight = current_weight + (elapsed_time / FULL_BLEND_TIME); - } - - // Make sure we're not taking the slider out of bounds - // (this is where some simple UI limits are stored) - F32 new_percent = weightToPercent(new_weight); - LLSliderCtrl* slider = getChild("param slider"); - if (slider) - { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); - wearable->writeToAvatar(); - gAgentAvatarp->updateVisualParams(); - - slider->setValue( weightToPercent( new_weight ) ); - } - } - } -} - -void LLScrollingPanelParam::onHintMouseUp( bool max ) -{ - F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32(); - - LLVOAvatar* avatar = gAgentAvatarp; - if (avatar) - { - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - - if (elapsed_time < PARAM_STEP_TIME_THRESHOLD) - { - LLViewerVisualParam* param = hint->getVisualParam(); - - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); - if(wearable) - { - // step in direction - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); - F32 range = mHintMax->getVisualParamWeight() - mHintMin->getVisualParamWeight(); - //if min, range should be negative. - if(!max) - range *= -1.f; - // step a fraction in the negative direction - F32 new_weight = current_weight + (range / 10.f); - F32 new_percent = weightToPercent(new_weight); - LLSliderCtrl* slider = getChild("param slider"); - if (slider) - { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); - wearable->writeToAvatar(); - slider->setValue( weightToPercent( new_weight ) ); - } - } - } - } - } - - LLVisualParamHint::requestHintUpdates( mHintMin, mHintMax ); -} - - -F32 LLScrollingPanelParam::weightToPercent( F32 weight ) -{ - LLViewerVisualParam* param = mParam; - return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; -} - -F32 LLScrollingPanelParam::percentToWeight( F32 percent ) -{ - LLViewerVisualParam* param = mParam; - return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); -} - -const std::string& LLFloaterCustomize::getEditGroup() -{ - return getCurrentWearablePanel()->getCurrentSubpart()->mEditGroup; -} - - ///////////////////////////////////////////////////////////////////// // LLFloaterCustomize @@ -1773,25 +405,19 @@ BOOL LLFloaterCustomize::postBuild() initWearablePanels(); // Tab container - const std::string &invalid_name = LLWearableType::getTypeName(LLWearableType::WT_INVALID); - for(U32 type=LLWearableType::WT_SHAPE;type("customize tab container"); + if(tab_container) { - std::string name = LLWearableType::getTypeName((LLWearableType::EType)type); - if(name != invalid_name) - { - name[0] = toupper(name[0]); - childSetTabChangeCallback("customize tab container", name, onTabChanged, (void*)type, onTabPrecommit ); - } + tab_container->setCommitCallback(boost::bind(&LLFloaterCustomize::onTabChanged, _2)); + tab_container->setValidateCallback(boost::bind(&LLFloaterCustomize::onTabPrecommit, this, _1, _2)); } // Remove underwear panels for teens if (gAgent.isTeen()) { - LLTabContainer* tab_container = getChild("customize tab container"); if (tab_container) { - LLPanel* panel; - panel = tab_container->getPanelByName("Undershirt"); + LLPanel* panel = tab_container->getPanelByName("Undershirt"); if (panel) tab_container->removeTabPanel(panel); panel = tab_container->getPanelByName("Underpants"); if (panel) tab_container->removeTabPanel(panel); @@ -1921,7 +547,7 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( old_wearable ) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE + item = gInventory.getItem(old_wearable->getItemID()); if(item) { const LLPermissions& perm = item->getPermissions(); @@ -1945,7 +571,7 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( old_wearable ) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE + item = gInventory.getItem(old_wearable->getItemID()); if(item) { const LLPermissions& perm = item->getPermissions(); @@ -2055,325 +681,6 @@ void* LLFloaterCustomize::createWearablePanel(void* userdata) void LLFloaterCustomize::initWearablePanels() { - ///////////////////////////////////////// - // Shape - LLPanelEditWearable* panel = mWearablePanelList[ LLWearableType::WT_SHAPE ]; - - // body - LLSubpart* part = new LLSubpart("mPelvis", "shape_body", LLVector3d(0.f,0.f,0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart( "Body", SUBPART_SHAPE_WHOLE, part ); - - // head supparts - const LLVector3d head_target(0.f, 0.f, 0.05f); - const LLVector3d head_camera(-0.5f, 0.05f, 0.07f); - - part = new LLSubpart("mHead", "shape_head", head_target, head_camera); - panel->addSubpart( "Head", SUBPART_SHAPE_HEAD, part ); - - part = new LLSubpart("mHead", "shape_eyes", head_target, head_camera); - panel->addSubpart( "Eyes", SUBPART_SHAPE_EYES, part ); - - part = new LLSubpart("mHead", "shape_ears", head_target, head_camera); - panel->addSubpart( "Ears", SUBPART_SHAPE_EARS, part ); - - part = new LLSubpart("mHead", "shape_nose", head_target, head_camera); - panel->addSubpart( "Nose", SUBPART_SHAPE_NOSE, part ); - - part = new LLSubpart("mHead", "shape_mouth", head_target, head_camera); - panel->addSubpart( "Mouth", SUBPART_SHAPE_MOUTH, part ); - - part = new LLSubpart("mHead", "shape_chin", head_target, head_camera); - panel->addSubpart( "Chin", SUBPART_SHAPE_CHIN, part ); - - // torso - part = new LLSubpart("mTorso", "shape_torso", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( "Torso", SUBPART_SHAPE_TORSO, part ); - - // legs - part = new LLSubpart("mPelvis", "shape_legs", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( "Legs", SUBPART_SHAPE_LEGS, part ); - - panel->childSetCommitCallback("sex radio", LLPanelEditWearable::onCommitSexChange, panel); - - ///////////////////////////////////////// - // Skin - panel = mWearablePanelList[ LLWearableType::WT_SKIN ]; - - part = new LLSubpart("mHead", "skin_color", head_target, head_camera); - panel->addSubpart( "Skin Color", SUBPART_SKIN_COLOR, part ); - - part = new LLSubpart("mHead", "skin_facedetail", head_target, head_camera); - panel->addSubpart( "Face Detail", SUBPART_SKIN_FACEDETAIL, part ); - - part = new LLSubpart("mHead", "skin_makeup", head_target, head_camera); - panel->addSubpart( "Makeup", SUBPART_SKIN_MAKEUP, part ); - - part = new LLSubpart("mPelvis", "skin_bodydetail", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f)); - panel->addSubpart( "Body Detail", SUBPART_SKIN_BODYDETAIL, part ); - - panel->addTextureDropTarget( TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE ); - panel->addTextureDropTarget( TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE ); - panel->addTextureDropTarget( TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE ); - - ///////////////////////////////////////// - // Hair - panel = mWearablePanelList[ LLWearableType::WT_HAIR ]; - - part = new LLSubpart("mHead", "hair_color", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f)); - panel->addSubpart( "Color", SUBPART_HAIR_COLOR, part ); - - part = new LLSubpart("mHead", "hair_style", head_target, head_camera); - panel->addSubpart( "Style", SUBPART_HAIR_STYLE, part ); - - part = new LLSubpart("mHead", "hair_eyebrows", head_target, head_camera); - panel->addSubpart( "Eyebrows", SUBPART_HAIR_EYEBROWS, part ); - - part = new LLSubpart("mHead", "hair_facial", head_target, head_camera, SEX_MALE); - panel->addSubpart( "Facial", SUBPART_HAIR_FACIAL, part ); - - panel->addTextureDropTarget(TEX_HAIR, "Texture", - LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), - FALSE ); - - ///////////////////////////////////////// - // Eyes - panel = mWearablePanelList[ LLWearableType::WT_EYES ]; - - part = new LLSubpart("mHead", "eyes", head_target, head_camera); - panel->addSubpart( LLStringUtil::null, SUBPART_EYES, part ); - - panel->addTextureDropTarget(TEX_EYES_IRIS, "Iris", - LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), - FALSE ); - - ///////////////////////////////////////// - // Shirt - panel = mWearablePanelList[ LLWearableType::WT_SHIRT ]; - - part = new LLSubpart("mTorso", "shirt", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SHIRT, part ); - - panel->addTextureDropTarget( TEX_UPPER_SHIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_SHIRT, "Color/Tint" ); - - - ///////////////////////////////////////// - // Pants - panel = mWearablePanelList[ LLWearableType::WT_PANTS ]; - - part = new LLSubpart("mPelvis", "pants", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_PANTS, part ); - - panel->addTextureDropTarget(TEX_LOWER_PANTS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_PANTS, "Color/Tint" ); - - - ///////////////////////////////////////// - // Shoes - panel = mWearablePanelList[ LLWearableType::WT_SHOES ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "shoes", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SHOES, part ); - - panel->addTextureDropTarget( TEX_LOWER_SHOES, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_SHOES, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Socks - panel = mWearablePanelList[ LLWearableType::WT_SOCKS ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "socks", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SOCKS, part ); - - panel->addTextureDropTarget( TEX_LOWER_SOCKS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_SOCKS, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Jacket - panel = mWearablePanelList[ LLWearableType::WT_JACKET ]; - - if (panel) - { - part = new LLSubpart("mTorso", "jacket", LLVector3d(), LLVector3d(-2.f, 0.1f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_JACKET, part ); - - panel->addTextureDropTarget( TEX_UPPER_JACKET, "Upper Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), - FALSE ); - panel->addTextureDropTarget( TEX_LOWER_JACKET, "Lower Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_JACKET, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Skirt - panel = mWearablePanelList[ LLWearableType::WT_SKIRT ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "skirt", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SKIRT, part ); - - panel->addTextureDropTarget( TEX_SKIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_SKIRT, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Gloves - panel = mWearablePanelList[ LLWearableType::WT_GLOVES ]; - - if (panel) - { - part = new LLSubpart("mTorso", "gloves", LLVector3d(), LLVector3d(-1.f, 0.15f, 0.f)); - panel->addSubpart( LLStringUtil::null, SUBPART_GLOVES, part ); - - panel->addTextureDropTarget( TEX_UPPER_GLOVES, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_GLOVES, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Undershirt - panel = mWearablePanelList[ LLWearableType::WT_UNDERSHIRT ]; - - if (panel) - { - part = new LLSubpart("mTorso", "undershirt", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_UNDERSHIRT, part ); - - panel->addTextureDropTarget( TEX_UPPER_UNDERSHIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_UNDERSHIRT, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Underpants - panel = mWearablePanelList[ LLWearableType::WT_UNDERPANTS ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "underpants", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_UNDERPANTS, part ); - - panel->addTextureDropTarget( TEX_LOWER_UNDERPANTS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_UNDERPANTS, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Alpha - panel = mWearablePanelList[LLWearableType::WT_ALPHA]; - - if (panel) - { - part = new LLSubpart("mPelvis", "alpha", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart(LLStringUtil::null, SUBPART_ALPHA, part); - - panel->addTextureDropTarget(TEX_LOWER_ALPHA, "Lower Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_UPPER_ALPHA, "Upper Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_HEAD_ALPHA, "Head Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_EYES_ALPHA, "Eye Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_HAIR_ALPHA, "Hair Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - - panel->addInvisibilityCheckbox(TEX_LOWER_ALPHA, "lower alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_UPPER_ALPHA, "upper alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_HEAD_ALPHA, "head alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_EYES_ALPHA, "eye alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_HAIR_ALPHA, "hair alpha texture invisible"); - } - - ///////////////////////////////////////// - // Tattoo - panel = mWearablePanelList[LLWearableType::WT_TATTOO]; - - if (panel) - { - part = new LLSubpart("mPelvis", "tattoo", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart(LLStringUtil::null, SUBPART_TATTOO, part); - - panel->addTextureDropTarget(TEX_LOWER_TATTOO, "Lower Tattoo", - LLUUID::null, - TRUE); - panel->addTextureDropTarget(TEX_UPPER_TATTOO, "Upper Tattoo", - LLUUID::null, - TRUE); - panel->addTextureDropTarget(TEX_HEAD_TATTOO, "Head Tattoo", - LLUUID::null, - TRUE); - panel->addColorSwatch(TEX_LOWER_TATTOO, "Color/Tint"); //-ASC-TTRFE - } - - ///////////////////////////////////////// - // Physics - - panel = mWearablePanelList[LLWearableType::WT_PHYSICS]; - - if(panel) - { - part = new LLSubpart("mTorso", "physics_breasts_updown", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Bounce", SUBPART_PHYSICS_BREASTS_UPDOWN, part); - - part = new LLSubpart("mTorso", "physics_breasts_inout", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Cleavage", SUBPART_PHYSICS_BREASTS_INOUT, part); - - part = new LLSubpart("mTorso", "physics_breasts_leftright", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Sway", SUBPART_PHYSICS_BREASTS_LEFTRIGHT, part); - - part = new LLSubpart("mTorso", "physics_belly_updown", LLVector3d(0.f, 0.f, -.05f), LLVector3d(-0.8f, 0.15f, 0.38f), false); - panel->addSubpart("Belly Bounce", SUBPART_PHYSICS_BELLY_UPDOWN, part); - - part = new LLSubpart("mPelvis", "physics_butt_updown", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f), false); - panel->addSubpart("Butt Bounce", SUBPART_PHYSICS_BUTT_UPDOWN, part); - - part = new LLSubpart("mPelvis", "physics_butt_leftright", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f), false); - panel->addSubpart("Butt Sway", SUBPART_PHYSICS_BUTT_LEFTRIGHT, part); - - part = new LLSubpart("mTorso", "physics_advanced", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), false); - panel->addSubpart("Advanced Parameters", SUBPART_PHYSICS_ADVANCED, part); - - } } //////////////////////////////////////////////////////////////////////////// @@ -2388,7 +695,7 @@ LLFloaterCustomize::~LLFloaterCustomize() void LLFloaterCustomize::switchToDefaultSubpart() { - getCurrentWearablePanel()->switchToDefaultSubpart(); + getCurrentWearablePanel()->showDefaultSubpart(); } void LLFloaterCustomize::draw() @@ -2415,39 +722,51 @@ void LLFloaterCustomize::draw() BOOL LLFloaterCustomize::isDirty() const { - for(S32 i = 0; i < LLWearableType::WT_COUNT; i++) + LLWearableType::EType cur = getCurrentWearableType(); + for(U32 i = 0; i < gAgentWearables.getWearableCount(cur); ++i) { - if( mWearablePanelList[i] - && mWearablePanelList[i]->isDirty() ) - { + LLWearable* wearable = gAgentWearables.getWearable(cur,i); + if(wearable && wearable->isDirty()) return TRUE; - } } return FALSE; } -// static -void LLFloaterCustomize::onTabPrecommit( void* userdata, bool from_click ) +bool LLFloaterCustomize::onTabPrecommit( LLUICtrl* ctrl, const LLSD& param ) { - LLWearableType::EType type = (LLWearableType::EType)(intptr_t) userdata; - if (type != LLWearableType::WT_INVALID && gFloaterCustomize && gFloaterCustomize->getCurrentWearableType() != type) + std::string panel_name = param.asString(); + for(U32 type=LLWearableType::WT_SHAPE;typeaskToSaveIfDirty(boost::bind(&onCommitChangeTab, _1)); - } - else - { - onCommitChangeTab(true); + std::string type_name = LLWearableType::getTypeName((LLWearableType::EType)type); + std::transform(panel_name.begin(), panel_name.end(), panel_name.begin(), tolower); + + if(type_name == panel_name) + { + if(LLFloaterCustomize::sCurrentWearableType != type) + { + askToSaveIfDirty(boost::bind(&LLFloaterCustomize::onCommitChangeTab, _1, (LLTabContainer*)ctrl, param.asString(), (LLWearableType::EType)type)); + return false; + } + } } + return true; } // static -void LLFloaterCustomize::onTabChanged( void* userdata, bool from_click ) +void LLFloaterCustomize::onTabChanged( const LLSD& param ) { - LLWearableType::EType wearable_type = (LLWearableType::EType) (intptr_t)userdata; - if (wearable_type != LLWearableType::WT_INVALID) + std::string panel_name = param.asString(); + for(U32 type=LLWearableType::WT_SHAPE;typegetChild("customize tab container"); - if (tab_container) - { - tab_container->setTab(-1); - } + LLFloaterCustomize::setCurrentWearableType(type); + ctrl->selectTabByName(panel_name); } @@ -2499,31 +815,7 @@ void LLFloaterCustomize::initScrollingPanelList() } } -void LLFloaterCustomize::clearScrollingPanelList() -{ - if( mScrollingPanelList ) - { - mScrollingPanelList->clearPanels(); - } -} - -void LLFloaterCustomize::generateVisualParamHints(LLViewerJointMesh* joint_mesh, LLFloaterCustomize::param_map& params, bool bVisualHint) -{ - // sorted_params is sorted according to magnitude of effect from - // least to greatest. Adding to the front of the child list - // reverses that order. - if( mScrollingPanelList ) - { - mScrollingPanelList->clearPanels(); - param_map::iterator end = params.end(); - for(param_map::iterator it = params.begin(); it != end; ++it) - { - mScrollingPanelList->addPanel( new LLScrollingPanelParam( "LLScrollingPanelParam", joint_mesh, (*it).second.second, (*it).second.first, bVisualHint) ); - } - } -} - -void LLFloaterCustomize::setWearable(LLWearableType::EType type, LLWearable* wearable, U32 perm_mask, BOOL is_complete) +void LLFloaterCustomize::wearablesChanged(LLWearableType::EType type) { llassert( type < LLWearableType::WT_COUNT ); gSavedSettings.setU32("AvatarSex", (gAgentAvatarp->getSex() == SEX_MALE) ); @@ -2531,24 +823,18 @@ void LLFloaterCustomize::setWearable(LLWearableType::EType type, LLWearable* wea LLPanelEditWearable* panel = mWearablePanelList[ type ]; if( panel ) { - panel->setWearable(wearable, perm_mask, is_complete); - updateScrollingPanelList((perm_mask & PERM_MODIFY) ? is_complete : FALSE); + panel->wearablesChanged(); } } -void LLFloaterCustomize::updateScrollingPanelList(BOOL allow_modify) +void LLFloaterCustomize::updateScrollingPanelList() { - if( mScrollingPanelList ) - { - LLScrollingPanelParam::sUpdateDelayFrames = 0; - mScrollingPanelList->updatePanels(allow_modify ); - } + getCurrentWearablePanel()->updateScrollingPanelList(); } - void LLFloaterCustomize::askToSaveIfDirty( boost::function cb ) { - if( isDirty()) + if(isDirty()) { // Ask if user wants to save, then continue to next step afterwards mNextStepAfterSaveCallback.connect(cb); @@ -2559,7 +845,7 @@ void LLFloaterCustomize::askToSaveIfDirty( boost::function cb ) } else { - cb(TRUE); //just clal it immediately. + cb(TRUE); //just call it immediately. } } @@ -2571,28 +857,36 @@ bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& resp BOOL proceed = FALSE; LLWearableType::EType cur = getCurrentWearableType(); - switch( option ) + for(U32 i = 0;i < gAgentWearables.getWearableCount(cur);++i) { - case 0: // "Save" - gAgentWearables.saveWearable( cur, 0 ); // TODO: MULTI-WEARABLE - proceed = TRUE; - break; - - case 1: // "Don't Save" + LLWearable* wearable = gAgentWearables.getWearable(cur,i); + if(wearable && wearable->isDirty()) { - gAgentWearables.revertWearable( cur, 0 ); // TODO: MULTI-WEARABLE - proceed = TRUE; + switch( option ) + { + case 0: // "Save" + gAgentWearables.saveWearable( cur, i ); + proceed = TRUE; + break; + + case 1: // "Don't Save" + { + gAgentWearables.revertWearable( cur, i ); + proceed = TRUE; + } + break; + + case 2: // "Cancel" + break; + + default: + llassert(0); + break; + } } - break; - - case 2: // "Cancel" - break; - - default: - llassert(0); - break; } + mNextStepAfterSaveCallback(proceed); mNextStepAfterSaveCallback.disconnect_all_slots(); //Should this be done? @@ -2615,10 +909,13 @@ void LLFloaterCustomize::fetchInventory() LLUUID item_id; for(S32 type = (S32)LLWearableType::WT_SHAPE; type < (S32)LLWearableType::WT_COUNT; ++type) { - item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type, 0); // TODO: MULTI-WEARABLE - if(item_id.notNull()) + for(U32 i = 0; i < gAgentWearables.getWearableCount((LLWearableType::EType)type); ++i) { - ids.push_back(item_id); + item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type, i); + if(item_id.notNull()) + { + ids.push_back(item_id); + } } } @@ -2641,7 +938,9 @@ void LLFloaterCustomize::updateInventoryUI() panel = mWearablePanelList[i]; if(panel) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType(), 0); // TODO: MULTI-WEARABLE + LLWearable* wearable = panel->getWearable(); + if(wearable) + item = gInventory.getItem(wearable->getItemID()); } if(item) { @@ -2663,26 +962,11 @@ void LLFloaterCustomize::updateInventoryUI() { panel->setUIPermissions(perm_mask, is_complete); } - BOOL is_vis = panel && item && is_complete && (perm_mask & PERM_MODIFY); - childSetVisible("panel_container", is_vis); + //BOOL is_vis = panel && item && is_complete && (perm_mask & PERM_MODIFY); + //childSetVisible("panel_container", is_vis); } } childSetEnabled("Make Outfit", all_complete); } -void LLFloaterCustomize::updateScrollingPanelUI() -{ - LLPanelEditWearable* panel = mWearablePanelList[sCurrentWearableType]; - if(panel) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType(), 0); // TODO: MULTI-WEARABLE - if(item) - { - U32 perm_mask = item->getPermissions().getMaskOwner(); - BOOL is_complete = item->isComplete(); - updateScrollingPanelList((perm_mask & PERM_MODIFY) ? is_complete : FALSE); - } - } -} - diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index c19a570ad..e603209fe 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -55,7 +55,7 @@ class LLMakeOutfitDialog; class LLRadioGroup; class LLScrollableContainerView; class LLScrollingPanelList; -class LLTabContainerVertical; +class LLTabContainer; class LLTextBox; class LLTextureCtrl; class LLViewerJointMesh; @@ -71,10 +71,6 @@ class AIFilePicker; class LLFloaterCustomize : public LLFloater { -public: - typedef std::pair editable_param; - typedef std::map param_map; - public: LLFloaterCustomize(); virtual ~LLFloaterCustomize(); @@ -87,14 +83,9 @@ public: // New methods - void clearScrollingPanelList(); - void generateVisualParamHints(LLViewerJointMesh* joint_mesh, - param_map& params, bool bVisualHint); - const std::string& getEditGroup(); - void updateScrollingPanelList(BOOL allow_modify); - - void setWearable(LLWearableType::EType type, LLWearable* wearable, U32 perm_mask, BOOL is_complete); + void wearablesChanged(LLWearableType::EType type); + void updateScrollingPanelList(); LLPanelEditWearable* getCurrentWearablePanel() { return mWearablePanelList[ sCurrentWearableType ]; } virtual BOOL isDirty() const; @@ -115,15 +106,15 @@ public: static void onBtnExport( void* userdata ); static void onBtnExport_continued(AIFilePicker* filepicker); - static void onTabChanged( void* userdata, bool from_click ); - static void onTabPrecommit( void* userdata, bool from_click ); + static void onTabChanged( const LLSD& param ); + bool onTabPrecommit( LLUICtrl* ctrl, const LLSD& param ); bool onSaveDialog(const LLSD& notification, const LLSD& response); - static void onCommitChangeTab(BOOL proceed); + static void onCommitChangeTab(BOOL proceed, LLTabContainer* ctrl, std::string panel_name, LLWearableType::EType type); void fetchInventory(); void updateInventoryUI(); - void updateScrollingPanelUI(); + LLScrollingPanelList* getScrollingPanelList() const { return mScrollingPanelList; } protected: LLPanelEditWearable* mWearablePanelList[ LLWearableType::WT_COUNT ]; diff --git a/indra/newview/llfloaterdirectory.cpp b/indra/newview/llfloaterdirectory.cpp index 7546370cc..128d7a379 100644 --- a/indra/newview/llfloaterdirectory.cpp +++ b/indra/newview/llfloaterdirectory.cpp @@ -144,23 +144,7 @@ LLFloaterDirectory::LLFloaterDirectory(const std::string& name) mPanelAvatarp->selectTab(0); } - childSetTabChangeCallback("Directory Tabs", "classified_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "events_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "places_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "land_sales_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "people_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "groups_panel", onTabChanged, this); - if (enableWebSearch) - { - // web search and showcase for SecondLife - childSetTabChangeCallback("Directory Tabs", "find_all_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "showcase_panel", onTabChanged, this); - } - - if(enableClassicAllSearch) - { - childSetTabChangeCallback("Directory Tabs", "find_all_old_panel", onTabChanged, this); - } + getChild("Directory Tabs")->setCommitCallback(boost::bind(&LLFloaterDirectory::onTabChanged,_2)); } LLFloaterDirectory::~LLFloaterDirectory() @@ -508,16 +492,9 @@ void LLFloaterDirectory::onClose(bool app_quitting) } // static -void LLFloaterDirectory::onTabChanged(void* data, bool from_click) +void LLFloaterDirectory::onTabChanged( const LLSD& param ) { - LLFloaterDirectory* self = (LLFloaterDirectory*)data; - if (!self) return; - - LLPanel *panel = self->childGetVisibleTab("Directory Tabs"); - if (panel) - { - gSavedSettings.setString("LastFindPanel", panel->getName()); - } + gSavedSettings.setString("LastFindPanel", param.asString()); } void LLFloaterDirectory::hideAllDetailPanels() diff --git a/indra/newview/llfloaterdirectory.h b/indra/newview/llfloaterdirectory.h index e43968624..0f57b0ff7 100644 --- a/indra/newview/llfloaterdirectory.h +++ b/indra/newview/llfloaterdirectory.h @@ -81,7 +81,7 @@ public: static void toggleEvents(void*); static void toggleFind(void*); - static void onTabChanged(void*, bool); + static void onTabChanged( const LLSD& param ); void hideAllDetailPanels(); diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index 9a629d7d4..37bcb873b 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -130,10 +130,7 @@ LLFloaterGodTools::LLFloaterGodTools() factory_map["request"] = LLCallbackMap(createPanelRequest, this); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_god_tools.xml", &factory_map); - childSetTabChangeCallback("GodTools Tabs", "grid", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "region", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "objects", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "request", onTabChanged, this); + getChild("GodTools Tabs")->setCommitCallback(boost::bind(&LLFloaterGodTools::onTabChanged,_1,_2)); sendRegionInfoRequest(); @@ -244,15 +241,12 @@ void LLFloaterGodTools::showPanel(const std::string& panel_name) if (panel) panel->setFocus(TRUE); } - -// static -void LLFloaterGodTools::onTabChanged(void* data, bool from_click) +//static +void LLFloaterGodTools::onTabChanged(LLUICtrl* ctrl, const LLSD& param) { - LLPanel* panel = (LLPanel*)data; - if (panel) - { + LLPanel* panel = (LLPanel*)ctrl->getChildView(param.asString(),false,false); + if(panel) panel->setFocus(TRUE); - } } diff --git a/indra/newview/llfloatergodtools.h b/indra/newview/llfloatergodtools.h index 75813ca88..3c36f256f 100644 --- a/indra/newview/llfloatergodtools.h +++ b/indra/newview/llfloatergodtools.h @@ -101,7 +101,7 @@ public: // Send possibly changed values to simulator. void sendGodUpdateRegionInfo(); - static void onTabChanged(void *data, bool from_click); + static void onTabChanged(LLUICtrl* ctrl, const LLSD& param); protected: U32 computeRegionFlags() const; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 6e102d58c..d5e9702d7 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -144,39 +144,39 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def mPrefsAscentVan(NULL) { mGeneralPanel = new LLPanelGeneral(); - mTabContainer->addTabPanel(mGeneralPanel, mGeneralPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mGeneralPanel, mGeneralPanel->getLabel()); mGeneralPanel->setDefaultBtn(default_btn); mInputPanel = new LLPanelInput(); - mTabContainer->addTabPanel(mInputPanel, mInputPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mInputPanel, mInputPanel->getLabel()); mInputPanel->setDefaultBtn(default_btn); mNetworkPanel = new LLPanelNetwork(); - mTabContainer->addTabPanel(mNetworkPanel, mNetworkPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mNetworkPanel, mNetworkPanel->getLabel()); mNetworkPanel->setDefaultBtn(default_btn); mWebPanel = new LLPanelWeb(); - mTabContainer->addTabPanel(mWebPanel, mWebPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mWebPanel, mWebPanel->getLabel()); mWebPanel->setDefaultBtn(default_btn); mDisplayPanel = new LLPanelDisplay(); - mTabContainer->addTabPanel(mDisplayPanel, mDisplayPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mDisplayPanel, mDisplayPanel->getLabel()); mDisplayPanel->setDefaultBtn(default_btn); mAudioPanel = new LLPanelAudioPrefs(); - mTabContainer->addTabPanel(mAudioPanel, mAudioPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mAudioPanel, mAudioPanel->getLabel()); mAudioPanel->setDefaultBtn(default_btn); mPrefsChat = new LLPrefsChat(); - mTabContainer->addTabPanel(mPrefsChat->getPanel(), mPrefsChat->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsChat->getPanel(), mPrefsChat->getPanel()->getLabel()); mPrefsChat->getPanel()->setDefaultBtn(default_btn); mPrefsVoice = new LLPrefsVoice(); - mTabContainer->addTabPanel(mPrefsVoice, mPrefsVoice->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsVoice, mPrefsVoice->getLabel()); mPrefsVoice->setDefaultBtn(default_btn); mPrefsIM = new LLPrefsIM(); - mTabContainer->addTabPanel(mPrefsIM->getPanel(), mPrefsIM->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsIM->getPanel(), mPrefsIM->getPanel()->getLabel()); mPrefsIM->getPanel()->setDefaultBtn(default_btn); #if LL_LCD_COMPILE @@ -185,7 +185,7 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def if (gLcdScreen->Enabled()) { mLCDPanel = new LLPanelLCD(); - mTabContainer->addTabPanel(mLCDPanel, mLCDPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mLCDPanel, mLCDPanel->getLabel()); mLCDPanel->setDefaultBtn(default_btn); } @@ -194,29 +194,31 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def #endif mMsgPanel = new LLPanelMsgs(); - mTabContainer->addTabPanel(mMsgPanel, mMsgPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mMsgPanel, mMsgPanel->getLabel()); mMsgPanel->setDefaultBtn(default_btn); mSkinsPanel = new LLPanelSkins(); - mTabContainer->addTabPanel(mSkinsPanel, mSkinsPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mSkinsPanel, mSkinsPanel->getLabel()); mSkinsPanel->setDefaultBtn(default_btn); mGridsPanel = HippoPanelGrids::create(); - mTabContainer->addTabPanel(mGridsPanel, mGridsPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mGridsPanel, mGridsPanel->getLabel()); mGridsPanel->setDefaultBtn(default_btn); mPrefsAscentChat = new LLPrefsAscentChat(); - mTabContainer->addTabPanel(mPrefsAscentChat, mPrefsAscentChat->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsAscentChat, mPrefsAscentChat->getLabel()); mPrefsAscentChat->setDefaultBtn(default_btn); mPrefsAscentSys = new LLPrefsAscentSys(); - mTabContainer->addTabPanel(mPrefsAscentSys, mPrefsAscentSys->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsAscentSys, mPrefsAscentSys->getLabel()); mPrefsAscentSys->setDefaultBtn(default_btn); mPrefsAscentVan = new LLPrefsAscentVan(); - mTabContainer->addTabPanel(mPrefsAscentVan, mPrefsAscentVan->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsAscentVan, mPrefsAscentVan->getLabel()); mPrefsAscentVan->setDefaultBtn(default_btn); + mTabContainer->setCommitCallback(boost::bind(LLPreferenceCore::onTabChanged,_1)); + if (!mTabContainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) { mTabContainer->selectFirstTab(); @@ -363,9 +365,9 @@ void LLPreferenceCore::cancel() } // static -void LLPreferenceCore::onTabChanged(void* user_data, bool from_click) +void LLPreferenceCore::onTabChanged(LLUICtrl* ctrl) { - LLTabContainer* self = (LLTabContainer*)user_data; + LLTabContainer* self = (LLTabContainer*)ctrl; gSavedSettings.setS32("LastPrefTab", self->getCurrentPanelIndex()); } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index a662a08c7..747a3ffb5 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -78,7 +78,7 @@ public: void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); - static void onTabChanged(void* user_data, bool from_click); + static void onTabChanged(LLUICtrl* ctrl); // refresh all the graphics preferences menus void refreshEnabledGraphics(); diff --git a/indra/newview/llfloatertest.cpp b/indra/newview/llfloatertest.cpp index e9aada3f6..83a0c6fed 100644 --- a/indra/newview/llfloatertest.cpp +++ b/indra/newview/llfloatertest.cpp @@ -160,6 +160,8 @@ LLFloaterTestImpl::LLFloaterTestImpl() addChild(tab); mTab = tab; + tab->setCommitCallback(boost::bind(&LLFloaterTestImpl::onClickTab,_1,_2)); + //----------------------------------------------------------------------- // First tab container panel //----------------------------------------------------------------------- @@ -167,8 +169,7 @@ LLFloaterTestImpl::LLFloaterTestImpl() LLRect(0, 400, 400, 0), // dummy rect TRUE); // bordered tab->addTabPanel(panel, std::string("First"), - TRUE, // select - onClickTab, this); + TRUE); // select y = panel->getRect().getHeight() - VPAD; @@ -284,8 +285,7 @@ LLFloaterTestImpl::LLFloaterTestImpl() LLRect(0, 400, 400, 0), // dummy rect TRUE); // bordered tab->addTabPanel(panel, std::string("Second"), - FALSE, // select - onClickTab, this); + FALSE); // select y = panel->getRect().getHeight() - VPAD; diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 6f638b695..f7ba56bf8 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -957,7 +957,7 @@ void LLFolderView::draw() else if (mShowEmptyMessage) { static LLCachedControl sSearchStatusColor(gColors, "InventorySearchStatusColor", LLColor4::white ); - if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) { mStatusText = std::string("Searching..."); // *TODO:translate } @@ -2003,7 +2003,7 @@ void LLFolderView::scrollToShowSelection() // However we allow scrolling for folder views with mAutoSelectOverride // (used in Places SP) as an exception because the selection in them // is not reset during items filtering. See STORM-133. - if ( (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mAutoSelectOverride) + if ( (!LLInventoryModelBackgroundFetch::instance().folderFetchActive() || mAutoSelectOverride) && mSelectedItems.size() ) { mNeedsScroll = TRUE; diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index ae48372e3..3c59b36fe 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -1049,7 +1049,7 @@ void LLFolderViewItem::draw() } if ((mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime")) - || (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() + || (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && root_is_loading && mShowLoadStatus)) { diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 5991cba8e..c89c414b5 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1178,7 +1178,7 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) group_datap->mChanged = TRUE; #if SHY_MOD //Group title script access - gGroupRoleChanger.CheckUpdateRole(group_id,group_data->mRoles); + gGroupRoleChanger.CheckUpdateRole(group_id,group_datap->mRoles); #endif //shy_mod LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_DATA); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c2a870ce1..8fcbb600e 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -200,6 +200,42 @@ bool isMarketplaceSendAction(const std::string& action) return ("send_to_marketplace" == action); } +// Used by LLFolderBridge as callback for directory fetching recursion +class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver +{ +public: + LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids) : LLInventoryFetchDescendentsObserver(ids) {} + ~LLRightClickInventoryFetchDescendentsObserver() {} + virtual void execute(bool clear_observer = false); + virtual void done() + { + execute(true); + } +}; + +// Used by LLFolderBridge as callback for directory content items fetching +class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver +{ +public: + LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : LLInventoryFetchItemsObserver(ids) { }; + ~LLRightClickInventoryFetchObserver() {} + void execute(bool clear_observer = false) + { + if (clear_observer) + { + dec_busy_count(); + gInventory.removeObserver(this); + delete this; + } + // we've downloaded all the items, so repaint the dialog + LLFolderBridge::staticFolderOptionsMenu(); + } + virtual void done() + { + execute(true); + } +}; + // void gotImageForSaveItemAs(BOOL success, LLViewerTexture *src_vi, @@ -1050,7 +1086,7 @@ void LLInvFVBridge::changeItemParent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - change_item_parent(model, item, new_parent_id, restamp); + model->changeItemParent(item, new_parent_id, restamp); } // static @@ -1059,7 +1095,7 @@ void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - change_category_parent(model, cat, new_parent_id, restamp); + model->changeCategoryParent(cat, new_parent_id, restamp); } LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, @@ -1464,7 +1500,8 @@ void LLItemBridge::selectItem() // if(!(gInventory.isObjectDescendentOf(mUUID, gSystemFolderRoot))) // - item->fetchFromServer(); + //item->fetchFromServer(); + LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false); } } @@ -2498,9 +2535,16 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, LLInventoryObject::object_list_t::iterator end = inventory_objects.end(); for ( ; it != end; ++it) { + LLInventoryItem* item = dynamic_cast(it->get()); + if (!item) + { + llwarns << "Invalid inventory item for drop" << llendl; + continue; + } + // coming from a task. Need to figure out if the person can // move/copy this item. - LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions()); + LLPermissions perm(item->getPermissions()); if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) && perm.allowTransferTo(gAgent.getID()))) // || gAgent.isGodlike()) @@ -2553,121 +2597,114 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, return accept; } -//Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver +void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) { -public: - LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : - LLInventoryFetchItemsObserver(ids), - mCopyItems(false) - { }; - LLRightClickInventoryFetchObserver(const uuid_vec_t& ids, - const LLUUID& cat_id, - bool copy_items) : - LLInventoryFetchItemsObserver(ids), - mCatID(cat_id), - mCopyItems(copy_items) - { }; - virtual void done() - { - // we've downloaded all the items, so repaint the dialog - LLFolderBridge::staticFolderOptionsMenu(); - - gInventory.removeObserver(this); - delete this; - } - -protected: - LLUUID mCatID; - bool mCopyItems; - -}; - -//Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver -{ -public: - LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids, - bool copy_items) : - LLInventoryFetchDescendentsObserver(ids), - mCopyItems(copy_items) - {} - ~LLRightClickInventoryFetchDescendentsObserver() {} - virtual void done(); -protected: - bool mCopyItems; -}; - -void LLRightClickInventoryFetchDescendentsObserver::done() -{ - // Avoid passing a NULL-ref as mCompleteFolders.front() down to - // gInventory.collectDescendents() + // Bail out immediately if no descendents if( mComplete.empty() ) { llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl; + if (clear_observer) + { dec_busy_count(); gInventory.removeObserver(this); delete this; + } return; } - // What we do here is get the complete information on the items in - // the library, and set up an observer that will wait for that to - // happen. - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mComplete.front(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - S32 count = item_array.count(); -#if 0 // HACK/TODO: Why? - // This early causes a giant menu to get produced, and doesn't seem to be needed. - if(!count) + // Copy the list of complete fetched folders while "this" is still valid + uuid_vec_t completed_folder = mComplete; + + // Clean up, and remove this as an observer now since recursive calls + // could notify observers and throw us into an infinite loop. + if (clear_observer) { - llwarns << "Nothing fetched in category " << mComplete.front() - << llendl; dec_busy_count(); gInventory.removeObserver(this); delete this; - return; } -#endif - uuid_vec_t ids; - for(S32 i = 0; i < count; ++i) + for (uuid_vec_t::iterator current_folder = completed_folder.begin(); current_folder != completed_folder.end(); ++current_folder) { - ids.push_back(item_array.get(i)->getUUID()); + // Get the information on the fetched folder items and subfolders and fetch those + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(*current_folder, cat_array, item_array); + + S32 item_count = item_array->count(); + S32 cat_count = cat_array->count(); + + // Move to next if current folder empty + if ((item_count == 0) && (cat_count == 0)) + { + continue; } - LLRightClickInventoryFetchObserver* outfit = new LLRightClickInventoryFetchObserver(ids, mComplete.front(), mCopyItems); + uuid_vec_t ids; + LLRightClickInventoryFetchObserver* outfit = NULL; + LLRightClickInventoryFetchDescendentsObserver* categories = NULL; - // clean up, and remove this as an observer since the call to the - // outfit could notify observers and throw us into an infinite - // loop. - dec_busy_count(); - gInventory.removeObserver(this); - delete this; + // Fetch the items + if (item_count) + { + for (S32 i = 0; i < item_count; ++i) + { + ids.push_back(item_array->get(i)->getUUID()); + } + outfit = new LLRightClickInventoryFetchObserver(ids); + } + // Fetch the subfolders + if (cat_count) + { + for (S32 i = 0; i < cat_count; ++i) + { + ids.push_back(cat_array->get(i)->getUUID()); + } + categories = new LLRightClickInventoryFetchDescendentsObserver(ids); + } - // increment busy count and either tell the inventory to check & - // call done, or add this object to the inventory for observation. - inc_busy_count(); - - // do the fetch + // Perform the item fetch + if (outfit) + { outfit->startFetch(); - outfit->done(); //Not interested in waiting and this will be right 99% of the time. + outfit->execute(); // Not interested in waiting and this will be right 99% of the time. + delete outfit; //Uncomment the following code for laggy Inventory UI. -/* if(outfit->isEverythingComplete()) + /* + if (outfit->isFinished()) { - // everything is already here - call done. - outfit->done(); + // everything is already here - call done. + outfit->execute(); + delete outfit; } else { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(outfit); - }*/ + // it's all on its way - add an observer, and the inventory + // will call done for us when everything is here. + inc_busy_count(); + gInventory.addObserver(outfit); + } + */ + } + // Perform the subfolders fetch : this is where we truly recurse down the folder hierarchy + if (categories) + { + categories->startFetch(); + if (categories->isFinished()) + { + // everything is already here - call done. + categories->execute(); + delete categories; + } + else + { + // it's all on its way - add an observer, and the inventory + // will call done for us when everything is here. + inc_busy_count(); + gInventory.addObserver(categories); + } + } + } } @@ -2980,7 +3017,7 @@ bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& re { // move it to the trash LLPreview::hide(mUUID); - remove_category(getInventoryModel(), mUUID); + getInventoryModel()->removeCategory(mUUID); return TRUE; } return FALSE; @@ -3336,16 +3373,19 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) folders.push_back(category->getUUID()); sSelf = getHandle(); - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders, FALSE); + LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders); fetch->startFetch(); - inc_busy_count(); if (fetch->isFinished()) { + // Do not call execute() or done() here as if the folder is here, there's likely no point drilling down + // This saves lots of time as buildContextMenu() is called a lot + delete fetch; buildContextMenuFolderOptions(flags); } else { // it's all on its way - add an observer, and the inventory will call done for us when everything is here. + inc_busy_count(); gInventory.addObserver(fetch); } } @@ -5543,6 +5583,35 @@ LLUIImagePtr LLWearableBridge::getIcon() const return LLInventoryIcon::getIcon(mAssetType, mInvType, mWearableType, FALSE); } +//LLAppearanceMgr::moveWearable unfortunately fails for non-link items, so links in CoF must be found for this to work. +void move_wearable_item(LLViewerInventoryItem* item, bool closer_to_body) +{ + if(!item) + return; + + if(item->getIsLinkType()) + { + if(LLAppearanceMgr::instance().moveWearable(item, closer_to_body)) + gAgentAvatarp->wearableUpdated(item->getWearableType(),TRUE); + } + else + { + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cats; + LLLinkedItemIDMatches is_linked_item_match(item->getUUID()); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_linked_item_match); + if(!items.empty()) + { + if(LLAppearanceMgr::instance().moveWearable(gInventory.getItem(items.front()->getUUID()),closer_to_body)) + gAgentAvatarp->wearableUpdated(item->getWearableType(),TRUE); + } + } +} + // virtual void LLWearableBridge::performAction(LLInventoryModel* model, std::string action) { @@ -5564,6 +5633,15 @@ void LLWearableBridge::performAction(LLInventoryModel* model, std::string action removeFromAvatar(); return; } + //These move + else if("move_forward" == action) + { + move_wearable_item(getItem(),false); + } + else if("move_back" == action) + { + move_wearable_item(getItem(),true); + } else LLItemBridge::performAction(model, action); } @@ -5686,6 +5764,15 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if (LLWearableType::getAllowMultiwear(mWearableType)) { items.push_back(std::string("Wearable Add")); + items.push_back(std::string("Wearable Move Forward")); + items.push_back(std::string("Wearable Move Back")); + + bool is_worn = get_is_item_worn(item->getUUID()); + if(!is_worn || !gAgentWearables.canMoveWearable(item->getUUID(),false)) + disabled_items.push_back(std::string("Wearable Move Forward")); + if(!is_worn || !gAgentWearables.canMoveWearable(item->getUUID(),true)) + disabled_items.push_back(std::string("Wearable Move Back")); + // if (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) // [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e if ( (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) || diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index a5bd75877..828ad5689 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -795,7 +795,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() + if (!LLInventoryModelBackgroundFetch::instance().folderFetchActive() && filtered_by_type && !filtered_by_all_types) { diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index b4724536d..14c2de40f 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -110,97 +110,6 @@ void append_path(const LLUUID& id, std::string& path) path.append(temp); } -void change_item_parent(LLInventoryModel* model, - LLViewerInventoryItem* item, - const LLUUID& new_parent_id, - BOOL restamp) -{ - // - bool send_parent_update = gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getRootFolderID()); - // - if(item->getParentUUID() != new_parent_id) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent_id); - // - if(send_parent_update) - // - new_item->updateParentOnServer(restamp); - model->updateItem(new_item); - model->notifyObservers(); - } -} - -void change_category_parent(LLInventoryModel* model, - LLViewerInventoryCategory* cat, - const LLUUID& new_parent_id, - BOOL restamp) -{ - if (!model || !cat) - { - return; - } - - // Can't move a folder into a child of itself. - if (model->isObjectDescendentOf(new_parent_id, cat->getUUID())) - { - return; - } - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - model->accountForUpdate(update); - - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent_id); - new_cat->updateParentOnServer(restamp); - model->updateCategory(new_cat); - model->notifyObservers(); -} - -void remove_category(LLInventoryModel* model, const LLUUID& cat_id) -{ - if (!model || !get_is_category_removable(model, cat_id)) - { - return; - } - - // Look for any gestures and deactivate them - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - gInventory.collectDescendents(cat_id, descendent_categories, descendent_items, FALSE); - - for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); - iter != descendent_items.end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - const LLUUID& item_id = item->getUUID(); - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item_id)) - { - LLGestureMgr::instance().deactivateGesture(item_id); - } - } - - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - if (cat) - { - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - change_category_parent(model, cat, trash_id, TRUE); - } -} - void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name) { LLViewerInventoryCategory* cat; @@ -553,8 +462,7 @@ void move_to_outbox_cb_action(const LLSD& payload) LLUUID parent = viitem->getParentUUID(); - change_item_parent( - &gInventory, + gInventory.changeItemParent( viitem, dest_folder_id, false); @@ -581,7 +489,7 @@ void move_to_outbox_cb_action(const LLSD& payload) if (cat_array->empty() && item_array->empty()) { - remove_category(&gInventory, parent); + gInventory.removeCategory(parent); } if (parent == top_level_folder) @@ -655,7 +563,7 @@ void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - change_item_parent(&gInventory, + gInventory.changeItemParent( viewer_inv_item, dest_folder, false); @@ -976,20 +884,24 @@ void LLSaveFolderState::setApply(BOOL apply) void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) { + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); + if(!bridge) return; + if(mApply) { // we're applying the open state - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); - if(!bridge) return; LLUUID id(bridge->getUUID()); if(mOpenFolders.find(id) != mOpenFolders.end()) { - folder->setOpen(TRUE); + if (!folder->isOpen()) + { + folder->setOpen(TRUE); + } } else { // keep selected filter in its current state, this is less jarring to user - if (!folder->isSelected()) + if (!folder->isSelected() && folder->isOpen()) { folder->setOpen(FALSE); } @@ -1000,8 +912,6 @@ void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) // we're recording state at this point if(folder->isOpen()) { - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); - if(!bridge) return; mOpenFolders.insert(bridge->getUUID()); } } diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 689f5f1a2..99d1ef24b 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -55,17 +55,6 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) void show_item_profile(const LLUUID& item_uuid); -void change_item_parent(LLInventoryModel* model, - LLViewerInventoryItem* item, - const LLUUID& new_parent_id, - BOOL restamp); - -void change_category_parent(LLInventoryModel* model, - LLViewerInventoryCategory* cat, - const LLUUID& new_parent_id, - BOOL restamp); - -void remove_category(LLInventoryModel* model, const LLUUID& cat_id); void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name); // Generates a string containing the path to the item specified by item_id. diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a2060a2a1..50234039e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -46,6 +46,8 @@ #include "llviewerregion.h" #include "llcallbacklist.h" #include "llvoavatarself.h" +#include "llgesturemgr.h" +#include #include "statemachine/aievent.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) @@ -1080,6 +1082,72 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) } } +// Migrated from llinventoryfunctions +void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, + const LLUUID& new_parent_id, + BOOL restamp) +{ + // + bool send_parent_update = gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getRootFolderID()); + // + if (item->getParentUUID() == new_parent_id) + { + LL_DEBUGS("Inventory") << "'" << item->getName() << "' (" << item->getUUID() + << ") is already in folder " << new_parent_id << LL_ENDL; + } + else + { + LL_INFOS("Inventory") << "Moving '" << item->getName() << "' (" << item->getUUID() + << ") from " << item->getParentUUID() << " to folder " + << new_parent_id << LL_ENDL; + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->setParent(new_parent_id); + // + if(send_parent_update) + // + new_item->updateParentOnServer(restamp); + updateItem(new_item); + notifyObservers(); + } +} + +// Migrated from llinventoryfunctions +void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, + const LLUUID& new_parent_id, + BOOL restamp) +{ + if (!cat) + { + return; + } + + // Can't move a folder into a child of itself. + if (isObjectDescendentOf(new_parent_id, cat->getUUID())) + { + return; + } + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer new_cat = new LLViewerInventoryCategory(cat); + new_cat->setParent(new_parent_id); + new_cat->updateParentOnServer(restamp); + updateCategory(new_cat); + notifyObservers(); +} + // Delete a particular inventory object by ID. void LLInventoryModel::deleteObject(const LLUUID& id) { @@ -1208,13 +1276,12 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) items, INCLUDE_TRASH); S32 count = items.count(); - S32 i; - for(i = 0; i < count; ++i) + for(S32 i = 0; i < count; ++i) { deleteObject(items.get(i)->getUUID()); } count = categories.count(); - for(i = 0; i < count; ++i) + for(S32 i = 0; i < count; ++i) { deleteObject(categories.get(i)->getUUID()); } @@ -1729,6 +1796,7 @@ bool LLInventoryModel::loadSkeleton( update_map_t child_counts; cat_array_t categories; item_array_t items; + item_array_t possible_broken_links; cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. std::string owner_id_str; owner_id.toString(owner_id_str); @@ -1815,6 +1883,8 @@ bool LLInventoryModel::loadSkeleton( // Add all the items loaded which are parented to a // category with a correctly cached parent S32 bad_link_count = 0; + S32 good_link_count = 0; + S32 recovered_link_count = 0; cat_map_t::iterator unparented = mCategoryMap.end(); for(item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); @@ -1831,26 +1901,56 @@ bool LLInventoryModel::loadSkeleton( // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. if (item->getIsBrokenLink()) { - bad_link_count++; + //bad_link_count++; lldebugs << "Attempted to add cached link item without baseobj present ( name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ). Ignoring and invalidating " << cat->getName() << " . " << llendl; - invalid_categories.insert(cit->second); + possible_broken_links.push_back(item); continue; } + else if (item->getIsLinkType()) + { + good_link_count++; + } addItem(item); cached_item_count += 1; ++child_counts[cat->getUUID()]; } } } - if (bad_link_count > 0) + if (possible_broken_links.size() > 0) { - llinfos << "Attempted to add " << bad_link_count - << " cached link items without baseobj present. " - << "The corresponding categories were invalidated." << llendl; + for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); + item_iter != possible_broken_links.end(); + ++item_iter) + { + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + const LLViewerInventoryCategory* cat = cit->second.get(); + if (item->getIsBrokenLink()) + { + bad_link_count++; + invalid_categories.insert(cit->second); + //llinfos << "link still broken: " << item->getName() << " in folder " << cat->getName() << llendl; + } + else + { + // was marked as broken because of loading order, its actually fine to load + addItem(item); + cached_item_count += 1; + ++child_counts[cat->getUUID()]; + recovered_link_count++; + } + } + + llinfos << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << good_link_count << " link items were successfully added. " + << recovered_link_count << " links added in recovery. " + << "The corresponding categories were invalidated." << llendl; } + } else { @@ -3099,27 +3199,62 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT notifyObservers(); } } + +//---------------------------------------------------------------------------- + void LLInventoryModel::removeItem(const LLUUID& item_id) { LLViewerInventoryItem* item = getItem(item_id); - const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(item && new_parent.notNull() && item->getParentUUID() != new_parent) + if (! item) { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent); - new_item->updateParentOnServer(TRUE); - updateItem(new_item); - notifyObservers(); + LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; + } + else + { + const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (new_parent.notNull()) + { + LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; + changeItemParent(item, new_parent, TRUE); + } } } +void LLInventoryModel::removeCategory(const LLUUID& category_id) +{ + if (! get_is_category_removable(this, category_id)) + { + return; + } + + // Look for any gestures and deactivate them + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + collectDescendents(category_id, descendent_categories, descendent_items, FALSE); + + for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); + iter != descendent_items.end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + const LLUUID& item_id = item->getUUID(); + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureMgr::instance().isGestureActive(item_id)) + { + LLGestureMgr::instance().deactivateGesture(item_id); + } + } + + LLViewerInventoryCategory* cat = getCategory(category_id); + if (cat) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id.notNull()) + { + changeCategoryParent(cat, trash_id, TRUE); + } + } +} const LLUUID &LLInventoryModel::getRootFolderID() const { return mRootFolderID; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 90e841fef..a7506e19a 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -316,6 +316,16 @@ public: // observer notification, or server update is performed. void moveObject(const LLUUID& object_id, const LLUUID& cat_id); + // Migrated from llinventoryfunctions + void changeItemParent(LLViewerInventoryItem* item, + const LLUUID& new_parent_id, + BOOL restamp); + + // Migrated from llinventoryfunctions + void changeCategoryParent(LLViewerInventoryCategory* cat, + const LLUUID& new_parent_id, + BOOL restamp); + //-------------------------------------------------------------------- // Delete //-------------------------------------------------------------------- @@ -325,8 +335,13 @@ public: // consistent internal state. No cache accounting, observer // notification, or server update is performed. void deleteObject(const LLUUID& id); + /// move Item item_id to Trash void removeItem(const LLUUID& item_id); - + /// move Category category_id to Trash + void removeCategory(const LLUUID& category_id); + /// removeItem() or removeCategory(), whichever is appropriate + void removeObject(const LLUUID& object_id); + // Delete a particular inventory object by ID, and delete it from // the server. Also updates linked items. void purgeObject(const LLUUID& id); diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 3fc36a290..74bb12058 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -43,6 +43,7 @@ const S32 MAX_FETCH_RETRIES = 10; LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : mBackgroundFetchActive(FALSE), + mFolderFetchActive(false), mAllFoldersFetched(FALSE), mRecursiveInventoryFetchStarted(FALSE), mRecursiveLibraryFetchStarted(FALSE), @@ -50,7 +51,7 @@ LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : mMinTimeBetweenFetches(0.3f), mMaxTimeBetweenFetches(10.f), mTimelyFetchPending(FALSE), - mBulkFetchCount(0) + mFetchCount(0) { } @@ -60,7 +61,7 @@ LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const { - return mFetchQueue.empty() && mBulkFetchCount<=0; + return mFetchQueue.empty() && mFetchCount<=0; } bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const @@ -98,19 +99,21 @@ bool LLInventoryModelBackgroundFetch::isEverythingFetched() const return mAllFoldersFetched; } -BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() const +BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const { - return mBackgroundFetchActive; + return mFolderFetchActive; } -void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive) +void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive) { - if (!mAllFoldersFetched || cat_id.notNull()) - { - LL_DEBUGS("InventoryFetch") << "Start fetching category: " << cat_id << ", recursive: " << recursive << LL_ENDL; + LLViewerInventoryCategory* cat = gInventory.getCategory(id); + if (cat || (id.isNull() && !isEverythingFetched())) + { // it's a folder, do a bulk fetch + LL_DEBUGS("InventoryFetch") << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL; mBackgroundFetchActive = TRUE; - if (cat_id.isNull()) + mFolderFetchActive = true; + if (id.isNull()) { if (!mRecursiveInventoryFetchStarted) { @@ -128,42 +131,41 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive else { // Specific folder requests go to front of queue. - if (mFetchQueue.empty() || mFetchQueue.front().mCatUUID != cat_id) + if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id) { - mFetchQueue.push_front(FetchQueueInfo(cat_id, recursive)); + mFetchQueue.push_front(FetchQueueInfo(id, recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } - if (cat_id == gInventory.getLibraryRootFolderID()) + if (id == gInventory.getLibraryRootFolderID()) { mRecursiveLibraryFetchStarted |= recursive; } - if (cat_id == gInventory.getRootFolderID()) + if (id == gInventory.getRootFolderID()) { mRecursiveInventoryFetchStarted |= recursive; } } } + else if (LLViewerInventoryItem* itemp = gInventory.getItem(id)) + { + if (!itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)) + { + mBackgroundFetchActive = TRUE; + + mFetchQueue.push_front(FetchQueueInfo(id, false, false)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + } } -//static void LLInventoryModelBackgroundFetch::findLostItems() { mBackgroundFetchActive = TRUE; + mFolderFetchActive = true; mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } -void LLInventoryModelBackgroundFetch::stopBackgroundFetch() -{ - if (mBackgroundFetchActive) - { - mBackgroundFetchActive = FALSE; - gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); - mBulkFetchCount=0; - mMinTimeBetweenFetches=0.0f; - } -} - void LLInventoryModelBackgroundFetch::setAllFoldersFetched() { if (mRecursiveInventoryFetchStarted && @@ -171,7 +173,7 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched() { mAllFoldersFetched = TRUE; } - stopBackgroundFetch(); + mFolderFetchActive = false; } void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) @@ -185,10 +187,9 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() if (mBackgroundFetchActive && gAgent.getRegion()) { // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. - std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2"); - if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty()) + if (gSavedSettings.getBOOL("UseHTTPInventory")) { - bulkFetch(url); + bulkFetch(); return; } @@ -203,6 +204,9 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() llinfos << "Inventory fetch completed" << llendl; setAllFoldersFetched(); + mBackgroundFetchActive = false; + mFolderFetchActive = false; + return; } @@ -232,79 +236,113 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() } const FetchQueueInfo info = mFetchQueue.front(); - LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID); - // category has been deleted, remove from queue. - if (!cat) + if (info.mIsCategory) { - mFetchQueue.pop_front(); - continue; - } - - if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && - LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) - { - // category exists but has no children yet, fetch the descendants - // for now, just request every time and rely on retry timer to throttle - if (cat->fetch()) + + LLViewerInventoryCategory* cat = gInventory.getCategory(info.mUUID); + + // Category has been deleted, remove from queue. + if (!cat) { + mFetchQueue.pop_front(); + continue; + } + + if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && + LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + // Category exists but has no children yet, fetch the descendants + // for now, just request every time and rely on retry timer to throttle. + if (cat->fetch()) + { + mFetchTimer.reset(); + mTimelyFetchPending = TRUE; + } + else + { + // The catagory also tracks if it has expired and here it says it hasn't + // yet. Get out of here because nothing is going to happen until we + // update the timers. + break; + } + } + // Do I have all my children? + else if (gInventory.isCategoryComplete(info.mUUID)) + { + // Finished with this category, remove from queue. + mFetchQueue.pop_front(); + + // Add all children to queue. + LLInventoryModel::cat_array_t* categories; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); + } + + // We received a response in less than the fast time. + if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time) + { + // Shrink timeouts based on success. + mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); + mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); + lldebugs << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; + } + + mTimelyFetchPending = FALSE; + continue; + } + else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) + { + // Received first packet, but our num descendants does not match db's num descendants + // so try again later. + mFetchQueue.pop_front(); + + if (mNumFetchRetries++ < MAX_FETCH_RETRIES) + { + // push on back of queue + mFetchQueue.push_back(info); + } + mTimelyFetchPending = FALSE; + mFetchTimer.reset(); + break; + } + + // Not enough time has elapsed to do a new fetch + break; + } + else + { + LLViewerInventoryItem* itemp = gInventory.getItem(info.mUUID); + + mFetchQueue.pop_front(); + if (!itemp) + { + continue; + } + + if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches) + { + itemp->fetchFromServer(); mFetchTimer.reset(); mTimelyFetchPending = TRUE; } - else + else if (itemp->mIsComplete) { - // The catagory also tracks if it has expired and here it says it hasn't - // yet. Get out of here because nothing is going to happen until we - // update the timers. - break; + mTimelyFetchPending = FALSE; } - } - // do I have all my children? - else if (gInventory.isCategoryComplete(info.mCatUUID)) - { - // finished with this category, remove from queue - mFetchQueue.pop_front(); - - // Add all children to queue. - LLInventoryModel::cat_array_t* categories; - gInventory.getDirectDescendentsOf(cat->getUUID(), categories); - for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); - it != categories->end(); - ++it) + else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); - } - - // we received a response in less than the fast time - if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time) - { - // shrink timeouts based on success - mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); - mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); - lldebugs << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; - } - - mTimelyFetchPending = FALSE; - continue; - } - else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) - { - // received first packet, but our num descendants does not match db's num descendants - // so try again later. - mFetchQueue.pop_front(); - - if (mNumFetchRetries++ < MAX_FETCH_RETRIES) - { - // push on back of queue mFetchQueue.push_back(info); + mFetchTimer.reset(); + mTimelyFetchPending = FALSE; } - mTimelyFetchPending = FALSE; - mFetchTimer.reset(); + // Not enough time has elapsed to do a new fetch break; } - - // not enough time has elapsed to do a new fetch - break; } // @@ -314,15 +352,35 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() } } -void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching) +void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching) { - mBulkFetchCount += fetching; - if (mBulkFetchCount < 0) + mFetchCount += fetching; + if (mFetchCount < 0) { - mBulkFetchCount = 0; + mFetchCount = 0; } } +class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder +{ +public: + LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {}; + void result(const LLSD& content); + void error(U32 status, const std::string& reason); +}; + +void LLInventoryModelFetchItemResponder::result( const LLSD& content ) +{ + LLInventoryModel::fetchInventoryResponder::result(content); + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +} + +void LLInventoryModelFetchItemResponder::error( U32 status, const std::string& reason ) +{ + LLInventoryModel::fetchInventoryResponder::error(status, reason); + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +} + class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder { @@ -459,7 +517,7 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) } } - fetcher->incrBulkFetch(-1); + fetcher->incrFetchCount(-1); if (fetcher->isBulkFetchProcessingComplete()) { @@ -478,9 +536,9 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str llinfos << "LLInventoryModelFetchDescendentsResponder::error " << status << ": " << reason << llendl; - fetcher->incrBulkFetch(-1); + fetcher->incrFetchCount(-1); - if (status==499) //timed out. Let's be awesome! + if (status==499) // timed out { for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); folder_it != mRequestSD["folders"].endArray(); @@ -509,27 +567,29 @@ BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat // Bundle up a bunch of requests to send all at once. // static -void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) +void LLInventoryModelBackgroundFetch::bulkFetch() { //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. - //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was + //If there are items in mFetchQueue, we want to check the time since the last bulkFetch was //sent. If it exceeds our retry time, go ahead and fire off another batch. - //Stopbackgroundfetch will be run from the Responder instead of here. + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return; S16 max_concurrent_fetches=8; F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely. - if (mMinTimeBetweenFetches < new_min_time) + if (mMinTimeBetweenFetches < new_min_time) { mMinTimeBetweenFetches=new_min_time; //HACK! See above. } if (gDisconnected || - (mBulkFetchCount > max_concurrent_fetches) || + (mFetchCount > max_concurrent_fetches) || (mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches)) { - return; // just bail if we are disconnected. + return; // just bail if we are disconnected } + U32 item_count=0; U32 folder_count=0; U32 max_batch_size=5; @@ -537,86 +597,163 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) uuid_vec_t recursive_cats; - LLSD body; - LLSD body_lib; + LLSD folder_request_body; + LLSD folder_request_body_lib; + LLSD item_request_body; + LLSD item_request_body_lib; - while( !(mFetchQueue.empty() ) && (folder_count < max_batch_size) ) + while (!mFetchQueue.empty() + && (item_count + folder_count) < max_batch_size) { const FetchQueueInfo& fetch_info = mFetchQueue.front(); - const LLUUID &cat_id = fetch_info.mCatUUID; - if (cat_id.isNull()) //DEV-17797 - { - LLSD folder_sd; - folder_sd["folder_id"] = LLUUID::null.asString(); - folder_sd["owner_id"] = gAgent.getID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - body["folders"].append(folder_sd); - folder_count++; - } - else - { - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (fetch_info.mIsCategory) + { + const LLUUID &cat_id = fetch_info.mUUID; + if (cat_id.isNull()) //DEV-17797 + { + LLSD folder_sd; + folder_sd["folder_id"] = LLUUID::null.asString(); + folder_sd["owner_id"] = gAgent.getID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + folder_request_body["folders"].append(folder_sd); + folder_count++; + } + else + { + const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - if (cat) - { - if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) - { - LLSD folder_sd; - folder_sd["folder_id"] = cat->getUUID(); - folder_sd["owner_id"] = cat->getOwnerID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - - if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) - body_lib["folders"].append(folder_sd); - else - body["folders"].append(folder_sd); - folder_count++; - } - // May already have this folder, but append child folders to list. - if (fetch_info.mRecursive) - { - LLInventoryModel::cat_array_t* categories; - gInventory.getDirectDescendentsOf(cat->getUUID(), categories); - for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); - it != categories->end(); - ++it) + if (cat) + { + if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); - } - } - } - } - if (fetch_info.mRecursive) - recursive_cats.push_back(cat_id); + LLSD folder_sd; + folder_sd["folder_id"] = cat->getUUID(); + folder_sd["owner_id"] = cat->getOwnerID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + + if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) + folder_request_body_lib["folders"].append(folder_sd); + else + folder_request_body["folders"].append(folder_sd); + folder_count++; + } + // May already have this folder, but append child folders to list. + if (fetch_info.mRecursive) + { + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + } + } + } + } + if (fetch_info.mRecursive) + recursive_cats.push_back(cat_id); + } + else + { + LLViewerInventoryItem* itemp = gInventory.getItem(fetch_info.mUUID); + if (itemp) + { + LLSD item_sd; + item_sd["owner_id"] = itemp->getPermissions().getOwner(); + item_sd["item_id"] = itemp->getUUID(); + if (itemp->getPermissions().getOwner() == gAgent.getID()) + { + item_request_body.append(item_sd); + } + else + { + item_request_body_lib.append(item_sd); + } + //itemp->fetchFromServer(); + item_count++; + } + } mFetchQueue.pop_front(); } - if (folder_count > 0) + if (item_count + folder_count > 0) { - mBulkFetchCount++; - if (body["folders"].size()) + if (folder_count) { - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body, recursive_cats); - LLHTTPClient::post(url, body, fetcher, 300.0); + std::string url = region->getCapability("FetchInventoryDescendents2"); + mFetchCount++; + if (folder_request_body["folders"].size()) + { + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); + LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); + } + if (folder_request_body_lib["folders"].size()) + { + std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); + + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); + LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); + } } - if (body_lib["folders"].size()) + if (item_count) { - std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); - - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats); - LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0); + std::string url; + + if (item_request_body.size()) + { + mFetchCount++; + url = region->getCapability("FetchInventory2"); + if (!url.empty()) + { + LLSD body; + body["agent_id"] = gAgent.getID(); + body["items"] = item_request_body; + + LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); + } + //else + //{ + // LLMessageSystem* msg = gMessageSystem; + // msg->newMessage("FetchInventory"); + // msg->nextBlock("AgentData"); + // msg->addUUID("AgentID", gAgent.getID()); + // msg->addUUID("SessionID", gAgent.getSessionID()); + // msg->nextBlock("InventoryData"); + // msg->addUUID("OwnerID", mPermissions.getOwner()); + // msg->addUUID("ItemID", mUUID); + // gAgent.sendReliableMessage(); + //} + } + + if (item_request_body_lib.size()) + { + mFetchCount++; + + url = region->getCapability("FetchLib2"); + if (!url.empty()) + { + LLSD body; + body["agent_id"] = gAgent.getID(); + body["items"] = item_request_body_lib; + + LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); + } + } } mFetchTimer.reset(); } + else if (isBulkFetchProcessingComplete()) { setAllFoldersFetched(); - } + } } bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const @@ -624,7 +761,7 @@ bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LL for (fetch_queue_t::const_iterator it = mFetchQueue.begin(); it != mFetchQueue.end(); ++it) { - const LLUUID& fetch_id = (*it).mCatUUID; + const LLUUID& fetch_id = (*it).mUUID; if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) return false; } diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index 0fac2c7a2..bc40cc5cb 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -48,7 +48,7 @@ public: // This gets triggered when performing a filter-search. void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE); - BOOL backgroundFetchActive() const; + BOOL folderFetchActive() const; bool isEverythingFetched() const; // completing the fetch once per session should be sufficient bool libraryFetchStarted() const; @@ -60,14 +60,13 @@ public: bool inventoryFetchInProgress() const; void findLostItems(); + void incrFetchCount(S16 fetching); protected: - void incrBulkFetch(S16 fetching); bool isBulkFetchProcessingComplete() const; - void bulkFetch(std::string url); + void bulkFetch(); void backgroundFetch(); static void backgroundFetchCB(void*); // background fetch idle function - void stopBackgroundFetch(); // stop fetch process void setAllFoldersFetched(); bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const; @@ -77,7 +76,8 @@ private: BOOL mAllFoldersFetched; BOOL mBackgroundFetchActive; - S16 mBulkFetchCount; + bool mFolderFetchActive; + S16 mFetchCount; BOOL mTimelyFetchPending; S32 mNumFetchRetries; @@ -87,11 +87,11 @@ private: struct FetchQueueInfo { - FetchQueueInfo(const LLUUID& id, BOOL recursive) : - mCatUUID(id), mRecursive(recursive) - { - } - LLUUID mCatUUID; + FetchQueueInfo(const LLUUID& id, BOOL recursive, bool is_category = true) : + mUUID(id), mRecursive(recursive), mIsCategory(is_category) + {} + LLUUID mUUID; + bool mIsCategory; BOOL mRecursive; }; typedef std::deque fetch_queue_t; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index d957b9f94..0f6fa9e78 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -841,7 +841,7 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) if(handled) { ECursorType cursor = getWindow()->getCursor(); - if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && cursor == UI_CURSOR_ARROW) + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && cursor == UI_CURSOR_ARROW) { // replace arrow cursor with arrow and hourglass cursor getWindow()->setCursor(UI_CURSOR_WORKING); diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 488ba2e3f..b6feb554a 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1598,7 +1598,11 @@ void LLManipTranslate::renderSnapGuides() LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER); LLGLEnable stipple(GL_LINE_STIPPLE); gGL.flush(); - glLineStipple(1, 0x3333); + + if (!LLGLSLShader::sNoFixedFunction) + { + glLineStipple(1, 0x3333); + } switch (mManipPart) { @@ -1712,16 +1716,20 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, gClipProgram.uniform4fv("clip_plane", 1, plane.v); BOOL particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES); +#if ENABLE_CLASSIC_CLOUDS BOOL clouds = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS); +#endif if (particles) { LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); } +#if ENABLE_CLASSIC_CLOUDS if (clouds) { LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS); } +#endif //stencil in volumes glStencilOp(GL_INCR, GL_INCR, GL_INCR); @@ -1742,10 +1750,12 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, { LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); } +#if ENABLE_CLASSIC_CLOUDS if (clouds) { LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS); } +#endif gGL.setColorMask(true, false); } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index ab64f5228..caf2ce7da 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -521,9 +521,11 @@ void LLMeshRepoThread::run() mLODReqQ.pop(); LLMeshRepository::sLODProcessing--; mMutex->unlock(); - if (fetchMeshLOD(req.mMeshParams, req.mLOD)) + if (!fetchMeshLOD(req.mMeshParams, req.mLOD, count))//failed, resubmit { - count++; + mMutex->lock(); + mLODReqQ.push(req) ; + mMutex->unlock(); } } } @@ -536,9 +538,11 @@ void LLMeshRepoThread::run() HeaderRequest req = mHeaderReqQ.front(); mHeaderReqQ.pop(); mMutex->unlock(); - if (fetchMeshHeader(req.mMeshParams)) + if (!fetchMeshHeader(req.mMeshParams, count))//failed, resubmit { - count++; + mMutex->lock(); + mHeaderReqQ.push(req) ; + mMutex->unlock(); } } } @@ -691,8 +695,9 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) return false; } + bool ret = true ; U32 header_size = mMeshHeaderSize[mesh_id]; - + if (header_size > 0) { S32 version = mMeshHeader[mesh_id]["version"].asInteger(); @@ -737,10 +742,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, - new LLMeshSkinInfoResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshSkinInfoResponder(mesh_id, offset, size)); + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } } @@ -750,7 +758,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) @@ -769,7 +777,8 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } U32 header_size = mMeshHeaderSize[mesh_id]; - + bool ret = true ; + if (header_size > 0) { S32 version = mMeshHeader[mesh_id]["version"].asInteger(); @@ -814,10 +823,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, offset, size, - new LLMeshDecompositionResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshDecompositionResponder(mesh_id, offset, size)); + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } } @@ -827,7 +839,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) @@ -840,12 +852,13 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) mHeaderMutex->lock(); if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) - { //we have no header info for this mesh, do nothing + { //we have no header info for this mesh, do nothing mHeaderMutex->unlock(); return false; } U32 header_size = mMeshHeaderSize[mesh_id]; + bool ret = true ; if (header_size > 0) { @@ -891,14 +904,18 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, offset, size, - new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } else - { //no physics shape whatsoever, report back NULL + { //no physics shape whatsoever, report back NULL physicsShapeReceived(mesh_id, NULL, 0); } } @@ -908,13 +925,12 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } -bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) +//return false if failed to get header +bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count) { - bool retval = false; - { //look for mesh in asset in vfs LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH); @@ -928,32 +944,37 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) LLMeshRepository::sCacheBytesRead += bytes; file.read(buffer, bytes); if (headerReceived(mesh_params, buffer, bytes)) - { //did not do an HTTP request, return false - return false; + { //did not do an HTTP request, return false + return true; } } } - //either cache entry doesn't exist or is corrupt, request header from simulator - + //either cache entry doesn't exist or is corrupt, request header from simulator + bool retval = true ; std::vector headers; headers.push_back("Accept: application/octet-stream"); std::string http_url = constructUrl(mesh_params.getSculptID()); if (!http_url.empty()) { - retval = true; //grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits //within the first 4KB - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + //NOTE -- this will break of headers ever exceed 4KB + retval = mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + if(retval) + { + LLMeshRepository::sHTTPRequestCount++; + } + count++; } return retval; } -bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) -{ //protected by mMutex +//return false if failed to get mesh lod. +bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count) +{ //protected by mMutex if (!mHeaderMutex) { return false; @@ -961,7 +982,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) mHeaderMutex->lock(); - bool retval = false; + bool retval = true; LLUUID mesh_id = mesh_params.getSculptID(); @@ -998,7 +1019,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (lodReceived(mesh_params, lod, buffer, size)) { delete[] buffer; - return false; + return true; } } @@ -1011,11 +1032,15 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - retval = true; - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + { + retval = mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, new LLMeshLODResponder(mesh_params, lod, offset, size)); + + if(retval) + { + LLMeshRepository::sHTTPRequestCount++; + } + count++; } else { @@ -2212,6 +2237,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para //first request for this mesh mLoadingMeshes[detail][mesh_params].insert(vobj->getID()); mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail)); + LLMeshRepository::sLODPending++; } } @@ -3228,7 +3254,6 @@ void LLPhysicsDecomp::doDecompositionSingleHull() LLCDMeshData mesh; -#if 1 setMeshData(mesh, true); LLCDResult ret = decomp->buildSingleHull() ; @@ -3264,88 +3289,6 @@ void LLPhysicsDecomp::doDecompositionSingleHull() mCurRequest->mHull[0] = p; mMutex->unlock(); } -#else - setMeshData(mesh, false); - - //set all parameters to default - std::map param_map; - - static const LLCDParam* params = NULL; - static S32 param_count = 0; - - if (!params) - { - param_count = decomp->getParameters(¶ms); - } - - for (S32 i = 0; i < param_count; ++i) - { - decomp->setParam(params[i].mName, params[i].mDefault.mIntOrEnumValue); - } - - const S32 STAGE_DECOMPOSE = mStageID["Decompose"]; - const S32 STAGE_SIMPLIFY = mStageID["Simplify"]; - const S32 DECOMP_PREVIEW = 0; - const S32 SIMPLIFY_RETAIN = 0; - - decomp->setParam("Decompose Quality", DECOMP_PREVIEW); - decomp->setParam("Simplify Method", SIMPLIFY_RETAIN); - decomp->setParam("Retain%", 0.f); - - LLCDResult ret = LLCD_OK; - ret = decomp->executeStage(STAGE_DECOMPOSE); - - if (ret) - { - llwarns << "Could not execute decomposition stage when attempting to create single hull." << llendl; - make_box(mCurRequest); - } - else - { - ret = decomp->executeStage(STAGE_SIMPLIFY); - - if (ret) - { - llwarns << "Could not execute simiplification stage when attempting to create single hull." << llendl; - make_box(mCurRequest); - } - else - { - S32 num_hulls =0; - if (LLConvexDecomposition::getInstance() != NULL) - { - num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(STAGE_SIMPLIFY); - } - - mMutex->lock(); - mCurRequest->mHull.clear(); - mCurRequest->mHull.resize(num_hulls); - mCurRequest->mHullMesh.clear(); - mMutex->unlock(); - - for (S32 i = 0; i < num_hulls; ++i) - { - std::vector p; - LLCDHull hull; - // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code - LLConvexDecomposition::getInstance()->getHullFromStage(STAGE_SIMPLIFY, i, &hull); - - const F32* v = hull.mVertexBase; - - for (S32 j = 0; j < hull.mNumVertices; ++j) - { - LLVector3 vert(v[0], v[1], v[2]); - p.push_back(vert); - v = (F32*) (((U8*) v) + hull.mVertexStrideBytes); - } - - mMutex->lock(); - mCurRequest->mHull[i] = p; - mMutex->unlock(); - } - } - } -#endif { completeCurrent(); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index a655b71d0..c106f810f 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -350,8 +350,8 @@ public: virtual void run(); void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod); - bool fetchMeshHeader(const LLVolumeParams& mesh_params); - bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod); + bool fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count); + bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count); bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size); bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size); bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp new file mode 100644 index 000000000..bfa43822c --- /dev/null +++ b/indra/newview/llpaneleditwearable.cpp @@ -0,0 +1,1602 @@ +/** + * @file llpaneleditwearable.cpp + * @brief UI panel for editing of a particular wearable item. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpaneleditwearable.h" +#include "llpanel.h" +#include "llwearable.h" +#include "lluictrl.h" +#include "llscrollingpanellist.h" +#include "llvisualparam.h" +#include "lltoolmorph.h" +#include "llviewerjointmesh.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llvoavatarself.h" +#include "lltexteditor.h" +#include "lltextbox.h" +#include "llagentwearables.h" +#include "llscrollingpanelparam.h" +#include "llradiogroup.h" +#include "llnotificationsutil.h" + +#include "llcolorswatch.h" +#include "lltexturectrl.h" +#include "lltextureentry.h" +#include "llviewercontrol.h" // gSavedSettings +#include "llviewertexturelist.h" +#include "llagentcamera.h" +#include "llmorphview.h" + +#include "llcommandhandler.h" +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "llfloatercustomize.h" + +#include "llwearablelist.h" + +// subparts of the UI for focus, camera position, etc. +enum ESubpart { + SUBPART_SHAPE_HEAD = 1, // avoid 0 + SUBPART_SHAPE_EYES, + SUBPART_SHAPE_EARS, + SUBPART_SHAPE_NOSE, + SUBPART_SHAPE_MOUTH, + SUBPART_SHAPE_CHIN, + SUBPART_SHAPE_TORSO, + SUBPART_SHAPE_LEGS, + SUBPART_SHAPE_WHOLE, + SUBPART_SHAPE_DETAIL, + SUBPART_SKIN_COLOR, + SUBPART_SKIN_FACEDETAIL, + SUBPART_SKIN_MAKEUP, + SUBPART_SKIN_BODYDETAIL, + SUBPART_HAIR_COLOR, + SUBPART_HAIR_STYLE, + SUBPART_HAIR_EYEBROWS, + SUBPART_HAIR_FACIAL, + SUBPART_EYES, + SUBPART_SHIRT, + SUBPART_PANTS, + SUBPART_SHOES, + SUBPART_SOCKS, + SUBPART_JACKET, + SUBPART_GLOVES, + SUBPART_UNDERSHIRT, + SUBPART_UNDERPANTS, + SUBPART_SKIRT, + SUBPART_ALPHA, + SUBPART_TATTOO, + SUBPART_PHYSICS_BREASTS_UPDOWN, + SUBPART_PHYSICS_BREASTS_INOUT, + SUBPART_PHYSICS_BREASTS_LEFTRIGHT, + SUBPART_PHYSICS_BELLY_UPDOWN, + SUBPART_PHYSICS_BUTT_UPDOWN, + SUBPART_PHYSICS_BUTT_LEFTRIGHT, + SUBPART_PHYSICS_ADVANCED, + }; + +using namespace LLVOAvatarDefines; + +typedef std::vector subpart_vec_t; + +// Locally defined classes + +class LLEditWearableDictionary : public LLSingleton +{ + //-------------------------------------------------------------------- + // Constructors and Destructors + //-------------------------------------------------------------------- +public: + LLEditWearableDictionary(); + virtual ~LLEditWearableDictionary(); + + //-------------------------------------------------------------------- + // Wearable Types + //-------------------------------------------------------------------- +public: + struct WearableEntry : public LLDictionaryEntry + { + WearableEntry(LLWearableType::EType type, + const std::string &title, + U8 num_color_swatches, // number of 'color_swatches' + U8 num_texture_pickers, // number of 'texture_pickers' + U8 num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts + + + const LLWearableType::EType mWearableType; + subpart_vec_t mSubparts; + texture_vec_t mColorSwatchCtrls; + texture_vec_t mTextureCtrls; + }; + + struct Wearables : public LLDictionary + { + Wearables(); + } mWearables; + + const WearableEntry* getWearable(LLWearableType::EType type) const { return mWearables.lookup(type); } + + //-------------------------------------------------------------------- + // Subparts + //-------------------------------------------------------------------- +public: + struct SubpartEntry : public LLDictionaryEntry + { + SubpartEntry(ESubpart part, + const std::string &joint, + const std::string &edit_group, + const std::string &button_name, + const LLVector3d &target_offset, + const LLVector3d &camera_offset, + const ESex &sex); + + + ESubpart mSubpart; + std::string mTargetJoint; + std::string mEditGroup; + std::string mButtonName; + LLVector3d mTargetOffset; + LLVector3d mCameraOffset; + ESex mSex; + }; + + struct Subparts : public LLDictionary + { + Subparts(); + } mSubparts; + + const SubpartEntry* getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); } + + //-------------------------------------------------------------------- + // Picker Control Entries + //-------------------------------------------------------------------- +public: + struct PickerControlEntry : public LLDictionaryEntry + { + PickerControlEntry(ETextureIndex tex_index, + const std::string name, + const LLUUID default_image_id = LLUUID::null, + const bool allow_no_texture = false + ); + ETextureIndex mTextureIndex; + const std::string mControlName; + const LLUUID mDefaultImageId; + const bool mAllowNoTexture; + }; + + struct ColorSwatchCtrls : public LLDictionary + { + ColorSwatchCtrls(); + } mColorSwatchCtrls; + + struct TextureCtrls : public LLDictionary + { + TextureCtrls(); + } mTextureCtrls; + + const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); } + const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); } +}; + +LLEditWearableDictionary::LLEditWearableDictionary() +{ + +} + +//virtual +LLEditWearableDictionary::~LLEditWearableDictionary() +{ +} + +LLEditWearableDictionary::Wearables::Wearables() +{ + // note the subpart that is listed first is treated as "default", regardless of what order is in enum. + // Please match the order presented in XUI. -Nyx + // this will affect what camera angle is shown when first editing a wearable + addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL)); + addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title",0,1,1, TEX_EYES_IRIS, SUBPART_EYES)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO)); + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS,"edit_physics_title",0,0,7, SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, SUBPART_PHYSICS_BELLY_UPDOWN, SUBPART_PHYSICS_BUTT_UPDOWN, SUBPART_PHYSICS_BUTT_LEFTRIGHT, SUBPART_PHYSICS_ADVANCED)); +} + +LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type, + const std::string &title, + U8 num_color_swatches, + U8 num_texture_pickers, + U8 num_subparts, ... ) : + LLDictionaryEntry(title), + mWearableType(type) +{ + va_list argp; + va_start(argp, num_subparts); + + for (U8 i = 0; i < num_color_swatches; ++i) + { + ETextureIndex index = (ETextureIndex)va_arg(argp,int); + mColorSwatchCtrls.push_back(index); + } + + for (U8 i = 0; i < num_texture_pickers; ++i) + { + ETextureIndex index = (ETextureIndex)va_arg(argp,int); + mTextureCtrls.push_back(index); + } + + for (U8 i = 0; i < num_subparts; ++i) + { + ESubpart part = (ESubpart)va_arg(argp,int); + mSubparts.push_back(part); + } +} + +LLEditWearableDictionary::Subparts::Subparts() +{ + addEntry(SUBPART_SHAPE_WHOLE, new SubpartEntry(SUBPART_SHAPE_WHOLE, "mPelvis", "shape_body","Body", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + const LLVector3d head_target(0.f, 0.f, 0.05f); + const LLVector3d head_camera(-0.5f, 0.05f, 0.07f); + addEntry(SUBPART_SHAPE_HEAD, new SubpartEntry(SUBPART_SHAPE_HEAD, "mHead", "shape_head","Head", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_EYES, new SubpartEntry(SUBPART_SHAPE_EYES, "mHead", "shape_eyes","Eyes", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_EARS, new SubpartEntry(SUBPART_SHAPE_EARS, "mHead", "shape_ears","Ears", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_NOSE, new SubpartEntry(SUBPART_SHAPE_NOSE, "mHead", "shape_nose","Nose", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_MOUTH, new SubpartEntry(SUBPART_SHAPE_MOUTH, "mHead", "shape_mouth","Mouth", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_CHIN, new SubpartEntry(SUBPART_SHAPE_CHIN, "mHead", "shape_chin","Chin", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_TORSO, new SubpartEntry(SUBPART_SHAPE_TORSO, "mTorso", "shape_torso","Torso", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_SHAPE_LEGS, new SubpartEntry(SUBPART_SHAPE_LEGS, "mPelvis", "shape_legs","Legs", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + + addEntry(SUBPART_SKIN_COLOR, new SubpartEntry(SUBPART_SKIN_COLOR, "mHead", "skin_color","Skin Color", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_FACEDETAIL, new SubpartEntry(SUBPART_SKIN_FACEDETAIL, "mHead", "skin_facedetail","Face Detail", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_MAKEUP, new SubpartEntry(SUBPART_SKIN_MAKEUP, "mHead", "skin_makeup","Makeup", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_BODYDETAIL, new SubpartEntry(SUBPART_SKIN_BODYDETAIL, "mPelvis", "skin_bodydetail","Body Detail", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f), SEX_BOTH)); + + addEntry(SUBPART_HAIR_COLOR, new SubpartEntry(SUBPART_HAIR_COLOR, "mHead", "hair_color","Color", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); + addEntry(SUBPART_HAIR_STYLE, new SubpartEntry(SUBPART_HAIR_STYLE, "mHead", "hair_style","Style", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); + addEntry(SUBPART_HAIR_EYEBROWS, new SubpartEntry(SUBPART_HAIR_EYEBROWS, "mHead", "hair_eyebrows","Eyebrows", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_HAIR_FACIAL, new SubpartEntry(SUBPART_HAIR_FACIAL, "mHead", "hair_facial","Facial", head_target, head_camera,SEX_MALE)); + + addEntry(SUBPART_EYES, new SubpartEntry(SUBPART_EYES, "mHead", "eyes",LLStringUtil::null, head_target, head_camera,SEX_BOTH)); + + addEntry(SUBPART_SHIRT, new SubpartEntry(SUBPART_SHIRT, "mTorso", "shirt",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_PANTS, new SubpartEntry(SUBPART_PANTS, "mPelvis", "pants",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_SHOES, new SubpartEntry(SUBPART_SHOES, "mPelvis", "shoes",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_SOCKS, new SubpartEntry(SUBPART_SOCKS, "mPelvis", "socks",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_JACKET, new SubpartEntry(SUBPART_JACKET, "mTorso", "jacket",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.f), LLVector3d(-2.f, 0.1f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_SKIRT, new SubpartEntry(SUBPART_SKIRT, "mPelvis", "skirt",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_GLOVES, new SubpartEntry(SUBPART_GLOVES, "mTorso", "gloves",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.f), LLVector3d(-1.f, 0.15f, 0.f), SEX_BOTH)); + addEntry(SUBPART_UNDERSHIRT, new SubpartEntry(SUBPART_UNDERSHIRT, "mTorso", "undershirt",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), SEX_BOTH)); + addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", LLStringUtil::null, LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, "mTorso", "physics_breasts_updown", "Breast Bounce", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BREASTS_INOUT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_INOUT, "mTorso", "physics_breasts_inout", "Breast Cleavage", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, "mTorso", "physics_breasts_leftright", "Breast Sway", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "Belly Bounce", LLVector3d(0.f, 0.f, -.05f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "Butt Bounce", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, "mTorso", "physics_butt_leftright", "Butt Sway", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_ADVANCED, new SubpartEntry(SUBPART_PHYSICS_ADVANCED, "mTorso", "physics_advanced", "Advanced Parameters", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); +} + +LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part, + const std::string &joint, + const std::string &edit_group, + const std::string &button_name, + const LLVector3d &target_offset, + const LLVector3d &camera_offset, + const ESex &sex) : + LLDictionaryEntry(edit_group), + mSubpart(part), + mTargetJoint(joint), + mEditGroup(edit_group), + mButtonName(button_name), + mTargetOffset(target_offset), + mCameraOffset(camera_offset), + mSex(sex) +{ +} + +LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls() +{ + addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" )); + addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" )); + addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" )); + addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" )); + addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" )); + addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" )); + addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" )); + addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" )); + addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" )); + addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" )); +} + +LLEditWearableDictionary::TextureCtrls::TextureCtrls() +{ + addEntry ( TEX_HEAD_BODYPAINT, new PickerControlEntry (TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE )); + addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); + addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE )); +} + +LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex tex_index, + const std::string name, + const LLUUID default_image_id, + const bool allow_no_texture) : + LLDictionaryEntry(name), + mTextureIndex(tex_index), + mControlName(name), + mDefaultImageId(default_image_id), + mAllowNoTexture(allow_no_texture) +{ +} + +// Helper functions. +static const texture_vec_t null_texture_vec; + +// Specializations of this template function return a vector of texture indexes of particular control type +// (i.e. LLColorSwatchCtrl or LLTextureCtrl) which are contained in given WearableEntry. +template +const texture_vec_t& +get_pickers_indexes(const LLEditWearableDictionary::WearableEntry *wearable_entry) { return null_texture_vec; } + +// Specializations of this template function return picker control entry for particular control type. +template +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) { return NULL; } + +typedef boost::function function_t; + +typedef struct PickerControlEntryNamePredicate +{ + PickerControlEntryNamePredicate(const std::string name) : mName (name) {}; + bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const + { + return (entry && entry->mName == mName); + } +private: + const std::string mName; +} PickerControlEntryNamePredicate; + +// A full specialization of get_pickers_indexes for LLColorSwatchCtrl +template <> +const texture_vec_t& +get_pickers_indexes (const LLEditWearableDictionary::WearableEntry *wearable_entry) +{ + if (!wearable_entry) + { + llwarns << "could not get LLColorSwatchCtrl indexes for null wearable entry." << llendl; + return null_texture_vec; + } + return wearable_entry->mColorSwatchCtrls; +} + +// A full specialization of get_pickers_indexes for LLTextureCtrl +template <> +const texture_vec_t& +get_pickers_indexes (const LLEditWearableDictionary::WearableEntry *wearable_entry) +{ + if (!wearable_entry) + { + llwarns << "could not get LLTextureCtrl indexes for null wearable entry." << llendl; + return null_texture_vec; + } + return wearable_entry->mTextureCtrls; +} + +// A full specialization of get_picker_entry for LLColorSwatchCtrl +template <> +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) +{ + return LLEditWearableDictionary::getInstance()->getColorSwatch(index); +} + +// A full specialization of get_picker_entry for LLTextureCtrl +template <> +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) +{ + return LLEditWearableDictionary::getInstance()->getTexturePicker(index); +} + +template +const LLEditWearableDictionary::PickerControlEntry* +find_picker_ctrl_entry_if(LLWearableType::EType type, const Predicate pred) +{ + const LLEditWearableDictionary::WearableEntry *wearable_entry + = LLEditWearableDictionary::getInstance()->getWearable(type); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl; + return NULL; + } + const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); + for (texture_vec_t::const_iterator + iter = indexes.begin(), + iter_end = indexes.end(); + iter != iter_end; ++iter) + { + const ETextureIndex te = *iter; + const LLEditWearableDictionary::PickerControlEntry* entry + = get_picker_entry(te); + if (!entry) + { + llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl; + continue; + } + if (pred(entry)) + { + return entry; + } + } + return NULL; +} + +template +void +for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun) +{ + if (!panel) + { + llwarns << "the panel wasn't passed for wearable of type: " << type << llendl; + return; + } + const LLEditWearableDictionary::WearableEntry *wearable_entry + = LLEditWearableDictionary::getInstance()->getWearable(type); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl; + return; + } + const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); + for (texture_vec_t::const_iterator + iter = indexes.begin(), + iter_end = indexes.end(); + iter != iter_end; ++iter) + { + const ETextureIndex te = *iter; + const LLEditWearableDictionary::PickerControlEntry* entry + = get_picker_entry(te); + if (!entry) + { + llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl; + continue; + } + fun (panel, entry); + } +} + +// The helper functions for pickers management +static void init_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onColorSwatchCommit, self, _1)); + // Can't get the color from the wearable here, since the wearable may not be set when this is called. + color_swatch_ctrl->setOriginal(LLColor4::white); + } +} + +static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + texture_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onTexturePickerCommit, self, _1)); + texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId); + texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture); + // Don't allow (no copy) or (notransfer) textures to be selected. + texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); + texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); + } +} + +static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex)); + } +} + +static void update_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + LLUUID new_id; + LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex); + if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) + { + new_id = lto->getID(); + } + else + { + new_id = LLUUID::null; + } + LLUUID old_id = texture_ctrl->getImageAssetID(); + if (old_id != new_id) + { + // texture has changed, close the floater to avoid DEV-22461 + texture_ctrl->closeFloater(); + } + texture_ctrl->setImageAssetID(new_id); + } +} + +static void set_enabled_color_swatch_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->setEnabled(enabled); + color_swatch_ctrl->setVisible(enabled); + } +} + +static void set_enabled_texture_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + texture_ctrl->setEnabled(enabled); + texture_ctrl->setVisible(enabled); + } +} + +class LLWearableSaveAsDialog : public LLModalDialog +{ +private: + std::string mItemName; + void (*mCommitCallback)(LLWearableSaveAsDialog*,void*); + void* mCallbackUserData; + LLPanelEditWearable* mParent; + +public: + LLWearableSaveAsDialog( const std::string& desc, LLPanelEditWearable* parent, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata ) + : LLModalDialog( LLStringUtil::null, 240, 100 ), + mCommitCallback( commit_cb ), + mCallbackUserData( userdata ), + mParent( parent ) + { + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml"); + + childSetAction("Save", LLWearableSaveAsDialog::onSave, this ); + childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this ); + + childSetTextArg("name ed", "[DESC]", desc); + } + ~LLWearableSaveAsDialog() + { + if(mParent && mParent->mActiveModal == this) + mParent->mActiveModal = NULL; + } + virtual void startModal() + { + LLModalDialog::startModal(); + LLLineEditor* edit = getChild("name ed"); + if (!edit) return; + edit->setFocus(TRUE); + edit->selectAll(); + } + + const std::string& getItemName() { return mItemName; } + + static void onSave( void* userdata ) + { + LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; + self->mItemName = self->childGetValue("name ed").asString(); + LLStringUtil::trim(self->mItemName); + if( !self->mItemName.empty() ) + { + if( self->mCommitCallback ) + { + self->mCommitCallback( self, self->mCallbackUserData ); + } + self->close(); // destroys this object + } + } + + static void onCancel( void* userdata ) + { + LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; + self->close(); // destroys this object + } +}; + +LLPanelEditWearable::LLPanelEditWearable( LLWearableType::EType type ) + + : LLPanel( LLWearableType::getTypeLabel( type ) ), + mType( type ), + mActiveModal( NULL ), + mCurrentIndex( 0 ), + mCurrentWearable( NULL ), + mPendingWearable( NULL ), + mPendingRefresh( false ) +{ +} +LLPanelEditWearable::~LLPanelEditWearable() +{ + if(mActiveModal) + { + mActiveModal->close(); + } +} + +BOOL LLPanelEditWearable::postBuild() +{ + std::string icon_name = LLInventoryIcon::getIconName(LLWearableType::getAssetType( mType ),LLInventoryType::IT_WEARABLE,mType,FALSE); + + childSetValue("icon", icon_name); + + childSetAction("Create New", LLPanelEditWearable::onBtnCreateNew, this ); + + // If PG, can't take off underclothing or shirt + mCanTakeOff = + LLWearableType::getAssetType( mType ) == LLAssetType::AT_CLOTHING && + !( gAgent.isTeen() && (mType == LLWearableType::WT_UNDERSHIRT || mType == LLWearableType::WT_UNDERPANTS) ); + childSetVisible("Take Off", mCanTakeOff); + childSetAction("Take Off", LLPanelEditWearable::onBtnTakeOff, this ); + + LLUICtrl* sex_radio = getChild("sex radio", true, false); + if(sex_radio) + { + sex_radio->setCommitCallback(boost::bind(&LLPanelEditWearable::onCommitSexChange,this)); + } + + childSetAction("Save", &LLPanelEditWearable::onBtnSave, (void*)this ); + + childSetAction("Save As", &LLPanelEditWearable::onBtnSaveAs, (void*)this ); + + childSetAction("Revert", &LLPanelEditWearable::onRevertButtonClicked, (void*)this ); + + configureAlphaCheckbox(LLVOAvatarDefines::TEX_LOWER_ALPHA, "lower alpha texture invisible"); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_UPPER_ALPHA, "upper alpha texture invisible"); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_HEAD_ALPHA, "head alpha texture invisible"); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_EYES_ALPHA, "eye alpha texture invisible"); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_HAIR_ALPHA, "hair alpha texture invisible"); + + { + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << mType << llendl; + } + U8 num_subparts = wearable_entry->mSubparts.size(); + + for (U8 index = 0; index < num_subparts; ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (!subpart_entry) + { + llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + continue; + } + + if(!subpart_entry->mButtonName.empty()) + { + llinfos << "Finding button " << subpart_entry->mButtonName << llendl; + llassert_always(getChild(subpart_entry->mButtonName,true,false)); + childSetAction(subpart_entry->mButtonName, &LLPanelEditWearable::onBtnSubpart, (void*)index); + } + } + // initialize texture and color picker controls + for_each_picker_ctrl_entry (this, mType, boost::bind(init_color_swatch_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(init_texture_ctrl, this, _1, _2)); + } + + LLTabContainer* tab = getChild("layer_tabs", true, false); + if(tab) + { + for(U32 i = 1; i <= LLAgentWearables::MAX_CLOTHING_PER_TYPE; ++i) + { + LLPanel* new_panel = new LLPanel(llformat("%i",i)); + tab->addTabPanel(new_panel, llformat("Layer %i",i)); + } + tab->setCommitCallback(boost::bind(&LLPanelEditWearable::onTabChanged, this, _1)); + tab->setValidateCallback(boost::bind(&LLPanelEditWearable::onTabPrecommit, this)); + } + + childSetTextArg("title_not_worn", "[DESC]", LLWearableType::getTypeLabel( mType )); + childSetTextArg("title_loading", "[DESC]", LLWearableType::getTypeLabel( mType )); + childSetTextArg("title_no_modify", "[DESC]", LLWearableType::getTypeLabel( mType )); + childSetTextArg("title", "[DESC]", LLWearableType::getTypeLabel( mType )); + return TRUE; +} + +BOOL LLPanelEditWearable::isDirty() const +{ + LLWearable* wearable = getWearable(); + return wearable && wearable->isDirty(); +} + +void LLPanelEditWearable::draw() +{ + if( gFloaterCustomize->isMinimized() || !isAgentAvatarValid()) + return; + + refreshWearables(false); + + LLWearable* wearable = getWearable(); + BOOL has_wearable = (wearable != NULL ); + BOOL has_any_wearable = has_wearable || gAgentWearables.getWearableCount(mType); + BOOL is_dirty = isDirty(); + BOOL is_modifiable = FALSE; + BOOL is_copyable = FALSE; + BOOL is_complete = FALSE; + LLInventoryItem* item = NULL; + if(wearable && (item = gInventory.getItem(wearable->getItemID()))) + { + const LLPermissions& perm = item->getPermissions(); + is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); + is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()); + is_complete = ((LLViewerInventoryItem*)item)->isComplete(); + } + + childSetEnabled("Save", has_wearable && is_modifiable && is_complete && is_dirty); + childSetEnabled("Save As", has_wearable && is_copyable && is_complete); + childSetEnabled("Revert", has_wearable && is_dirty ); + childSetEnabled("Take Off", has_wearable); + childSetVisible("Take Off", has_wearable && mCanTakeOff); + childSetVisible("Create New", !has_any_wearable); + childSetVisible("not worn instructions", !has_any_wearable); + childSetVisible("title_not_worn", !has_any_wearable); + childSetVisible("no modify instructions",has_wearable && !is_modifiable); + childSetVisible("title_no_modify", has_wearable && !is_modifiable); + childSetVisible("title", has_wearable && is_modifiable && is_complete); + childSetVisible("title_loading", (!has_wearable && has_any_wearable) || (has_wearable && is_modifiable && !is_complete)); + childSetVisible("path", has_wearable); + childSetVisible("square", has_wearable && !is_modifiable); //lock icon + + /*LLTabContainer* tab = getChild("layer_tabs", true, false); + if(tab) + { + tab->setEnabled(has_any_wearable); + tab->setVisible(has_any_wearable); + }*/ + + if(has_wearable && is_modifiable) + { + for_each_picker_ctrl_entry (this, mType, boost::bind(update_color_swatch_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(update_texture_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_complete, _1, _2)); + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->setEnabled(is_copyable && is_complete); + ctrl->setVisible(is_copyable && is_complete); + } + } + } + else + { + hideTextureControls(); + } + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (wearable_entry) + { + U8 num_subparts = wearable_entry->mSubparts.size(); + + for (U8 index = 0; index < num_subparts; ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (!subpart_entry) + { + llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + continue; + } + + childSetVisible(subpart_entry->mButtonName,has_wearable); + if( has_wearable && is_complete && is_modifiable ) + { + childSetEnabled(subpart_entry->mButtonName, subpart_entry->mSex & gAgentAvatarp->getSex() ); + } + else + { + childSetEnabled(subpart_entry->mButtonName, FALSE ); + } + } + } + + LLTextBox *av_height = getChild("avheight",FALSE,FALSE); + if(av_height) //Only display this if the element exists + { + // Display the shape's nominal height. + // + // The value for avsize is the best available estimate from + // measuring against prims. + float avsize = gAgentAvatarp->mBodySize.mV[VZ] + .195; + int inches = (int)(avsize / .0254f); + int feet = inches / 12; + inches %= 12; + + std::ostringstream avheight(std::ostringstream::trunc); + avheight << std::fixed << std::setprecision(2) << avsize << " m (" + << feet << "' " << inches << "\")"; + av_height->setVisible(TRUE); + av_height->setTextArg("[AVHEIGHT]",avheight.str()); + } + + LLPanel::draw(); +} + +void LLPanelEditWearable::setVisible(BOOL visible) +{ + LLPanel::setVisible( visible ); + if( !visible ) + { + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); + } +} + +void LLPanelEditWearable::onTabChanged(LLUICtrl* ctrl) +{ + if(mPendingWearable) + return; + U32 tab_index = ((LLTabContainer*)ctrl)->getCurrentPanelIndex(); + U32 wearable_index = gAgentWearables.getWearableCount(mType) - tab_index - 1; + if(wearable_index != mCurrentIndex ) + { + setWearableIndex(wearable_index); + } +} + +bool LLPanelEditWearable::onTabPrecommit() +{ + return !mPendingWearable; +} + +void LLPanelEditWearable::setWearableIndex(S32 index) +{ + if(mPendingWearable) + return; + + mCurrentIndex = index; + + LLTabContainer* tab = getChild("layer_tabs", true, false); + if(tab) + { + U32 tab_index = gAgentWearables.getWearableCount(mType) - index - 1; + + if(tab->getCurrentPanelIndex() != tab_index) + tab->selectTab(tab_index); + } + + LLWearable* wearable = gAgentWearables.getWearable(mType,mCurrentIndex); + + if(wearable == getWearable()) + return; + + mCurrentWearable = wearable; + + + if(wearable) + { + childSetTextArg("title", "[DESC]", wearable->getName() ); + childSetTextArg("title_no_modify", "[DESC]", wearable->getName()); + } + else + { + childSetTextArg("title", "[DESC]", std::string(LLWearableType::getTypeLabel( mType )) ); + childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); + } + + if(mActiveModal) + mActiveModal->close(); + + U32 perm_mask = wearable ? PERM_NONE : PERM_ALL; + BOOL is_complete = wearable ? FALSE : TRUE; + if(wearable) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(wearable->getItemID()); + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + if(!is_complete) + { + item->fetchFromServer(); + } + } + } + setUIPermissions(perm_mask, is_complete); + if (mType == LLWearableType::WT_ALPHA) + { + initPreviousAlphaTextures(); + updateAlphaCheckboxes(); + + } + + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart((ESubpart)mCurrentSubpart); + if(subpart_entry) + { + value_map_t sorted_params; + getSortedParams(sorted_params, subpart_entry->mEditGroup, ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE); + buildParamList(gFloaterCustomize->getScrollingPanelList(), sorted_params); + } + + if(wearable) + { + std::string path; + const LLUUID& item_id = wearable->getItemID(); + append_path(item_id, path); + childSetTextArg("path", "[PATH]", path); + } + + updateScrollingPanelList(); + +} + +void LLPanelEditWearable::refreshWearables(bool force_immediate) +{ + if(!force_immediate && !mPendingRefresh) + return; + + mPendingRefresh = false; + + U32 index; + if(mPendingWearable) + { + index = gAgentWearables.getWearableIndex(mPendingWearable); + if(index == LLAgentWearables::MAX_CLOTHING_PER_TYPE) + return; + mPendingWearable = NULL; + } + else + { + index = gAgentWearables.getWearableIndex(getWearable()); + if(index == LLAgentWearables::MAX_CLOTHING_PER_TYPE) + { + index = gAgentWearables.getWearableCount(mType); + if(index) + --index; + } + } + + + + LLTabContainer* tab = getChild("layer_tabs", true, false); + if(tab) + { + for(U32 i = 0; i < LLAgentWearables::MAX_CLOTHING_PER_TYPE; ++i) + { + tab->enableTabButton(i, i < gAgentWearables.getWearableCount(mType)); + } + } + setWearableIndex(index); +} + +void LLPanelEditWearable::wearablesChanged() +{ + mPendingRefresh = true; +} + +// static +void LLPanelEditWearable::onRevertButtonClicked( void* userdata ) +{ + LLPanelEditWearable *panel = (LLPanelEditWearable*) userdata; + panel->revertChanges(); +} + +void LLPanelEditWearable::onBtnSave( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + self->saveChanges(false); +} + +// static +void LLPanelEditWearable::onBtnSaveAs( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + if(self->mActiveModal) + return; + LLWearable* wearable = self->getWearable(); + if( wearable ) + { + self->mActiveModal = new LLWearableSaveAsDialog( wearable->getName(), self, onSaveAsCommit, self ); + self->mActiveModal->startModal(); + // LLWearableSaveAsDialog deletes itself. + } +} + +// static +void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + self->saveChanges(true, save_as_dialog->getItemName()); +} + +// static +void LLPanelEditWearable::onCommitSexChange() +{ + if (!isAgentAvatarValid()) return; + + LLWearableType::EType type = mType; // TODO: MULTI-WEARABLE + U32 index = mCurrentIndex; // TODO: MULTI-WEARABLE + + if( !gAgentWearables.isWearableModifiable(type, index)) + { + return; + } + + LLViewerVisualParam* param = static_cast(gAgentAvatarp->getVisualParam( "male" )); + if( !param ) + { + return; + } + + bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE; + LLWearable* wearable = gAgentWearables.getWearable(type, index); + if (wearable) + { + wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE); + } + param->setWeight( is_new_sex_male, FALSE ); + + gAgentAvatarp->updateSexDependentLayerSets( FALSE ); + + gAgentAvatarp->updateVisualParams(); + + updateScrollingPanelUI(); + + //if(!wearable) + //{ + // return; + //} + + + + //wearable->setVisualParamWeight(param->getID(), (new_sex == SEX_MALE), TRUE); + //wearable->writeToAvatar(); + //avatar->updateVisualParams(); + +// gFloaterCustomize->clearScrollingPanelList(); + + // Assumes that we're in the "Shape" Panel. + //self->setSubpart( SUBPART_SHAPE_WHOLE ); +} + + +// static +void LLPanelEditWearable::onBtnCreateNew( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLSD payload; + payload["wearable_type"] = (S32)self->getType(); + LLNotificationsUtil::add("AutoWearNewClothing", LLSD(), payload, &onSelectAutoWearOption); +} + +bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLVOAvatar* avatar = gAgentAvatarp; + if(avatar) + { + // Create a new wearable in the default folder for the wearable's asset type. + LLWearable* wearable = LLWearableList::instance().createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger() ); + LLAssetType::EType asset_type = wearable->getAssetType(); + + LLUUID folder_id; + // regular UI, items get created in normal folder + folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); + + // Only auto wear the new item if the AutoWearNewClothing checkbox is selected. + LLPointer cb = option == 0 ? + new WearOnAvatarCallback : NULL; + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), + asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), cb); + } + return false; +} + +LLWearable* LLPanelEditWearable::getWearable() const +{ + return mCurrentWearable;//gAgentWearables.getWearable(mType, mCurrentIndex); // TODO: MULTI-WEARABLE +} + + +void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) +{ + const LLTextureCtrl* texture_ctrl = dynamic_cast(ctrl); + if (!texture_ctrl) + { + llwarns << "got commit signal from not LLTextureCtrl." << llendl; + return; + } + + if (getWearable()) + { + LLWearableType::EType type = getWearable()->getType(); + const PickerControlEntryNamePredicate name_pred(texture_ctrl->getName()); + const LLEditWearableDictionary::PickerControlEntry* entry + = find_picker_ctrl_entry_if(type, name_pred); + if (entry) + { + // Set the new version + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID()); + if( image->getID() == IMG_DEFAULT ) + { + image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); + } + if (getWearable()) + { + U32 index = gAgentWearables.getWearableIndex(getWearable()); + gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index); + LLVisualParamHint::requestHintUpdates(); + gAgentAvatarp->wearableUpdated(type, FALSE); + } + if (mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) + { + mPreviousAlphaTexture[entry->mTextureIndex] = image->getID(); + } + } + else + { + llwarns << "could not get texture picker dictionary entry for wearable of type: " << type << llendl; + } + } +} + +void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* base_ctrl ) +{ + LLColorSwatchCtrl* ctrl = (LLColorSwatchCtrl*) base_ctrl; + + if (getWearable()) + { + LLWearableType::EType type = getWearable()->getType(); + const PickerControlEntryNamePredicate name_pred(ctrl->getName()); + const LLEditWearableDictionary::PickerControlEntry* entry + = find_picker_ctrl_entry_if(type, name_pred); + if (entry) + { + const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex); + const LLColor4& new_color = LLColor4(ctrl->getValue()); + if( old_color != new_color ) + { + getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); + LLVisualParamHint::requestHintUpdates(); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } + } + else + { + llwarns << "could not get color swatch dictionary entry for wearable of type: " << type << llendl; + } + } +} + + +void LLPanelEditWearable::hideTextureControls() +{ + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, FALSE, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->setEnabled(FALSE); + ctrl->setVisible(FALSE); + } + } +} + +void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name) +{ + if (!getWearable() || (!force_save_as && !isDirty())) + { + // do nothing if no unsaved changes + return; + } + + U32 index = gAgentWearables.getWearableIndex(getWearable()); + + if (force_save_as) + { + // the name of the wearable has changed, re-save wearable with new name + LLAppearanceMgr::instance().removeCOFItemLinks(getWearable()->getItemID(),false); + LLWearable* new_wearable = gAgentWearables.saveWearableAs(mType, index, new_name, FALSE); + if(new_wearable) + { + mPendingWearable = new_wearable; + mCurrentWearable = new_wearable; + childSetTextArg("title", "[DESC]", new_wearable->getName()); + childSetTextArg("title_no_modify", "[DESC]", new_wearable->getName()); + } + } + else + { + gAgentWearables.saveWearable(mType, index, TRUE, new_name); + } +} + +void LLPanelEditWearable::revertChanges() +{ + LLWearable* wearable = getWearable(); + if (!wearable || !isDirty()) + { + // no unsaved changes to revert + return; + } + + wearable->revertValues(); + childSetTextArg("title", "[DESC]", wearable->getName() ); + gAgentAvatarp->wearableUpdated(mType, FALSE); + if (mType == LLWearableType::WT_ALPHA) + { + updateAlphaCheckboxes(); + } +} + +void LLPanelEditWearable::showDefaultSubpart() +{ + refreshWearables(true); + changeCamera(0); +} + + + +void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) +{ + BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE; + BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE; + + childSetEnabled("Save", is_modifiable && is_complete); + childSetEnabled("Save As", is_copyable && is_complete); + childSetEnabled("sex radio", is_modifiable && is_complete); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_copyable && is_modifiable && is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_modifiable && is_complete, _1, _2)); + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->setEnabled(is_copyable && is_modifiable && is_complete); + ctrl->setVisible(is_copyable && is_modifiable && is_complete); + } + } +} + +// static +void LLPanelEditWearable::onBtnSubpart(void* userdata) +{ + LLFloaterCustomize* floater_customize = gFloaterCustomize; + if (!floater_customize) return; + LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel(); + if (!self) return; + self->changeCamera( (S32)(intptr_t)userdata ); +} + +void LLPanelEditWearable::changeCamera(U8 subpart) +{ + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (!wearable_entry) + { + llinfos << "could not get wearable dictionary entry for wearable type: " << mType << llendl; + return; + } + + if (subpart >= wearable_entry->mSubparts.size()) + { + llinfos << "accordion tab expanded for invalid subpart. Wearable type: " << mType << " subpart num: " << subpart << llendl; + return; + } + + ESubpart subpart_e = wearable_entry->mSubparts[subpart]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (!subpart_entry) + { + llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + return; + } + + mCurrentSubpart = subpart_e; + //Update the buttons to reflect the current selected subpart. + for (U8 index = 0; index < wearable_entry->mSubparts.size(); ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (subpart_entry) + { + LLButton* btn = getChild(subpart_entry->mButtonName); + { + btn->setToggleState( subpart == subpart_e ); + } + } + } + + // Update the thumbnails we display + LLWearable* wearable = getWearable(); + LLViewerInventoryItem* item = wearable ? gInventory.getItem(wearable->getItemID()) : NULL; + U32 perm_mask = 0x0; + BOOL is_complete = FALSE; + bool can_export = false; + bool can_import = false; + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + + if (subpart_e < SUBPART_EYES) // body parts only + { + can_import = true; + + if (is_complete && + gAgent.getID() == item->getPermissions().getOwner() && + gAgent.getID() == item->getPermissions().getCreator() && + (PERM_ITEM_UNRESTRICTED & + perm_mask) == PERM_ITEM_UNRESTRICTED) + { + can_export = true; + } + } + } + setUIPermissions(perm_mask, is_complete); + + value_map_t sorted_params; + getSortedParams(sorted_params, subpart_entry->mEditGroup, ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE); + buildParamList(gFloaterCustomize->getScrollingPanelList(), sorted_params); + updateScrollingPanelUI(); + gFloaterCustomize->childSetEnabled("Export", can_export); + gFloaterCustomize->childSetEnabled("Import", can_import); + + // Update the camera + gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) ); + gMorphView->setCameraTargetOffset( subpart_entry->mTargetOffset ); + gMorphView->setCameraOffset( subpart_entry->mCameraOffset ); + gMorphView->setCameraDistToDefault(); + if (gSavedSettings.getBOOL("AppearanceCameraMovement")) + { + gMorphView->updateCamera(); + } +} + +void LLPanelEditWearable::updateScrollingPanelList() +{ + updateScrollingPanelUI(); +} + +void LLPanelEditWearable::updateScrollingPanelUI() +{ + LLWearable* wearable = getWearable(); + // do nothing if we don't have a valid wearable we're editing + if(!wearable) + { + return; + } + + llinfos << llformat("%#.8lX",wearable) << llendl; + llinfos << "cur_wearable->isDirty()=" << wearable->isDirty() << llendl; + + LLViewerInventoryItem* item = gInventory.getItem(wearable->getItemID()); + if(item) + { + U32 perm_mask = item->getPermissions().getMaskOwner(); + BOOL is_complete = item->isComplete(); + LLScrollingPanelParam::sUpdateDelayFrames = 0; + gFloaterCustomize->getScrollingPanelList()->updatePanels((perm_mask & PERM_MODIFY) && is_complete); + } +} + +// static +void LLPanelEditWearable::onBtnTakeOff( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + + LLWearable* wearable = self->getWearable(); + if( !wearable ) + { + return; + } + + LLAppearanceMgr::instance().removeItemFromAvatar(wearable->getItemID()); + self->refreshWearables(true); +} + +// static +void LLPanelEditWearable::getSortedParams(value_map_t &sorted_params, const std::string &edit_group, bool editable) +{ + if(!getWearable())return; + + LLWearable::visual_param_vec_t param_list; + ESex avatar_sex = gAgentAvatarp->getSex(); + + getWearable()->getVisualParams(param_list); + + for (LLWearable::visual_param_vec_t::iterator iter = param_list.begin(); + iter != param_list.end(); + ++iter) + { + LLViewerVisualParam *param = (LLViewerVisualParam*) *iter; + + if (param->getID() == -1 + || !param->isTweakable() + || param->getEditGroup() != edit_group + || !(param->getSex() & avatar_sex)) + { + continue; + } + + // negative getDisplayOrder() to make lowest order the highest priority + value_map_t::value_type vt(-param->getDisplayOrder(), editable_param(editable, param)); + llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates + sorted_params.insert(vt); + } +} + +void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params) +{ + // sorted_params is sorted according to magnitude of effect from + // least to greatest. Adding to the front of the child list + // reverses that order. + if( panel_list ) + { + panel_list->clearPanels(); + value_map_t::iterator end = sorted_params.end(); + for(value_map_t::iterator it = sorted_params.begin(); it != end; ++it) + { + LLScrollingPanelParam *panel_param = NULL; + panel_param = new LLScrollingPanelParam( "LLScrollingPanelParam", NULL, (*it).second.second, (*it).second.first, getWearable(), (mType != LLWearableType::WT_PHYSICS)); + panel_list->addPanel( panel_param ); + } + } +} + +void LLPanelEditWearable::configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name) +{ + LLCheckBoxCtrl* checkbox = getChild(name, true, false); + if(checkbox) + { + checkbox->setCommitCallback(boost::bind(&LLPanelEditWearable::onInvisibilityCommit, this, checkbox, te)); + initPreviousAlphaTextureEntry(te); + mAlphaCheckbox2Index[name] = te; + } +} + +void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te) +{ + if (!checkbox_ctrl) return; + if (!getWearable()) return; + + llinfos << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << llendl; + + bool new_invis_state = checkbox_ctrl->get(); + if (new_invis_state) + { + LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te); + mPreviousAlphaTexture[te] = lto->getID(); + + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE ); + U32 index = gAgentWearables.getWearableIndex(getWearable()); + gAgentAvatarp->setLocalTexture(te, image, FALSE, index); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } + else + { + // Try to restore previous texture, if any. + LLUUID prev_id = mPreviousAlphaTexture[te]; + if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) + { + prev_id = LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ); + } + if (prev_id.isNull()) return; + + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); + if (!image) return; + + U32 index = gAgentWearables.getWearableIndex(getWearable()); + gAgentAvatarp->setLocalTexture(te, image, FALSE, index); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } +} + +void LLPanelEditWearable::updateAlphaCheckboxes() +{ + if(!getWearable())return; + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLVOAvatarDefines::ETextureIndex te = (LLVOAvatarDefines::ETextureIndex)iter->second; + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->set(!gAgentAvatarp->isTextureVisible(te, getWearable())); + } + } +} + +void LLPanelEditWearable::initPreviousAlphaTextures() +{ + initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA); + initPreviousAlphaTextureEntry(TEX_UPPER_ALPHA); + initPreviousAlphaTextureEntry(TEX_HEAD_ALPHA); + initPreviousAlphaTextureEntry(TEX_EYES_ALPHA); + initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA); +} + +void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLVOAvatarDefines::ETextureIndex te) +{ + if(!getWearable()) + return; + LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te); + if (lto) + { + mPreviousAlphaTexture[te] = lto->getID(); + } +} diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h new file mode 100644 index 000000000..d1877ecaf --- /dev/null +++ b/indra/newview/llpaneleditwearable.h @@ -0,0 +1,141 @@ +/** + * @file llpaneleditwearable.h + * @brief A LLPanel dedicated to the editing of wearables. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELEDITWEARABLE_H +#define LL_LLPANELEDITWEARABLE_H + +#include "llpanel.h" +#include "llscrollingpanellist.h" +#include "llmodaldialog.h" +#include "llvoavatardefines.h" +#include "llwearabletype.h" + +class LLAccordionCtrl; +class LLCheckBoxCtrl; +class LLWearable; +class LLTextBox; +class LLViewerInventoryItem; +class LLViewerVisualParam; +class LLVisualParamHint; +class LLViewerJointMesh; +class LLAccordionCtrlTab; +class LLJoint; +class LLLineEditor; +class LLSubpart; +class LLWearableSaveAsDialog; + +using namespace LLVOAvatarDefines; + +class LLPanelEditWearable : public LLPanel +{ +public: + LLPanelEditWearable( LLWearableType::EType type ); + virtual ~LLPanelEditWearable(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL isDirty() const; // LLUICtrl + /*virtual*/ void draw(); + + // changes camera angle to default for selected subpart + void changeCamera(U8 subpart); + + const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); } + LLWearableType::EType getType() const{ return mType; } + LLWearable* getWearable() const; + + void onTabChanged(LLUICtrl* ctrl); + bool onTabPrecommit(); + + void setWearableIndex(S32 index); + void refreshWearables(bool force_immediate); + void wearablesChanged(); + + void saveChanges(bool force_save_as = false, std::string new_name = std::string()); + + void setUIPermissions(U32 perm_mask, BOOL is_complete); + + void hideTextureControls(); + void revertChanges(); + + void showDefaultSubpart(); + + void updateScrollingPanelList(); + + static void onRevertButtonClicked( void* userdata ); + void onCommitSexChange(); + + virtual void setVisible( BOOL visible ); + + typedef std::pair editable_param; + typedef std::map value_map_t; + + void updateScrollingPanelUI(); + void getSortedParams(value_map_t &sorted_params, const std::string &edit_group, bool editable); + void buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params); + + // Callbacks + static void onBtnSubpart( void* userdata ); + static void onBtnTakeOff( void* userdata ); + static void onBtnSave( void* userdata ); + + static void onBtnSaveAs( void* userdata ); + static void onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ); + + static void onBtnTakeOffDialog( S32 option, void* userdata ); + static void onBtnCreateNew( void* userdata ); + static bool onSelectAutoWearOption(const LLSD& notification, const LLSD& response); + + void onColorSwatchCommit(const LLUICtrl*); + void onTexturePickerCommit(const LLUICtrl*); + + //alpha mask checkboxes + void configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name); + void onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te); + void updateAlphaCheckboxes(); + void initPreviousAlphaTextures(); + void initPreviousAlphaTextureEntry(LLVOAvatarDefines::ETextureIndex te); + +private: + + LLWearableType::EType mType; + BOOL mCanTakeOff; + typedef std::map string_texture_index_map_t; + string_texture_index_map_t mAlphaCheckbox2Index; + + typedef std::map s32_uuid_map_t; + s32_uuid_map_t mPreviousAlphaTexture; + U32 mCurrentSubpart; + U32 mCurrentIndex; + LLWearable* mCurrentWearable; + LLWearable* mPendingWearable; //For SaveAs. There's a period where the old wearable will be removed, but the new one will still be pending, + //so this is needed to retain focus on this wearables tab over the messy transition. + bool mPendingRefresh; //LLAgentWearables::setWearableOutfit fires a buttload of remove/wear calls which spams wearablesChanged + //a bazillion pointless (and not particularly valid) times. Deferring to draw effectively sorts it all out. +public: + LLModalDialog* mActiveModal; +}; + +#endif diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index b1e55d30c..49b59720d 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -250,10 +250,8 @@ BOOL LLPanelGroup::postBuild() // Pass on whether or not to allow edit to tabs. panelp->setAllowEdit(mAllowEdit); panelp->addObserver(this); - - mTabContainer->setTabChangeCallback(panelp, onClickTab); - mTabContainer->setTabUserData(panelp, this); } + mTabContainer->setCommitCallback(boost::bind(&LLPanelGroup::handleClickTab,this)); updateTabVisibility(); // Act as though this tab was just activated. @@ -321,13 +319,6 @@ void LLPanelGroup::tabChanged() } } -// static -void LLPanelGroup::onClickTab(void* user_data, bool from_click) -{ - LLPanelGroup* self = static_cast(user_data); - self->handleClickTab(); -} - void LLPanelGroup::handleClickTab() { // If we are already handling a transition, @@ -377,7 +368,7 @@ void LLPanelGroup::selectTab(std::string tab_name) if ( tabp && mTabContainer ) { mTabContainer->selectTabPanel(tabp); - onClickTab(this, false); + handleClickTab(); } } diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index 445fb2850..52cb72f36 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -70,7 +70,6 @@ public: static void onBtnCancel(void*); static void onBtnApply(void*); static void onBtnRefresh(void*); - static void onClickTab(void*,bool); void handleClickTab(); void setGroupID(const LLUUID& group_id); diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp index fa0432b6c..4baa6cd8b 100644 --- a/indra/newview/llpanelgrouplandmoney.cpp +++ b/indra/newview/llpanelgrouplandmoney.cpp @@ -82,7 +82,7 @@ public: static void clickEarlierCallback(void* data); static void clickLaterCallback(void* data); - static void clickTabCallback(void* user_data, bool from_click); + void clickTabCallback(const LLSD ¶m); static LLMap sInstanceIDs; static std::map sTabsToHandlers; @@ -924,8 +924,7 @@ LLGroupMoneyTabEventHandler::LLGroupMoneyTabEventHandler(LLButton* earlier_butto if ( tab_containerp && panelp ) { - tab_containerp->setTabChangeCallback(panelp, clickTabCallback); - tab_containerp->setTabUserData(panelp, this); + tab_containerp->setCommitCallback(boost::bind(&LLGroupMoneyTabEventHandler::clickTabCallback, this, _2)); } sInstanceIDs.addData(mImplementationp->mPanelID, this); @@ -997,11 +996,10 @@ void LLGroupMoneyTabEventHandler::clickLaterCallback(void* data) if ( selfp ) selfp->onClickLater(); } -//static -void LLGroupMoneyTabEventHandler::clickTabCallback(void* data, bool from_click) +void LLGroupMoneyTabEventHandler::clickTabCallback(const LLSD& param) { - LLGroupMoneyTabEventHandler* selfp = (LLGroupMoneyTabEventHandler*) data; - if ( selfp ) selfp->onClickTab(); + if(param.asString() == "group_money_details_tab") + onClickTab(); } // ************************************************** diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index cf07b5edb..155ab8dde 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -147,10 +147,6 @@ BOOL LLPanelGroupRoles::postBuild() { LLPanelGroupSubTab* subtabp = (LLPanelGroupSubTab*) mSubTabContainer->getPanelByIndex(i); - // Add click callbacks to all the tabs. - mSubTabContainer->setTabChangeCallback(subtabp, onClickSubTab); - mSubTabContainer->setTabUserData(subtabp, this); - // Hand the subtab a pointer to this LLPanelGroupRoles, so that it can // look around for the widgets it is interested in. if (!subtabp->postBuildSubTab(this)) return FALSE; @@ -158,6 +154,9 @@ BOOL LLPanelGroupRoles::postBuild() subtabp->addObserver(this); } + // Add click callbacks to all the tabs. + mSubTabContainer->setCommitCallback(boost::bind(&LLPanelGroupRoles::handleClickSubTab,this)); + // Set the current tab to whatever is currently being shown. mCurrentTab = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel(); if (!mCurrentTab) @@ -198,13 +197,6 @@ BOOL LLPanelGroupRoles::isVisibleByAgent(LLAgent* agentp) } -// static -void LLPanelGroupRoles::onClickSubTab(void* user_data, bool from_click) -{ - LLPanelGroupRoles* self = static_cast(user_data); - self->handleClickSubTab(); -} - void LLPanelGroupRoles::handleClickSubTab() { // If we are already handling a transition, diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 3083c2d56..8ceac9b44 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -64,7 +64,6 @@ public: virtual BOOL isVisibleByAgent(LLAgent* agentp); static void* createTab(void* data); - static void onClickSubTab(void*,bool); void handleClickSubTab(); // Checks if the current tab needs to be applied, and tries to switch to the requested tab. diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index ac746097b..d2cbb0ca2 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -215,9 +215,7 @@ BOOL LLInventoryView::postBuild() sActiveViews.put(this); - childSetTabChangeCallback("inventory filter tabs", "All Items", onFilterSelected, this); - childSetTabChangeCallback("inventory filter tabs", "Recent Items", onFilterSelected, this); - childSetTabChangeCallback("inventory filter tabs", "Worn Items", onFilterSelected, this); + getChild("inventory filter tabs")->setCommitCallback(boost::bind(&LLInventoryView::onFilterSelected,this)); childSetAction("Inventory.ResetAll",onResetAll,this); childSetAction("Inventory.ExpandAll",onExpandAll,this); @@ -764,21 +762,19 @@ void LLInventoryView::onCollapseAll(void* userdata) self->mActivePanel->closeAllFolders(); } -//static -void LLInventoryView::onFilterSelected(void* userdata, bool from_click) +void LLInventoryView::onFilterSelected() { - LLInventoryView* self = (LLInventoryView*) userdata; // Find my index - self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs"); + mActivePanel = (LLInventoryPanel*)childGetVisibleTab("inventory filter tabs"); - if (!self->mActivePanel) + if (!mActivePanel) { return; } - //self->setFilterSubString(self->mFilterSubString); - LLInventoryFilter* filter = self->mActivePanel->getFilter(); - LLFloaterInventoryFinder *finder = self->getFinder(); + //>setFilterSubString(self->mFilterSubString); + LLInventoryFilter* filter = mActivePanel->getFilter(); + LLFloaterInventoryFinder *finder = getFinder(); if (finder) { finder->changeFilter(filter); @@ -788,8 +784,8 @@ void LLInventoryView::onFilterSelected(void* userdata, bool from_click) // If our filter is active we may be the first thing requiring a fetch so we better start it here. LLInventoryModelBackgroundFetch::instance().start(); } - self->setFilterTextFromFilter(); - self->updateSortControls(); + setFilterTextFromFilter(); + updateSortControls(); } const std::string LLInventoryView::getFilterSubString() @@ -862,7 +858,7 @@ void LLInventoryView::updateItemcountText() { std::ostringstream title; title << "Inventory"; - if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive()) + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive()) { LLLocale locale(LLLocale::USER_LOCALE); std::string item_count_string; diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 44f6c7f09..dee764118 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -107,7 +107,7 @@ public: static BOOL checkFoldersByName(void *user_data); - static void onFilterSelected(void* userdata, bool from_click); + void onFilterSelected(); const std::string getFilterSubString(); void setFilterSubString(const std::string& string); diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index bdda36cfd..fbcd93912 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -510,8 +510,7 @@ BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask) } mCharacter->updateVisualParams(); } - if(physics_unsupported) //Only use emerald physics if avatarphysiscs is really off, or the client doesn't seem to support new physics. - ((LLVOAvatar*)mCharacter)->idleUpdateBoobEffect(); //Fall back to emerald physics + ((LLVOAvatar*)mCharacter)->idleUpdateBoobEffect(); //Emerald physics will fix params it altered if wearable physics are disabled. return TRUE; } diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index afc2a3c77..aa6905f2b 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -577,7 +577,7 @@ void LLMultiPreview::handleReshape(const LLRect& new_rect, bool by_user) } -void LLMultiPreview::tabOpen(LLFloater* opened_floater, bool from_click) +void LLMultiPreview::tabOpen(LLFloater* opened_floater) { LLPreview* opened_preview = (LLPreview*)opened_floater; if (opened_preview && opened_preview->getAssetStatus() == LLPreview::PREVIEW_ASSET_UNLOADED) diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h index ed6bb3087..02184af85 100644 --- a/indra/newview/llpreview.h +++ b/indra/newview/llpreview.h @@ -53,7 +53,7 @@ public: LLMultiPreview(const LLRect& rect); /*virtual*/void open(); /*Flawfinder: ignore*/ - /*virtual*/void tabOpen(LLFloater* opened_floater, bool from_click); + /*virtual*/void tabOpen(LLFloater* opened_floater); /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); static LLMultiPreview* getAutoOpenInstance(const LLUUID& id); diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp new file mode 100644 index 000000000..88127e68f --- /dev/null +++ b/indra/newview/llscrollingpanelparam.cpp @@ -0,0 +1,322 @@ +/** + * @file llscrollingpanelparam.cpp + * @brief UI panel for a list of visual param panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llscrollingpanelparam.h" +#include "llviewerjointmesh.h" +#include "llviewervisualparam.h" +#include "llwearable.h" +#include "llviewervisualparam.h" +#include "lltoolmorph.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llviewborder.h" +#include "llvoavatarself.h" +#include "llagentwearables.h" +#include "llfloatercustomize.h" + +// Constants for LLPanelVisualParam +const F32 LLScrollingPanelParam::PARAM_STEP_TIME_THRESHOLD = 0.25f; + +const S32 LLScrollingPanelParam::PARAM_HINT_WIDTH = 128; +const S32 LLScrollingPanelParam::PARAM_HINT_HEIGHT = 128; + +const S32 BTN_BORDER = 2; +const S32 PARAM_HINT_LABEL_HEIGHT = 16; +const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + LLScrollingPanelParam::PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH); +const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + LLScrollingPanelParam::PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; + +// LLScrollingPanelParam +//static +S32 LLScrollingPanelParam::sUpdateDelayFrames = 0; + +LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, bool bVisualHint ) + : LLScrollingPanelParamBase( name, mesh, param, allow_modify, wearable, bVisualHint, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 )), + mLess(NULL), + mMore(NULL) +{ + + if(bVisualHint) + { + S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; + S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT; + F32 min_weight = param->getMinWeight(); + F32 max_weight = param->getMaxWeight(); + + mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, mWearable, min_weight); + pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; + mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, mWearable, max_weight ); + + mHintMin->setAllowsUpdates( FALSE ); + mHintMax->setAllowsUpdates( FALSE ); + + // *TODO::translate + std::string min_name = param->getMinDisplayName(); + std::string max_name = param->getMaxDisplayName(); + childSetValue("min param text", min_name); + childSetValue("max param text", max_name); + mLess = getChild("less"); + mLess->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, false) ); + mLess->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, false) ); + mLess->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, false) ); + mLess->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + + mMore = getChild("more"); + mMore->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, true) ); + mMore->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, true) ); + mMore->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, true) ); + mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + } + + setVisible(FALSE); + setBorderVisible( FALSE ); +} + +LLScrollingPanelParam::~LLScrollingPanelParam() +{ + mHintMin = NULL; + mHintMax = NULL; +} + +void LLScrollingPanelParam::updatePanel(BOOL allow_modify) +{ + if(!mWearable) + { + // not editing a wearable just now, no update necessary + return; + } + + LLScrollingPanelParamBase::updatePanel(allow_modify); + + if(mHintMin) + mHintMin->requestUpdate( sUpdateDelayFrames++ ); + if(mHintMax) + mHintMax->requestUpdate( sUpdateDelayFrames++ ); + + if(mLess) + mLess->setEnabled(mAllowModify); + if(mMore) + mMore->setEnabled(mAllowModify); +} + +void LLScrollingPanelParam::setVisible( BOOL visible ) +{ + if( getVisible() != visible ) + { + LLPanel::setVisible( visible ); + if(mHintMin) + mHintMin->setAllowsUpdates( visible ); + if(mHintMax) + mHintMax->setAllowsUpdates( visible ); + + if( visible ) + { + if(mHintMin) + mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ ); + if(mHintMax) + mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ ); + } + } +} + +void LLScrollingPanelParam::draw() +{ + if( !mWearable || gFloaterCustomize->isMinimized() ) + { + return; + } + + if(mLess) + mLess->setVisible(mHintMin && mHintMin->getVisible()); + if(mMore) + mMore->setVisible(mHintMax && mHintMax->getVisible()); + + // Draw all the children except for the labels + childSetVisible( "min param text", FALSE ); + childSetVisible( "max param text", FALSE ); + LLPanel::draw(); + + // Draw the hints over the "less" and "more" buttons. + if(mHintMin) + { + gGL.pushMatrix(); + { + const LLRect& r = mHintMin->getRect(); + F32 left = (F32)(r.mLeft + BTN_BORDER); + F32 bot = (F32)(r.mBottom + BTN_BORDER); + gGL.translatef(left, bot, 0.f); + mHintMin->draw(); + } + gGL.popMatrix(); + } + + if(mHintMax) + { + gGL.pushMatrix(); + { + const LLRect& r = mHintMax->getRect(); + F32 left = (F32)(r.mLeft + BTN_BORDER); + F32 bot = (F32)(r.mBottom + BTN_BORDER); + gGL.translatef(left, bot, 0.f); + mHintMax->draw(); + } + gGL.popMatrix(); + } + + + // Draw labels on top of the buttons + childSetVisible( "min param text", TRUE ); + drawChild(getChild("min param text"), BTN_BORDER, BTN_BORDER); + + childSetVisible( "max param text", TRUE ); + drawChild(getChild("max param text"), BTN_BORDER, BTN_BORDER); +} + +// static +void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata) +{ +} + +// static +void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata) +{ + LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; + LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); +} + +void LLScrollingPanelParam::onHintMouseDown( bool max ) +{ + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + LLViewerVisualParam* param = hint->getVisualParam(); + + if(!mWearable || !param) + { + return; + } + + // morph towards this result + F32 current_weight = mWearable->getVisualParamWeight( hint->getVisualParam()->getID() ); + + // if we have maxed out on this morph, we shouldn't be able to click it + if( hint->getVisualParamWeight() != current_weight ) + { + mMouseDownTimer.reset(); + mLastHeldTime = 0.f; + } +} + +void LLScrollingPanelParam::onHintHeldDown( bool max ) +{ + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + LLViewerVisualParam* param = hint->getVisualParam(); + + if(!mWearable || !param) + { + return; + } + + F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); + + if (current_weight != hint->getVisualParamWeight() ) + { + const F32 FULL_BLEND_TIME = 2.f; + F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime; + mLastHeldTime += elapsed_time; + + F32 new_weight; + if (current_weight > hint->getVisualParamWeight() ) + { + new_weight = current_weight - (elapsed_time / FULL_BLEND_TIME); + } + else + { + new_weight = current_weight + (elapsed_time / FULL_BLEND_TIME); + } + + // Make sure we're not taking the slider out of bounds + // (this is where some simple UI limits are stored) + F32 new_percent = weightToPercent(new_weight); + LLSliderCtrl* slider = getChild("param slider"); + if (slider) + { + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + mWearable->setVisualParamWeight(param->getID(), new_weight, FALSE); + mWearable->writeToAvatar(); + gAgentAvatarp->updateVisualParams(); + + slider->setValue( weightToPercent( new_weight ) ); + } + } + } +} + +void LLScrollingPanelParam::onHintMouseUp( bool max ) +{ + F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32(); + + if (isAgentAvatarValid()) + { + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + + if (elapsed_time < PARAM_STEP_TIME_THRESHOLD) + { + LLViewerVisualParam* param = hint->getVisualParam(); + + if(mWearable) + { + // step in direction + F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); + F32 range = mHintMax->getVisualParamWeight() - mHintMin->getVisualParamWeight(); + //if min, range should be negative. + if(!max) + range *= -1.f; + // step a fraction in the negative direction + F32 new_weight = current_weight + (range / 10.f); + F32 new_percent = weightToPercent(new_weight); + LLSliderCtrl* slider = getChild("param slider"); + if (slider) + { + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + mWearable->setVisualParamWeight(param->getID(), new_weight, FALSE); + mWearable->writeToAvatar(); + slider->setValue( weightToPercent( new_weight ) ); + } + } + } + } + } + + LLVisualParamHint::requestHintUpdates( mHintMin, mHintMax ); +} + diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h new file mode 100644 index 000000000..8c02e5fa6 --- /dev/null +++ b/indra/newview/llscrollingpanelparam.h @@ -0,0 +1,75 @@ +/** + * @file llscrollingpanelparam.h + * @brief the scrolling panel containing a list of visual param + * panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_SCROLLINGPANELPARAM_H +#define LL_SCROLLINGPANELPARAM_H + +#include "llscrollingpanelparambase.h" + +class LLViewerJointMesh; +class LLViewerVisualParam; +class LLWearable; +class LLVisualParamHint; +class LLViewerVisualParam; +class LLJoint; + +class LLScrollingPanelParam : public LLScrollingPanelParamBase +{ +public: + LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, bool bVisualHint ); + virtual ~LLScrollingPanelParam(); + + virtual void draw(); + virtual void setVisible( BOOL visible ); + virtual void updatePanel(BOOL allow_modify); + + static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata); + static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata); + + void onHintMouseUp( bool max ); + void onHintMouseDown( bool max ); + void onHintHeldDown( bool max ); + +public: + // Constants for LLPanelVisualParam + const static F32 PARAM_STEP_TIME_THRESHOLD; + + const static S32 PARAM_HINT_WIDTH; + const static S32 PARAM_HINT_HEIGHT; + LLPointer mHintMin; + LLPointer mHintMax; + LLButton* mLess; + LLButton* mMore; + static S32 sUpdateDelayFrames; + +protected: + LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. + F32 mLastHeldTime; +}; + + +#endif diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp new file mode 100644 index 000000000..0a83ac44a --- /dev/null +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -0,0 +1,138 @@ +/** + * @file llscrollingpanelparam.cpp + * @brief UI panel for a list of visual param panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llscrollingpanelparambase.h" +#include "llviewerjointmesh.h" +#include "llviewervisualparam.h" +#include "llwearable.h" +#include "llviewervisualparam.h" +#include "lltoolmorph.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llviewborder.h" +#include "llvoavatarself.h" +#include "llagentwearables.h" + +LLScrollingPanelParamBase::LLScrollingPanelParamBase( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, bool bVisualHint, LLRect rect ) + : LLScrollingPanel( name, rect ), + mParam(param), + mAllowModify(allow_modify), + mWearable(wearable) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); + //Set up the slider + LLSliderCtrl *slider = getChild("param slider"); + + //Kill everything that isn't the slider... + if(!bVisualHint) + { + child_list_t to_remove; + child_list_t::const_iterator it; + for (it = getChildList()->begin(); it != getChildList()->end(); it++) + { + if ((*it) != slider && (*it)->getName() != "panel border") + { + to_remove.push_back(*it); + } + } + for (it = to_remove.begin(); it != to_remove.end(); it++) + { + removeChild(*it); + delete (*it); + } + slider->translate(0,/*PARAM_HINT_HEIGHT*/128); + reshape(getRect().getWidth(),getRect().getHeight()-128); + } + + slider->setValue(weightToPercent(param->getWeight())); + slider->setLabelArg("[DESC]", param->getDisplayName()); + slider->setEnabled(mAllowModify); + slider->setCommitCallback(boost::bind(&LLScrollingPanelParamBase::onSliderMoved, this, _1)); + + setVisible(FALSE); + setBorderVisible( FALSE ); +} + +LLScrollingPanelParamBase::~LLScrollingPanelParamBase() +{ +} + +void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify) +{ + LLViewerVisualParam* param = mParam; + + if(!mWearable) + { + // not editing a wearable just now, no update necessary + return; + } + + F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); + childSetValue("param slider", weightToPercent( current_weight ) ); + mAllowModify = allow_modify; + childSetEnabled("param slider", mAllowModify); +} + +void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl) +{ + if(!mParam) + { + return; + } + + if(!mWearable) + { + return; + } + + LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; + + F32 current_weight = mWearable->getVisualParamWeight(mParam->getID()); + F32 new_weight = percentToWeight( (F32)slider->getValue().asReal() ); + if (current_weight != new_weight ) + { + mWearable->setVisualParamWeight( mParam->getID(), new_weight, FALSE); + mWearable->writeToAvatar(); + gAgentAvatarp->updateVisualParams(); + } +} + +F32 LLScrollingPanelParamBase::weightToPercent( F32 weight ) +{ + LLViewerVisualParam* param = mParam; + return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; +} + +F32 LLScrollingPanelParamBase::percentToWeight( F32 percent ) +{ + LLViewerVisualParam* param = mParam; + return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); +} diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h new file mode 100644 index 000000000..d114f622d --- /dev/null +++ b/indra/newview/llscrollingpanelparambase.h @@ -0,0 +1,62 @@ +/** + * @file llscrollingpanelparam.h + * @brief the scrolling panel containing a list of visual param + * panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_SCROLLINGPANELPARAMBASE_H +#define LL_SCROLLINGPANELPARAMBASE_H + +#include "llpanel.h" +#include "llscrollingpanellist.h" + +class LLViewerJointMesh; +class LLViewerVisualParam; +class LLWearable; +class LLVisualParamHint; +class LLViewerVisualParam; +class LLJoint; + +class LLScrollingPanelParamBase : public LLScrollingPanel +{ +public: + LLScrollingPanelParamBase( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, bool bVisualHint, LLRect rect ); + virtual ~LLScrollingPanelParamBase(); + + virtual void updatePanel(BOOL allow_modify); + + void onSliderMoved(LLUICtrl* ctrl); + + F32 weightToPercent( F32 weight ); + F32 percentToWeight( F32 percent ); + +public: + LLViewerVisualParam* mParam; +protected: + BOOL mAllowModify; + LLWearable *mWearable; +}; + +#endif diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 91ef5123e..2d476dfbb 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -90,12 +90,32 @@ static F32 sCurMaxTexPriority = 1.f; class LLOcclusionQueryPool : public LLGLNamePool { +public: + LLOcclusionQueryPool() + { + mCurQuery = 1; + } + protected: + + std::list mAvailableName; + GLuint mCurQuery; + virtual GLuint allocateName() { - GLuint name; - glGenQueriesARB(1, &name); - return name; + GLuint ret = 0; + + if (!mAvailableName.empty()) + { + ret = mAvailableName.front(); + mAvailableName.pop_front(); + } + else + { + ret = mCurQuery++; + } + + return ret; } virtual void releaseName(GLuint name) @@ -103,7 +123,8 @@ protected: #if LL_TRACK_PENDING_OCCLUSION_QUERIES LLSpatialGroup::sPendingQueries.erase(name); #endif - glDeleteQueriesARB(1, &name); + llassert(std::find(mAvailableName.begin(), mAvailableName.end(), name) == mAvailableName.end()); + mAvailableName.push_back(name); } }; @@ -265,78 +286,40 @@ U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) return (U8*) (sOcclusionIndices+cypher*8); } - -static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); -void LLSpatialGroup::buildOcclusion() + +//create a vertex buffer for efficiently rendering cubes +LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage) { - //if (mOcclusionVerts.isNull()) - { - mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, - LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling. - mOcclusionVerts->allocateBuffer(8, 64, true); - - LLStrider idx; - mOcclusionVerts->getIndexStrider(idx); - for (U32 i = 0; i < 64; i++) - { - *idx++ = sOcclusionIndices[i]; - } - } + LLVertexBuffer* ret = new LLVertexBuffer(type_mask, usage); - LLVector4a fudge; - fudge.splat(SG_OCCLUSION_FUDGE); - - LLVector4a r; - r.setAdd(mBounds[1], fudge); + ret->allocateBuffer(8, 64, true); LLStrider pos; - + LLStrider idx; + + ret->getVertexStrider(pos); + ret->getIndexStrider(idx); + + pos[0] = LLVector3(-1,-1,-1); + pos[1] = LLVector3(-1,-1, 1); + pos[2] = LLVector3(-1, 1,-1); + pos[3] = LLVector3(-1, 1, 1); + pos[4] = LLVector3( 1,-1,-1); + pos[5] = LLVector3( 1,-1, 1); + pos[6] = LLVector3( 1, 1,-1); + pos[7] = LLVector3( 1, 1, 1); + + for (U32 i = 0; i < 64; i++) { - LLFastTimer t(FTM_BUILD_OCCLUSION); - mOcclusionVerts->getVertexStrider(pos); + idx[i] = sOcclusionIndices[i]; } - { - LLVector4a* v = (LLVector4a*) pos.get(); + ret->flush(); - 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 - - for (S32 i = 0; i < 8; ++i) - { - LLVector4a p; - p.setMul(s, octant[i]); - p.add(c); - v[i] = p; - } - } - - { - mOcclusionVerts->flush(); - LLVertexBuffer::unbind(); - } - - clearState(LLSpatialGroup::OCCLUSION_DIRTY); + return ret; } +static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group); @@ -398,8 +381,6 @@ LLSpatialGroup::~LLSpatialGroup() } } - mOcclusionVerts = NULL; - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); clearDrawMap(); } @@ -568,6 +549,11 @@ void LLSpatialGroup::rebuildGeom() if (!isDead()) { mSpatialPartition->rebuildGeom(this); + + if (isState(LLSpatialGroup::MESH_DIRTY)) + { + gPipeline.markMeshDirty(this); + } } } @@ -580,20 +566,14 @@ void LLSpatialGroup::rebuildMesh() } static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); +static LLFastTimer::DeclareTimer FTM_ADD_GEOMETRY_COUNT("Add Geometry"); +static LLFastTimer::DeclareTimer FTM_CREATE_VB("Create VB"); +static LLFastTimer::DeclareTimer FTM_GET_GEOMETRY("Get Geometry"); void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) { - /*if (!gPipeline.hasRenderType(mDrawableType)) - { - return; - }*/ - if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) { - /*if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && mRenderByGroup) - { - llerrs << "WTF?" << llendl; - }*/ return; } @@ -610,27 +590,36 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) //get geometry count U32 index_count = 0; U32 vertex_count = 0; - - addGeometryCount(group, vertex_count, index_count); + + { + LLFastTimer t(FTM_ADD_GEOMETRY_COUNT); + addGeometryCount(group, vertex_count, index_count); + } if (vertex_count > 0 && index_count > 0) { //create vertex buffer containing volume geometry for this node - group->mBuilt = 1.f; - if (group->mVertexBuffer.isNull() || - !group->mVertexBuffer->isWriteable() || - (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) { - group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); - group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true); - stop_glerror(); + LLFastTimer t(FTM_CREATE_VB); + group->mBuilt = 1.f; + if (group->mVertexBuffer.isNull() || + !group->mVertexBuffer->isWriteable() || + (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) + { + group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); + group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true); + stop_glerror(); + } + else + { + group->mVertexBuffer->resizeBuffer(vertex_count, index_count); + stop_glerror(); + } } - else + { - group->mVertexBuffer->resizeBuffer(vertex_count, index_count); - stop_glerror(); + LLFastTimer t(FTM_GET_GEOMETRY); + getGeometry(group); } - - getGeometry(group); } else { @@ -821,11 +810,6 @@ void LLSpatialGroup::shift(const LLVector4a &offset) setState(GEOM_DIRTY); gPipeline.markRebuild(this, TRUE); } - - if (mOcclusionVerts.notNull()) - { - setState(OCCLUSION_DIRTY); - } } class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler @@ -1077,6 +1061,7 @@ void LLSpatialGroup::clearOcclusionState(eOcclusionState state, S32 mode) //====================================== LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : + mObjectBoxSize(1.f), mState(0), mGeometryBytes(0), mSurfaceArea(0.f), @@ -1121,8 +1106,6 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : mVisible[i] = 0; } - mOcclusionVerts = NULL; - mRadius = 1; mPixelArea = 1024.f; } @@ -1352,10 +1335,14 @@ void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNo unbound(); } -void LLSpatialGroup::destroyGL() +void LLSpatialGroup::destroyGL(bool keep_occlusion) { setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); - gPipeline.markRebuild(this, TRUE); + + if (!keep_occlusion) + { //going to need a rebuild + gPipeline.markRebuild(this, TRUE); + } mLastUpdateTime = gFrameTimeSeconds; mVertexBuffer = NULL; @@ -1363,16 +1350,18 @@ void LLSpatialGroup::destroyGL() clearDrawMap(); - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) + if (!keep_occlusion) { - if (mOcclusionQuery[i]) + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) { - sQueryPool.release(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; + if (mOcclusionQuery[i]) + { + sQueryPool.release(mOcclusionQuery[i]); + mOcclusionQuery[i] = 0; + } } } - mOcclusionVerts = NULL; for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) { @@ -1380,7 +1369,10 @@ void LLSpatialGroup::destroyGL() for (S32 j = 0; j < drawable->getNumFaces(); j++) { LLFace* facep = drawable->getFace(j); - facep->clearVertexBuffer(); + if (facep) + { + facep->clearVertexBuffer(); + } } } } @@ -1443,15 +1435,14 @@ BOOL LLSpatialGroup::rebound() mBounds[1].mul(0.5f); } - setState(OCCLUSION_DIRTY); - clearState(DIRTY); return TRUE; } static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion Wait"); + void LLSpatialGroup::checkOcclusion() { if (LLPipeline::sUseOcclusion > 1) @@ -1470,7 +1461,9 @@ void LLSpatialGroup::checkOcclusion() { glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) + static LLCachedControl wait_for_query("RenderSynchronousOcclusion", true); + + if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) { //query was issued last frame, wait until it's available S32 max_loop = 1024; LLFastTimer t(FTM_OCCLUSION_WAIT); @@ -1579,12 +1572,6 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); } - if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY)) - { - LLFastTimer t(FTM_OCCLUSION_BUILD); - buildOcclusion(); - } - // Depth clamp all water to avoid it being culled as a result of being // behind the far clip plane, and in the case of edge water to avoid // it being culled while still visible. @@ -1615,10 +1602,13 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); } - { - LLFastTimer t(FTM_OCCLUSION_SET_BUFFER); - mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); - } + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader); + + shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, mBounds[0].getF32ptr()); + shader->uniform3f(LLShaderMgr::BOX_SIZE, mBounds[1][0]+SG_OCCLUSION_FUDGE, + mBounds[1][1]+SG_OCCLUSION_FUDGE, + mBounds[1][2]+SG_OCCLUSION_FUDGE); if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) { @@ -1627,12 +1617,12 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) LLGLSquashToFarClip squash(glh_get_current_projection(), 1); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); } else { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); } } else @@ -1640,12 +1630,12 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) LLFastTimer t(FTM_OCCLUSION_DRAW); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); } else { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); } } @@ -2371,18 +2361,21 @@ void pushVerts(LLSpatialGroup* group, U32 mask) void pushVerts(LLFace* face, U32 mask) { - llassert(face->verify()); - - LLVertexBuffer* buffer = face->getVertexBuffer(); - - if (buffer && (face->getGeomCount() >= 3)) + if (face) { - buffer->setBuffer(mask); - U16 start = face->getGeomStart(); - U16 end = start + face->getGeomCount()-1; - U32 count = face->getIndicesCount(); - U16 offset = face->getIndicesStart(); - buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); + llassert(face->verify()); + + LLVertexBuffer* buffer = face->getVertexBuffer(); + + if (buffer && (face->getGeomCount() >= 3)) + { + buffer->setBuffer(mask); + U16 start = face->getGeomStart(); + U16 end = start + face->getGeomCount()-1; + U32 count = face->getIndicesCount(); + U16 offset = face->getIndicesStart(); + buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); + } } } @@ -2417,7 +2410,7 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask) { if (group->mSpatialPartition->mRenderByGroup) { - if (!group->mDrawMap.empty()) + if (!group->mDrawMap.empty() && !group->mDrawMap.begin()->second.empty()) { LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin()); LLRenderPass::applyModelMatrix(*params); @@ -2520,7 +2513,7 @@ void renderOctree(LLSpatialGroup* group) for (S32 j = 0; j < drawable->getNumFaces(); j++) { LLFace* face = drawable->getFace(j); - if (face->getVertexBuffer()) + if (face && face->getVertexBuffer()) { if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f) { @@ -2570,34 +2563,25 @@ void renderOctree(LLSpatialGroup* group) LLVector4a size = group->mObjectBounds[1]; size.mul(1.01f); size.add(fudge); - - { - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - drawBox(group->mObjectBounds[0], fudge); - } + + //{ + // LLGLDepthTest depth(GL_TRUE, GL_FALSE); + // drawBox(group->mObjectBounds[0], fudge); + //} gGL.setSceneBlendType(LLRender::BT_ALPHA); - if (group->mBuilt <= 0.f) + //if (group->mBuilt <= 0.f) { //draw opaque outline - gGL.color4f(col.mV[0], col.mV[1], col.mV[2], 1.f); - drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); + //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f); + //drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); - if (group->mOctreeNode->isLeaf()) - { - gGL.diffuseColor4f(1,1,1,1); - } - else - { - gGL.diffuseColor4f(0,1,1,1); - } - + gGL.diffuseColor4f(0,1,1,1); drawBoxOutline(group->mBounds[0],group->mBounds[1]); - - + //draw bounding box for draw info - if (group->mSpatialPartition->mRenderByGroup) + /*if (group->mSpatialPartition->mRenderByGroup) { gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f); for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) @@ -2614,7 +2598,7 @@ void renderOctree(LLSpatialGroup* group) drawBoxOutline(center, size); } } - } + }*/ } // LLSpatialGroup::OctreeNode* node = group->mOctreeNode; @@ -2897,15 +2881,17 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) for (S32 i = 0; i < drawable->getNumFaces(); i++) { LLFace* facep = drawable->getFace(i); + if (facep) + { + ext = facep->mExtents; - ext = facep->mExtents; - - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - size.setSub(ext[1], ext[0]); - size.mul(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); + drawBoxOutline(pos,size); + } } //render drawable bounding box @@ -3398,18 +3384,21 @@ void renderPhysicsShapes(LLSpatialGroup* group) for (S32 i = 0; i < drawable->getNumFaces(); ++i) { LLFace* face = drawable->getFace(i); - LLVertexBuffer* buff = face->getVertexBuffer(); - if (buff) + if (face) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + LLVertexBuffer* buff = face->getVertexBuffer(); + if (buff) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buff->setBuffer(LLVertexBuffer::MAP_VERTEX); - gGL.diffuseColor3f(0.2f, 0.5f, 0.3f); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + gGL.diffuseColor3f(0.2f, 0.5f, 0.3f); + buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); - gGL.diffuseColor3f(0.2f, 1.f, 0.3f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + gGL.diffuseColor3f(0.2f, 1.f, 0.3f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + } } } } @@ -3433,6 +3422,7 @@ void renderTexturePriority(LLDrawable* drawable) //LLViewerTexture* imagep = facep->getTexture(); //if (imagep) + if (facep) { //F32 vsize = imagep->mMaxVirtualSize; @@ -3450,7 +3440,7 @@ void renderTexturePriority(LLDrawable* drawable) } //else //{ - // gGL.color4f(1,0,1,1); + // gGL.diffuseColor4f(1,0,1,1); //} LLVector4a center; @@ -3463,13 +3453,13 @@ void renderTexturePriority(LLDrawable* drawable) drawBox(center, size); /*S32 boost = imagep->getBoostLevel(); - if (boost) + if (boost>LLViewerTexture::BOOST_NONE) { F32 t = (F32) boost / (F32) (LLViewerTexture::BOOST_MAX_LEVEL-1); LLVector4 col = lerp(boost_cold, boost_hot, t); LLGLEnable blend_on(GL_BLEND); gGL.blendFunc(GL_SRC_ALPHA, GL_ONE); - gGL.color4fv(col.mV); + gGL.diffuseColor4fv(col.mV); drawBox(center, size); gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); }*/ @@ -3485,7 +3475,11 @@ void renderPoints(LLDrawable* drawablep) gGL.diffuseColor3f(1,1,1); for (S32 i = 0; i < drawablep->getNumFaces(); i++) { - gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV); + LLFace * face = drawablep->getFace(i); + if (face) + { + gGL.vertex3fv(face->mCenterLocal.mV); + } } gGL.end(); } @@ -3562,7 +3556,11 @@ void renderLights(LLDrawable* drawablep) for (S32 i = 0; i < drawablep->getNumFaces(); i++) { - pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); + LLFace * face = drawablep->getFace(i); + if (face) + { + pushVerts(face, LLVertexBuffer::MAP_VERTEX); + } } const LLVector4a* ext = drawablep->getSpatialExtents(); @@ -3960,18 +3958,21 @@ public: for (U32 i = 0; i < (U32)drawable->getNumFaces(); ++i) { LLFace* facep = drawable->getFace(i); - U8 index = facep->getTextureIndex(); - if (facep->mDrawInfo) + if (facep) { - if (index < 255) + U8 index = facep->getTextureIndex(); + if (facep->mDrawInfo) { - if (facep->mDrawInfo->mTextureList.size() <= index) + if (index < 255) { - llerrs << "Face texture index out of bounds." << llendl; - } - else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture()) - { - llerrs << "Face texture index incorrect." << llendl; + if (facep->mDrawInfo->mTextureList.size() <= index) + { + llerrs << "Face texture index out of bounds." << llendl; + } + else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture()) + { + llerrs << "Face texture index incorrect." << llendl; + } } } } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 19b6e2faf..95ba1c036 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -268,11 +268,10 @@ public: SKIP_FRUSTUM_CHECK = 0x00000020, IN_IMAGE_QUEUE = 0x00000040, IMAGE_DIRTY = 0x00000080, - OCCLUSION_DIRTY = 0x00000100, - MESH_DIRTY = 0x00000200, - NEW_DRAWINFO = 0x00000400, - IN_BUILD_Q1 = 0x00000800, - IN_BUILD_Q2 = 0x00001000, + MESH_DIRTY = 0x00000100, + NEW_DRAWINFO = 0x00000200, + IN_BUILD_Q1 = 0x00000400, + IN_BUILD_Q2 = 0x00000800, STATE_MASK = 0x0000FFFF, } eSpatialState; @@ -318,10 +317,9 @@ public: BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax); void unbound(); BOOL rebound(); - void buildOcclusion(); //rebuild mOcclusionVerts void checkOcclusion(); //read back last occlusion query (if any) void doOcclusion(LLCamera* camera); //issue occlusion query - void destroyGL(); + void destroyGL(bool keep_occlusion = false); void updateDistance(LLCamera& camera); BOOL needsUpdate(); @@ -363,6 +361,8 @@ public: LLVector4a mViewAngle; LLVector4a mLastUpdateViewAngle; + F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3() + protected: virtual ~LLSpatialGroup(); @@ -384,7 +384,6 @@ public: LLSpatialPartition* mSpatialPartition; LLPointer mVertexBuffer; - LLPointer mOcclusionVerts; GLuint mOcclusionQuery[LLViewerCamera::NUM_CAMERAS]; U32 mBufferUsage; @@ -635,6 +634,7 @@ class LLParticlePartition : public LLSpatialPartition { public: LLParticlePartition(); + virtual void rebuildGeom(LLSpatialGroup* group); virtual void getGeometry(LLSpatialGroup* group); virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count); virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera); @@ -649,18 +649,24 @@ public: }; //spatial partition for grass (implemented in LLVOGrass.cpp) -class LLGrassPartition : public LLParticlePartition +class LLGrassPartition : public LLSpatialPartition { public: LLGrassPartition(); + virtual void getGeometry(LLSpatialGroup* group); + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count); +protected: + U32 mRenderPass; }; //spatial partition for clouds (implemented in LLVOClouds.cpp) +#if ENABLE_CLASSIC_CLOUDS class LLCloudPartition : public LLParticlePartition { public: LLCloudPartition(); }; +#endif //class for wrangling geometry out of volumes (implemented in LLVOVolume.cpp) class LLVolumeGeometryManager: public LLGeometryManager diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a1fad9902..4a28e53a9 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -4284,11 +4284,13 @@ bool process_login_success_response(std::string& password) gMoonTextureID = id; } +#if ENABLE_CLASSIC_CLOUDS id = global_textures["cloud_texture_id"]; if(id.notNull()) { gCloudTextureID = id; } +#endif } diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 0b8e4c608..770f6579a 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -236,8 +236,8 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 const F32 xyScaleInv = (1.f / xyScale)*(0.2222222222f); F32 vec[3] = { - (F32)fmod((mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f), - (F32)fmod((mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f), + (F32)fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f), + (F32)fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f), 0.f }; F32 rand_val = llclamp(noise2(vec)* 0.75f + 0.5f, 0.f, 1.f); diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 3ed7d65e0..2b6195521 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -55,6 +55,9 @@ using namespace LLVOAvatarDefines; static const S32 BAKE_UPLOAD_ATTEMPTS = 7; static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power of 2 each attempt +// runway consolidate +extern std::string self_av_string(); + class LLTexLayerInfo { friend class LLTexLayer; @@ -495,7 +498,7 @@ void LLTexLayerSetBuffer::doUpload() } LLPointer compressedImage = new LLImageJ2C; - compressedImage->setRate(0.f); + //compressedImage->setRate(0.f); const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) if (compressedImage->encode(baked_image, comment_text)) { @@ -578,7 +581,7 @@ void LLTexLayerSetBuffer::doUpload() args["BODYREGION"] = mTexLayerSet->getBodyRegionName(); args["RESOLUTION"] = lod_str; LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args); - llinfos << "Uploading [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Uploading [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << LL_ENDL; } } else @@ -632,7 +635,7 @@ void LLTexLayerSetBuffer::doUpdate() args["BODYREGION"] = mTexLayerSet->getBodyRegionName(); args["RESOLUTION"] = lod_str; LLNotificationsUtil::add("AvatarRezSelfBakedTextureUpdateNotification",args); - llinfos << "Locally updating [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUpdateTimer.getElapsedTimeF32() << " ]" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Locally updating [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUpdateTimer.getElapsedTimeF32() << " ]" << LL_ENDL; } } diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h index f220b68d0..4f43547da 100644 --- a/indra/newview/lltexlayer.h +++ b/indra/newview/lltexlayer.h @@ -31,7 +31,6 @@ #include "lldynamictexture.h" #include "llvoavatardefines.h" #include "lltexlayerparams.h" -#include "lllocaltextureobject.h" class LLVOAvatar; class LLVOAvatarSelf; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 58c9afbde..d8e477fa4 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -245,9 +245,9 @@ bool LLTextureCacheLocalFileWorker::doRead() } } #else - if (!mDataSize || mDataSize > local_size - mOffset) + if (!mDataSize || mDataSize > local_size) { - mDataSize = local_size - mOffset; + mDataSize = local_size; } mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); @@ -375,7 +375,7 @@ bool LLTextureCacheRemoteWorker::doRead() llassert(local_size != 0); // we're assuming there is a non empty local file here... if (!mDataSize || mDataSize > local_size - mOffset) { - mDataSize = local_size - mOffset; + mDataSize = local_size - mOffset; } // Allocate read buffer mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 4862c7db7..72132496e 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2,31 +2,25 @@ * @file lltexturefetch.cpp * @brief Object which fetches textures from the cache and/or network * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -57,6 +51,7 @@ #include "llviewerregion.h" #include "llviewerstats.h" #include "llworld.h" +#include "llstartup.h" ////////////////////////////////////////////////////////////////////////////// class LLTextureFetchWorker : public LLWorkerClass @@ -936,6 +931,8 @@ void LLTextureFetchWorker::startWork(S32 param) // Called from LLWorkerThread::processRequest() bool LLTextureFetchWorker::doWork(S32 param) { + static const F32 FETCHING_TIMEOUT = 120.f;//seconds + LLMutexLock lock(&mWorkMutex); if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) @@ -1295,6 +1292,8 @@ bool LLTextureFetchWorker::doWork(S32 param) bool res = false; if (!mUrl.empty()) { + mRequestedTimer.reset(); + mLoaded = FALSE; mGetStatus = 0; mGetReason.clear(); @@ -1486,6 +1485,13 @@ bool LLTextureFetchWorker::doWork(S32 param) } else { + if(FETCHING_TIMEOUT < mRequestedTimer.getElapsedTimeF32()) + { + //timeout, abort. + mState = DONE; + return true; + } + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return false; } @@ -2367,6 +2373,7 @@ void LLTextureFetch::commonUpdate() } } + // MAIN THREAD //virtual S32 LLTextureFetch::update(F32 max_time_ms) @@ -2382,14 +2389,20 @@ S32 LLTextureFetch::update(F32 max_time_ms) mNetworkQueueMutex.unlock() ; } - + S32 res = LLWorkerThread::update(max_time_ms); if (!mDebugPause) { - sendRequestListToSimulators(); + // this is the startup state when send_complete_agent_movement() message is sent. + // Before this, the RequestImages message sent by sendRequestListToSimulators + // won't work so don't bother trying + if (LLStartUp::getStartupState() > STATE_AGENT_SEND) + { + sendRequestListToSimulators(); + } } - + if (!mThreaded) { commonUpdate(); diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index ff4f66e63..db5d56fd8 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -282,7 +282,24 @@ bool LLToolMgr::canEdit() void LLToolMgr::toggleBuildMode() { - if (!inBuildMode()) + if (inBuildMode()) + { + if (gSavedSettings.getBOOL("EditCameraMovement")) + { + // just reset the view, will pull us out of edit mode + handle_reset_view(); + } + else + { + // manually disable edit mode, but do not affect the camera + gAgentCamera.resetView(false); + gFloaterTools->close(); + gViewerWindow->showCursor(); + } + // avoid spurious avatar movements pulling out of edit mode + LLViewerJoystick::getInstance()->setNeedsReset(); + } + else { ECameraMode camMode = gAgentCamera.getCameraMode(); if (CAMERA_MODE_MOUSELOOK == camMode || CAMERA_MODE_CUSTOMIZE_AVATAR == camMode) @@ -332,24 +349,8 @@ void LLToolMgr::toggleBuildMode() LLViewerJoystick::getInstance()->setNeedsReset(); } - else - { - if (gSavedSettings.getBOOL("EditCameraMovement")) - { - // just reset the view, will pull us out of edit mode - handle_reset_view(); - } - else - { - // manually disable edit mode, but do not affect the camera - gAgentCamera.resetView(false); - gFloaterTools->close(); - gViewerWindow->showCursor(); - } - // avoid spurious avatar movements pulling out of edit mode - LLViewerJoystick::getInstance()->setNeedsReset(); - } } + bool LLToolMgr::inBuildMode() { // when entering mouselook inEdit() immediately returns true before diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index f95a8f085..f9d880aa0 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -64,6 +64,7 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "pipeline.h" +#include "llagentwearables.h" //static @@ -80,6 +81,7 @@ LLVisualParamHint::LLVisualParamHint( S32 width, S32 height, LLViewerJointMesh *mesh, LLViewerVisualParam *param, + LLWearable *wearable, F32 param_weight) : LLViewerDynamicTexture(width, height, 3, LLViewerDynamicTexture::ORDER_MIDDLE, TRUE ), @@ -87,6 +89,7 @@ LLVisualParamHint::LLVisualParamHint( mIsVisible( FALSE ), mJointMesh( mesh ), mVisualParam( param ), + mWearablePtr( wearable ), mVisualParamWeight( param_weight ), mAllowsUpdates( TRUE ), mDelayFrames( 0 ), @@ -152,8 +155,8 @@ BOOL LLVisualParamHint::needsRender() void LLVisualParamHint::preRender(BOOL clear_depth) { mLastParamWeight = mVisualParam->getWeight(); - //mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); - gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); + if(mWearablePtr)mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f); gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f); gAgentAvatarp->updateComposites(); @@ -252,7 +255,9 @@ BOOL LLVisualParamHint::render() gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } - gAgentAvatarp->setVisualParamWeight(mVisualParam, mLastParamWeight); + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); + if(mWearablePtr)mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); + gAgentAvatarp->updateVisualParams(); gGL.color4f(1,1,1,1); mGLTexturep->setGLTextureCreated(true); return TRUE; diff --git a/indra/newview/lltoolmorph.h b/indra/newview/lltoolmorph.h index 0fdfd403f..950a3ab11 100644 --- a/indra/newview/lltoolmorph.h +++ b/indra/newview/lltoolmorph.h @@ -62,6 +62,7 @@ public: S32 width, S32 height, LLViewerJointMesh *mesh, LLViewerVisualParam *param, + LLWearable *wearable, F32 param_weight); /*virtual*/ S8 getType() const ; @@ -89,6 +90,7 @@ protected: BOOL mIsVisible; // is this distortion hint visible? LLViewerJointMesh* mJointMesh; // mesh that this distortion applies to LLViewerVisualParam* mVisualParam; // visual param applied by this hint + LLWearable* mWearablePtr; // wearable we're editing F32 mVisualParamWeight; // weight for this visual parameter BOOL mAllowsUpdates; // updates are blocked unless this is true S32 mDelayFrames; // updates are blocked for this many frames diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 9b3a87d0e..bacfa4938 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -779,38 +779,26 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) llinfos << "LLToolPie handleDoubleClick (becoming mouseDown)" << llendl; } - if (gSavedSettings.getBOOL("DoubleClickAutoPilot") || gSavedSettings.getBOOL("DoubleClickTeleport")) + if (gSavedSettings.getBOOL("DoubleClickAutoPilot")) { - if (mPick.mPickType == LLPickInfo::PICK_LAND - && !mPick.mPosGlobal.isExactlyZero()) + if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || + (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) { handle_go_to(); return TRUE; } - else if (mPick.mObjectID.notNull() - && !mPick.mPosGlobal.isExactlyZero()) - { - // Hit an object - // Do not go to attachments... - if (mPick.getObject() && !mPick.getObject()->isHUDAttachment()) - { - // HACK: Call the last hit position the point we hit on the object - //gLastHitPosGlobal += gLastHitObjectOffset; - handle_go_to(); - return TRUE; - } - } - } else - /* code added to support double click teleports */ - if (gSavedSettings.getBOOL("DoubleClickTeleport")) + } + else if (gSavedSettings.getBOOL("DoubleClickTeleport")) { LLViewerObject* objp = mPick.getObject(); LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; + bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND; bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero(); bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch()); bool has_click_action = final_click_action(objp); + if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action))) { LLVector3d pos = mPick.mPosGlobal; @@ -821,30 +809,6 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) } return FALSE; - - /* JC - don't do go-there, because then double-clicking on physical - objects gets you into trouble. - - // If double-click on object or land, go there. - LLViewerObject *object = gViewerWindow->getLastPick().getObject(); - if (object) - { - if (object->isAvatar()) - { - LLFloaterAvatarInfo::showFromAvatar(object->getID()); - } - else - { - handle_go_to(NULL); - } - } - else if (!gLastHitPosGlobal.isExactlyZero()) - { - handle_go_to(NULL); - } - - return TRUE; - */ } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 1b190259b..3200caa0f 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -579,10 +579,11 @@ bool handleCloudSettingsChanged(const LLSD& newvalue) if((bool)LLPipeline::hasRenderTypeControl((void*)LLPipeline::RENDER_TYPE_WL_CLOUDS)!=bCloudsEnabled) LLPipeline::toggleRenderTypeControl((void*)LLPipeline::RENDER_TYPE_WL_CLOUDS); +#if ENABLE_CLASSIC_CLOUDS if( !gSavedSettings.getBOOL("SkyUseClassicClouds") ) bCloudsEnabled = false; - if((bool)LLPipeline::hasRenderTypeControl((void*)LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS)!=bCloudsEnabled ) LLPipeline::toggleRenderTypeControl((void*)LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS); +#endif return true; } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 7d65692e1..8b8c8b703 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -813,12 +813,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo gTextureList.updateImages(max_image_decode_time); } - { + /*{ LLFastTimer t(FTM_IMAGE_UPDATE_DELETE); //remove dead textures from GL LLImageGL::deleteDeadTextures(); stop_glerror(); - } + }*/ } llpushcallstacks ; LLGLState::checkStates(); @@ -948,6 +948,29 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo && !gRestoreGL) { LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + + LLCachedControl render_depth_pre_pass("RenderDepthPrePass", false); + if (render_depth_pre_pass && LLGLSLShader::sNoFixedFunction) + { + gGL.setColorMask(false, false); + + U32 types[] = { + LLRenderPass::PASS_SIMPLE, + LLRenderPass::PASS_FULLBRIGHT, + LLRenderPass::PASS_SHINY + }; + + U32 num_types = LL_ARRAY_SIZE(types); + gOcclusionProgram.bind(); + for (U32 i = 0; i < num_types; i++) + { + gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); + } + + gOcclusionProgram.unbind(); + } + + gGL.setColorMask(true, false); if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 5164daf22..52abedded 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -127,7 +127,11 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object) { for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++) { - object->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER); + LLFace *face = object->mDrawable->getFace(face_num); + if (face) + { + face->setState(LLFace::HUD_RENDER); + } } } @@ -146,7 +150,11 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object) { for (S32 face_num = 0; face_num < childp->mDrawable->getNumFaces(); face_num++) { - childp->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER); + LLFace * face = childp->mDrawable->getFace(face_num); + if (face) + { + face->setState(LLFace::HUD_RENDER); + } } } } @@ -260,7 +268,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) { for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++) { - object->mDrawable->getFace(face_num)->clearState(LLFace::HUD_RENDER); + LLFace * face = object->mDrawable->getFace(face_num); + if (face) + { + face->clearState(LLFace::HUD_RENDER); + } } } } @@ -278,7 +290,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) { for (S32 face_num = 0; face_num < childp->mDrawable->getNumFaces(); face_num++) { - childp->mDrawable->getFace(face_num)->clearState(LLFace::HUD_RENDER); + LLFace * face = childp->mDrawable->getFace(face_num); + if (face) + { + face->clearState(LLFace::HUD_RENDER); + } } } } diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h index 0191f0cae..dd5dae1dc 100644 --- a/indra/newview/llviewerjointmesh.h +++ b/indra/newview/llviewerjointmesh.h @@ -61,6 +61,7 @@ public: //----------------------------------------------------------------------------- class LLViewerJointMesh : public LLViewerJoint { + friend class LLVOAvatar; protected: LLColor4 mColor; // color value // LLColor4 mSpecular; // specular color (always white for now) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a7d915c1b..669c57d43 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -875,8 +875,6 @@ void init_menus() gLoginMenuBarView->setBackgroundColor( color ); gMenuHolder->addChild(gLoginMenuBarView); - - LLToolMgr::getInstance()->initMenu(sMenus); } @@ -1371,7 +1369,11 @@ void init_debug_rendering_menu(LLMenuGL* menu) &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GRASS, '0', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); //NOTE: Using a static variable, as an unsigned long long cannot fit in the space of a pointer. Pass pointer to callbacks - static U64 cloud_flags = (1ULL<addChild(new LLMenuItemCheckGL("Clouds", //This clobbers skyuseclassicclouds, but.. big deal. &LLPipeline::toggleRenderPairedTypeControl, NULL, &LLPipeline::hasRenderPairedTypeControl, @@ -2751,44 +2753,32 @@ bool handle_go_to() */ // [/RLVa:KB] - // JAMESDEBUG try simulator autopilot + // try simulator autopilot std::vector strings; std::string val; LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - if (gSavedSettings.getBOOL("DoubleClickTeleport") - ) + val = llformat("%g", pos.mdV[VX]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VY]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VZ]); + strings.push_back(val); + send_generic_message("autopilot", strings); + + LLViewerParcelMgr::getInstance()->deselectLand(); + + if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) { - LLVector3d hips_offset(0.0f, 0.0f, 1.2f); - gAgent.teleportViaLocation(pos + hips_offset); + gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); } - else + else { - // JAMESDEBUG try simulator autopilot - std::vector strings; - std::string val; - val = llformat("%g", pos.mdV[VX]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VY]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VZ]); - strings.push_back(val); - send_generic_message("autopilot", strings); - - LLViewerParcelMgr::getInstance()->deselectLand(); - - if (gAgentAvatarp && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) - { - gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); - } - else - { - // Snap camera back to behind avatar - gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); - } - - // Could be first use - LLFirstUse::useGoTo(); + // Snap camera back to behind avatar + gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); } + + // Could be first use + LLFirstUse::useGoTo(); return true; } @@ -9518,4 +9508,6 @@ void initialize_menus() addMenu(new RlvEnableIfNot(), "RLV.EnableIfNot"); } // [/RLVa:KB] + + LLToolMgr::getInstance()->initMenu(sMenus); } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index b8e828643..ff8edd698 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -175,8 +175,10 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco res = NULL; break; case LL_PCODE_LEGACY_TEXT_BUBBLE: res = new LLVOTextBubble(id, pcode, regionp); break; +#if ENABLE_CLASSIC_CLOUDS case LL_VO_CLOUDS: res = new LLVOClouds(id, pcode, regionp); break; +#endif case LL_VO_SURFACE_PATCH: res = new LLVOSurfacePatch(id, pcode, regionp); break; case LL_VO_SKY: @@ -442,7 +444,9 @@ void LLViewerObject::dump() const llinfos << "PositionAgent: " << getPositionAgent() << llendl; llinfos << "PositionGlobal: " << getPositionGlobal() << llendl; llinfos << "Velocity: " << getVelocity() << llendl; - if (mDrawable.notNull() && mDrawable->getNumFaces()) + if (mDrawable.notNull() && + mDrawable->getNumFaces() && + mDrawable->getFace(0)) { LLFacePool *poolp = mDrawable->getFace(0)->getPool(); if (poolp) @@ -4555,7 +4559,11 @@ U32 LLViewerObject::getNumVertices() const num_faces = mDrawable->getNumFaces(); for (i = 0; i < num_faces; i++) { - num_vertices += mDrawable->getFace(i)->getGeomCount(); + LLFace * facep = mDrawable->getFace(i); + if (facep) + { + num_vertices += facep->getGeomCount(); + } } } return num_vertices; @@ -4570,7 +4578,11 @@ U32 LLViewerObject::getNumIndices() const num_faces = mDrawable->getNumFaces(); for (i = 0; i < num_faces; i++) { - num_indices += mDrawable->getFace(i)->getIndicesCount(); + LLFace * facep = mDrawable->getFace(i); + if (facep) + { + num_indices += facep->getIndicesCount(); + } } } return num_indices; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 2bcee1478..edbc688d9 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -951,7 +951,10 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) iter != idle_list.end(); iter++) { objectp = *iter; - if (objectp->getPCode() == LLViewerObject::LL_VO_CLOUDS || + if ( +#if ENABLE_CLASSIC_CLOUDS + objectp->getPCode() == LLViewerObject::LL_VO_CLOUDS || +#endif objectp->isAvatar()) { objectp->idleUpdate(agent, world, frame_time); @@ -1732,7 +1735,10 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) LLViewerObject* last_objectp = NULL; for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++) { - LLViewerObject* objectp = drawablep->getFace(face_num)->getViewerObject(); + LLFace * facep = drawablep->getFace(face_num); + if (!facep) continue; + + LLViewerObject* objectp = facep->getViewerObject(); if (objectp && objectp != last_objectp) { diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index e70975b11..94a2968b4 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -482,7 +482,7 @@ void LLViewerPartSim::checkParticleCount(U32 size) LLViewerPartSim::LLViewerPartSim() { LLMemType mt(LLMemType::MTYPE_PARTICLES); - sMaxParticleCount = gSavedSettings.getS32("RenderMaxPartCount"); + sMaxParticleCount = llmin(gSavedSettings.getS32("RenderMaxPartCount"), LL_MAX_PARTICLE_COUNT); static U32 id_seed = 0; mID = ++id_seed; } diff --git a/indra/newview/llviewerpartsim.h b/indra/newview/llviewerpartsim.h index 8f1f72518..7e625f2c0 100644 --- a/indra/newview/llviewerpartsim.h +++ b/indra/newview/llviewerpartsim.h @@ -45,6 +45,8 @@ class LLViewerRegion; class LLViewerTexture; class LLVOPartGroup; +#define LL_MAX_PARTICLE_COUNT 8192 + typedef void (*LLVPCallback)(LLViewerPart &part, const F32 dt); /////////////////// diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 2e96edcb4..37af34e02 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -336,7 +336,9 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE +#if ENABLE_CLASSIC_CLOUDS mImpl->mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD +#endif mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE @@ -366,7 +368,9 @@ LLViewerRegion::~LLViewerRegion() // Can't do this on destruction, because the neighbor pointers might be invalid. // This should be reference counted... disconnectAllNeighbors(); +#if ENABLE_CLASSIC_CLOUDS mCloudLayer.destroy(); +#endif LLViewerPartSim::getInstance()->cleanupRegion(this); gObjectList.killObjects(this); @@ -502,7 +506,9 @@ void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global) updateRenderMatrix(); mImpl->mLandp->setOriginGlobal(origin_global); mWind.setOriginGlobal(origin_global); +#if ENABLE_CLASSIC_CLOUDS mCloudLayer.setOriginGlobal(origin_global); +#endif calculateCenterGlobal(); } @@ -778,14 +784,18 @@ void LLViewerRegion::forceUpdate() void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction) { mImpl->mLandp->connectNeighbor(neighborp->mImpl->mLandp, direction); +#if ENABLE_CLASSIC_CLOUDS mCloudLayer.connectNeighbor(&(neighborp->mCloudLayer), direction); +#endif } void LLViewerRegion::disconnectAllNeighbors() { mImpl->mLandp->disconnectAllNeighbors(); +#if ENABLE_CLASSIC_CLOUDS mCloudLayer.disconnectAllNeighbors(); +#endif } LLVLComposition * LLViewerRegion::getComposition() const diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 3d33e9b7f..b7fd43602 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -86,7 +86,9 @@ public: PARTITION_WATER, PARTITION_TREE, PARTITION_PARTICLE, +#if ENABLE_CLASSIC_CLOUDS PARTITION_CLOUD, +#endif PARTITION_GRASS, PARTITION_VOLUME, PARTITION_BRIDGE, @@ -354,7 +356,9 @@ protected: public: LLWind mWind; +#if ENABLE_CLASSIC_CLOUDS LLCloudLayer mCloudLayer; +#endif LLViewerParcelOverlay *mParcelOverlay; LLStat mBitStat; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 175f0bfec..0eb0b3cc2 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -73,9 +73,16 @@ LLVector4 gShinyOrigin; // Make sure WL Sky is the first program LLGLSLShader gWLSkyProgram(LLViewerShaderMgr::SHADER_WINDLIGHT); LLGLSLShader gWLCloudProgram(LLViewerShaderMgr::SHADER_WINDLIGHT); +//transform shaders +LLGLSLShader gTransformPositionProgram(LLViewerShaderMgr::SHADER_TRANSFORM); +LLGLSLShader gTransformTexCoordProgram(LLViewerShaderMgr::SHADER_TRANSFORM); +LLGLSLShader gTransformNormalProgram(LLViewerShaderMgr::SHADER_TRANSFORM); +LLGLSLShader gTransformColorProgram(LLViewerShaderMgr::SHADER_TRANSFORM); +LLGLSLShader gTransformBinormalProgram(LLViewerShaderMgr::SHADER_TRANSFORM); //utility shaders LLGLSLShader gOcclusionProgram(LLViewerShaderMgr::SHADER_INTERFACE); +LLGLSLShader gOcclusionCubeProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gCustomAlphaProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gGlowCombineProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gSplatTextureRectProgram(LLViewerShaderMgr::SHADER_INTERFACE); @@ -189,6 +196,7 @@ LLGLSLShader gDeferredSunProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredBlurLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSoftenProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList +LLGLSLShader gDeferredShadowCubeProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredShadowAlphaMaskProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredAvatarShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED);//Not in mShaderList LLGLSLShader gDeferredAttachmentShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED); @@ -389,6 +397,7 @@ void LLViewerShaderMgr::setShaders() S32 wl_class = 2; S32 water_class = 2; S32 deferred_class = 0; + S32 transform_class = gGLManager.mHasTransformFeedback ? 1 : 0; if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && gSavedSettings.getBOOL("RenderDeferred") && @@ -436,6 +445,7 @@ void LLViewerShaderMgr::setShaders() mVertexShaderLevel[SHADER_EFFECT] = effect_class; mVertexShaderLevel[SHADER_WINDLIGHT] = wl_class; mVertexShaderLevel[SHADER_DEFERRED] = deferred_class; + mVertexShaderLevel[SHADER_TRANSFORM] = transform_class; BOOL loaded = loadBasicShaders(); @@ -445,65 +455,109 @@ void LLViewerShaderMgr::setShaders() gPipeline.mVertexShadersLoaded = 1; // Load all shaders to set max levels - loadShadersEnvironment(); - loadShadersWater(); - loadShadersWindLight(); - loadShadersEffects(); - loadShadersInterface(); - - // Load max avatar shaders to set the max level - mVertexShaderLevel[SHADER_AVATAR] = 3; - mMaxAvatarShaderLevel = 3; - - if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject()) - { - BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); - S32 avatar_class = 1; - - // cloth is a class3 shader - if(avatar_cloth) - { - avatar_class = 3; - } + loaded = loadShadersEnvironment(); - // Set the actual level - mVertexShaderLevel[SHADER_AVATAR] = avatar_class; - loadShadersAvatar(); - if (mVertexShaderLevel[SHADER_AVATAR] != avatar_class) - { - if (mVertexShaderLevel[SHADER_AVATAR] == 0) + if (loaded) + { + loaded = loadShadersWater(); + } + + if (loaded) + { + loaded = loadShadersWindLight(); + } + + if (loaded) + { + loaded = loadShadersEffects(); + } + + if (loaded) + { + loaded = loadShadersInterface(); + } + + if (loaded) + { + loaded = loadTransformShaders(); + } + + if (loaded) + { + // Load max avatar shaders to set the max level + mVertexShaderLevel[SHADER_AVATAR] = 3; + mMaxAvatarShaderLevel = 3; + + if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject()) + { //hardware skinning is enabled and rigged attachment shaders loaded correctly + BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); + S32 avatar_class = 1; + + // cloth is a class3 shader + if(avatar_cloth) { + avatar_class = 3; + } + + // Set the actual level + mVertexShaderLevel[SHADER_AVATAR] = avatar_class; + loadShadersAvatar(); + if (mVertexShaderLevel[SHADER_AVATAR] != avatar_class) + { + if (mVertexShaderLevel[SHADER_AVATAR] == 0) + { + gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + } + if(llmax(mVertexShaderLevel[SHADER_AVATAR]-1,0) >= 3) + { + avatar_cloth = true; + } + else + { + avatar_cloth = false; + } + gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); + } + } + else + { //hardware skinning not possible, neither is deferred rendering + mVertexShaderLevel[SHADER_AVATAR] = 0; + mVertexShaderLevel[SHADER_DEFERRED] = 0; + + if (gSavedSettings.getBOOL("RenderAvatarVP")) + { + gSavedSettings.setBOOL("RenderDeferred", FALSE); + gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); gSavedSettings.setBOOL("RenderAvatarVP", FALSE); } - if(llmax(mVertexShaderLevel[SHADER_AVATAR]-1,0) >= 3) - { - avatar_cloth = true; - } - else - { - avatar_cloth = false; - } - gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); + + loadShadersAvatar(); // unloads + + loaded = loadShadersObject(); } } - else - { - mVertexShaderLevel[SHADER_AVATAR] = 0; - mVertexShaderLevel[SHADER_DEFERRED] = 0; - if (gSavedSettings.getBOOL("RenderAvatarVP")) - { - gSavedSettings.setBOOL("RenderDeferred", FALSE); - gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + if (!loaded) + { //some shader absolutely could not load, try to fall back to a simpler setting + if (gSavedSettings.getBOOL("WindLightUseAtmosShaders")) + { //disable windlight and try again + gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE); + reentrance = false; + setShaders(); + return; } - loadShadersAvatar(); // unloads - loadShadersObject(); - } + if (gSavedSettings.getBOOL("VertexShaderEnable")) + { //disable shaders outright and try again + gSavedSettings.setBOOL("VertexShaderEnable", FALSE); + reentrance = false; + setShaders(); + return; + } + } - if (!loadShadersDeferred()) - { + if (loaded && !loadShadersDeferred()) + { //everything else succeeded but deferred failed, disable deferred and try again gSavedSettings.setBOOL("RenderDeferred", FALSE); reentrance = false; setShaders(); @@ -629,12 +683,13 @@ BOOL LLViewerShaderMgr::loadBasicShaders() // (in order of shader function call depth for reference purposes, deepest level first) shaders.clear(); - S32 ch = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); + S32 ch = 1; - static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false); - if (gGLManager.mGLVersion < 3.1f || no_texture_indexing) - { //force to 1 texture index channel for old drivers - ch = 1; + if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) + { //use indexed texture rendering for GLSL >= 1.30 + static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false); + if(!no_texture_indexing) + ch = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); } std::vector index_channels; @@ -688,7 +743,7 @@ BOOL LLViewerShaderMgr::loadShadersEnvironment() if (mVertexShaderLevel[SHADER_ENVIRONMENT] == 0) { unloadShaderClass(SHADER_ENVIRONMENT); - return FALSE; + return TRUE; } if (success) @@ -726,7 +781,7 @@ BOOL LLViewerShaderMgr::loadShadersWater() if (mVertexShaderLevel[SHADER_WATER] == 0) { unloadShaderClass(SHADER_WATER); - return FALSE; + return TRUE; } if (success) @@ -808,7 +863,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects() if (mVertexShaderLevel[SHADER_EFFECT] == 0) { unloadShaderClass(SHADER_EFFECT); - return FALSE; + return TRUE; } if(LLPipeline::sRenderGlow) @@ -1083,7 +1138,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSpotLightProgram.mName = "Deferred SpotLight Shader"; gDeferredSpotLightProgram.mShaderFiles.clear(); gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/spotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredSpotLightProgram.createShader(NULL, NULL); } @@ -1092,7 +1147,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredMultiSpotLightProgram.mName = "Deferred MultiSpotLight Shader"; gDeferredMultiSpotLightProgram.mShaderFiles.clear(); - gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredMultiSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL); @@ -1235,6 +1290,16 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredShadowProgram.createShader(NULL, NULL); } + if (success) + { + gDeferredShadowCubeProgram.mName = "Deferred Shadow Cube Shader"; + gDeferredShadowCubeProgram.mShaderFiles.clear(); + gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowCubeV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredShadowCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredShadowCubeProgram.createShader(NULL, NULL); + } + if (success) { gDeferredShadowAlphaMaskProgram.mName = "Deferred Shadow Alpha Mask Shader"; @@ -2230,7 +2295,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() if (mVertexShaderLevel[SHADER_AVATAR] == 0) { unloadShaderClass(SHADER_AVATAR); - return FALSE; + return TRUE; } if (success) @@ -2324,7 +2389,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (mVertexShaderLevel[SHADER_INTERFACE] == 0) { unloadShaderClass(SHADER_INTERFACE); - return FALSE; + return TRUE; } if (success) @@ -2465,6 +2530,16 @@ BOOL LLViewerShaderMgr::loadShadersInterface() success = gOcclusionProgram.createShader(NULL, NULL); } + if (success) + { + gOcclusionCubeProgram.mName = "Occlusion Cube Shader"; + gOcclusionCubeProgram.mShaderFiles.clear(); + gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionCubeV.glsl", GL_VERTEX_SHADER_ARB)); + gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB)); + gOcclusionCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + success = gOcclusionCubeProgram.createShader(NULL, NULL); + } + if (success) { gDebugProgram.mName = "Debug Shader"; @@ -2511,7 +2586,7 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() if (mVertexShaderLevel[SHADER_WINDLIGHT] < 2) { unloadShaderClass(SHADER_WINDLIGHT); - return FALSE; + return TRUE; } if (success) @@ -2541,6 +2616,91 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() return success; } +BOOL LLViewerShaderMgr::loadTransformShaders() +{ + BOOL success = TRUE; + + if (mVertexShaderLevel[SHADER_TRANSFORM] < 1) + { + unloadShaderClass(SHADER_TRANSFORM); + return TRUE; + } + + if (success) + { + gTransformPositionProgram.mName = "Position Transform Shader"; + gTransformPositionProgram.mShaderFiles.clear(); + gTransformPositionProgram.mShaderFiles.push_back(make_pair("transform/positionV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformPositionProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "position_out", + "texture_index_out", + }; + + success = gTransformPositionProgram.createShader(NULL, NULL, 2, varyings); + } + + if (success) + { + gTransformTexCoordProgram.mName = "TexCoord Transform Shader"; + gTransformTexCoordProgram.mShaderFiles.clear(); + gTransformTexCoordProgram.mShaderFiles.push_back(make_pair("transform/texcoordV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformTexCoordProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "texcoord_out", + }; + + success = gTransformTexCoordProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformNormalProgram.mName = "Normal Transform Shader"; + gTransformNormalProgram.mShaderFiles.clear(); + gTransformNormalProgram.mShaderFiles.push_back(make_pair("transform/normalV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformNormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "normal_out", + }; + + success = gTransformNormalProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformColorProgram.mName = "Color Transform Shader"; + gTransformColorProgram.mShaderFiles.clear(); + gTransformColorProgram.mShaderFiles.push_back(make_pair("transform/colorV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "color_out", + }; + + success = gTransformColorProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformBinormalProgram.mName = "Binormal Transform Shader"; + gTransformBinormalProgram.mShaderFiles.clear(); + gTransformBinormalProgram.mShaderFiles.push_back(make_pair("transform/binormalV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformBinormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "binormal_out", + }; + + success = gTransformBinormalProgram.createShader(NULL, NULL, 1, varyings); + } + + + return success; +} + std::string LLViewerShaderMgr::getShaderDirPrefix(void) { return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/class"); diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index dffe2a3dc..d41fb5f78 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -60,6 +60,7 @@ public: BOOL loadShadersWater(); BOOL loadShadersInterface(); BOOL loadShadersWindLight(); + BOOL loadTransformShaders(); std::vector mVertexShaderLevel; S32 mMaxAvatarShaderLevel; @@ -75,6 +76,7 @@ public: SHADER_WINDLIGHT, SHADER_WATER, SHADER_DEFERRED, + SHADER_TRANSFORM, SHADER_COUNT }; @@ -227,8 +229,15 @@ inline bool operator != (LLViewerShaderMgr::shader_iter const & a, LLViewerShade extern LLVector4 gShinyOrigin; +//transform shaders +extern LLGLSLShader gTransformPositionProgram; +extern LLGLSLShader gTransformTexCoordProgram; +extern LLGLSLShader gTransformNormalProgram; +extern LLGLSLShader gTransformColorProgram; +extern LLGLSLShader gTransformBinormalProgram; //utility shaders extern LLGLSLShader gOcclusionProgram; +extern LLGLSLShader gOcclusionCubeProgram; extern LLGLSLShader gCustomAlphaProgram; extern LLGLSLShader gGlowCombineProgram; extern LLGLSLShader gSplatTextureRectProgram; @@ -348,6 +357,7 @@ extern LLGLSLShader gDeferredBlurLightProgram; extern LLGLSLShader gDeferredAvatarProgram; extern LLGLSLShader gDeferredSoftenProgram; extern LLGLSLShader gDeferredShadowProgram; +extern LLGLSLShader gDeferredShadowCubeProgram; extern LLGLSLShader gDeferredShadowAlphaMaskProgram; extern LLGLSLShader gDeferredPostProgram; extern LLGLSLShader gDeferredCoFProgram; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 10b608761..0455f18a7 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -2,33 +2,26 @@ * @file llviewertexture.cpp * @brief Object which handles a received image (and associated texture(s)) * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ #include "llviewerprecompiledheaders.h" @@ -100,6 +93,7 @@ S32 LLViewerTexture::sMaxBoundTextureMemInMegaBytes = 0; S32 LLViewerTexture::sMaxTotalTextureMemInMegaBytes = 0; S32 LLViewerTexture::sMaxDesiredTextureMemInBytes = 0 ; S8 LLViewerTexture::sCameraMovingDiscardBias = 0 ; +F32 LLViewerTexture::sCameraMovingBias = 0.0f ; S32 LLViewerTexture::sMaxSculptRez = 128 ; //max sculpt image size const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64 ; const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez ; @@ -109,6 +103,9 @@ S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA ; BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE ; F32 LLViewerTexture::sCurrentTime = 0.0f ; //BOOL LLViewerTexture::sUseTextureAtlas = FALSE ; +F32 LLViewerTexture::sTexelPixelRatio = 1.0f; + +LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve image quality by const F32 desired_discard_bias_max = (F32)MAX_DISCARD_LEVEL; // max number of levels to reduce image quality by @@ -192,7 +189,12 @@ LLViewerTexture* LLViewerTextureManager::findTexture(const LLUUID& id) #endif //NEW_MEDIA_TEXTURE return tex ; } - + +LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id) +{ + return gTextureList.findImage(id); +} + #if NEW_MEDIA_TEXTURE LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &media_id) { @@ -406,7 +408,7 @@ void LLViewerTextureManager::cleanup() void LLViewerTexture::initClass() { LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture() ; - + sTexelPixelRatio = gSavedSettings.getF32("TexelPixelRatio"); if(gAuditTexture) { LLImageGL::setHighlightTexture(LLViewerTexture::OTHER) ; @@ -561,7 +563,8 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ; F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed(); - sCameraMovingDiscardBias = (S8)llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1) ; + sCameraMovingBias = llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1); + sCameraMovingDiscardBias = (S8)(sCameraMovingBias); LLViewerTexture::sFreezeImageScalingDown = (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) < 0.75f * sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) && (BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) < 0.75f * sMaxTotalTextureMemInMegaBytes * texmem_middle_bound_scale) ; @@ -745,6 +748,7 @@ void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) co mNeedsGLTexture = TRUE ; } + virtual_size *= sTexelPixelRatio; if(!mMaxVirtualSizeResetCounter) { //flag to reset the values because the old values are used. @@ -1923,6 +1927,8 @@ S32 LLViewerFetchedTexture::getCurrentDiscardLevelForFetching() bool LLViewerFetchedTexture::updateFetch() { static LLCachedControl textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled"); + static LLCachedControl sCameraMotionThreshold(gSavedSettings,"TextureCameraMotionThreshold"); + static LLCachedControl sCameraMotionBoost(gSavedSettings,"TextureCameraMotionBoost"); if(textures_decode_disabled) { return false ; @@ -2091,14 +2097,18 @@ bool LLViewerFetchedTexture::updateFetch() { //load the texture progressively. S32 delta_level = (mBoostLevel > LLViewerTexture::BOOST_NONE) ? 2 : 1 ; - if(current_discard < 0) + if (current_discard < 0) { desired_discard = llmax(desired_discard, getMaxDiscardLevel() - delta_level); } - else + else if (LLViewerTexture::sCameraMovingBias < sCameraMotionThreshold) { - desired_discard = llmax(desired_discard, current_discard - delta_level); + desired_discard = llmax(desired_discard, current_discard - sCameraMotionBoost); } + else + { + desired_discard = llmax(desired_discard, current_discard - delta_level); + } if (mIsFetching) { @@ -2166,6 +2176,17 @@ bool LLViewerFetchedTexture::updateFetch() return mIsFetching ? true : false; } +void LLViewerFetchedTexture::forceToDeleteRequest() +{ + if (mHasFetcher) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = FALSE; + mIsFetching = FALSE ; + resetTextureStats(); + } +} + void LLViewerFetchedTexture::setIsMissingAsset() { if (mUrl.empty()) diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 9c019b03d..85a6b4915 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -322,6 +322,7 @@ protected: } LLGLTextureState; LLGLTextureState mTextureState ; + static F32 sTexelPixelRatio; public: static const U32 sCurrentFileVersion; static S32 sImageCount; @@ -336,6 +337,7 @@ public: static S32 sMaxTotalTextureMemInMegaBytes; static S32 sMaxDesiredTextureMemInBytes ; static S8 sCameraMovingDiscardBias; + static F32 sCameraMovingBias; static S32 sMaxSculptRez ; static S32 sMinLargeImageSize ; static S32 sMaxSmallImageSize ; @@ -343,6 +345,16 @@ public: static F32 sCurrentTime ; //static BOOL sUseTextureAtlas ; + enum EDebugTexels + { + DEBUG_TEXELS_OFF, + DEBUG_TEXELS_CURRENT, + DEBUG_TEXELS_DESIRED, + DEBUG_TEXELS_FULL + }; + + static EDebugTexels sDebugTexelsMode; + static LLPointer sNullImagep; // Null texture for non-textured objects. static LLPointer sBlackImagep; // Texture to show NOTHING (pure black) }; @@ -491,6 +503,7 @@ public: BOOL hasFetcher() const { return mHasFetcher;} void setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;} + void forceToDeleteRequest(); protected: /*virtual*/ void switchToCachedImage(); S32 getCurrentDiscardLevelForFetching() ; @@ -710,6 +723,7 @@ public: //"find-texture" just check if the texture exists, if yes, return it, otherwise return null. // static LLViewerTexture* findTexture(const LLUUID& id) ; + static LLViewerFetchedTexture* findFetchedTexture(const LLUUID& id) ; #if NEW_MEDIA_TEXTURE static LLViewerMediaTexture* findMediaTexture(const LLUUID& id) ; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 4f5f3272f..4be8df0e9 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -64,6 +64,7 @@ #include "llviewerstats.h" #include "pipeline.h" #include "llappviewer.h" +#include "llagent.h" //////////////////////////////////////////////////////////////////////////// @@ -622,6 +623,11 @@ static LLFastTimer::DeclareTimer FTM_IMAGE_MEDIA("Media"); void LLViewerTextureList::updateImages(F32 max_time) { + if(gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + { + clearFetchingRequests(); + return; + } LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec()); S32 global_raw_memory; @@ -693,6 +699,24 @@ void LLViewerTextureList::updateImages(F32 max_time) } } +void LLViewerTextureList::clearFetchingRequests() +{ + if (LLAppViewer::getTextureFetch()->getNumRequests() == 0) + { + return; + } + + for (image_priority_list_t::iterator iter = mImageList.begin(); + iter != mImageList.end(); ++iter) + { + LLViewerFetchedTexture* image = *iter; + if(image->hasFetcher()) + { + image->forceToDeleteRequest() ; + } + } +} + void LLViewerTextureList::updateImagesDecodePriorities() { // Update the decode priority for N images each frame diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 034dc3e69..fa414ad5f 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -2,33 +2,26 @@ * @file llviewertexturelist.h * @brief Object for managing the list of images within a region * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ #ifndef LL_LLVIEWERTEXTURELIST_H @@ -116,6 +109,8 @@ public: void doPreloadImages(); void doPrefetchImages(); + void clearFetchingRequests(); + static S32 getMinVideoRamSetting(); static S32 getMaxVideoRamSetting(bool get_recommended = false); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index c20231a49..273b69da1 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -178,6 +178,7 @@ #include "llviewershadermgr.h" #include "llviewerstats.h" #include "llvoavatarself.h" +#include "llvopartgroup.h" #include "llvovolume.h" #include "llworld.h" #include "llworldmapview.h" @@ -1183,7 +1184,8 @@ void LLViewerWindow::handleFocusLost(LLWindow *window) BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) { // Let the voice chat code check for its PTT key. Note that this never affects event processing. - gVoiceClient->keyDown(key, mask); + if(gVoiceClient) + gVoiceClient->keyDown(key, mask); if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME) { @@ -4823,6 +4825,8 @@ void LLViewerWindow::stopGL(BOOL save_state) LLVOAvatar::destroyGL(); stop_glerror(); + LLVOPartGroup::destroyGL(); + LLViewerDynamicTexture::destroyGL(); stop_glerror(); @@ -4875,6 +4879,7 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) gBumpImageList.restoreGL(); LLViewerDynamicTexture::restoreGL(); LLVOAvatar::restoreGL(); + LLVOPartGroup::restoreGL(); gResizeScreenTexture = TRUE; gWindowResized = TRUE; @@ -5514,8 +5519,10 @@ void LLPickInfo::getSurfaceInfo() if (objectp->mDrawable.notNull() && mObjectFace > -1) { LLFace* facep = objectp->mDrawable->getFace(mObjectFace); - - mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal); + if (facep) + { + mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal); + } } // and XY coords: diff --git a/indra/newview/llvlmanager.cpp b/indra/newview/llvlmanager.cpp index 07ef26266..b586ab673 100644 --- a/indra/newview/llvlmanager.cpp +++ b/indra/newview/llvlmanager.cpp @@ -100,7 +100,9 @@ void LLVLManager::unpackData(const S32 num_packets) } else if (CLOUD_LAYER_CODE == datap->mType) { +#if ENABLE_CLASSIC_CLOUDS datap->mRegionp->mCloudLayer.decompress(bit_pack, &goph); +#endif } } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 653d19866..c639fb330 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -208,6 +208,9 @@ const S32 MAX_BUBBLE_CHAT_UTTERANCES = 12; const F32 CHAT_FADE_TIME = 8.0; const F32 BUBBLE_CHAT_TIME = CHAT_FADE_TIME * 3.f; +const U32 EMERALD_BOOB_SIZE_PARAM = 105; +const U32 EMERALD_BOOB_GRAVITY_PARAM = 507; + const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); //Singu note: FADE and ALWAYS are swapped around from LL's source to match our preference panel. @@ -615,6 +618,10 @@ SHClientTagMgr::SHClientTagMgr() gSavedSettings.getControl("AscentFriendColor")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); gSavedSettings.getControl("AscentMutedColor")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); + gSavedSettings.getControl("AscentUseCustomTag")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); + gSavedSettings.getControl("AscentCustomTagColor")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); + gSavedSettings.getControl("AscentCustomTagLabel")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); + if(!getIsEnabled()) return; @@ -624,9 +631,6 @@ SHClientTagMgr::SHClientTagMgr() //These only matter to the agent avatar. Don't iterate over everything. gSavedSettings.getControl("AscentUseTag")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); - gSavedSettings.getControl("AscentUseCustomTag")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); - gSavedSettings.getControl("AscentCustomTagColor")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); - gSavedSettings.getControl("AscentCustomTagLabel")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); gSavedSettings.getControl("AscentReportClientUUID")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); //Fire off a AgentSetAppearance update if these change. @@ -724,9 +728,6 @@ void SHClientTagMgr::updateAgentAvatarTag() } const LLSD SHClientTagMgr::generateClientTag(const LLVOAvatar* pAvatar) const { - if(!getIsEnabled()) - return LLSD(); - static const LLCachedControl avatar_name_color(gColors,"AvatarNameColor",LLColor4(LLColor4U(251, 175, 93, 255)) ); LLUUID id; @@ -745,6 +746,10 @@ const LLSD SHClientTagMgr::generateClientTag(const LLVOAvatar* pAvatar) const info.insert("color", ascent_custom_tag_color.get().getValue()); return info; } + else if(!getIsEnabled()) + { + return LLSD(); + } else if (ascent_use_tag) { id.set(ascent_report_client_uuid,false); @@ -752,6 +757,9 @@ const LLSD SHClientTagMgr::generateClientTag(const LLVOAvatar* pAvatar) const } else { + if(!getIsEnabled()) + return LLSD(); + LLTextureEntry* pTextureEntry = pAvatar->getTE(TEX_HEAD_BODYPAINT); if (!pTextureEntry) return LLSD(); @@ -817,17 +825,6 @@ const LLSD SHClientTagMgr::generateClientTag(const LLVOAvatar* pAvatar) const if(!mClientDefinitions.empty()) { std::map::const_iterator it = mClientDefinitions.find(id); - /*S32 idx = ll_rand(mClientDefinitions.size()-1); - for(;it!=mClientDefinitions.end();++it) - { - if(!idx--) - { - llinfos << "[" << idx << "] Returning " << it->second["name"] << " : " << it->second["id"] << llendl; - return it->second; - } - else - llinfos << "[" << idx << "] Skipping " << it->second["name"] << " : " << it->second["id"] << llendl; - }*/ if(it != mClientDefinitions.end()) { return it->second; @@ -1044,6 +1041,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsSkin(FALSE), mLastSkinTime(0.f), mUpdatePeriod(1), + mFirstFullyVisible(TRUE), mFullyLoaded(FALSE), mPreviousFullyLoaded(FALSE), mFullyLoadedInitialized(FALSE), @@ -1051,6 +1049,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mLoadedCallbacksPaused(FALSE), mHasPelvisOffset( FALSE ), mRenderUnloadedAvatar(LLCachedControl(gSavedSettings, "RenderUnloadedAvatar")), + mLastRezzedStatus(-1), mFirstSetActualBoobGravRan( false ), mSupportsPhysics( false ), // @@ -1137,33 +1136,45 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mLastPelvisFixup = 0.0f; } -//------------------------------------------------------------------------ -// LLVOAvatar::~LLVOAvatar() -//------------------------------------------------------------------------ +std::string LLVOAvatar::avString() const +{ + std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); + return " Avatar '" + getFullname() + "' " + viz_string + " "; +} + +void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string comment) +{ + LL_INFOS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() + << "sec ]" + << avString() + << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() + << " Notification " << notification_name + << " : " << comment + << llendl; + + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add(notification_name,args); + } +} LLVOAvatar::~LLVOAvatar() { //App teardown is a mess. Avatar destruction can be unpredictable due to all potential refs to the smartptr. //Cannot guarantee that LLNotificationUtil will be usable during shutdown chain. - if (!LLApp::isQuitting() && gSavedSettings.getBOOL("DebugAvatarRezTime")) + if (!LLApp::isQuitting()) { if (!mFullyLoaded) { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args); + debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud"); } else { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftNotification",args); + debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding"); } - } lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; @@ -1248,6 +1259,55 @@ BOOL LLVOAvatar::isFullyBaked() return TRUE; } +BOOL LLVOAvatar::isFullyTextured() const +{ + for (U32 i = 0; i < (U32)mMeshLOD.size(); i++) + { + LLViewerJoint* joint = (LLViewerJoint*) mMeshLOD[i]; + if (i==MESH_ID_SKIRT && !isWearingWearableType(LLWearableType::WT_SKIRT)) + { + continue; // don't care about skirt textures if we're not wearing one. + } + if (!joint) + { + continue; // nonexistent LOD OK. + } + std::vector::iterator meshIter = joint->mMeshParts.begin(); + if (meshIter != joint->mMeshParts.end()) + { + LLViewerJointMesh *mesh = (LLViewerJointMesh *) *meshIter; + if (!mesh) + { + continue; // nonexistent mesh OK + } + if (mesh->mTexture.notNull() && mesh->mTexture->hasGLTexture()) + { + continue; // Mesh exists and has a baked texture. + } + if (mesh->mLayerSet && mesh->mLayerSet->hasComposite()) + { + continue; // Mesh exists and has a composite texture. + } + // Fail + return FALSE; + } + } + return TRUE; +} + +BOOL LLVOAvatar::hasGray() const +{ + return !getIsCloud() && !isFullyTextured(); +} + +S32 LLVOAvatar::getRezzedStatus() const +{ + if (getIsCloud()) return 0; + if (isFullyTextured()) return 2; + llassert(hasGray()); + return 1; // gray +} + void LLVOAvatar::deleteLayerSetCaches(bool clearAll) { for (U32 i = 0; i < mBakedTextureDatas.size(); i++) @@ -1263,7 +1323,7 @@ void LLVOAvatar::deleteLayerSetCaches(bool clearAll) } if (mBakedTextureDatas[i].mMaskTexName) { - glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); mBakedTextureDatas[i].mMaskTexName = 0 ; } } @@ -1294,6 +1354,31 @@ BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) return res; } +// static +void LLVOAvatar::getNearbyRezzedStats(std::vector& counts) +{ + counts.clear(); + counts.resize(3); + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* inst = (LLVOAvatar*) *iter; + if (!inst) + continue; + S32 rez_status = inst->getRezzedStatus(); + counts[rez_status]++; + } +} + +// static +std::string LLVOAvatar::rezStatusToString(S32 rez_status) +{ + if (rez_status==0) return "cloud"; + if (rez_status==1) return "gray"; + if (rez_status==2) return "textured"; + return "unknown"; +} + // static void LLVOAvatar::getMeshInfo (mesh_info_t* mesh_info) { @@ -1722,7 +1807,7 @@ void LLVOAvatar::initInstance(void) sBoobConfig.mass = EmeraldBoobUtils::convertMass(gSavedSettings.getF32("EmeraldBoobMass")); sBoobConfig.hardness = EmeraldBoobUtils::convertHardness(gSavedSettings.getF32("EmeraldBoobHardness")); sBoobConfig.velMax = EmeraldBoobUtils::convertVelMax(gSavedSettings.getF32("EmeraldBoobVelMax")); - sBoobConfig.velMin = EmeraldBoobUtils::convertVelMin(gSavedSettings.getF32("EmeraldBoobVelMin")); + sBoobConfig.velMin = EmeraldBoobUtils::convertVelMin(gSavedSettings.getF32("EmeraldBoobVelMin"))*sBoobConfig.velMax; sBoobConfig.friction = EmeraldBoobUtils::convertFriction(gSavedSettings.getF32("EmeraldBoobFriction")); sBoobConfig.enabled = gSavedSettings.getBOOL("EmeraldBreastPhysicsToggle"); sBoobConfig.XYInfluence = gSavedSettings.getF32("EmeraldBoobXYInfluence"); @@ -2421,11 +2506,17 @@ void LLVOAvatar::releaseMeshData() if (mDrawable.notNull()) { LLFace* facep = mDrawable->getFace(0); - facep->setSize(0, 0); - for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++) + if (facep) { - facep = mDrawable->getFace(i); facep->setSize(0, 0); + for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++) + { + facep = mDrawable->getFace(i); + if (facep) + { + facep->setSize(0, 0); + } + } } } @@ -2510,15 +2601,20 @@ void LLVOAvatar::updateMeshData() part_index-- ; } - LLFace* facep ; - if(f_num < mDrawable->getNumFaces()) + LLFace* facep = NULL; + if(f_num < mDrawable->getNumFaces()) { facep = mDrawable->getFace(f_num); } else { - facep = mDrawable->addFace(mDrawable->getFace(0)->getPool(), mDrawable->getFace(0)->getTexture()) ; + facep = mDrawable->getFace(0); + if (facep) + { + facep = mDrawable->addFace(facep->getPool(), facep->getTexture()) ; + } } + if (!facep) continue; // resize immediately facep->setSize(num_vertices, num_indices); @@ -2669,18 +2765,12 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); // Print out arrival information once we have name of avatar. - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + if (has_name && getNVPair("FirstName")) { - if (has_name && getNVPair("FirstName")) - { - mDebugExistenceTimer.reset(); - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezArrivedNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl; - } + mDebugExistenceTimer.reset(); + debugAvatarRezTime("AvatarRezArrivedNotification","avatar arrived"); } + if(retval & LLViewerObject::INVALID_UPDATE) { if(isSelf()) @@ -2863,6 +2953,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) idleUpdateNameTag( root_pos_last ); idleUpdateRenderCost(); + return TRUE; } @@ -3189,30 +3280,29 @@ void LLVOAvatar::idleUpdateBoobEffect() if(mFirstSetActualBoobGravRan) { // should probably be moved somewhere where it is only called when boobsize changes - LLVisualParam *param; + static const LLCachedControl avatar_physics("AvatarPhysics",false); + + EmeraldBoobState newBoobState; - // BOOBS - param = getVisualParam(105); //boob size - mLocalBoobConfig.boobSize = param->getCurrentWeight(); - EmeraldBoobInputs boobInputs; - boobInputs.type = 0; - boobInputs.chestPosition = mChestp->getWorldPosition(); - boobInputs.chestRotation = mChestp->getWorldRotation(); - boobInputs.elapsedTime = mBoobBounceTimer.getElapsedTimeF32(); - boobInputs.appearanceFlag = getAppearanceFlag(); + if(!avatar_physics || (!isSelf() && !mSupportsPhysics)) + { + mLocalBoobConfig.boobSize = getVisualParam(EMERALD_BOOB_SIZE_PARAM)->getCurrentWeight(); + EmeraldBoobInputs boobInputs; + boobInputs.chestPosition = mChestp->getWorldPosition(); + boobInputs.chestRotation = mChestp->getWorldRotation(); + boobInputs.elapsedTime = mBoobBounceTimer.getElapsedTimeF32(); + + newBoobState = EmeraldBoobUtils::idleUpdate(sBoobConfig, mLocalBoobConfig, mBoobState, boobInputs); + } - EmeraldBoobState newBoobState = EmeraldBoobUtils::idleUpdate(sBoobConfig, mLocalBoobConfig, mBoobState, boobInputs); if(mBoobState.boobGrav != newBoobState.boobGrav) { - LLVisualParam *param; - param = getVisualParam(507); - - ESex avatar_sex = getSex(); + LLVisualParam *param = getVisualParam(EMERALD_BOOB_GRAVITY_PARAM); param->stopAnimating(FALSE); param->setWeight(llclamp(newBoobState.boobGrav+getActualBoobGrav(), -1.5f, 2.f), FALSE); - param->apply(avatar_sex); + param->apply(getSex()); updateVisualParams(); } @@ -3258,16 +3348,16 @@ void LLVOAvatar::idleUpdateLoadingEffect() // update visibility when avatar is partially loaded if (updateIsFullyLoaded()) // changed? { - if (isFullyLoaded() && isSelf()) + if (isFullyLoaded() && mFirstFullyVisible && isSelf()) { - static bool first_fully_visible = true; - if (first_fully_visible) - { - llinfos << "self isFullyLoaded, first_fully_visible" << llendl; - - first_fully_visible = false; - LLAppearanceMgr::instance().onFirstFullyVisible(); - } + LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + mFirstFullyVisible = FALSE; + LLAppearanceMgr::instance().onFirstFullyVisible(); + } + if (isFullyLoaded() && mFirstFullyVisible && !isSelf()) + { + LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + mFirstFullyVisible = FALSE; } if (isFullyLoaded()) { @@ -3576,26 +3666,15 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); bool is_cloud = getIsCloud(); - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + if (is_appearance != mNameAppearance) { - if (is_appearance != mNameAppearance) + if (is_appearance) { - if (is_appearance) - { - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl; - } - else - { - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl; - } + debugAvatarRezTime("AvatarRezEnteredAppearanceNotification","entered appearance mode"); + } + else + { + debugAvatarRezTime("AvatarRezLeftAppearanceNotification","left appearance mode"); } } @@ -3698,6 +3777,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) // Suppress SLID display if display name matches exactly (ugh) if (show_usernames && !av_name.mIsDisplayNameDefault && !av_name.mUsername.empty()) { + firstnameText.push_back(' '); firstnameText.push_back('('); firstnameText.append(av_name.mUsername); //Defer for later formatting firstnameText.push_back(')'); @@ -4617,7 +4697,7 @@ void LLVOAvatar::updateVisibility() LLNameValue* firstname = getNVPair("FirstName"); if (firstname) { - llinfos << "Avatar " << firstname->getString() << " updating visiblity" << llendl; + LL_DEBUGS("Avatar") << avString() << " updating visibility" << LL_ENDL; } else { @@ -4772,10 +4852,14 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) mNeedsSkin = FALSE; mLastSkinTime = gFrameTimeSeconds; - LLVertexBuffer* vb = mDrawable->getFace(0)->getVertexBuffer(); - if (vb) + LLFace * face = mDrawable->getFace(0); + if (face) { - vb->flush(); + LLVertexBuffer* vb = face->getVertexBuffer(); + if (vb) + { + vb->flush(); + } } } } @@ -4789,7 +4873,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) LLNameValue* firstname = getNVPair("FirstName"); if (firstname) { - llinfos << "Avatar " << firstname->getString() << " in render" << llendl; + LL_DEBUGS("Avatar") << avString() << " in render" << LL_ENDL; } else { @@ -7366,10 +7450,10 @@ BOOL LLVOAvatar::isVisible() const } // Determine if we have enough avatar data to render -BOOL LLVOAvatar::getIsCloud() +BOOL LLVOAvatar::getIsCloud() const { // Do we have a shape? - if (visualParamWeightsAreDefault()) + if ((const_cast(this))->visualParamWeightsAreDefault()) { return TRUE; } @@ -7388,11 +7472,53 @@ BOOL LLVOAvatar::getIsCloud() return FALSE; } +void LLVOAvatar::updateRezzedStatusTimers() +{ + // State machine for rezzed status. Statuses are 0 = cloud, 1 = gray, 2 = textured. + // Purpose is to collect time data for each period of cloud or cloud+gray. + S32 rez_status = getRezzedStatus(); + if (rez_status != mLastRezzedStatus) + { + LL_DEBUGS("Avatar") << avString() << "rez state change: " << mLastRezzedStatus << " -> " << rez_status << LL_ENDL; + /*bool is_cloud_or_gray = (rez_status==0 || rez_status==1); + bool was_cloud_or_gray = (mLastRezzedStatus==0 || mLastRezzedStatus==1); + bool is_cloud = (rez_status==0); + bool was_cloud = (mLastRezzedStatus==0); + + ]// Non-cloud to cloud + if (is_cloud && !was_cloud) + { + // start cloud timer. + getPhases().startPhase("cloud"); + } + else if (was_cloud && !is_cloud) + { + // stop cloud timer, which will capture stats. + getPhases().stopPhase("cloud"); + } + + // Non-cloud-or-gray to cloud-or-gray + if (is_cloud_or_gray && !was_cloud_or_gray) + { + // start cloud-or-gray timer. + getPhases().startPhase("cloud-or-gray"); + } + else if (was_cloud_or_gray && !is_cloud_or_gray) + { + // stop cloud-or-gray timer, which will capture stats. + getPhases().stopPhase("cloud-or-gray"); + }*/ + + mLastRezzedStatus = rez_status; + } +} + // call periodically to keep isFullyLoaded up to date. // returns true if the value has changed. BOOL LLVOAvatar::updateIsFullyLoaded() { const BOOL loading = getIsCloud(); + updateRezzedStatusTimers(); updateRuthTimer(loading); return processFullyLoadedChange(loading); } @@ -7407,27 +7533,19 @@ void LLVOAvatar::updateRuthTimer(bool loading) if (mPreviousFullyLoaded) { mRuthTimer.reset(); - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezCloudNotification",args); - } - mRuthDebugTimer.reset(); + debugAvatarRezTime("AvatarRezCloudNotification","became cloud"); } const F32 LOADING_TIMEOUT__SECONDS = 120.f; if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS) { - llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " + LL_DEBUGS("Avatar") << avString() + << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) " << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) " << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) " << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )." - << llendl; + << LL_ENDL; LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); mRuthTimer.reset(); @@ -7444,20 +7562,13 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE); - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + if (!mPreviousFullyLoaded && !loading && mFullyLoaded) { - if (!mPreviousFullyLoaded && !loading && mFullyLoaded) - { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezNotification",args); - } + debugAvatarRezTime("AvatarRezNotification","fully loaded"); } // did our loading state "change" from last call? + // runway - why are we updating every 30 calls even if nothing has changed? const S32 UPDATE_RATE = 30; BOOL changed = ((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call @@ -7909,8 +8020,8 @@ LLColor4 LLVOAvatar::getDummyColor() } void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const -{ - llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl; +{ + LL_DEBUGS("Avatar") << avString() << (isSelf() ? "Self: " : "Other: ") << context << LL_ENDL; for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); ++iter) @@ -7920,27 +8031,27 @@ void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const const LLViewerTexture* te_image = getImage(iter->first,0); if( !te_image ) { - llinfos << " " << texture_dict->mName << ": null ptr" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": null ptr" << LL_ENDL; } else if( te_image->getID().isNull() ) { - llinfos << " " << texture_dict->mName << ": null UUID" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": null UUID" << LL_ENDL; } else if( te_image->getID() == IMG_DEFAULT ) { - llinfos << " " << texture_dict->mName << ": IMG_DEFAULT" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": IMG_DEFAULT" << LL_ENDL; } else if (te_image->getID() == IMG_INVISIBLE) { - llinfos << " " << texture_dict->mName << ": IMG_INVISIBLE" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": IMG_INVISIBLE" << LL_ENDL; } else if( te_image->getID() == IMG_DEFAULT_AVATAR ) { - llinfos << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << LL_ENDL; } else { - llinfos << " " << texture_dict->mName << ": " << te_image->getID() << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": " << te_image->getID() << LL_ENDL; } } } @@ -8071,6 +8182,7 @@ void LLVOAvatar::rebuildHUD() //----------------------------------------------------------------------------- void LLVOAvatar::onFirstTEMessageReceived() { + LL_INFOS("Avatar") << avString() << LL_ENDL; if( !mFirstTEMessageReceived ) { mFirstTEMessageReceived = TRUE; @@ -8099,6 +8211,7 @@ void LLVOAvatar::onFirstTEMessageReceived() image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), src_callback_list, paused); } + LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL; image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), src_callback_list, paused ); } @@ -8157,14 +8270,16 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) LLMemType mt(LLMemType::MTYPE_AVATAR); -// llinfos << "processAvatarAppearance start " << mID << llendl; BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived; - mFirstAppearanceMessageReceived = TRUE; + LL_INFOS("Avatar") << avString() << "processAvatarAppearance start " << mID + << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL; + + if( isSelf() ) { - llwarns << "Received AvatarAppearance for self" << llendl; + llwarns << avString() << "Received AvatarAppearance for self" << llendl; if( mFirstTEMessageReceived ) { // llinfos << "processAvatarAppearance end " << mID << llendl; @@ -8207,7 +8322,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) // (isTextureDefined(TEX_HAIR_BAKED) ? "HAIR" : "hair " ) << (getTEImage(TEX_HAIR_BAKED)->getID()) << std::endl << // (isTextureDefined(TEX_EYES_BAKED) ? "EYES" : "eyes" ) << (getTEImage(TEX_EYES_BAKED)->getID()) << llendl ; - if( !is_first_appearance_message ) + if( is_first_appearance_message ) { onFirstTEMessageReceived(); } @@ -8229,6 +8344,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); if( num_blocks > 1 ) { + LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL; BOOL params_changed = FALSE; BOOL interp_params = FALSE; @@ -8261,23 +8377,10 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) { mSupportsPhysics = true; } - else if(param->getID() == 507 && newWeight != getActualBoobGrav()) + else if(param->getID() == EMERALD_BOOB_GRAVITY_PARAM && newWeight != getActualBoobGrav()) { - llwarns << "Boob Grav SET to " << newWeight << " for " << getFullname() << llendl; setActualBoobGrav(newWeight); } - /*if(param->getID() == 795 && newWeight != getActualButtGrav()) - { - llwarns << "Butt Grav SET to " << newWeight << " for " << getFullname() << llendl; - setActualButtGrav(newWeight); - } - if(param->getID() == 157 && newWeight != getActualFatGrav()) - { - llwarns << "Fat Grav SET to " << newWeight << " for " << getFullname() << llendl; - setActualFatGrav(newWeight); - } - */ - if (is_first_appearance_message || (param->getWeight() != newWeight)) { @@ -8406,7 +8509,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture } U32 gl_name; - LLImageGL::generateTextures(1, &gl_name ); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_ALPHA8, 1, &gl_name ); stop_glerror(); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); @@ -8443,7 +8546,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture maskData->mLastDiscardLevel = discard_level; if (self->mBakedTextureDatas[baked_index].mMaskTexName) { - LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); } self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; found_texture_id = true; @@ -8476,6 +8579,11 @@ void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTextu { LLUUID *avatar_idp = (LLUUID *)userdata; LLVOAvatar *selfp = gObjectList.findAvatar(*avatar_idp); + + if (selfp) + { + LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << LL_ENDL; + } if (!success && selfp) { @@ -8487,13 +8595,20 @@ void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTextu } } -void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +// Static +void LLVOAvatar::onBakedTextureLoaded(BOOL success, + LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, + S32 discard_level, BOOL final, void* userdata) { //llinfos << "onBakedTextureLoaded: " << src_vi->getID() << llendl; LLUUID id = src_vi->getID(); LLUUID *avatar_idp = (LLUUID *)userdata; LLVOAvatar *selfp = gObjectList.findAvatar(*avatar_idp); + if (selfp) + { + LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << " id " << src_vi->getID() << LL_ENDL; + } if (selfp && !success) { @@ -8525,6 +8640,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 ); if (id == image_baked->getID()) { + LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; mBakedTextureDatas[i].mIsLoaded = true; mBakedTextureDatas[i].mLastTextureIndex = id; mBakedTextureDatas[i].mIsUsed = true; @@ -8608,6 +8724,11 @@ void LLVOAvatar::dumpArchetypeXML( void* ) } apr_file_printf( file, "\t\n" ); apr_file_printf( file, "\n\n" ); + //explictly close the file if it is still open which it should be + if (file) + { + outfile.close(); + } } @@ -9279,7 +9400,7 @@ BOOL LLVOAvatar::updateLOD() BOOL res = updateJointLODs(); LLFace* facep = mDrawable->getFace(0); - if (!facep->getVertexBuffer()) + if (!facep || !facep->getVertexBuffer()) { dirtyMesh(2); } @@ -9492,7 +9613,9 @@ void LLVOAvatar::idleUpdateRenderCost() } } - setDebugText(llformat("%d", cost)); + + std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); + setDebugText(llformat("%s %d", viz_string.c_str(), cost)); mVisualComplexity = cost; F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 87e23906c..e0d4b3bf5 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -326,14 +326,21 @@ public: public: BOOL isFullyLoaded() const; bool visualParamWeightsAreDefault(); + virtual BOOL getIsCloud() const; + BOOL isFullyTextured() const; + BOOL hasGray() const; + S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = fully textured. + void updateRezzedStatusTimers(); + + S32 mLastRezzedStatus; protected: - virtual BOOL getIsCloud(); BOOL updateIsFullyLoaded(); BOOL processFullyLoadedChange(bool loading); void updateRuthTimer(bool loading); F32 calcMorphAmount(); private: + BOOL mFirstFullyVisible; BOOL mFullyLoaded; BOOL mPreviousFullyLoaded; BOOL mFullyLoadedInitialized; @@ -567,9 +574,10 @@ public: virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const; -protected: BOOL isFullyBaked(); static BOOL areAllNearbyInstancesBaked(S32& grey_avatars); + static void getNearbyRezzedStats(std::vector& counts); + static std::string rezStatusToString(S32 status); //-------------------------------------------------------------------- // Baked textures @@ -600,9 +608,6 @@ protected: bakedtexturedata_vec_t mBakedTextureDatas; LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; BOOL mLoadedCallbacksPaused; - -public: - const BakedTextureData& getBakedTextureData(LLVOAvatarDefines::ETextureIndex idx) const {return mBakedTextureDatas[idx];} //-------------------------------------------------------------------- // Local Textures //-------------------------------------------------------------------- @@ -918,6 +923,9 @@ private: BOOL mStepOnLand; U8 mStepMaterial; LLVector3 mStepObjectVelocity; + +public: + bool mSupportsPhysics; //Client supports v2 wearable physics. Disable emerald physics. //-------------------------------------------------------------------- // Emerald legacy boob bounce @@ -939,10 +947,7 @@ private: LLFrameTimer mBoobBounceTimer; EmeraldAvatarLocalBoobConfig mLocalBoobConfig; EmeraldBoobState mBoobState; - -public: - bool mSupportsPhysics; //Client supports v2 wearable physics. Disable emerald physics. - + /** Physics ** ** *******************************************************************************/ @@ -980,6 +985,7 @@ private: public: std::string getFullname() const; // Returns "FirstName LastName" + std::string avString() const; // Frequently used string in log messages "Avatar '* labels); static void getAnimNames(LLDynamicArray* names); @@ -1078,11 +1084,14 @@ private: F32 mAdjustedPixelArea; std::string mDebugText; + //-------------------------------------------------------------------- // Avatar Rez Metrics //-------------------------------------------------------------------- public: + void debugAvatarRezTime(std::string notification_name, std::string comment = ""); F32 debugGetExistenceTimeElapsedF32() const { return mDebugExistenceTimer.getElapsedTimeF32(); } + protected: LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory. @@ -1228,4 +1237,6 @@ private: extern const F32 SELF_ADDITIONAL_PRI; extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; +extern const U32 EMERALD_BOOB_SIZE_PARAM; //"Breast Size" +extern const U32 EMERALD_BOOB_GRAVITY_PARAM; //"Breast_Gravity" #endif // LL_VO_AVATAR_H diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 37921cabf..fdfc565e3 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -136,7 +136,8 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, LLVOAvatar(id, pcode, regionp), mScreenp(NULL), mLastRegionHandle(0), - mRegionCrossingCount(0) + mRegionCrossingCount(0), + mInitialBakesLoaded(false) { gAgentWearables.setAvatarObject(this); gAgentCamera.setAvatarObject(this); @@ -172,6 +173,7 @@ void LLVOAvatarSelf::initInstance() { mDebugBakedTextureTimes[i][0] = -1.0f; mDebugBakedTextureTimes[i][1] = -1.0f; + mInitialBakeIDs[i] = LLUUID::null; } // [RLVa:KB] - Checked: 2010-12-12 (RLVa-1.2.2c) | Added: RLVa-1.2.2c @@ -655,6 +657,11 @@ BOOL LLVOAvatarSelf::setParamWeight(LLViewerVisualParam *param, F32 weight, BOOL } } + if(param->getID() == EMERALD_BOOB_GRAVITY_PARAM && weight != getActualBoobGrav()) + { + setActualBoobGrav(weight); + } + return LLCharacter::setVisualParamWeight(param,weight,upload_bake); } @@ -710,6 +717,40 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) } } +//virtual +U32 LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp) +{ + U32 retval = LLVOAvatar::processUpdateMessage(mesgsys,user_data,block_num,update_type,dp); + + if (mInitialBakesLoaded == false && retval == 0x0) + { + // call update textures to force the images to be created + updateMeshTextures(); + + // unpack the texture UUIDs to the texture slots + retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); + + // need to trigger a few operations to get the avatar to use the new bakes + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + const LLVOAvatarDefines::ETextureIndex te = mBakedTextureDatas[i].mTextureIndex; + LLUUID texture_id = getTEImage(te)->getID(); + setNewBakedTexture(te, texture_id); + mInitialBakeIDs[i] = texture_id; + } + + onFirstTEMessageReceived(); + + mInitialBakesLoaded = true; + } + + return retval; +} + void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index) { if (te >= TEX_NUM_INDICES) @@ -1908,7 +1949,7 @@ void LLVOAvatarSelf::dumpTotalLocalTextureByteCount() llinfos << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << llendl; } -BOOL LLVOAvatarSelf::getIsCloud() +BOOL LLVOAvatarSelf::getIsCloud() const { // do we have our body parts? if (gAgentWearables.getWearableCount(LLWearableType::WT_SHAPE) == 0 || @@ -2369,6 +2410,18 @@ void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid { if ( mBakedTextureDatas[i].mTextureIndex == te && mBakedTextureDatas[i].mTexLayerSet) { + if (mInitialBakeIDs[i] != LLUUID::null) + { + if (mInitialBakeIDs[i] == uuid) + { + llinfos << "baked texture correctly loaded at login! " << i << llendl; + } + else + { + llwarns << "baked texture does not match id loaded at login!" << i << llendl; + } + mInitialBakeIDs[i] = LLUUID::null; + } mBakedTextureDatas[i].mTexLayerSet->cancelUpload(); } } @@ -2496,6 +2549,20 @@ LLTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const return NULL; } +LLTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index) const +{ + /* switch(index) + case TEX_HEAD_BAKED: + case TEX_HEAD_BODYPAINT: + return mHeadLayerSet; */ + if (baked_index >= 0 && baked_index < BAKED_NUM_INDICES) + { + return mBakedTextureDatas[baked_index].mTexLayerSet; + } + return NULL; +} + + // static void LLVOAvatarSelf::onCustomizeStart() { @@ -2629,7 +2696,7 @@ void LLVOAvatarSelf::deleteScratchTextures() namep; namep = sScratchTexNames.getNextData() ) { - LLImageGL::deleteTextures(1, (U32 *)namep ); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, (U32 *)namep ); stop_glerror(); } diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index adb2874eb..0105315ff 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -93,15 +93,27 @@ public: /*virtual*/ void updateVisualParams(); /*virtual*/ void idleUpdateAppearanceAnimation(); + /*virtual*/ U32 processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp); + private: // helper function. Passed in param is assumed to be in avatar's parameter list. BOOL setParamWeight(LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE ); + /** Initialization ** ** *******************************************************************************/ +private: + LLUUID mInitialBakeIDs[6]; + bool mInitialBakesLoaded; + + /******************************************************************************** ** ** ** STATE @@ -121,7 +133,7 @@ public: // Loading state //-------------------------------------------------------------------- public: - /*virtual*/ BOOL getIsCloud(); + /*virtual*/ BOOL getIsCloud() const; //-------------------------------------------------------------------- // Region state @@ -229,6 +241,7 @@ public: void requestLayerSetUpload(LLVOAvatarDefines::EBakedTextureIndex i); void requestLayerSetUpdate(LLVOAvatarDefines::ETextureIndex i); LLTexLayerSet* getLayerSet(LLVOAvatarDefines::ETextureIndex index) const; + LLTexLayerSet* getLayerSet(LLVOAvatarDefines::EBakedTextureIndex baked_index) const; //-------------------------------------------------------------------- // Composites diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp index 18e597b15..b63103acb 100644 --- a/indra/newview/llvoclouds.cpp +++ b/indra/newview/llvoclouds.cpp @@ -52,6 +52,7 @@ #include "pipeline.h" #include "llspatialpartition.h" +#if ENABLE_CLASSIC_CLOUDS LLUUID gCloudTextureID = IMG_CLOUD_POOF; @@ -119,29 +120,48 @@ static LLFastTimer::DeclareTimer FTM_UPDATE_CLOUDS("Cloud Update"); BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(FTM_UPDATE_CLOUDS); - if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS))) - { - return TRUE; - } - if (drawable->isVisible()) + dirtySpatialGroup(); + + S32 num_parts = mCloudGroupp->getNumPuffs(); + LLFace *facep; + LLSpatialGroup* group = drawable->getSpatialGroup(); + if (!group && num_parts) + { + drawable->movePartition(); + group = drawable->getSpatialGroup(); + } + + if (group && group->isVisible()) { dirtySpatialGroup(TRUE); } - LLFace *facep; - - S32 num_faces = mCloudGroupp->getNumPuffs(); - - if (num_faces > drawable->getNumFaces()) + if (!num_parts) { - drawable->setNumFacesFast(num_faces, NULL, getTEImage(0)); + if (group && drawable->getNumFaces()) + { + group->setState(LLSpatialGroup::GEOM_DIRTY); + } + drawable->setNumFaces(0, NULL, getTEImage(0)); + LLPipeline::sCompiles++; + return TRUE; + } + + if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS))) + { + return TRUE; + } + + if (num_parts > drawable->getNumFaces()) + { + drawable->setNumFacesFast(num_parts+num_parts/4, NULL, getTEImage(0)); } mDepth = (getPositionAgent()-LLViewerCamera::getInstance()->getOrigin())*LLViewerCamera::getInstance()->getAtAxis(); S32 face_indx = 0; - for ( ; face_indx < num_faces; face_indx++) + for ( ; face_indx < num_parts; face_indx++) { facep = drawable->getFace(face_indx); if (!facep) @@ -150,16 +170,18 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) continue; } + facep->setTEOffset(face_indx); facep->setSize(4, 6); - facep->setTEOffset(face_indx); - facep->setTexture(getTEImage(0)); + facep->setViewerObject(this); + const LLCloudPuff &puff = mCloudGroupp->getPuff(face_indx); const LLVector3 puff_pos_agent = gAgent.getPosAgentFromGlobal(puff.getPositionGlobal()); facep->mCenterLocal = puff_pos_agent; /// Update cloud color based on sun color. LLColor4 float_color(LLColor3(gSky.getSunDiffuseColor() + gSky.getSunAmbientColor()),puff.getAlpha()); facep->setFaceColor(float_color); + facep->setTexture(getTEImage(0)); } for ( ; face_indx < drawable->getNumFaces(); face_indx++) { @@ -174,8 +196,8 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) facep->setSize(0,0); } - drawable->movePartition(); - + mDrawable->movePartition(); + LLPipeline::sCompiles++; return TRUE; } @@ -212,8 +234,6 @@ void LLVOClouds::getGeometry(S32 idx, color.setVec(float_color); facep->setFaceColor(float_color); - U32 vert_offset = facep->getGeomIndex(); - LLVector4a part_pos_agent; part_pos_agent.load3(facep->mCenterLocal.mV); LLVector4a at; @@ -250,33 +270,15 @@ void LLVOClouds::getGeometry(S32 idx, verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; - // *verticesp++ = puff_pos_agent - right + up; - // *verticesp++ = puff_pos_agent - right - up; - // *verticesp++ = puff_pos_agent + right + up; - // *verticesp++ = puff_pos_agent + right - up; - *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; - *texcoordsp++ = LLVector2(0.f, 1.f); - *texcoordsp++ = LLVector2(0.f, 0.f); - *texcoordsp++ = LLVector2(1.f, 1.f); - *texcoordsp++ = LLVector2(1.f, 0.f); - *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; - - *indicesp++ = vert_offset + 0; - *indicesp++ = vert_offset + 1; - *indicesp++ = vert_offset + 2; - - *indicesp++ = vert_offset + 1; - *indicesp++ = vert_offset + 3; - *indicesp++ = vert_offset + 2; } U32 LLVOClouds::getPartitionType() const @@ -302,3 +304,4 @@ LLCloudPartition::LLCloudPartition() mPartitionType = LLViewerRegion::PARTITION_CLOUD; } +#endif diff --git a/indra/newview/llvoclouds.h b/indra/newview/llvoclouds.h index dfe664beb..685400f32 100644 --- a/indra/newview/llvoclouds.h +++ b/indra/newview/llvoclouds.h @@ -42,7 +42,7 @@ class LLViewerCloudGroup; class LLCloudGroup; - +#if ENABLE_CLASSIC_CLOUDS class LLVOClouds : public LLAlphaObject { public: @@ -82,4 +82,5 @@ protected: extern LLUUID gCloudTextureID; +#endif #endif // LL_VO_CLOUDS_H diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 1fa3fcac6..5a58ae770 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -41,6 +41,7 @@ #include "llnotificationsutil.h" #include "llviewerwindow.h" #include "lldrawable.h" +#include "lldrawpoolalpha.h" #include "llface.h" #include "llsky.h" #include "llsurface.h" @@ -403,8 +404,10 @@ BOOL LLVOGrass::updateLOD() { mNumBlades <<= 1; } - - face->setSize(mNumBlades*8, mNumBlades*12); + if (face) + { + face->setSize(mNumBlades*8, mNumBlades*12); + } gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } else if (num_blades <= (mNumBlades >> 1)) @@ -414,7 +417,10 @@ BOOL LLVOGrass::updateLOD() mNumBlades >>=1; } - face->setSize(mNumBlades*8, mNumBlades*12); + if (face) + { + face->setSize(mNumBlades*8, mNumBlades*12); + } gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); return TRUE; } @@ -472,14 +478,16 @@ void LLVOGrass::plantBlades() } LLFace *face = mDrawable->getFace(0); + if (face) + { + face->setTexture(getTEImage(0)); + face->setState(LLFace::GLOBAL); + face->setSize(mNumBlades * 8, mNumBlades * 12); + face->setVertexBuffer(NULL); + face->setTEOffset(0); + face->mCenterLocal = mPosition + mRegionp->getOriginAgent(); + } - face->setTexture(getTEImage(0)); - face->setState(LLFace::GLOBAL); - face->setSize(mNumBlades * 8, mNumBlades * 12); - face->setVertexBuffer(NULL); - face->setTEOffset(0); - face->mCenterLocal = mPosition + mRegionp->getOriginAgent(); - mDepth = (face->mCenterLocal - LLViewerCamera::getInstance()->getOrigin())*LLViewerCamera::getInstance()->getAtAxis(); mDrawable->setPosition(face->mCenterLocal); mDrawable->movePartition(); @@ -509,6 +517,8 @@ void LLVOGrass::getGeometry(S32 idx, LLColor4U color(255,255,255,255); LLFace *face = mDrawable->getFace(idx); + if (!face) + return; F32 width = sSpeciesTable[mSpecies]->mBladeSizeX; F32 height = sSpeciesTable[mSpecies]->mBladeSizeY; @@ -617,6 +627,7 @@ U32 LLVOGrass::getPartitionType() const } LLGrassPartition::LLGrassPartition() +: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB) { mDrawableType = LLPipeline::RENDER_TYPE_GRASS; mPartitionType = LLViewerRegion::PARTITION_GRASS; @@ -627,6 +638,143 @@ LLGrassPartition::LLGrassPartition() mBufferUsage = GL_DYNAMIC_DRAW_ARB; } +void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count) +{ + group->mBufferUsage = mBufferUsage; + + mFaceList.clear(); + + LLViewerCamera* camera = LLViewerCamera::getInstance(); + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawablep = *i; + + if (drawablep->isDead()) + { + continue; + } + + LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get(); + obj->mDepth = 0.f; + + if (drawablep->isAnimating()) + { + group->mBufferUsage = GL_STREAM_DRAW_ARB; + } + + U32 count = 0; + for (S32 j = 0; j < drawablep->getNumFaces(); ++j) + { + drawablep->updateFaceSize(j); + + LLFace* facep = drawablep->getFace(j); + if ( !facep || !facep->hasGeometry()) + { + continue; + } + + if ((facep->getGeomCount() + vertex_count) <= 65536) + { + count++; + facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis(); + obj->mDepth += facep->mDistance; + + mFaceList.push_back(facep); + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + llassert(facep->getIndicesCount() < 65536); + } + else + { + facep->clearVertexBuffer(); + } + } + + obj->mDepth /= count; + } +} + +static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB"); + +void LLGrassPartition::getGeometry(LLSpatialGroup* group) +{ + LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + LLFastTimer ftm(FTM_REBUILD_GRASS_VB); + + std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); + + U32 index_count = 0; + U32 vertex_count = 0; + + group->clearDrawMap(); + + LLVertexBuffer* buffer = group->mVertexBuffer; + + LLStrider indicesp; + LLStrider verticesp; + LLStrider normalsp; + LLStrider texcoordsp; + LLStrider colorsp; + + buffer->getVertexStrider(verticesp); + buffer->getNormalStrider(normalsp); + buffer->getColorStrider(colorsp); + buffer->getTexCoord0Strider(texcoordsp); + buffer->getIndexStrider(indicesp); + + LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass]; + + for (std::vector::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i) + { + LLFace* facep = *i; + LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject(); + facep->setGeomIndex(vertex_count); + facep->setIndicesIndex(index_count); + facep->setVertexBuffer(buffer); + facep->setPoolType(LLDrawPool::POOL_ALPHA); + object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp); + + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + + S32 idx = draw_vec.size()-1; + + BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); + F32 vsize = facep->getVirtualSize(); + + if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && + draw_vec[idx]->mTexture == facep->getTexture() && + (U16) (draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount()) <= (U32) gGLManager.mGLMaxVertexRange && + //draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && + draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() < 4096 && + draw_vec[idx]->mFullbright == fullbright) + { + draw_vec[idx]->mCount += facep->getIndicesCount(); + draw_vec[idx]->mEnd += facep->getGeomCount(); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } + else + { + U32 start = facep->getGeomIndex(); + U32 end = start + facep->getGeomCount()-1; + U32 offset = facep->getIndicesStart(); + U32 count = facep->getIndicesCount(); + LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), + //facep->getTexture(), + buffer, fullbright); + info->mExtents[0] = group->mObjectExtents[0]; + info->mExtents[1] = group->mObjectExtents[1]; + info->mVSize = vsize; + draw_vec.push_back(info); + //for alpha sorting + facep->setDrawInfo(info); + } + } + + buffer->flush(); + mFaceList.clear(); +} + // virtual void LLVOGrass::updateDrawable(BOOL force_damped) { @@ -713,7 +861,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; diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp index ebb7bfda7..3300cb697 100644 --- a/indra/newview/llvoground.cpp +++ b/indra/newview/llvoground.cpp @@ -88,6 +88,7 @@ LLDrawable *LLVOGround::createDrawable(LLPipeline *pipeline) return mDrawable; } +// TO DO - this always returns TRUE, BOOL LLVOGround::updateGeometry(LLDrawable *drawable) { LLStrider verticesp; @@ -102,6 +103,8 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable) if (drawable->getNumFaces() < 1) drawable->addFace(poolp, NULL); face = drawable->getFace(0); + if (!face) + return TRUE; if (!face->getVertexBuffer()) { diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index c6a50207f..c5ceee40c 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -49,11 +49,145 @@ #include "llviewerregion.h" #include "pipeline.h" #include "llspatialpartition.h" +#include "llviewerobjectlist.h" const F32 MAX_PART_LIFETIME = 120.f; extern U64 gFrameTime; +LLPointer LLVOPartGroup::sVB = NULL; +S32 LLVOPartGroup::sVBSlotFree[]; +S32* LLVOPartGroup::sVBSlotCursor = NULL; + +//static +void LLVOPartGroup::restoreGL() +{ + //Just iterate over all particle faces and mark their vbo index as 'uninitialized' since sVBSlotFree & sVBSlotCursor will be clobbered. + for (int i=0; imDrawable) + { + if (obj->mDrawable->getRenderType() == LLPipeline::RENDER_TYPE_PARTICLES || + obj->mDrawable->getRenderType() == LLPipeline::RENDER_TYPE_HUD_PARTICLES +#if ENABLE_CLASSIC_CLOUDS + || obj->mDrawable->getRenderType() == LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS +#endif + ) + { + for (S32 j = 0; j < obj->mDrawable->getNumFaces(); ++j) + { + LLFace* facep = obj->mDrawable->getFace(j); + if(facep) + facep->setIndicesIndex(0xFFFFFFFF); + } + } + } + } + for (S32 i = 0; i < LL_MAX_PARTICLE_COUNT; ++i) + { + sVBSlotFree[i] = i; + } + + sVBSlotCursor = sVBSlotFree; + + sVB = new LLVertexBuffer(VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + U32 count = LL_MAX_PARTICLE_COUNT; + sVB->allocateBuffer(count*4, count*6, true); + + //indices and texcoords are always the same, set once + LLStrider indicesp; + + LLStrider verticesp; + + sVB->getIndexStrider(indicesp); + sVB->getVertexStrider(verticesp); + + LLVector4a v; + v.set(0,0,0,0); + + + U16 vert_offset = 0; + + for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) + { + *indicesp++ = vert_offset + 0; + *indicesp++ = vert_offset + 1; + *indicesp++ = vert_offset + 2; + + *indicesp++ = vert_offset + 1; + *indicesp++ = vert_offset + 3; + *indicesp++ = vert_offset + 2; + + *verticesp++ = v; + + vert_offset += 4; + } + + LLStrider texcoordsp; + sVB->getTexCoord0Strider(texcoordsp); + + for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) + { + *texcoordsp++ = LLVector2(0.f, 1.f); + *texcoordsp++ = LLVector2(0.f, 0.f); + *texcoordsp++ = LLVector2(1.f, 1.f); + *texcoordsp++ = LLVector2(1.f, 0.f); + } + + sVB->flush(); + +} + +//static +void LLVOPartGroup::destroyGL() +{ + sVB = NULL; +} + +//static +S32 LLVOPartGroup::findAvailableVBSlot() +{ + if (sVBSlotCursor >= sVBSlotFree+LL_MAX_PARTICLE_COUNT) + { //no more available slots + return -1; + } + + S32 ret = *sVBSlotCursor; + sVBSlotCursor++; + + + return ret; +} + +bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end) +{ + while (start < end) + { + if (*start == idx) + { //not allocated (in free list) + return false; + } + ++start; + } + + //allocated (not in free list) + return true; +} + +//static +void LLVOPartGroup::freeVBSlot(S32 idx) +{ + llassert(idx < LL_MAX_PARTICLE_COUNT && idx >= 0); + llassert(sVBSlotCursor > sVBSlotFree); + llassert(ll_is_part_idx_allocated(idx, sVBSlotCursor, sVBSlotFree+LL_MAX_PARTICLE_COUNT)); + + if (sVBSlotCursor > sVBSlotFree) + { + sVBSlotCursor--; + *sVBSlotCursor = idx; + } +} LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLAlphaObject(id, pcode, regionp), mViewerPartGroupp(NULL) @@ -287,9 +421,6 @@ void LLVOPartGroup::getGeometry(S32 idx, const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); - U32 vert_offset = mDrawable->getFace(idx)->getGeomIndex(); - - LLVector4a part_pos_agent; part_pos_agent.load3(part.mPosAgent.mV); LLVector4a camera_agent; @@ -361,33 +492,18 @@ void LLVOPartGroup::getGeometry(S32 idx, verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; - // *verticesp++ = part_pos_agent + up - right; - // *verticesp++ = part_pos_agent - up - right; - // *verticesp++ = part_pos_agent + up + right; - // *verticesp++ = part_pos_agent - up + right; - *colorsp++ = part.mColor; *colorsp++ = part.mColor; *colorsp++ = part.mColor; *colorsp++ = part.mColor; - *texcoordsp++ = LLVector2(0.f, 1.f); - *texcoordsp++ = LLVector2(0.f, 0.f); - *texcoordsp++ = LLVector2(1.f, 1.f); - *texcoordsp++ = LLVector2(1.f, 0.f); - - *normalsp++ = normal; - *normalsp++ = normal; - *normalsp++ = normal; - *normalsp++ = normal; - - *indicesp++ = vert_offset + 0; - *indicesp++ = vert_offset + 1; - *indicesp++ = vert_offset + 2; - - *indicesp++ = vert_offset + 1; - *indicesp++ = vert_offset + 3; - *indicesp++ = vert_offset + 2; + if (!(part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK)) + { //not fullbright, needs normal + *normalsp++ = normal; + *normalsp++ = normal; + *normalsp++ = normal; + *normalsp++ = normal; + } } U32 LLVOPartGroup::getPartitionType() const @@ -412,6 +528,49 @@ LLHUDParticlePartition::LLHUDParticlePartition() : mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE; } +static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VBO("Particle VBO"); + +void LLParticlePartition::rebuildGeom(LLSpatialGroup* group) +{ + if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) + { + return; + } + + if (group->changeLOD()) + { + group->mLastUpdateDistance = group->mDistance; + group->mLastUpdateViewAngle = group->mViewAngle; + } + + LLFastTimer ftm(FTM_REBUILD_PARTICLE_VBO); + + group->clearDrawMap(); + + //get geometry count + U32 index_count = 0; + U32 vertex_count = 0; + + addGeometryCount(group, vertex_count, index_count); + + + if (vertex_count > 0 && index_count > 0) + { + group->mBuilt = 1.f; + //use one vertex buffer for all groups + group->mVertexBuffer = LLVOPartGroup::sVB; + getGeometry(group); + } + else + { + group->mVertexBuffer = NULL; + group->mBufferMap.clear(); + } + + group->mLastUpdateTime = gFrameTimeSeconds; + group->clearState(LLSpatialGroup::GEOM_DIRTY); +} + void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count) { group->mBufferUsage = mBufferUsage; @@ -431,11 +590,6 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get(); obj->mDepth = 0.f; - if (drawablep->isAnimating()) - { - group->mBufferUsage = GL_STREAM_DRAW_ARB; - } - U32 count = 0; for (S32 j = 0; j < drawablep->getNumFaces(); ++j) { @@ -447,36 +601,28 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co continue; } - if ((facep->getGeomCount() + vertex_count) <= 65536) - { - count++; - facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis(); - obj->mDepth += facep->mDistance; + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + + count++; + facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis(); + obj->mDepth += facep->mDistance; - mFaceList.push_back(facep); - vertex_count += facep->getGeomCount(); - index_count += facep->getIndicesCount(); - llassert(facep->getIndicesCount() < 65536); - } - else - { - facep->clearVertexBuffer(); - } + mFaceList.push_back(facep); + llassert(facep->getIndicesCount() < 65536); } obj->mDepth /= count; } } -static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB"); -static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VB("Particle VB"); + +static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_GEOM("Particle Geom"); void LLParticlePartition::getGeometry(LLSpatialGroup* group) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - LLFastTimer ftm(mDrawableType == LLPipeline::RENDER_TYPE_GRASS ? - FTM_REBUILD_GRASS_VB : - FTM_REBUILD_PARTICLE_VB); + LLFastTimer ftm(FTM_REBUILD_PARTICLE_GEOM); std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); @@ -496,21 +642,44 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) buffer->getVertexStrider(verticesp); buffer->getNormalStrider(normalsp); buffer->getColorStrider(colorsp); - buffer->getTexCoord0Strider(texcoordsp); - buffer->getIndexStrider(indicesp); - + LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass]; for (std::vector::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i) { LLFace* facep = *i; LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject(); - facep->setGeomIndex(vertex_count); - facep->setIndicesIndex(index_count); - facep->setVertexBuffer(buffer); - facep->setPoolType(LLDrawPool::POOL_ALPHA); - object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp); + + if (facep->getIndicesStart() == 0xFFFFFFFF) + { //set the indices of this face + S32 idx = LLVOPartGroup::findAvailableVBSlot(); + if (idx >= 0) + { + facep->setGeomIndex(idx*4); + facep->setIndicesIndex(idx*6); + facep->setVertexBuffer(LLVOPartGroup::sVB); + facep->setPoolType(LLDrawPool::POOL_ALPHA); + } + else + { + continue; //out of space in particle buffer + } + } + + S32 geom_idx = (S32) facep->getGeomIndex(); + + LLStrider cur_idx = indicesp + facep->getIndicesStart(); + LLStrider cur_vert = verticesp + geom_idx; + LLStrider cur_norm = normalsp + geom_idx; + LLStrider cur_tc = texcoordsp + geom_idx; + LLStrider cur_col = colorsp + geom_idx; + + object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_idx); + llassert(facep->getGeomCount() == 4); + llassert(facep->getIndicesCount() == 6); + + vertex_count += facep->getGeomCount(); index_count += facep->getIndicesCount(); @@ -519,26 +688,39 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); F32 vsize = facep->getVirtualSize(); - if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && + bool batched = false; + + if (idx >= 0 && draw_vec[idx]->mTexture == facep->getTexture() && - (U16) (draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount()) <= (U32) gGLManager.mGLMaxVertexRange && - //draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && - draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() < 4096 && draw_vec[idx]->mFullbright == fullbright) { - draw_vec[idx]->mCount += facep->getIndicesCount(); - draw_vec[idx]->mEnd += facep->getGeomCount(); - draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1) + { + batched = true; + draw_vec[idx]->mCount += facep->getIndicesCount(); + draw_vec[idx]->mEnd += facep->getGeomCount(); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } + else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1) + { + batched = true; + draw_vec[idx]->mCount += facep->getIndicesCount(); + draw_vec[idx]->mStart -= facep->getGeomCount(); + draw_vec[idx]->mOffset = facep->getIndicesStart(); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } } - else + + + if (!batched) { U32 start = facep->getGeomIndex(); U32 end = start + facep->getGeomCount()-1; U32 offset = facep->getIndicesStart(); U32 count = facep->getIndicesCount(); - LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), + LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), //facep->getTexture(), - buffer, fullbright); + buffer, fullbright); info->mExtents[0] = group->mObjectExtents[0]; info->mExtents[1] = group->mObjectExtents[1]; info->mVSize = vsize; @@ -548,7 +730,6 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) } } - buffer->flush(); mFaceList.clear(); } diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h index f11289365..4c2e073d7 100644 --- a/indra/newview/llvopartgroup.h +++ b/indra/newview/llvopartgroup.h @@ -37,18 +37,32 @@ #include "v3math.h" #include "v3color.h" #include "llframetimer.h" +#include "llviewerpartsim.h" +#include "llvertexbuffer.h" class LLViewerPartGroup; class LLVOPartGroup : public LLAlphaObject { public: + + //vertex buffer for holding all particles + static LLPointer sVB; + static S32 sVBSlotFree[LL_MAX_PARTICLE_COUNT]; + static S32* sVBSlotCursor; + + static void restoreGL(); + static void destroyGL(); + static S32 findAvailableVBSlot(); + static void freeVBSlot(S32 idx); + enum { - VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) | - (1 << LLVertexBuffer::TYPE_NORMAL) | - (1 << LLVertexBuffer::TYPE_TEXCOORD0) | - (1 << LLVertexBuffer::TYPE_COLOR) + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_TEXTURE_INDEX }; LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 610697742..a16b4adc9 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -302,18 +302,20 @@ void LLVOSurfacePatch::updateFaceSize(S32 idx) } LLFace* facep = mDrawable->getFace(idx); - - S32 num_vertices = 0; - S32 num_indices = 0; - - if (mLastStride) + if (facep) { - getGeomSizesMain(mLastStride, num_vertices, num_indices); - getGeomSizesNorth(mLastStride, mLastNorthStride, num_vertices, num_indices); - getGeomSizesEast(mLastStride, mLastEastStride, num_vertices, num_indices); - } + S32 num_vertices = 0; + S32 num_indices = 0; + + if (mLastStride) + { + getGeomSizesMain(mLastStride, num_vertices, num_indices); + getGeomSizesNorth(mLastStride, mLastNorthStride, num_vertices, num_indices); + getGeomSizesEast(mLastStride, mLastEastStride, num_vertices, num_indices); + } - facep->setSize(num_vertices, num_indices); + facep->setSize(num_vertices, num_indices); + } } BOOL LLVOSurfacePatch::updateLOD() @@ -328,30 +330,32 @@ void LLVOSurfacePatch::getGeometry(LLStrider &verticesp, LLStrider &indicesp) { LLFace* facep = mDrawable->getFace(0); + if (facep) + { + U32 index_offset = facep->getGeomIndex(); - U32 index_offset = facep->getGeomIndex(); - - updateMainGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - updateNorthGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - updateEastGeometry(facep, + updateMainGeometry(facep, verticesp, normalsp, texCoords0p, texCoords1p, indicesp, index_offset); + updateNorthGeometry(facep, + verticesp, + normalsp, + texCoords0p, + texCoords1p, + indicesp, + index_offset); + updateEastGeometry(facep, + verticesp, + normalsp, + texCoords0p, + texCoords1p, + indicesp, + index_offset); + } } void LLVOSurfacePatch::updateMainGeometry(LLFace *facep, @@ -870,7 +874,11 @@ void LLVOSurfacePatch::dirtyGeom() if (mDrawable) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - mDrawable->getFace(0)->setVertexBuffer(NULL); + LLFace* facep = mDrawable->getFace(0); + if (facep) + { + facep->setVertexBuffer(NULL); + } mDrawable->movePartition(); } } diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 39886e8fb..e50c11ced 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -58,7 +58,8 @@ #include "pipeline.h" #include "llspatialpartition.h" #include "llnotificationsutil.h" -#include "llviewerwindow.h" +#include "raytrace.h" +#include "llglslshader.h" extern LLPipeline gPipeline; @@ -504,11 +505,16 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree. { mReferenceBuffer = NULL ; - mDrawable->getFace(0)->setVertexBuffer(NULL); + LLFace * facep = drawable->getFace(0); + if (facep) + { + facep->setVertexBuffer(NULL); + } return TRUE ; } - if (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer()) + if (mDrawable->getFace(0) && + (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer())) { const F32 SRR3 = 0.577350269f; // sqrt(1/3) const F32 SRR2 = 0.707106781f; // sqrt(1/2) @@ -521,6 +527,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) S32 lod; LLFace *face = drawable->getFace(0); + if (!face) return TRUE; face->mCenterAgent = getPositionAgent(); face->mCenterLocal = face->mCenterAgent; @@ -894,6 +901,7 @@ void LLVOTree::updateMesh() calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches); LLFace* facep = mDrawable->getFace(0); + if (!facep) return; LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); buff->allocateBuffer(vert_count, index_count, TRUE); facep->setVertexBuffer(buff); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 11fa5bb69..1ae31e9b3 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -338,6 +338,7 @@ void LLVOVolume::animateTextures() for (S32 i = start; i <= end; i++) { LLFace* facep = mDrawable->getFace(i); + if (!facep) continue; if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue; const LLTextureEntry* te = facep->getTextureEntry(); @@ -429,7 +430,7 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { LLViewerObject::idleUpdate(agent, world, time); - static LLFastTimer::DeclareTimer ftm("Volume"); + static LLFastTimer::DeclareTimer ftm("Volume Idle"); LLFastTimer t(ftm); if (mDead || mDrawable.isNull()) @@ -474,6 +475,20 @@ void LLVOVolume::updateTextures() if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME) { updateTextureVirtualSize(); + + if (mDrawable.notNull() && !isVisible() && !mDrawable->isActive()) + { //delete vertex buffer to free up some VRAM + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->destroyGL(true); + + //flag the group as having changed geometry so it gets a rebuild next time + //it becomes visible + group->setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); + } + } + } } @@ -508,8 +523,19 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) if(!forced) { if(!isVisible()) - { - return; + { //don't load textures for non-visible faces + const S32 num_faces = mDrawable->getNumFaces(); + for (S32 i = 0; i < num_faces; i++) + { + LLFace* face = mDrawable->getFace(i); + if (face) + { + face->setPixelArea(0.f); + face->setVirtualSize(0.f); + } + } + + return ; } if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE)) @@ -536,6 +562,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) for (S32 i = 0; i < num_faces; i++) { LLFace* face = mDrawable->getFace(i); + if (!face) continue; const LLTextureEntry *te = face->getTextureEntry(); LLViewerTexture *imagep = face->getTexture(); if (!imagep || !te || @@ -568,19 +595,9 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) } mPixelArea = llmax(mPixelArea, face->getPixelArea()); - + if (face->mTextureMatrix != NULL) { - // Animating textures also rez badly in Snowglobe because the - // actual displayed area is only a fraction (corresponding to one - // frame) of the animating texture. Let's fix that here: - /* if (mTextureAnimp && mTextureAnimp->mScaleS > 0.0f && mTextureAnimp->mScaleT > 0.0f) - { - // Adjust to take into account the actual frame size which is only a - // portion of the animating texture - vsize = vsize / mTextureAnimp->mScaleS / mTextureAnimp->mScaleT; - }*/ - if ((vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE) || (vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE)) { @@ -866,6 +883,27 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo } } + + static LLCachedControl use_transform_feedback("RenderUseTransformFeedback", false); + + bool cache_in_vram = use_transform_feedback && gTransformPositionProgram.mProgramObject && + (!mVolumeImpl || !mVolumeImpl->isVolumeUnique()); + + if (cache_in_vram) + { //this volume might be used as source data for a transform object, put it in vram + LLVolume* volume = getVolume(); + for (S32 i = 0; i < volume->getNumFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + if (face.mVertexBuffer.notNull()) + { //already cached + break; + } + volume->genBinormals(i); + LLFace::cacheFaceInVRAM(face); + } + } + return TRUE; } return FALSE; @@ -1034,7 +1072,8 @@ BOOL LLVOVolume::calcLOD() llround(radius, 0.01f)); - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO)) + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) && + mDrawable->getFace(0)) { //setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail)); @@ -1113,25 +1152,23 @@ void LLVOVolume::updateFaceFlags() for (S32 i = 0; i < getVolume()->getNumFaces(); i++) { LLFace *face = mDrawable->getFace(i); - if (!face) + if (face) { - return; - } + BOOL fullbright = getTE(i)->getFullbright(); + face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); - BOOL fullbright = getTE(i)->getFullbright(); - face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); - - if (fullbright || (mMaterial == LL_MCODE_LIGHT)) - { - face->setState(LLFace::FULLBRIGHT); - } - if (mDrawable->isLight()) - { - face->setState(LLFace::LIGHT); - } - if (isHUDAttachment()) - { - face->setState(LLFace::HUD_RENDER); + if (fullbright || (mMaterial == LL_MCODE_LIGHT)) + { + face->setState(LLFace::FULLBRIGHT); + } + if (mDrawable->isLight()) + { + face->setState(LLFace::LIGHT); + } + if (isHUDAttachment()) + { + face->setState(LLFace::HUD_RENDER); + } } } } @@ -1168,6 +1205,8 @@ void LLVOVolume::regenFaces() for (S32 i = 0; i < mNumFaces; i++) { LLFace* facep = count_changed ? addFace(i) : mDrawable->getFace(i); + if (!facep) continue; + facep->setTEOffset(i); facep->setTexture(getTEImage(i)); facep->setViewerObject(this); @@ -1245,11 +1284,11 @@ void LLVOVolume::preRebuild() } } -void LLVOVolume::updateRelativeXform() +void LLVOVolume::updateRelativeXform(bool force_identity) { if (mVolumeImpl) { - mVolumeImpl->updateRelativeXform(); + mVolumeImpl->updateRelativeXform(force_identity); return; } @@ -1269,15 +1308,16 @@ void LLVOVolume::updateRelativeXform() mRelativeXform.invert(); mRelativeXformInvTrans.transpose(); } - else if (drawable->isActive()) + else if (drawable->isActive() || force_identity) { // setup relative transforms LLQuaternion delta_rot; LLVector3 delta_pos, delta_scale; //matrix from local space to parent relative/global space - delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation(); - delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition(); + bool use_identity = force_identity || drawable->isSpatialRoot(); + delta_rot = use_identity ? LLQuaternion() : mDrawable->getRotation(); + delta_pos = use_identity ? LLVector3(0,0,0) : mDrawable->getPosition(); delta_scale = mDrawable->getScale(); // Vertex transform (4x4) @@ -1378,7 +1418,11 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) return res; } - dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); + LLSpatialGroup* group = drawable->getSpatialGroup(); + if (group) + { + group->dirtyMesh(); + } BOOL compiled = FALSE; @@ -1389,8 +1433,10 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) return TRUE; // No update to complete } - if (mVolumeChanged || mFaceMappingChanged ) + if (mVolumeChanged || mFaceMappingChanged || mDrawable->isState(LLDrawable::REBUILD_MATERIAL)) { + dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); + compiled = TRUE; if (mVolumeChanged) @@ -1409,6 +1455,8 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) } else if ((mLODChanged) || (mSculptChanged)) { + dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); + LLVolume *old_volumep, *new_volumep; F32 old_lod, new_lod; S32 old_num_faces, new_num_faces ; @@ -1490,16 +1538,19 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) void LLVOVolume::updateFaceSize(S32 idx) { LLFace* facep = mDrawable->getFace(idx); - if (idx >= getVolume()->getNumVolumeFaces()) + if (facep) { - facep->setSize(0,0, true); - } - else - { - const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); - facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, - true); // <--- volume faces should be padded for 16-byte alignment + if (idx >= getVolume()->getNumVolumeFaces()) + { + facep->setSize(0,0, true); + } + else + { + const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); + facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, + true); // <--- volume faces should be padded for 16-byte alignment + } } } @@ -2340,6 +2391,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const for (U32 i = 0; i < num_faces; ++i) { const LLFace* face = drawablep->getFace(i); + if (!face) continue; const LLTextureEntry* te = face->getTextureEntry(); const LLViewerTexture* img = face->getTexture(); @@ -2615,6 +2667,7 @@ F32 LLVOVolume::getBinRadius() for (S32 i = 0; i < mDrawable->getNumFaces(); i++) { LLFace* face = mDrawable->getFace(i); + if (!face) continue; if (face->getPoolType() == LLDrawPool::POOL_ALPHA && !face->canRenderAsMask()) { @@ -2696,9 +2749,12 @@ LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const { LLVector3 ret = pos - getRenderPosition(); ret = ret * ~getRenderRotation(); - LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); - LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); - ret.scaleVec(invObjScale); + if (!isVolumeGlobal()) + { + LLVector3 objScale = getScale(); + LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); + ret.scaleVec(invObjScale); + } return ret; } @@ -2716,8 +2772,12 @@ LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const { LLVector3 ret = dir; - LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); - ret.scaleVec(objScale); + if (!isVolumeGlobal()) + { + LLVector3 objScale = getScale(); + ret.scaleVec(objScale); + } + ret = ret * getRenderRotation(); ret += getRenderPosition(); @@ -2845,7 +2905,8 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e { LLFace* face = mDrawable->getFace(face_hit); - if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))) + if (face && + (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))) { v_end = p; if (face_hitp != NULL) @@ -3155,8 +3216,11 @@ bool can_batch_texture(LLFace* facep) return true; } +static LLFastTimer::DeclareTimer FTM_REGISTER_FACE("Register Face"); + void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) { + LLFastTimer t(FTM_REGISTER_FACE); LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); // if (facep->getViewerObject()->isSelected() && gHideSelectedObjects) @@ -3195,9 +3259,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, const LLMatrix4* model_mat = NULL; LLDrawable* drawable = facep->getDrawable(); - if (drawable->isActive()) + + if (drawable->isState(LLDrawable::ANIMATED_CHILD)) { - model_mat = &(drawable->getRenderMatrix()); + model_mat = &drawable->getWorldMatrix(); + } + else if (drawable->isActive()) + { + model_mat = &drawable->getRenderMatrix(); } else { @@ -3208,6 +3277,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } } + //drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD))); + U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0; LLViewerTexture* tex = facep->getTexture(); @@ -3296,8 +3367,9 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) } -static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume"); -static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume VB"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_FACE_LIST("Build Face List"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info"); static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) { @@ -3344,19 +3416,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) { - LLFastTimer ftm(FTM_REBUILD_VBO); - LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); - rebuildMesh(group); } return; } + LLFastTimer ftm(FTM_REBUILD_VOLUME_VB); + group->mBuilt = 1.f; - LLFastTimer ftm(FTM_REBUILD_VBO); - - LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); - + LLVOAvatar* pAvatarVO = NULL; LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); @@ -3383,6 +3451,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->mGeometryBytes = 0; group->mSurfaceArea = 0; + //cache object box size since it might be used for determining visibility + group->mObjectBoxSize = group->mObjectBounds[1].getLength3().getF32(); + group->clearDrawMap(); mFaceList.clear(); @@ -3404,359 +3475,375 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool emissive = false; - //get all the faces into a list - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { - LLDrawable* drawablep = *drawable_iter; + LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST); + + //get all the faces into a list + for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + { + LLDrawable* drawablep = *drawable_iter; - if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) - { - continue; - } - - if (drawablep->isAnimating()) - { //fall back to stream draw for animating verts - useage = GL_STREAM_DRAW_ARB; - } - - LLVOVolume* vobj = drawablep->getVOVolume(); - - if (!vobj) - { - continue; - } - - if (vobj->isMesh() && - (vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled())) - { - continue; - } - - LLVolume* volume = vobj->getVolume(); - if (volume) - { - const LLVector3& scale = vobj->getScale(); - group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); - } - - llassert_always(vobj); - vobj->updateTextureVirtualSize(true); - vobj->preRebuild(); - - drawablep->clearState(LLDrawable::HAS_ALPHA); - - bool rigged = vobj->isAttachment() && - vobj->isMesh() && - gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); - - bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); - - bool is_rigged = false; - - //for each face - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - LLFace* facep = drawablep->getFace(i); - - //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render - // batch, it will recover its vertex buffer reference from the spatial group - facep->setVertexBuffer(NULL); - - //sum up face verts and indices - drawablep->updateFaceSize(i); - - - - if (rigged) + if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) { - if (!facep->isState(LLFace::RIGGED)) - { //completely reset vertex buffer - facep->clearVertexBuffer(); - } - - facep->setState(LLFace::RIGGED); - is_rigged = true; - - //get drawpool of avatar with rigged face - LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - - //Determine if we've received skininfo that contains an - //alternate bind matrix - if it does then apply the translational component - //to the joints of the avatar. - bool pelvisGotSet = false; + continue; + } + + if (drawablep->isAnimating()) + { //fall back to stream draw for animating verts + useage = GL_STREAM_DRAW_ARB; + } - if ( pAvatarVO ) + LLVOVolume* vobj = drawablep->getVOVolume(); + + if (!vobj) + { + continue; + } + + if (vobj->isMesh() && + (vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled())) + { + continue; + } + + LLVolume* volume = vobj->getVolume(); + if (volume) + { + const LLVector3& scale = vobj->getScale(); + group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); + } + + llassert_always(vobj); + vobj->updateTextureVirtualSize(true); + vobj->preRebuild(); + + drawablep->clearState(LLDrawable::HAS_ALPHA); + + bool rigged = vobj->isAttachment() && + vobj->isMesh() && + gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); + + bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); + + bool is_rigged = false; + + //for each face + for (S32 i = 0; i < drawablep->getNumFaces(); i++) + { + LLFace* facep = drawablep->getFace(i); + if (!facep) { - LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); - - if ( pSkinData ) + continue; + } + + //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render + // batch, it will recover its vertex buffer reference from the spatial group + facep->setVertexBuffer(NULL); + + //sum up face verts and indices + drawablep->updateFaceSize(i); + + + + if (rigged) + { + if (!facep->isState(LLFace::RIGGED)) + { //completely reset vertex buffer + facep->clearVertexBuffer(); + } + + facep->setState(LLFace::RIGGED); + is_rigged = true; + + //get drawpool of avatar with rigged face + LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); + + //Determine if we've received skininfo that contains an + //alternate bind matrix - if it does then apply the translational component + //to the joints of the avatar. + bool pelvisGotSet = false; + + if ( pAvatarVO ) { - const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) - { - const int jointCnt = pSkinData->mJointNames.size(); - const F32 pelvisZOffset = pSkinData->mPelvisOffset; - bool fullRig = (jointCnt>=20) ? true : false; - if ( fullRig ) - { - for ( int i=0; igetVolume()->getParams().getSculptID(); + const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); + + if ( pSkinData ) + { + const int bindCnt = pSkinData->mAlternateBindMatrix.size(); + if ( bindCnt > 0 ) + { + const int jointCnt = pSkinData->mJointNames.size(); + const F32 pelvisZOffset = pSkinData->mPelvisOffset; + bool fullRig = (jointCnt>=20) ? true : false; + if ( fullRig ) { - std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); - //llinfos<<"joint name "<getJoint( lookingForJoint ); - if ( pJoint && pJoint->getId() != currentId ) - { - pJoint->setId( currentId ); - const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); - //Set the joint position - pJoint->storeCurrentXform( jointPos ); - //If joint is a pelvis then handle old/new pelvis to foot values - if ( lookingForJoint == "mPelvis" ) - { + for ( int i=0; imJointNames[i].c_str(); + //llinfos<<"joint name "<getJoint( lookingForJoint ); + if ( pJoint && pJoint->getId() != currentId ) + { + pJoint->setId( currentId ); + const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); + //Set the joint position pJoint->storeCurrentXform( jointPos ); - if ( !pAvatarVO->hasPelvisOffset() ) - { - pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); - //Trigger to rebuild viewer AV - pelvisGotSet = true; + //If joint is a pelvis then handle old/new pelvis to foot values + if ( lookingForJoint == "mPelvis" ) + { + pJoint->storeCurrentXform( jointPos ); + if ( !pAvatarVO->hasPelvisOffset() ) + { + pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); + //Trigger to rebuild viewer AV + pelvisGotSet = true; + } } - } + } } - } - } + } + } } } - } - //If we've set the pelvis to a new position we need to also rebuild some information that the - //viewer does at launch (e.g. body size etc.) - if ( pelvisGotSet ) - { - pAvatarVO->postPelvisSetRecalc(); - } - - 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) + //If we've set the pelvis to a new position we need to also rebuild some information that the + //viewer does at launch (e.g. body size etc.) + if ( pelvisGotSet ) { - ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); + pAvatarVO->postPelvisSetRecalc(); } - //add face to new pool - LLViewerTexture* tex = facep->getTexture(); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - - if (type == LLDrawPool::POOL_ALPHA) + if (pool) { - if (te->getColor().mV[3] > 0.f) + 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->getColor().mV[3] > 0.f) + { + 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_ALPHA); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); } else { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); + if (LLPipeline::sRenderDeferred) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); + } } } - } - else if (te->getShiny()) - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); - } else { - if (LLPipeline::sRenderDeferred) + if (te->getFullbright()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); + } + else { pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); } - else + } + + if (te->getGlow()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); + } + + if (LLPipeline::sRenderDeferred) + { + if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); + if (te->getBumpmap()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); + } } } } - 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); - } - } - - - if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) - { - facep->clearVertexBuffer(); - continue; - } - - cur_total += facep->getGeomCount(); - - if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) - { - const LLTextureEntry* te = facep->getTextureEntry(); - LLViewerTexture* tex = facep->getTexture(); - - if (te->getGlow() >= 1.f/255.f) - { - emissive = true; - } - - if (facep->isState(LLFace::TEXTURE_ANIM)) - { - if (!vobj->mTexAnimMode) - { - facep->clearState(LLFace::TEXTURE_ANIM); - } - } - - BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - if (type != LLDrawPool::POOL_ALPHA && force_simple) - { - type = LLDrawPool::POOL_SIMPLE; - } - facep->setPoolType(type); - - if (vobj->isHUDAttachment()) - { - facep->setState(LLFace::FULLBRIGHT); - } - - if (vobj->mTextureAnimp && vobj->mTexAnimMode) - { - if (vobj->mTextureAnimp->mFace <= -1) - { - S32 face; - for (face = 0; face < vobj->getNumTEs(); face++) - { - drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM); - } - } - else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) - { - drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM); - } - } - - if (type == LLDrawPool::POOL_ALPHA) - { - if (facep->canRenderAsMask()) - { //can be treated as alpha mask - simple_faces.push_back(facep); - } - else - { - if (te->getColor().mV[3] > 0.f) - { //only treat as alpha in the pipeline if < 100% transparent - drawablep->setState(LLDrawable::HAS_ALPHA); - } - alpha_faces.push_back(facep); - } + continue; } else { - if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) + 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); + } + } + + + if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) + { + facep->clearVertexBuffer(); + continue; + } + + cur_total += facep->getGeomCount(); + + if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) + { + const LLTextureEntry* te = facep->getTextureEntry(); + LLViewerTexture* tex = facep->getTexture(); + + if (te->getGlow() >= 1.f/255.f) { - facep->mLastUpdateTime = gFrameTimeSeconds; + emissive = true; } - if (gPipeline.canUseWindLightShadersOnObjects() - && LLPipeline::sRenderBump) + if (facep->isState(LLFace::TEXTURE_ANIM)) { - if (te->getBumpmap()) - { //needs normal + binormal - bump_faces.push_back(facep); + if (!vobj->mTexAnimMode) + { + facep->clearState(LLFace::TEXTURE_ANIM); } - else if (te->getShiny() || !te->getFullbright()) - { //needs normal + } + + BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); + U32 type = gPipeline.getPoolTypeFromTE(te, tex); + if (type != LLDrawPool::POOL_ALPHA && force_simple) + { + type = LLDrawPool::POOL_SIMPLE; + } + facep->setPoolType(type); + + if (vobj->isHUDAttachment()) + { + facep->setState(LLFace::FULLBRIGHT); + } + + if (vobj->mTextureAnimp && vobj->mTexAnimMode) + { + if (vobj->mTextureAnimp->mFace <= -1) + { + S32 face; + for (face = 0; face < vobj->getNumTEs(); face++) + { + LLFace * facep = drawablep->getFace(face); + if (facep) + { + facep->setState(LLFace::TEXTURE_ANIM); + } + } + } + else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) + { + LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace); + if (facep) + { + facep->setState(LLFace::TEXTURE_ANIM); + } + } + } + + if (type == LLDrawPool::POOL_ALPHA) + { + if (facep->canRenderAsMask()) + { //can be treated as alpha mask simple_faces.push_back(facep); } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); + else + { + if (te->getColor().mV[3] > 0.f) + { //only treat as alpha in the pipeline if < 100% transparent + drawablep->setState(LLDrawable::HAS_ALPHA); + } + alpha_faces.push_back(facep); } } else { - if (te->getBumpmap() && LLPipeline::sRenderBump) - { //needs normal + binormal - bump_faces.push_back(facep); + if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) + { + facep->mLastUpdateTime = gFrameTimeSeconds; } - else if ((te->getShiny() && LLPipeline::sRenderBump) || - !(te->getFullbright() || bake_sunlight)) - { //needs normal - simple_faces.push_back(facep); + + if (gPipeline.canUseWindLightShadersOnObjects() + && LLPipeline::sRenderBump) + { + if (te->getBumpmap()) + { //needs normal + binormal + bump_faces.push_back(facep); + } + else if (te->getShiny() || !te->getFullbright()) + { //needs normal + simple_faces.push_back(facep); + } + else + { //doesn't need normal + facep->setState(LLFace::FULLBRIGHT); + fullbright_faces.push_back(facep); + } } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); + else + { + if (te->getBumpmap() && LLPipeline::sRenderBump) + { //needs normal + binormal + bump_faces.push_back(facep); + } + else if ((te->getShiny() && LLPipeline::sRenderBump) || + !(te->getFullbright() || bake_sunlight)) + { //needs normal + simple_faces.push_back(facep); + } + else + { //doesn't need normal + facep->setState(LLFace::FULLBRIGHT); + fullbright_faces.push_back(facep); + } } } } + else + { //face has no renderable geometry + facep->clearVertexBuffer(); + } + } + + if (is_rigged) + { + drawablep->setState(LLDrawable::RIGGED); } else - { //face has no renderable geometry - facep->clearVertexBuffer(); - } - } - - if (is_rigged) - { - drawablep->setState(LLDrawable::RIGGED); - } - else - { - drawablep->clearState(LLDrawable::RIGGED); + { + drawablep->clearState(LLDrawable::RIGGED); + } } } @@ -3823,15 +3910,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry"); -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild"); + void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { llassert(group); static int warningsCount = 20; if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY)) { - LLFastTimer tm(FTM_VOLUME_GEOM); + LLFastTimer ftm(FTM_REBUILD_VOLUME_VB); + LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ; group->mBuilt = 1.f; @@ -3840,19 +3927,18 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { - LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL); LLDrawable* drawablep = *drawable_iter; - /*if (drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) - { - continue; - }*/ - - if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) ) + if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { LLVOVolume* vobj = drawablep->getVOVolume(); vobj->preRebuild(); + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(true); + } + LLVolume* volume = vobj->getVolume(); for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { @@ -3862,6 +3948,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) LLVertexBuffer* buff = face->getVertexBuffer(); if (buff) { + llassert(!face->isState(LLFace::RIGGED)); face->getGeometryVolume(*volume, face->getTEOffset(), vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()); @@ -3872,6 +3959,12 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) } } } + + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(); + } + drawablep->clearState(LLDrawable::REBUILD_ALL); } @@ -3904,10 +3997,13 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { LLFace* face = drawablep->getFace(i); - LLVertexBuffer* buff = face ? face->getVertexBuffer() : NULL; - if (buff && buff->isLocked()) + if (face) { - buff->flush(); + LLVertexBuffer* buff = face->getVertexBuffer(); + if (buff && buff->isLocked()) + { + buff->flush(); + } } } } @@ -3916,7 +4012,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); } - llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO)); +// llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO)); } struct CompareBatchBreakerModified @@ -3942,10 +4038,22 @@ struct CompareBatchBreakerModified } }; +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FIND_VB("Find VB"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB"); + + + + + void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector& faces, BOOL distance_sort, BOOL batch_textures) { - U32 buffer_usage = group->mBufferUsage; + LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); + U32 buffer_usage = group->mBufferUsage; + #if LL_DARWIN // HACK from Leslie: // Disable VBO usage for alpha on Mac OS X because it kills the framerate @@ -3962,15 +4070,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: U32 max_vertices = (render_max_vbo_size*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); - if (!distance_sort) { - //sort faces by things that break batches - std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified()); - } - else - { - //sort faces by distance - std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); + LLFastTimer t(FTM_GEN_DRAW_INFO_SORT); + if (!distance_sort) + { + //sort faces by things that break batches + std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified()); + } + else + { + //sort faces by distance + std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); + } } bool hud_group = group->isHUDGroup() ; @@ -3986,12 +4097,13 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: buffer_index = -1; } - S32 texture_index_channels = LLGLSLShader::sIndexedTextureChannels-1; //always reserve one for shiny for now just for simplicity + S32 texture_index_channels = 1; - static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false); - if (gGLManager.mGLVersion < 3.1f || no_texture_indexing) + if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) { - texture_index_channels = 1; + static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false); + if(!no_texture_indexing) + texture_index_channels = LLGLSLShader::sIndexedTextureChannels-1; //always reserve one for shiny for now just for simplicity; } if (LLPipeline::sRenderDeferred && distance_sort) @@ -4037,57 +4149,86 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: std::vector texture_list; - if (batch_textures) { - U8 cur_tex = 0; - facep->setTextureIndex(cur_tex); - texture_list.push_back(tex); - - //if (can_batch_texture(facep)) + LLFastTimer t(FTM_GEN_DRAW_INFO_FACE_SIZE); + if (batch_textures) { - while (i != faces.end()) + U8 cur_tex = 0; + facep->setTextureIndex(cur_tex); + texture_list.push_back(tex); + + //if (can_batch_texture(facep)) { - facep = *i; - if (facep->getTexture() != tex) + while (i != faces.end()) { - if (distance_sort) - { //textures might be out of order, see if texture exists in current batch - bool found = false; - for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx) - { - if (facep->getTexture() == texture_list[tex_idx]) + facep = *i; + if (facep->getTexture() != tex) + { + if (distance_sort) + { //textures might be out of order, see if texture exists in current batch + bool found = false; + for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx) { - cur_tex = tex_idx; - found = true; - break; + if (facep->getTexture() == texture_list[tex_idx]) + { + cur_tex = tex_idx; + found = true; + break; + } + } + + if (!found) + { + cur_tex = texture_list.size(); } } - - if (!found) + else { - cur_tex = texture_list.size(); + cur_tex++; } - } - else - { - cur_tex++; + + if (!can_batch_texture(facep)) + { //face is bump mapped or has an animated texture matrix -- can't + //batch more than 1 texture at a time + break; + } + + if (cur_tex >= texture_index_channels) + { //cut batches when index channels are depleted + break; + } + + tex = facep->getTexture(); + + texture_list.push_back(tex); } - if (!can_batch_texture(facep)) - { //face is bump mapped or has an animated texture matrix -- can't - //batch more than 1 texture at a time + if (geom_count + facep->getGeomCount() > max_vertices) + { //cut batches on geom count too big break; } - if (cur_tex >= texture_index_channels) - { //cut batches when index channels are depleted - break; - } + ++i; + index_count += facep->getIndicesCount(); + geom_count += facep->getGeomCount(); - tex = facep->getTexture(); - - texture_list.push_back(tex); + facep->setTextureIndex(cur_tex); } + } + + tex = texture_list[0]; + } + else + { + while (i != faces.end() && + (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) + { + facep = *i; + + + //face has no texture index + facep->mDrawInfo = NULL; + facep->setTextureIndex(255); if (geom_count + facep->getGeomCount() > max_vertices) { //cut batches on geom count too big @@ -4097,69 +4238,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: ++i; index_count += facep->getIndicesCount(); geom_count += facep->getGeomCount(); - - facep->setTextureIndex(cur_tex); } } - - tex = texture_list[0]; } - else - { - while (i != faces.end() && - (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) - { - facep = *i; - - //face has no texture index - facep->mDrawInfo = NULL; - facep->setTextureIndex(255); - - if (geom_count + facep->getGeomCount() > max_vertices) - { //cut batches on geom count too big - break; - } - - ++i; - index_count += facep->getIndicesCount(); - geom_count += facep->getGeomCount(); - } - } - - //create/delete/resize vertex buffer if needed + //create vertex buffer LLVertexBuffer* buffer = NULL; - { //try to find a buffer to reuse - LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter); - - if (found_iter != group->mBufferMap[mask].end()) - { - if ((U32) buffer_index < found_iter->second.size()) - { - buffer = found_iter->second[buffer_index]; - } - } - } - - if (!buffer || !buffer->isWriteable()) - { //create new buffer if needed + { + LLFastTimer t(FTM_GEN_DRAW_INFO_ALLOCATE); buffer = createVertexBuffer(mask, buffer_usage); buffer->allocateBuffer(geom_count, index_count, TRUE); } - else - { //resize pre-existing buffer - if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != buffer_usage || - buffer->getTypeMask() != mask) - { - buffer = createVertexBuffer(mask, buffer_usage); - buffer->allocateBuffer(geom_count, index_count, TRUE); - } - else - { - buffer->resizeBuffer(geom_count, index_count); - } - } group->mGeometryBytes += buffer->getSize() + buffer->getIndicesSize(); @@ -4193,10 +4283,22 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: LLVOVolume* vobj = drawablep->getVOVolume(); LLVolume* volume = vobj->getVolume(); + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(true); + } + U32 te_idx = facep->getTEOffset(); + llassert(!facep->isState(LLFace::RIGGED)); + facep->getGeometryVolume(*volume, te_idx, - vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset); + vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true); + + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(false); + } } } @@ -4247,7 +4349,6 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } } else if (gPipeline.canUseVertexShaders() - && group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD && LLPipeline::sRenderBump && te->getShiny()) { //shiny @@ -4360,6 +4461,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun mFaceList.clear(); //for each drawable + for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { LLDrawable* drawablep = *drawable_iter; @@ -4380,17 +4482,21 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun //sum up face verts and indices drawablep->updateFaceSize(i); LLFace* facep = drawablep->getFace(i); - if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) + if (facep) { - vertex_count += facep->getGeomCount(); - index_count += facep->getIndicesCount(); - llassert(facep->getIndicesCount() < 65536); - //remember face (for sorting) - mFaceList.push_back(facep); - } - else - { - facep->clearVertexBuffer(); + if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA && + facep->getGeomCount() + vertex_count <= 65536) + { + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + + //remember face (for sorting) + mFaceList.push_back(facep); + } + else + { + facep->clearVertexBuffer(); + } } } } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index b4c08b797..cc7b5cf10 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -81,7 +81,7 @@ public: virtual bool isVolumeGlobal() const = 0; // Are we in global space? virtual bool isActive() const = 0; // Is this object currently active? virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const = 0; - virtual void updateRelativeXform() = 0; + virtual void updateRelativeXform(bool force_identity = false) = 0; virtual U32 getID() const = 0; virtual void preRebuild() = 0; }; @@ -203,7 +203,7 @@ public: LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); - void updateRelativeXform(); + void updateRelativeXform(bool force_identity = false); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); /*virtual*/ void updateFaceSize(S32 idx); /*virtual*/ BOOL updateLOD(); diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 6614a97d8..20294d0c3 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -151,6 +151,10 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) drawable->addFace(poolp, NULL); } face = drawable->getFace(0); + if (!face) + { + return TRUE; + } // LLVector2 uvs[4]; // LLVector3 vtx[4]; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 1e12feb84..4da0c0ade 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -584,31 +584,9 @@ BOOL LLWearable::isDirty() const U8 a = F32_to_U8( saved_weight, param->getMinWeight(), param->getMaxWeight() ); U8 b = F32_to_U8( current_weight, param->getMinWeight(), param->getMaxWeight() ); - if(gAgentAvatarp->getAppearanceFlag() == true) - { - //boob - if(param->getID() == 507) - { - if( is_in_map(mVisualParamIndexMap, param->getID() ) ) - current_weight = mVisualParamIndexMap.find(param->getID())->second->getWeight(); - else - current_weight = gAgentAvatarp->getActualBoobGrav(); - current_weight = llclamp( current_weight, param->getMinWeight(), param->getMaxWeight() ); - b = F32_to_U8( current_weight, param->getMinWeight(), param->getMaxWeight() ); - } - } - else - { - //boob - if(param->getID() == 507) - { - a = F32_to_U8( gAgentAvatarp->getActualBoobGrav(), param->getMinWeight(), param->getMaxWeight() ); - } - } - if( a != b ) { - llwarns << "param ID " << param->getID() << " was changed." << llendl; + //llwarns << "param ID " << param->getID() << " was changed." << llendl; return TRUE; } } @@ -699,10 +677,6 @@ void LLWearable::writeToAvatar() S32 param_id = param->getID(); F32 weight = getVisualParamWeight(param_id); - //ZOMG: When switching shapes from inventory - if(param_id == 507) - gAgentAvatarp->setActualBoobGrav(weight); - gAgentAvatarp->setVisualParamWeight( param_id, weight, FALSE ); } } @@ -727,36 +701,12 @@ void LLWearable::writeToAvatar() gAgentAvatarp->setLocalTextureTE(te, image, 0); } } - - /*if( gFloaterCustomize ) - { - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType, 0)); // TODO: MULTI-WEARABLE - U32 perm_mask = PERM_NONE; - BOOL is_complete = FALSE; - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - if(!is_complete) - { - item->fetchFromServer(); - } - } - gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); - LLFloaterCustomize::setCurrentWearableType( mType ); - }*/ ESex new_sex = gAgentAvatarp->getSex(); if( old_sex != new_sex ) { gAgentAvatarp->updateSexDependentLayerSets( FALSE ); } - -// if( upload_bake ) -// { -// gAgent.sendAgentSetAppearance(); -// } } @@ -787,7 +737,7 @@ void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake if(gAgentCamera.cameraCustomizeAvatar()) { - gFloaterCustomize->setWearable(type, NULL, PERM_ALL, TRUE); + gFloaterCustomize->wearablesChanged(type); } gAgentAvatarp->updateVisualParams(); @@ -824,21 +774,6 @@ void LLWearable::copyDataFrom(const LLWearable* src) { S32 id = param->getID(); F32 weight = src->getVisualParamWeight(id); - //llwarns << "------------------------------" << llendl; - //llwarns << "copydatafrom" << llendl; - //llwarns << "------------------------------" << llendl; - - //if(id == 507) - //{ - // llwarns << "weight = " << weight << llendl; - // llwarns << "actual = " << avatar->getActualBoobGrav() << llendl; - // llwarns << "mVisualParamMap[id] = " << mVisualParamMap[id] << llendl; - //} - - //pretty sure right - if(id == 507) - gAgentAvatarp->setActualBoobGrav(weight); - mSavedVisualParamMap[id] = weight; } } @@ -1077,6 +1012,9 @@ void LLWearable::revertValues() { panel->updateScrollingPanelList(); }*/ + if( gFloaterCustomize && gAgentWearables.getWearableIndex(this)==0 ) + gFloaterCustomize->updateScrollingPanelList(); + } BOOL LLWearable::isOnTop() const @@ -1118,6 +1056,9 @@ void LLWearable::saveValues() { panel->updateScrollingPanelList(); }*/ + + if( gFloaterCustomize && gAgentWearables.getWearableIndex(this)==0) + gFloaterCustomize->updateScrollingPanelList(); } void LLWearable::syncImages(te_map_t &src, te_map_t &dst) @@ -1218,23 +1159,6 @@ void LLWearable::pullCrossWearableValues() { if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (param->isTweakable()) ) { - - - //pretty sure is right - if(param->getID() == 507) - avatar->setActualBoobGrav(param->getWeight()); - //if(param->getID() == 151) - // avatar->setActualButtGrav(param->getWeight()); - //if(param->getID() == 157) - // avatar->setActualFatGrav(param->getWeight()); - - //if(param->getID() == 507) - //{ - // llwarns << "current = " << avatar->getActualBoobGrav() << llendl; - // llwarns << "param weight = " << param->getWeight() << llendl; - //} - - mVisualParamMap[param->getID()] = param->getWeight(); } } diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 7de47258e..6f92bedf9 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -200,9 +200,11 @@ LLViewerRegion* LLWorld::addRegion(const U64 ®ion_handle, const LLHost &host) } //Classic clouds +#if ENABLE_CLASSIC_CLOUDS regionp->mCloudLayer.create(regionp); regionp->mCloudLayer.setWidth((F32)mWidth); regionp->mCloudLayer.setWindPointer(®ionp->mWind); +#endif mRegionList.push_back(regionp); mActiveRegionList.push_back(regionp); @@ -682,6 +684,7 @@ void LLWorld::updateParticles() LLViewerPartSim::getInstance()->updateSimulation(); } +#if ENABLE_CLASSIC_CLOUDS void LLWorld::updateClouds(const F32 dt) { static const LLCachedControl freeze_time("FreezeTime",false); @@ -740,6 +743,7 @@ LLCloudGroup* LLWorld::findCloudGroup(const LLCloudPuff &puff) } return NULL; } +#endif void LLWorld::renderPropertyLines() diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 760934d5b..a9b3f3b53 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -124,8 +124,10 @@ public: void updateRegions(F32 max_update_time); void updateVisibilities(); void updateParticles(); +#if ENABLE_CLASSIC_CLOUDS void updateClouds(const F32 dt); LLCloudGroup * findCloudGroup(const LLCloudPuff &puff); +#endif void renderPropertyLines(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 742af1be0..babbedc5a 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -222,6 +222,7 @@ std::string gPoolNames[] = void drawBox(const LLVector3& c, const LLVector3& r); void drawBoxOutline(const LLVector3& pos, const LLVector3& size); U32 nhpo2(U32 v); +LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage); glh::matrix4f glh_copy_matrix(F32* src) { @@ -360,9 +361,11 @@ LLPipeline::LLPipeline() : mInitialized(FALSE), mVertexShadersEnabled(FALSE), mVertexShadersLoaded(0), + mTransformFeedbackPrimitives(0), mRenderDebugFeatureMask(0), mRenderDebugMask(0), mOldRenderDebugMask(0), + mMeshDirtyQueryObject(0), mGroupQ1Locked(false), mGroupQ2Locked(false), mResetVertexBuffers(false), @@ -450,6 +453,11 @@ void LLPipeline::init() mSpotLightFade[i] = 1.f; } + if (mCubeVB.isNull()) + { + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0); mDeferredVB->allocateBuffer(8, 0, true); setLightingDetail(-1); @@ -458,7 +466,8 @@ void LLPipeline::init() gSavedSettings.getControl("RenderUseFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("RenderAvatarMaxVisible")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); //gSavedSettings.getControl("RenderDelayVBUpdate")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - + gSavedSettings.getControl("UseOcclusion")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("VertexShaderEnable")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); } LLPipeline::~LLPipeline() @@ -562,6 +571,12 @@ void LLPipeline::destroyGL() sDelayedVBOEnable = 30; LLVertexBuffer::sEnableVBOs = FALSE; } + + } + if (mMeshDirtyQueryObject) + { + glDeleteQueriesARB(1, &mMeshDirtyQueryObject); + mMeshDirtyQueryObject = 0; } } @@ -826,6 +841,7 @@ void LLPipeline::refreshCachedSettings() LLPipeline::sUseOcclusion = (!gUseWireframe + && LLGLSLShader::sNoFixedFunction && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) ? 2 : 0; @@ -837,13 +853,13 @@ void LLPipeline::releaseGLBuffers() if (mNoiseMap) { - LLImageGL::deleteTextures(1, &mNoiseMap); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 0, 1, &mNoiseMap); mNoiseMap = 0; } if (mTrueNoiseMap) { - LLImageGL::deleteTextures(1, &mTrueNoiseMap); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 0, 1, &mTrueNoiseMap); mTrueNoiseMap = 0; } @@ -867,7 +883,7 @@ void LLPipeline::releaseLUTBuffers() { if (mLightFunc) { - LLImageGL::deleteTextures(1, &mLightFunc); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_R8, 0, 1, &mLightFunc); mLightFunc = 0; } } @@ -942,7 +958,7 @@ void LLPipeline::createGLBuffers() noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f; } - LLImageGL::generateTextures(1, &mNoiseMap); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 1, &mNoiseMap); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise, false); @@ -958,7 +974,7 @@ void LLPipeline::createGLBuffers() noise[i] = ll_frand()*2.0-1.0; } - LLImageGL::generateTextures(1, &mTrueNoiseMap); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 1, &mTrueNoiseMap); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise, false); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); @@ -1014,7 +1030,7 @@ void LLPipeline::createLUTBuffers() } } - LLImageGL::generateTextures(1, &mLightFunc); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_R8, 1, &mLightFunc); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, ls, false); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); @@ -1631,6 +1647,16 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) if (done) { drawablep->clearState(LLDrawable::ON_MOVE_LIST); + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { //will likely not receive any future world matrix updates + // -- this keeps attachments from getting stuck in space and falling off your avatar + drawablep->clearState(LLDrawable::ANIMATED_CHILD); + markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, TRUE); + if (drawablep->getVObj()) + { + drawablep->getVObj()->dirtySpatialGroup(TRUE); + } + } iter = moved_list.erase(curiter); } } @@ -2026,8 +2052,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl gGLLastMatrix = NULL; gGL.loadMatrix(gGLLastModelView); - - LLVertexBuffer::unbind(); LLGLDisable blend(GL_BLEND); LLGLDisable test(GL_ALPHA_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -2071,7 +2095,16 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl { //if no shader is currently bound, use the occlusion shader instead of fixed function if we can // (shadow render uses a special shader that clamps to clip planes) bound_shader = true; - gOcclusionProgram.bind(); + gOcclusionCubeProgram.bind(); + } + + if (sUseOcclusion > 1) + { + if (mCubeVB.isNull()) + { //cube VB will be used for issuing occlusion queries + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); } for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); @@ -2103,7 +2136,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl if (bound_shader) { - gOcclusionProgram.unbind(); + gOcclusionCubeProgram.unbind(); } camera.disableUserClipPlane(); @@ -2143,10 +2176,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl { mScreen.flush(); } - /*else if (LLPipeline::sUseOcclusion > 1) - { - glFlush(); - }*/ } void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) @@ -2240,14 +2269,20 @@ void LLPipeline::doOcclusion(LLCamera& camera) { if (LLPipeline::sShadowRender) { - gDeferredShadowProgram.bind(); + gDeferredShadowCubeProgram.bind(); } else { - gOcclusionProgram.bind(); + gOcclusionCubeProgram.bind(); } } + if (mCubeVB.isNull()) + { //cube VB will be used for issuing occlusion queries + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) { LLSpatialGroup* group = *iter; @@ -2259,11 +2294,11 @@ void LLPipeline::doOcclusion(LLCamera& camera) { if (LLPipeline::sShadowRender) { - gDeferredShadowProgram.unbind(); + gDeferredShadowCubeProgram.unbind(); } else { - gOcclusionProgram.unbind(); + gOcclusionCubeProgram.unbind(); } } @@ -2282,6 +2317,8 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) return update_complete; } +static LLFastTimer::DeclareTimer FTM_SEED_VBO_POOLS("Seed VBO Pool"); + void LLPipeline::updateGL() { while (!LLGLUpdate::sGLQ.empty()) @@ -2291,6 +2328,11 @@ void LLPipeline::updateGL() glu->mInQ = FALSE; LLGLUpdate::sGLQ.pop_front(); } + + { //seed VBO Pools + LLFastTimer t(FTM_SEED_VBO_POOLS); + LLVertexBuffer::seedPools(); + } } void LLPipeline::rebuildPriorityGroups() @@ -2668,11 +2710,16 @@ void LLPipeline::processPartitionQ() mPartitionQ.clear(); } + +void LLPipeline::markMeshDirty(LLSpatialGroup* group) +{ + mMeshDirtyGroup.push_back(group); +} + void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) { LLMemType mt(LLMemType::MTYPE_PIPELINE); - //llassert(is_main_thread()); - + if (group && !group->isDead() && group->mSpatialPartition) { if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD) @@ -3039,7 +3086,11 @@ void renderScriptedBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3066,7 +3117,11 @@ void renderScriptedTouchBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3092,7 +3147,11 @@ void renderPhysicalBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3118,7 +3177,11 @@ void renderParticleBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3136,7 +3199,11 @@ void renderSoundHighlights(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3166,45 +3233,20 @@ void LLPipeline::postSort(LLCamera& camera) //rebuild groups sCull->assertDrawMapsEmpty(); - /*LLSpatialGroup::sNoDelete = FALSE; - for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (sUseOcclusion && - group->isState(LLSpatialGroup::OCCLUDED)) - { - continue; - } - - group->rebuildGeom(); - } - LLSpatialGroup::sNoDelete = TRUE;*/ - - rebuildPriorityGroups(); llpushcallstacks ; - const S32 bin_count = 1024*8; - - static LLCullResult::drawinfo_list_t alpha_bins[bin_count]; - static U32 bin_size[bin_count]; - - //clear one bin per frame to avoid memory bloat - static S32 clear_idx = 0; - clear_idx = (1+clear_idx)%bin_count; - alpha_bins[clear_idx].clear(); - - for (U32 j = 0; j < bin_count; j++) - { - bin_size[j] = 0; - } - + //build render map for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { LLSpatialGroup* group = *i; + + static LLCachedControl RenderAutoHideSurfaceAreaLimit("RenderAutoHideSurfaceAreaLimit", 0.f); if (sUseOcclusion && - group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + group->isOcclusionState(LLSpatialGroup::OCCLUDED) || + (RenderAutoHideSurfaceAreaLimit > 0.f && + group->mSurfaceArea > RenderAutoHideSurfaceAreaLimit*llmax(group->mObjectBoxSize, 10.f))) { continue; } @@ -3268,14 +3310,44 @@ void LLPipeline::postSort(LLCamera& camera) } } } + + //flush particle VB + LLVOPartGroup::sVB->flush(); + + /*bool use_transform_feedback = gTransformPositionProgram.mProgramObject && !mMeshDirtyGroup.empty(); + + if (use_transform_feedback) + { //place a query around potential transform feedback code for synchronization + mTransformFeedbackPrimitives = 0; + + if (!mMeshDirtyQueryObject) + { + glGenQueriesARB(1, &mMeshDirtyQueryObject); + } + + glBeginQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mMeshDirtyQueryObject); + }*/ + + //pack vertex buffers for groups that chose to delay their updates + for (LLSpatialGroup::sg_vector_t::iterator iter = mMeshDirtyGroup.begin(); iter != mMeshDirtyGroup.end(); ++iter) + { + (*iter)->rebuildMesh(); + } + + /*if (use_transform_feedback) + }*/ + + mMeshDirtyGroup.clear(); + if (!sShadowRender) { std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); } + llpushcallstacks ; - forAllVisibleDrawables(updateParticleActivity); + forAllVisibleDrawables(updateParticleActivity); //for llfloateravatarlist // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus static const LLCachedControl beacons_visible("BeaconsVisible", false); @@ -3373,7 +3445,11 @@ void LLPipeline::postSort(LLCamera& camera) { if (object->mDrawable) { - gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te)); + LLFace * facep = object->mDrawable->getFace(te); + if (facep) + { + gPipeline.mSelectedFaces.push_back(facep); + } } return true; } @@ -5994,7 +6070,6 @@ LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj) return NULL; } - void LLPipeline::resetVertexBuffers(LLDrawable* drawable) { if (!drawable) @@ -6005,13 +6080,15 @@ void LLPipeline::resetVertexBuffers(LLDrawable* drawable) for (S32 i = 0; i < drawable->getNumFaces(); i++) { LLFace* facep = drawable->getFace(i); - facep->clearVertexBuffer(); + if (facep) + { + facep->clearVertexBuffer(); + } } } void LLPipeline::resetVertexBuffers() -{ - mResetVertexBuffers = true; +{ mResetVertexBuffers = true; } void LLPipeline::doResetVertexBuffers() @@ -6020,9 +6097,11 @@ void LLPipeline::doResetVertexBuffers() { return; } - + mResetVertexBuffers = false; + mCubeVB = NULL; + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { @@ -6041,11 +6120,14 @@ void LLPipeline::doResetVertexBuffers() gSky.resetVertexBuffers(); + LLVOPartGroup::destroyGL(); + LLVertexBuffer::cleanupClass(); //delete all name pool caches LLGLNamePool::cleanupPools(); + if (LLVertexBuffer::sGLCount > 0) { llwarns << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << llendl; @@ -6064,6 +6146,8 @@ void LLPipeline::doResetVertexBuffers() LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind"); LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping); + + LLVOPartGroup::restoreGL(); } void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture) @@ -7368,12 +7452,17 @@ void LLPipeline::renderDeferredLighting() std::list light_colors; LLVertexBuffer::unbind(); - LLVector4a* v = (LLVector4a*) vert.get(); { bindDeferredShader(gDeferredLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + if (mCubeVB.isNull()) + { + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) { @@ -7419,25 +7508,7 @@ void LLPipeline::renderDeferredLighting() } sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - //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 - mDeferredVB->getVertexStrider(vert); - v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000 - v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001 - v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010 - v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011 - - v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100 - v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101 - v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110 - v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111 - + if (camera->getOrigin().mV[0] > c[0] + s + 0.2f || camera->getOrigin().mV[0] < c[0] - s - 0.2f || camera->getOrigin().mV[1] > c[1] + s + 0.2f || @@ -7455,16 +7526,13 @@ void LLPipeline::renderDeferredLighting() } LLFastTimer ftm(FTM_LOCAL_LIGHTS); - //glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); - gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); + gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); - //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); gGL.syncMatrices(); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center)); + + mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); stop_glerror(); } } @@ -7477,6 +7545,9 @@ void LLPipeline::renderDeferredLighting() continue; } + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s)); light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); } @@ -7489,7 +7560,7 @@ void LLPipeline::renderDeferredLighting() LLGLDepthTest depth(GL_TRUE, GL_FALSE); bindDeferredShader(gDeferredSpotLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); @@ -7507,36 +7578,17 @@ void LLPipeline::renderDeferredLighting() sVisibleLightCount++; - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - setupSpotLight(gDeferredSpotLightProgram, drawablep); LLColor3 col = volume->getLightColor(); - - //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 - mDeferredVB->getVertexStrider(vert); - v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000 - v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001 - v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010 - v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011 - - v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100 - v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101 - v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110 - v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111 - gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); + gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); gGL.syncMatrices(); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center)); + + mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); } gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); unbindDeferredShader(gDeferredSpotLightProgram); @@ -7568,8 +7620,6 @@ void LLPipeline::renderDeferredLighting() LLVector4 light[max_count]; LLVector4 col[max_count]; -// glVertexPointer(2, GL_FLOAT, 0, vert); - F32 far_z = 0.f; while (!fullscreen_lights.empty()) @@ -8007,7 +8057,11 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) gPipeline.pushRenderTypeMask(); if (detail < 4) { +#if ENABLE_CLASSIC_CLOUDS clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, END_RENDER_TYPES); +#else + clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES); +#endif if (detail < 3) { clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); @@ -8064,7 +8118,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) { clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND, LLPipeline::RENDER_TYPE_SKY, +#if ENABLE_CLASSIC_CLOUDS LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, +#endif LLPipeline::RENDER_TYPE_WL_CLOUDS, LLPipeline::RENDER_TYPE_WL_SKY, END_RENDER_TYPES); @@ -8222,7 +8278,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera if (use_shader) { - gDeferredShadowProgram.bind(); + gDeferredShadowCubeProgram.bind(); } updateCull(shadow_cam, result); @@ -8239,17 +8295,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera stop_glerror(); gGLLastMatrix = NULL; - { - //LLGLDepthTest depth(GL_TRUE); - //glClear(GL_DEPTH_BUFFER_BIT); - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); stop_glerror(); - //glCullFace(GL_FRONT); - LLVertexBuffer::unbind(); { @@ -8257,10 +8306,14 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera { //occlusion program is general purpose depth-only no-textures gOcclusionProgram.bind(); } + else + { + gDeferredShadowProgram.bind(); + } gGL.diffuseColor4f(1,1,1,1); gGL.setColorMask(false, false); - + LLFastTimer ftm(FTM_SHADOW_SIMPLE); gGL.getTexUnit(0)->disable(); for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) @@ -8306,7 +8359,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera //glCullFace(GL_BACK); - gDeferredShadowProgram.bind(); + gDeferredShadowCubeProgram.bind(); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); doOcclusion(shadow_cam); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index cfc897c41..4ad8a5e19 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -167,6 +167,7 @@ public: void markRebuild(LLSpatialGroup* group, BOOL priority = FALSE); void markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL, BOOL priority = FALSE); void markPartitionMove(LLDrawable* drawablep); + void markMeshDirty(LLSpatialGroup* group); //get the object between start and end that's closest to start. LLViewerObject* lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end, @@ -371,7 +372,7 @@ private: void removeFromQuickLookup( LLDrawPool* poolp ); BOOL updateDrawableGeom(LLDrawable* drawable, BOOL priority); void assertInitializedDoError(); - bool assertInitialized() { const bool is_init = isInit(); if (!is_init) assertInitializedDoError(); return is_init; } + bool assertInitialized() { const bool is_init = isInit(); if (!is_init) assertInitializedDoError(); return is_init; }; public: enum {GPU_CLASS_MAX = 3 }; @@ -412,7 +413,9 @@ public: RENDER_TYPE_VOLUME, RENDER_TYPE_PARTICLES, RENDER_TYPE_WL_CLOUDS, +#if ENABLE_CLASSIC_CLOUDS RENDER_TYPE_CLASSIC_CLOUDS, +#endif RENDER_TYPE_HUD_PARTICLES, NUM_RENDER_TYPES, END_RENDER_TYPES = NUM_RENDER_TYPES @@ -538,6 +541,9 @@ public: //utility buffer for rendering post effects, gets abused by renderDeferredLighting LLPointer mDeferredVB; + //utility buffer for rendering cubes, 8 vertices are corners of a cube [-1, 1] + LLPointer mCubeVB; + //sun shadow map LLRenderTarget mShadow[6]; std::vector mShadowFrustPoints[4]; @@ -589,6 +595,7 @@ public: BOOL mVertexShadersEnabled; S32 mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed + U32 mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback protected: BOOL mRenderTypeEnabled[NUM_RENDER_TYPES]; std::stack mRenderTypeEnableStack; @@ -646,6 +653,9 @@ protected: LLSpatialGroup::sg_vector_t mGroupQ1; //priority LLSpatialGroup::sg_vector_t mGroupQ2; // non-priority + LLSpatialGroup::sg_vector_t mMeshDirtyGroup; //groups that need rebuildMesh called + U32 mMeshDirtyQueryObject; + LLDrawable::drawable_list_t mPartitionQ; //drawables that need to update their spatial partition radius bool mGroupQ2Locked; diff --git a/indra/newview/skins/default/xui/en-us/floater_customize.xml b/indra/newview/skins/default/xui/en-us/floater_customize.xml index d77f5e14c..939aff135 100644 --- a/indra/newview/skins/default/xui/en-us/floater_customize.xml +++ b/indra/newview/skins/default/xui/en-us/floater_customize.xml @@ -86,17 +86,17 @@ mouse_opaque="true" name="path" v_pad="0" width="373"> Located in [PATH] - - Put on a new shape by dragging one from your inventory + +Put on a new shape by dragging one from your inventory to your avatar. Alternately, you create a new one from scratch and wear it. You do not have permission to modify this wearable. @@ -106,8 +106,8 @@ scratch and wear it. mouse_opaque="true" name="Item Action Label" v_pad="0" width="100"> Shape: -