From 51fabc385079a0b5fab4611bb5b16fea5dc26372 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Tue, 21 Aug 2012 18:21:11 -0400 Subject: SH-3261 SH-3324 WIP Starting extraction of wearable/appearance libraries First pass at cmake configs, and starting to try to move wearable class. Things are broken, checkpointing work to collaborate. --- indra/llappearance/CMakeLists.txt | 78 +++ indra/llappearance/llwearable.cpp | 1285 +++++++++++++++++++++++++++++++++++++ indra/llappearance/llwearable.h | 165 +++++ 3 files changed, 1528 insertions(+) create mode 100644 indra/llappearance/CMakeLists.txt create mode 100644 indra/llappearance/llwearable.cpp create mode 100644 indra/llappearance/llwearable.h (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt new file mode 100644 index 0000000000..39bfbc9a21 --- /dev/null +++ b/indra/llappearance/CMakeLists.txt @@ -0,0 +1,78 @@ +# -*- cmake -*- + +project(llappearance) + +include(00-Common) +include(LLCommon) +include(Viewer) +include(LLAudio) +include(LLCharacter) +include(LLCommon) +include(LLImage) +include(LLImageJ2COJ) +include(LLInventory) +include(LLMath) +include(LLMessage) +include(LLPhysicsExtensions) +include(LLPlugin) +include(LLPrimitive) +include(LLRender) +include(LLUI) +include(LLVFS) +include(LLWindow) +include(LLXML) +include(Linking) +include(LLKDU) +include(ViewerMiscLibs) +include(LLLogin) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${VIEWER_INCLUDE_DIRS} + ${LLAUDIO_INCLUDE_DIRS} + ${LLCHARACTER_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLPHYSICS_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLKDU_INCLUDE_DIRS} + ${LLINVENTORY_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS} + ${LLPLUGIN_INCLUDE_DIRS} + ${LLPRIMITIVE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLUI_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} + ${LLLOGIN_INCLUDE_DIRS} + ) + +set(llappearance_SOURCE_FILES + llwearable.cpp + ) + +set(llappearance_HEADER_FILES + llwearable.h + CMakeLists.txt + ) + +set_source_files_properties(${llappearance_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llappearance_SOURCE_FILES ${llappearance_HEADER_FILES}) + +add_library (llappearance ${llappearance_SOURCE_FILES}) + +#add unit tests +#if (LL_TESTS) +# INCLUDE(LLAddBuildTest) +# SET(llappearance_TEST_SOURCE_FILES +# # no real unit tests yet! +# ) +# LL_ADD_PROJECT_UNIT_TESTS(llappearance "${llappearance_TEST_SOURCE_FILES}") + + #set(TEST_DEBUG on) +# set(test_libs llappearance ${LLCOMMON_LIBRARIES}) +#endif (LL_TESTS) diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp new file mode 100644 index 0000000000..d72999d8c7 --- /dev/null +++ b/indra/llappearance/llwearable.cpp @@ -0,0 +1,1285 @@ +/** + * @file llwearable.cpp + * @brief LLWearable class implementation + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//#include "llviewerprecompiledheaders.h" + +//#include "llagent.h" +//#include "llagentcamera.h" +#include "llagentwearables.h" +//#include "lldictionary.h" +//#include "llfloatersidepanelcontainer.h" +//#include "lllocaltextureobject.h" +//#include "llnotificationsutil.h" +//#include "llviewertexturelist.h" +//#include "llinventorymodel.h" +//#include "llinventoryobserver.h" +//#include "llsidepanelappearance.h" +#include "lltexlayer.h" +//#include "lltexglobalcolor.h" +//#include "lltrans.h" +//#include "llviewerregion.h" +#include "llvisualparam.h" +//#include "llvoavatar.h" +//#include "llvoavatarself.h" +//#include "llvoavatardefines.h" +#include "llwearable.h" +//#include "llviewercontrol.h" + +using namespace LLVOAvatarDefines; + +// static +S32 LLWearable::sCurrentDefinitionVersion = 1; + +// support class - remove for 2.1 (hackity hack hack) +class LLOverrideBakedTextureUpdate +{ +public: + LLOverrideBakedTextureUpdate(bool temp_state) + { + U32 num_bakes = (U32) LLVOAvatarDefines::BAKED_NUM_INDICES; + for( U32 index = 0; index < num_bakes; ++index ) + { + composite_enabled[index] = gAgentAvatarp->isCompositeUpdateEnabled(index); + } + gAgentAvatarp->setCompositeUpdatesEnabled(temp_state); + } + + ~LLOverrideBakedTextureUpdate() + { + U32 num_bakes = (U32)LLVOAvatarDefines::BAKED_NUM_INDICES; + for( U32 index = 0; index < num_bakes; ++index ) + { + gAgentAvatarp->setCompositeUpdatesEnabled(index, composite_enabled[index]); + } + } +private: + bool composite_enabled[LLVOAvatarDefines::BAKED_NUM_INDICES]; +}; + +// Private local functions +static std::string terse_F32_to_string(F32 f); +static std::string asset_id_to_filename(const LLUUID &asset_id); + +LLWearable::LLWearable(const LLTransactionID& transaction_id) : + mDefinitionVersion(LLWearable::sCurrentDefinitionVersion), + mType(LLWearableType::WT_INVALID) +{ + mTransactionID = transaction_id; + mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); +} + +LLWearable::LLWearable(const LLAssetID& asset_id) : + mDefinitionVersion( LLWearable::sCurrentDefinitionVersion ), + mType(LLWearableType::WT_INVALID) +{ + mAssetID = asset_id; + mTransactionID.setNull(); +} + +LLWearable::~LLWearable() +{ +} + +const std::string& LLWearable::getTypeLabel() const +{ + return LLWearableType::getTypeLabel(mType); +} + +const std::string& LLWearable::getTypeName() const +{ + return LLWearableType::getTypeName(mType); +} + +LLAssetType::EType LLWearable::getAssetType() const +{ + return LLWearableType::getAssetType(mType); +} + +BOOL LLWearable::exportFile(LLFILE* file) const +{ + // header and version + if( fprintf( file, "LLWearable version %d\n", mDefinitionVersion ) < 0 ) + { + return FALSE; + } + + // name + if( fprintf( file, "%s\n", mName.c_str() ) < 0 ) + { + return FALSE; + } + + // description + if( fprintf( file, "%s\n", mDescription.c_str() ) < 0 ) + { + return FALSE; + } + + // permissions + if( !mPermissions.exportFile( file ) ) + { + return FALSE; + } + + // sale info + if( !mSaleInfo.exportFile( file ) ) + { + return FALSE; + } + + // wearable type + S32 type = (S32)mType; + if( fprintf( file, "type %d\n", type ) < 0 ) + { + return FALSE; + } + + // parameters + S32 num_parameters = mVisualParamIndexMap.size(); + if( fprintf( file, "parameters %d\n", num_parameters ) < 0 ) + { + return FALSE; + } + + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); + iter != mVisualParamIndexMap.end(); + ++iter) + { + S32 param_id = iter->first; + const LLVisualParam* param = iter->second; + F32 param_weight = param->getWeight(); + if( fprintf( file, "%d %s\n", param_id, terse_F32_to_string( param_weight ).c_str() ) < 0 ) + { + return FALSE; + } + } + + // texture entries + S32 num_textures = mTEMap.size(); + if( fprintf( file, "textures %d\n", num_textures ) < 0 ) + { + return FALSE; + } + + for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter) + { + S32 te = iter->first; + const LLUUID& image_id = iter->second->getID(); + if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 ) + { + return FALSE; + } + } + return TRUE; +} + + +void LLWearable::createVisualParams() +{ + for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam()) + { + if (param->getWearableType() == mType) + { + addVisualParam(param->cloneParam(this)); + } + } + + // resync driver parameters to point to the newly cloned driven parameters + for (visual_param_index_map_t::iterator param_iter = mVisualParamIndexMap.begin(); + param_iter != mVisualParamIndexMap.end(); + ++param_iter) + { + LLVisualParam* param = param_iter->second; + LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam; + // need this line to disambiguate between versions of LLCharacter::getVisualParam() + LLVisualParam*(LLVOAvatarSelf::*avatar_function)(S32)const = &LLVOAvatarSelf::getVisualParam; + param->resetDrivenParams(); + if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false)) + { + if( !param->linkDrivenParams(boost::bind(avatar_function,gAgentAvatarp.get(),_1 ), true)) + { + llwarns << "could not link driven params for wearable " << getName() << " id: " << param->getID() << llendl; + continue; + } + } + } +} + +BOOL LLWearable::importFile( LLFILE* file ) +{ + // *NOTE: changing the type or size of this buffer will require + // changes in the fscanf() code below. You would be better off + // rewriting this to use streams and not require an open FILE. + char text_buffer[2048]; /* Flawfinder: ignore */ + S32 fields_read = 0; + + // suppress texlayerset updates while wearables are being imported. Layersets will be updated + // when the wearables are "worn", not loaded. Note state will be restored when this object is destroyed. + LLOverrideBakedTextureUpdate stop_bakes(false); + + // read header and version + fields_read = fscanf( file, "LLWearable version %d\n", &mDefinitionVersion ); + if( fields_read != 1 ) + { + // Shouldn't really log the asset id for security reasons, but + // we need it in this case. + llwarns << "Bad Wearable asset header: " << mAssetID << llendl; + //gVFS->dumpMap(); + return FALSE; + } + + + // Temoprary hack to allow wearables with definition version 24 to still load. + // This should only affect lindens and NDA'd testers who have saved wearables in 2.0 + // the extra check for version == 24 can be removed before release, once internal testers + // have loaded these wearables again. See hack pt 2 at bottom of function to ensure that + // these wearables get re-saved with version definition 22. + if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 ) + { + llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; + return FALSE; + } + + // name + int next_char = fgetc( file ); /* Flawfinder: ignore */ + if( '\n' == next_char ) + { + // no name + mName = ""; + } + else + { + ungetc( next_char, file ); + fields_read = fscanf( /* Flawfinder: ignore */ + file, + "%2047[^\n]", + text_buffer); + if( (1 != fields_read) || (fgetc( file ) != '\n') ) /* Flawfinder: ignore */ + { + llwarns << "Bad Wearable asset: early end of file" << llendl; + return FALSE; + } + mName = text_buffer; + LLStringUtil::truncate(mName, DB_INV_ITEM_NAME_STR_LEN ); + } + + // description + next_char = fgetc( file ); /* Flawfinder: ignore */ + if( '\n' == next_char ) + { + // no description + mDescription = ""; + } + else + { + ungetc( next_char, file ); + fields_read = fscanf( /* Flawfinder: ignore */ + file, + "%2047[^\n]", + text_buffer ); + if( (1 != fields_read) || (fgetc( file ) != '\n') ) /* Flawfinder: ignore */ + { + llwarns << "Bad Wearable asset: early end of file" << llendl; + return FALSE; + } + mDescription = text_buffer; + LLStringUtil::truncate(mDescription, DB_INV_ITEM_DESC_STR_LEN ); + } + + // permissions + S32 perm_version; + fields_read = fscanf( file, " permissions %d\n", &perm_version ); + if( (fields_read != 1) || (perm_version != 0) ) + { + llwarns << "Bad Wearable asset: missing permissions" << llendl; + return FALSE; + } + if( !mPermissions.importFile( file ) ) + { + return FALSE; + } + + // sale info + S32 sale_info_version; + fields_read = fscanf( file, " sale_info %d\n", &sale_info_version ); + if( (fields_read != 1) || (sale_info_version != 0) ) + { + llwarns << "Bad Wearable asset: missing sale_info" << llendl; + return FALSE; + } + // Sale info used to contain next owner perm. It is now in the + // permissions. Thus, we read that out, and fix legacy + // objects. It's possible this op would fail, but it should pick + // up the vast majority of the tasks. + BOOL has_perm_mask = FALSE; + U32 perm_mask = 0; + if( !mSaleInfo.importFile(file, has_perm_mask, perm_mask) ) + { + return FALSE; + } + if(has_perm_mask) + { + // fair use fix. + if(!(perm_mask & PERM_COPY)) + { + perm_mask |= PERM_TRANSFER; + } + mPermissions.setMaskNext(perm_mask); + } + + // wearable type + S32 type = -1; + fields_read = fscanf( file, "type %d\n", &type ); + if( fields_read != 1 ) + { + llwarns << "Bad Wearable asset: bad type" << llendl; + return FALSE; + } + if( 0 <= type && type < LLWearableType::WT_COUNT ) + { + setType((LLWearableType::EType)type); + } + else + { + mType = LLWearableType::WT_COUNT; + llwarns << "Bad Wearable asset: bad type #" << type << llendl; + return FALSE; + } + + // parameters header + S32 num_parameters = 0; + fields_read = fscanf( file, "parameters %d\n", &num_parameters ); + if( fields_read != 1 ) + { + llwarns << "Bad Wearable asset: missing parameters block" << llendl; + return FALSE; + } + + if( num_parameters != mVisualParamIndexMap.size() ) + { + llwarns << "Wearable parameter mismatch. Reading in " << num_parameters << " from file, but created " << mVisualParamIndexMap.size() << " from avatar parameters. type: " << mType << llendl; + } + + // parameters + S32 i; + for( i = 0; i < num_parameters; i++ ) + { + S32 param_id = 0; + F32 param_weight = 0.f; + fields_read = fscanf( file, "%d %f\n", ¶m_id, ¶m_weight ); + if( fields_read != 2 ) + { + llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl; + return FALSE; + } + mSavedVisualParamMap[param_id] = param_weight; + } + + // textures header + S32 num_textures = 0; + fields_read = fscanf( file, "textures %d\n", &num_textures); + if( fields_read != 1 ) + { + llwarns << "Bad Wearable asset: missing textures block" << llendl; + return FALSE; + } + + // textures + for( i = 0; i < num_textures; i++ ) + { + S32 te = 0; + fields_read = fscanf( /* Flawfinder: ignore */ + file, + "%d %2047s\n", + &te, text_buffer); + if( fields_read != 2 ) + { + llwarns << "Bad Wearable asset: bad texture, #" << i << llendl; + return FALSE; + } + + if( !LLUUID::validate( text_buffer ) ) + { + llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl; + return FALSE; + } + LLUUID id = LLUUID(text_buffer); + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( id ); + if( mTEMap.find(te) != mTEMap.end() ) + { + delete mTEMap[te]; + } + if( mSavedTEMap.find(te) != mSavedTEMap.end() ) + { + delete mSavedTEMap[te]; + } + + if(gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime")) + { + image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te), NULL); + } + LLUUID textureid(text_buffer); + mTEMap[te] = new LLLocalTextureObject(image, textureid); + mSavedTEMap[te] = new LLLocalTextureObject(image, textureid); + createLayers(te); + } + + // copy all saved param values to working params + revertValues(); + + return TRUE; +} + + +// Avatar parameter and texture definitions can change over time. +// This function returns true if parameters or textures have been added or removed +// since this wearable was created. +BOOL LLWearable::isOldVersion() const +{ + if (!isAgentAvatarValid()) return FALSE; + + if( LLWearable::sCurrentDefinitionVersion < mDefinitionVersion ) + { + llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; + llassert(0); + } + + if( LLWearable::sCurrentDefinitionVersion != mDefinitionVersion ) + { + return TRUE; + } + + S32 param_count = 0; + for( LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam() ) + { + if( (param->getWearableType() == mType) && (param->isTweakable() ) ) + { + param_count++; + if( !is_in_map(mVisualParamIndexMap, param->getID() ) ) + { + return TRUE; + } + } + } + if( param_count != mVisualParamIndexMap.size() ) + { + return TRUE; + } + + + S32 te_count = 0; + for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) + { + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) + { + te_count++; + if( !is_in_map(mTEMap, te ) ) + { + return TRUE; + } + } + } + if( te_count != mTEMap.size() ) + { + return TRUE; + } + + return FALSE; +} + +// Avatar parameter and texture definitions can change over time. +// * If parameters or textures have been REMOVED since the wearable was created, +// they're just ignored, so we consider the wearable clean even though isOldVersion() +// will return true. +// * If parameters or textures have been ADDED since the wearable was created, +// they are taken to have default values, so we consider the wearable clean +// only if those values are the same as the defaults. +BOOL LLWearable::isDirty() const +{ + if (!isAgentAvatarValid()) return FALSE; + + for( LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam() ) + { + if( (param->getWearableType() == mType) + && (param->isTweakable() ) + && !param->getCrossWearable()) + { + F32 current_weight = getVisualParamWeight(param->getID()); + current_weight = llclamp( current_weight, param->getMinWeight(), param->getMaxWeight() ); + F32 saved_weight = get_if_there(mSavedVisualParamMap, param->getID(), param->getDefaultWeight()); + saved_weight = llclamp( saved_weight, param->getMinWeight(), param->getMaxWeight() ); + + U8 a = F32_to_U8( saved_weight, param->getMinWeight(), param->getMaxWeight() ); + U8 b = F32_to_U8( current_weight, param->getMinWeight(), param->getMaxWeight() ); + if( a != b ) + { + return TRUE; + } + } + } + + for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) + { + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) + { + te_map_t::const_iterator current_iter = mTEMap.find(te); + if(current_iter != mTEMap.end()) + { + const LLUUID& current_image_id = current_iter->second->getID(); + te_map_t::const_iterator saved_iter = mSavedTEMap.find(te); + if(saved_iter != mSavedTEMap.end()) + { + const LLUUID& saved_image_id = saved_iter->second->getID(); + if (saved_image_id != current_image_id) + { + // saved vs current images are different, wearable is dirty + return TRUE; + } + } + else + { + // image found in current image list but not saved image list + return TRUE; + } + } + } + } + + return FALSE; +} + + +void LLWearable::setParamsToDefaults() +{ + if (!isAgentAvatarValid()) return; + + for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam() ) + { + if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) ) + { + setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE); + } + } +} + +void LLWearable::setTexturesToDefaults() +{ + for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) + { + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) + { + LLUUID id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + LLViewerFetchedTexture * image = LLViewerTextureManager::getFetchedTexture( id ); + if( mTEMap.find(te) == mTEMap.end() ) + { + mTEMap[te] = new LLLocalTextureObject(image, id); + createLayers(te); + } + else + { + // Local Texture Object already created, just set image and UUID + LLLocalTextureObject *lto = mTEMap[te]; + lto->setID(id); + lto->setImage(image); + } + } + } +} + +// Updates the user's avatar's appearance +void LLWearable::writeToAvatar() +{ + if (!isAgentAvatarValid()) return; + + ESex old_sex = gAgentAvatarp->getSex(); + + // Pull params + for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam() ) + { + // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the + // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way. + if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) ) + { + S32 param_id = param->getID(); + F32 weight = getVisualParamWeight(param_id); + + gAgentAvatarp->setVisualParamWeight( param_id, weight, FALSE ); + } + } + + // Pull texture entries + for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) + { + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) + { + te_map_t::const_iterator iter = mTEMap.find(te); + LLUUID image_id; + if(iter != mTEMap.end()) + { + image_id = iter->second->getID(); + } + else + { + image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + } + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE ); + // MULTI-WEARABLE: assume index 0 will be used when writing to avatar. TODO: eliminate the need for this. + gAgentAvatarp->setLocalTextureTE(te, image, 0); + } + } + + ESex new_sex = gAgentAvatarp->getSex(); + if( old_sex != new_sex ) + { + gAgentAvatarp->updateSexDependentLayerSets( FALSE ); + } + +// if( upload_bake ) +// { +// gAgent.sendAgentSetAppearance(); +// } +} + + +// Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values. +// static +void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ) +{ + if (!isAgentAvatarValid()) return; + + // You can't just remove body parts. + if( (type == LLWearableType::WT_SHAPE) || + (type == LLWearableType::WT_SKIN) || + (type == LLWearableType::WT_HAIR) || + (type == LLWearableType::WT_EYES) ) + { + return; + } + + // Pull params + for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam() ) + { + if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable() ) ) + { + S32 param_id = param->getID(); + gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight(), upload_bake ); + } + } + + if(gAgentCamera.cameraCustomizeAvatar()) + { + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); + } + + gAgentAvatarp->updateVisualParams(); + gAgentAvatarp->wearableUpdated(type, FALSE); + +// if( upload_bake ) +// { +// gAgent.sendAgentSetAppearance(); +// } +} + +// Does not copy mAssetID. +// Definition version is current: removes obsolete enties and creates default values for new ones. +void LLWearable::copyDataFrom(const LLWearable* src) +{ + if (!isAgentAvatarValid()) return; + + mDefinitionVersion = LLWearable::sCurrentDefinitionVersion; + + mName = src->mName; + mDescription = src->mDescription; + mPermissions = src->mPermissions; + mSaleInfo = src->mSaleInfo; + + setType(src->mType); + + mSavedVisualParamMap.clear(); + // Deep copy of mVisualParamMap (copies only those params that are current, filling in defaults where needed) + for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam() ) + { + if( (param->getWearableType() == mType) ) + { + S32 id = param->getID(); + F32 weight = src->getVisualParamWeight(id); + mSavedVisualParamMap[id] = weight; + } + } + + destroyTextures(); + // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) + for (S32 te = 0; te < TEX_NUM_INDICES; te++) + { + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) + { + te_map_t::const_iterator iter = src->mTEMap.find(te); + LLUUID image_id; + LLViewerFetchedTexture *image = NULL; + if(iter != src->mTEMap.end()) + { + image = src->getLocalTextureObject(te)->getImage(); + image_id = src->getLocalTextureObject(te)->getID(); + mTEMap[te] = new LLLocalTextureObject(image, image_id); + mSavedTEMap[te] = new LLLocalTextureObject(image, image_id); + mTEMap[te]->setBakedReady(src->getLocalTextureObject(te)->getBakedReady()); + mTEMap[te]->setDiscard(src->getLocalTextureObject(te)->getDiscard()); + } + else + { + image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + image = LLViewerTextureManager::getFetchedTexture( image_id ); + mTEMap[te] = new LLLocalTextureObject(image, image_id); + mSavedTEMap[te] = new LLLocalTextureObject(image, image_id); + } + createLayers(te); + } + } + + // Probably reduntant, but ensure that the newly created wearable is not dirty by setting current value of params in new wearable + // to be the same as the saved values (which were loaded from src at param->cloneParam(this)) + revertValues(); +} + +void LLWearable::setItemID(const LLUUID& item_id) +{ + mItemID = item_id; +} + +const LLUUID& LLWearable::getItemID() const +{ + return mItemID; +} + +void LLWearable::setType(LLWearableType::EType type) +{ + mType = type; + createVisualParams(); +} + +LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) +{ + te_map_t::iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + LLLocalTextureObject* lto = iter->second; + return lto; + } + return NULL; +} + +const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const +{ + te_map_t::const_iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + const LLLocalTextureObject* lto = iter->second; + return lto; + } + return NULL; +} + +std::vector LLWearable::getLocalTextureListSeq() +{ + std::vector result; + + for(te_map_t::const_iterator iter = mTEMap.begin(); + iter != mTEMap.end(); iter++) + { + LLLocalTextureObject* lto = iter->second; + result.push_back(lto); + } + + return result; +} + +void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject <o) +{ + if( mTEMap.find(index) != mTEMap.end() ) + { + mTEMap.erase(index); + } + mTEMap[index] = new LLLocalTextureObject(lto); +} + + +void LLWearable::addVisualParam(LLVisualParam *param) +{ + if( mVisualParamIndexMap[param->getID()] ) + { + delete mVisualParamIndexMap[param->getID()]; + } + param->setIsDummy(FALSE); + mVisualParamIndexMap[param->getID()] = param; + mSavedVisualParamMap[param->getID()] = param->getDefaultWeight(); +} + +void LLWearable::setVisualParams() +{ + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); iter++) + { + S32 id = iter->first; + LLVisualParam *wearable_param = iter->second; + F32 value = wearable_param->getWeight(); + gAgentAvatarp->setVisualParamWeight(id, value, FALSE); + } +} + + +void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake) +{ + if( is_in_map(mVisualParamIndexMap, param_index ) ) + { + LLVisualParam *wearable_param = mVisualParamIndexMap[param_index]; + wearable_param->setWeight(value, upload_bake); + } + else + { + llerrs << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl; + } +} + +F32 LLWearable::getVisualParamWeight(S32 param_index) const +{ + if( is_in_map(mVisualParamIndexMap, param_index ) ) + { + const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second; + return wearable_param->getWeight(); + } + else + { + llwarns << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl; + } + return (F32)-1.0; +} + +LLVisualParam* LLWearable::getVisualParam(S32 index) const +{ + visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.find(index); + return (iter == mVisualParamIndexMap.end()) ? NULL : iter->second; +} + + +void LLWearable::getVisualParams(visual_param_vec_t &list) +{ + visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); + visual_param_index_map_t::iterator end = mVisualParamIndexMap.end(); + + // add all visual params to the passed-in vector + for( ; iter != end; ++iter ) + { + list.push_back(iter->second); + } +} + +void LLWearable::animateParams(F32 delta, BOOL upload_bake) +{ + for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); + iter != mVisualParamIndexMap.end(); + ++iter) + { + LLVisualParam *param = (LLVisualParam*) iter->second; + param->animate(delta, upload_bake); + } +} + +LLColor4 LLWearable::getClothesColor(S32 te) const +{ + LLColor4 color; + U32 param_name[3]; + if( LLVOAvatar::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) + { + for( U8 index = 0; index < 3; index++ ) + { + color.mV[index] = getVisualParamWeight(param_name[index]); + } + } + return color; +} + +void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ) +{ + U32 param_name[3]; + if( LLVOAvatar::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) + { + for( U8 index = 0; index < 3; index++ ) + { + setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake); + } + } +} + +void LLWearable::revertValues() +{ + //update saved settings so wearable is no longer dirty + // non-driver params first + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + F32 value = iter->second; + LLVisualParam *param = getVisualParam(id); + if(param && !dynamic_cast(param) ) + { + setVisualParamWeight(id, value, TRUE); + } + } + + //then driver params + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + F32 value = iter->second; + LLVisualParam *param = getVisualParam(id); + if(param && dynamic_cast(param) ) + { + setVisualParamWeight(id, value, TRUE); + } + } + + // make sure that saved values are sane + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + LLVisualParam *param = getVisualParam(id); + if( param ) + { + mSavedVisualParamMap[id] = param->getWeight(); + } + } + + syncImages(mSavedTEMap, mTEMap); + + + LLSidepanelAppearance *panel = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); + if( panel ) + { + panel->updateScrollingPanelList(); + } +} + +BOOL LLWearable::isOnTop() const +{ + return (this == gAgentWearables.getTopWearable(mType)); +} + +void LLWearable::createLayers(S32 te) +{ + LLTexLayerSet *layer_set = gAgentAvatarp->getLayerSet((ETextureIndex)te); + if (layer_set) + { + layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this); + } + else + { + llerrs << "could not find layerset for LTO in wearable!" << llendl; + } +} + +void LLWearable::saveValues() +{ + //update saved settings so wearable is no longer dirty + mSavedVisualParamMap.clear(); + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter) + { + S32 id = iter->first; + LLVisualParam *wearable_param = iter->second; + F32 value = wearable_param->getWeight(); + mSavedVisualParamMap[id] = value; + } + + // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) + syncImages(mTEMap, mSavedTEMap); + + + LLSidepanelAppearance *panel = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); + if( panel ) + { + panel->updateScrollingPanelList(); + } +} + +void LLWearable::syncImages(te_map_t &src, te_map_t &dst) +{ + // Deep copy of src (copies only those tes that are current, filling in defaults where needed) + for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) + { + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) + { + te_map_t::const_iterator iter = src.find(te); + LLUUID image_id; + LLViewerFetchedTexture *image = NULL; + LLLocalTextureObject *lto = NULL; + if(iter != src.end()) + { + // there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map. + lto = iter->second; + image = lto->getImage(); + image_id = lto->getID(); + } + else + { + // there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map. + image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + image = LLViewerTextureManager::getFetchedTexture( image_id ); + } + + if( dst.find(te) != dst.end() ) + { + // there's already an entry in the destination map for the texture. Just update its values. + dst[te]->setImage(image); + dst[te]->setID(image_id); + } + else + { + // no entry found in the destination map, we need to create a new Local Texture Object + dst[te] = new LLLocalTextureObject(image, image_id); + } + + if( lto ) + { + // If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map. + dst[te]->setBakedReady(lto->getBakedReady()); + dst[te]->setDiscard(lto->getDiscard()); + } + } + } +} + +void LLWearable::destroyTextures() +{ + for( te_map_t::iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter ) + { + LLLocalTextureObject *lto = iter->second; + delete lto; + } + mTEMap.clear(); + for( te_map_t::iterator iter = mSavedTEMap.begin(); iter != mSavedTEMap.end(); ++iter ) + { + LLLocalTextureObject *lto = iter->second; + delete lto; + } + mSavedTEMap.clear(); +} + +void LLWearable::pullCrossWearableValues() +{ + // scan through all of the avatar's visual parameters + for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam()) + { + if( param ) + { + LLDriverParam *driver_param = dynamic_cast(param); + if(driver_param) + { + // parameter is a driver parameter, have it update its + driver_param->updateCrossDrivenParams(getType()); + } + } + } +} + + +void LLWearable::setLabelUpdated() const +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, getItemID()); +} + +void LLWearable::refreshName() +{ + LLUUID item_id = getItemID(); + LLInventoryItem* item = gInventory.getItem(item_id); + if( item ) + { + mName = item->getName(); + } +} + +struct LLWearableSaveData +{ + LLWearableType::EType mType; +}; + +void LLWearable::saveNewAsset() const +{ +// llinfos << "LLWearable::saveNewAsset() type: " << getTypeName() << llendl; + //llinfos << *this << llendl; + + const std::string filename = asset_id_to_filename(mAssetID); + LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ + BOOL successful_save = FALSE; + if(fp && exportFile(fp)) + { + successful_save = TRUE; + } + if(fp) + { + fclose(fp); + fp = NULL; + } + if(!successful_save) + { + std::string buffer = llformat("Unable to save '%s' to wearable file.", mName.c_str()); + llwarns << buffer << llendl; + + LLSD args; + args["NAME"] = mName; + LLNotificationsUtil::add("CannotSaveWearableOutOfSpace", args); + return; + } + + // save it out to database + if( gAssetStorage ) + { + /* + std::string url = gAgent.getRegion()->getCapability("NewAgentInventory"); + if (!url.empty()) + { + llinfos << "Update Agent Inventory via capability" << llendl; + LLSD body; + body["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::assetToFolderType(getAssetType())); + body["asset_type"] = LLAssetType::lookup(getAssetType()); + body["inventory_type"] = LLInventoryType::lookup(LLInventoryType::IT_WEARABLE); + body["name"] = getName(); + body["description"] = getDescription(); + LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, filename)); + } + else + { + } + */ + LLWearableSaveData* data = new LLWearableSaveData; + data->mType = mType; + gAssetStorage->storeAssetData(filename, mTransactionID, getAssetType(), + &LLWearable::onSaveNewAssetComplete, + (void*)data); + } +} + +// static +void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userdata, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) +{ + LLWearableSaveData* data = (LLWearableSaveData*)userdata; + const std::string& type_name = LLWearableType::getTypeName(data->mType); + if(0 == status) + { + // Success + llinfos << "Saved wearable " << type_name << llendl; + } + else + { + std::string buffer = llformat("Unable to save %s to central asset store.", type_name.c_str()); + llwarns << buffer << " Status: " << status << llendl; + LLSD args; + args["NAME"] = type_name; + LLNotificationsUtil::add("CannotSaveToAssetStore", args); + } + + // Delete temp file + const std::string src_filename = asset_id_to_filename(new_asset_id); + LLFile::remove(src_filename); + + // delete the context data + delete data; + +} + +std::ostream& operator<<(std::ostream &s, const LLWearable &w) +{ + s << "wearable " << LLWearableType::getTypeName(w.mType) << "\n"; + s << " Name: " << w.mName << "\n"; + s << " Desc: " << w.mDescription << "\n"; + //w.mPermissions + //w.mSaleInfo + + s << " Params:" << "\n"; + for (LLWearable::visual_param_index_map_t::const_iterator iter = w.mVisualParamIndexMap.begin(); + iter != w.mVisualParamIndexMap.end(); ++iter) + { + S32 param_id = iter->first; + LLVisualParam *wearable_param = iter->second; + F32 param_weight = wearable_param->getWeight(); + s << " " << param_id << " " << param_weight << "\n"; + } + + s << " Textures:" << "\n"; + for (LLWearable::te_map_t::const_iterator iter = w.mTEMap.begin(); + iter != w.mTEMap.end(); ++iter) + { + S32 te = iter->first; + const LLUUID& image_id = iter->second->getID(); + s << " " << te << " " << image_id << "\n"; + } + return s; +} + + +std::string terse_F32_to_string(F32 f) +{ + std::string r = llformat("%.2f", f); + S32 len = r.length(); + + // "1.20" -> "1.2" + // "24.00" -> "24." + while (len > 0 && ('0' == r[len - 1])) + { + r.erase(len-1, 1); + len--; + } + if ('.' == r[len - 1]) + { + // "24." -> "24" + r.erase(len-1, 1); + } + else if (('-' == r[0]) && ('0' == r[1])) + { + // "-0.59" -> "-.59" + r.erase(1, 1); + } + else if ('0' == r[0]) + { + // "0.59" -> ".59" + r.erase(0, 1); + } + return r; +} + +std::string asset_id_to_filename(const LLUUID &asset_id) +{ + std::string asset_id_string; + asset_id.toString(asset_id_string); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id_string) + ".wbl"; + return filename; +} diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h new file mode 100644 index 0000000000..c8f9ef1fb9 --- /dev/null +++ b/indra/llappearance/llwearable.h @@ -0,0 +1,165 @@ +/** + * @file llwearable.h + * @brief LLWearable class header file + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLWEARABLE_H +#define LL_LLWEARABLE_H + +//#include "lluuid.h" +//#include "llstring.h" +//#include "llpermissions.h" +//#include "llsaleinfo.h" +//#include "llassetstorage.h" +//#include "llwearabletype.h" +//#include "llfile.h" +//#include "lllocaltextureobject.h" + +class LLViewerInventoryItem; +class LLVisualParam; +class LLTexGlobalColorInfo; +class LLTexGlobalColor; + +class LLWearable +{ + friend class LLWearableList; + + //-------------------------------------------------------------------- + // Constructors and destructors + //-------------------------------------------------------------------- +private: + // Private constructors used by LLWearableList + LLWearable(const LLTransactionID& transactionID); + LLWearable(const LLAssetID& assetID); +public: + virtual ~LLWearable(); + + //-------------------------------------------------------------------- + // Accessors + //-------------------------------------------------------------------- +public: + const LLUUID& getItemID() const; + const LLAssetID& getAssetID() const { return mAssetID; } + const LLTransactionID& getTransactionID() const { return mTransactionID; } + LLWearableType::EType getType() const { return mType; } + void setType(LLWearableType::EType type); + const std::string& getName() const { return mName; } + void setName(const std::string& name) { mName = name; } + const std::string& getDescription() const { return mDescription; } + void setDescription(const std::string& desc) { mDescription = desc; } + const LLPermissions& getPermissions() const { return mPermissions; } + void setPermissions(const LLPermissions& p) { mPermissions = p; } + const LLSaleInfo& getSaleInfo() const { return mSaleInfo; } + void setSaleInfo(const LLSaleInfo& info) { mSaleInfo = info; } + const std::string& getTypeLabel() const; + const std::string& getTypeName() const; + LLAssetType::EType getAssetType() const; + S32 getDefinitionVersion() const { return mDefinitionVersion; } + void setDefinitionVersion( S32 new_version ) { mDefinitionVersion = new_version; } + +public: + typedef std::vector visual_param_vec_t; + + BOOL isDirty() const; + BOOL isOldVersion() const; + + void writeToAvatar(); + void removeFromAvatar( BOOL upload_bake ) { LLWearable::removeFromAvatar( mType, upload_bake ); } + static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ); + + BOOL exportFile(LLFILE* file) const; + BOOL importFile(LLFILE* file); + + void setParamsToDefaults(); + void setTexturesToDefaults(); + + void saveNewAsset() const; + static void onSaveNewAssetComplete( const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status ); + + void copyDataFrom(const LLWearable* src); + + static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; } + + friend std::ostream& operator<<(std::ostream &s, const LLWearable &w); + void setItemID(const LLUUID& item_id); + + LLLocalTextureObject* getLocalTextureObject(S32 index); + const LLLocalTextureObject* getLocalTextureObject(S32 index) const; + std::vector getLocalTextureListSeq(); + + void setLocalTextureObject(S32 index, LLLocalTextureObject <o); + void addVisualParam(LLVisualParam *param); + void setVisualParams(); + void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); + F32 getVisualParamWeight(S32 index) const; + LLVisualParam* getVisualParam(S32 index) const; + void getVisualParams(visual_param_vec_t &list); + void animateParams(F32 delta, BOOL upload_bake); + + LLColor4 getClothesColor(S32 te) const; + void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ); + + void revertValues(); + void saveValues(); + void pullCrossWearableValues(); + + BOOL isOnTop() const; + + // Something happened that requires the wearable's label to be updated (e.g. worn/unworn). + void setLabelUpdated() const; + + // the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem, + // not the wearable asset itself. + void refreshName(); + +private: + typedef std::map te_map_t; + typedef std::map visual_param_index_map_t; + + void createLayers(S32 te); + void createVisualParams(); + void syncImages(te_map_t &src, te_map_t &dst); + void destroyTextures(); + + static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml. + S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created. + std::string mName; + std::string mDescription; + LLPermissions mPermissions; + LLSaleInfo mSaleInfo; + LLAssetID mAssetID; + LLTransactionID mTransactionID; + LLWearableType::EType mType; + + typedef std::map param_map_t; + param_map_t mSavedVisualParamMap; // last saved version of visual params + + visual_param_index_map_t mVisualParamIndexMap; + + te_map_t mTEMap; // maps TE to LocalTextureObject + te_map_t mSavedTEMap; // last saved version of TEMap + LLUUID mItemID; // ID of the inventory item in the agent's inventory +}; + +#endif // LL_LLWEARABLE_H -- cgit v1.2.3 From c355fb98d3f4040196b7b8586dc9328fccb906d2 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 3 Sep 2012 06:12:50 +0000 Subject: Extracted texture baking system into llappearance library. --- indra/llappearance/CMakeLists.txt | 32 +- indra/llappearance/llavatarappearance.cpp | 174 +++ indra/llappearance/llavatarappearance.h | 128 ++ indra/llappearance/llinventoryicon.cpp | 184 +++ indra/llappearance/llinventoryicon.h | 102 ++ indra/llappearance/lljointpickname.h | 46 + indra/llappearance/lllocaltextureobject.cpp | 213 +++ indra/llappearance/lllocaltextureobject.h | 87 ++ indra/llappearance/lltexglobalcolor.cpp | 154 +++ indra/llappearance/lltexglobalcolor.h | 83 ++ indra/llappearance/lltexlayer.cpp | 1778 +++++++++++++++++++++++++ indra/llappearance/lltexlayer.h | 269 ++++ indra/llappearance/lltexlayerparams.cpp | 571 ++++++++ indra/llappearance/lltexlayerparams.h | 195 +++ indra/llappearance/lltexturemanagerbridge.cpp | 32 + indra/llappearance/lltexturemanagerbridge.h | 45 + indra/llappearance/llviewervisualparam.cpp | 165 +++ indra/llappearance/llviewervisualparam.h | 109 ++ indra/llappearance/llvoavatardefines.cpp | 249 ++++ indra/llappearance/llvoavatardefines.h | 226 ++++ indra/llappearance/llwearable.cpp | 868 +----------- indra/llappearance/llwearable.h | 87 +- indra/llappearance/llwearabletype.cpp | 162 +++ indra/llappearance/llwearabletype.h | 76 ++ 24 files changed, 5128 insertions(+), 907 deletions(-) create mode 100644 indra/llappearance/llavatarappearance.cpp create mode 100644 indra/llappearance/llavatarappearance.h create mode 100644 indra/llappearance/llinventoryicon.cpp create mode 100644 indra/llappearance/llinventoryicon.h create mode 100644 indra/llappearance/lljointpickname.h create mode 100644 indra/llappearance/lllocaltextureobject.cpp create mode 100644 indra/llappearance/lllocaltextureobject.h create mode 100644 indra/llappearance/lltexglobalcolor.cpp create mode 100644 indra/llappearance/lltexglobalcolor.h create mode 100644 indra/llappearance/lltexlayer.cpp create mode 100644 indra/llappearance/lltexlayer.h create mode 100644 indra/llappearance/lltexlayerparams.cpp create mode 100644 indra/llappearance/lltexlayerparams.h create mode 100644 indra/llappearance/lltexturemanagerbridge.cpp create mode 100644 indra/llappearance/lltexturemanagerbridge.h create mode 100644 indra/llappearance/llviewervisualparam.cpp create mode 100644 indra/llappearance/llviewervisualparam.h create mode 100644 indra/llappearance/llvoavatardefines.cpp create mode 100644 indra/llappearance/llvoavatardefines.h create mode 100644 indra/llappearance/llwearabletype.cpp create mode 100644 indra/llappearance/llwearabletype.h (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index 39bfbc9a21..bc4748b87f 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -28,34 +28,48 @@ include(LLLogin) include_directories( ${LLCOMMON_INCLUDE_DIRS} - ${VIEWER_INCLUDE_DIRS} - ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} - ${LLCOMMON_INCLUDE_DIRS} ${LLPHYSICS_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} ${LLKDU_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLMESSAGE_INCLUDE_DIRS} - ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS} - ${LLPLUGIN_INCLUDE_DIRS} - ${LLPRIMITIVE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLUI_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} - ${LLLOGIN_INCLUDE_DIRS} ) set(llappearance_SOURCE_FILES + llavatarappearance.cpp + llinventoryicon.cpp + lllocaltextureobject.cpp + lltexglobalcolor.cpp + lltexlayer.cpp + lltexlayerparams.cpp + lltexturemanagerbridge.cpp llwearable.cpp + llwearabletype.cpp + llviewervisualparam.cpp + llvoavatardefines.cpp ) set(llappearance_HEADER_FILES - llwearable.h CMakeLists.txt + + llavatarappearance.h + llinventoryicon.cpp + lljointpickname.h + lllocaltextureobject.h + lltexglobalcolor.h + lltexlayer.h + lltexlayerparams.h + lltexturemanagerbridge.h + llwearable.h + llwearabletype.h + llviewervisualparam.h + llvoavatardefines.h ) set_source_files_properties(${llappearance_HEADER_FILES} diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp new file mode 100644 index 0000000000..1ca0161d7e --- /dev/null +++ b/indra/llappearance/llavatarappearance.cpp @@ -0,0 +1,174 @@ +/** + * @File llavatarappearance.cpp + * @brief Implementation of LLAvatarAppearance class + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llavatarappearance.h" +#include "lltexglobalcolor.h" + +const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); + +LLAvatarAppearance::LLAvatarAppearance() : + LLCharacter(), + mTexSkinColor( NULL ), + mTexHairColor( NULL ), + mTexEyeColor( NULL ), + mIsDummy(FALSE) +{ + mDebugExistenceTimer.reset(); +} + +using namespace LLVOAvatarDefines; + +//static +BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) +{ + switch( te ) + { + case TEX_UPPER_SHIRT: + param_name[0] = 803; //"shirt_red"; + param_name[1] = 804; //"shirt_green"; + param_name[2] = 805; //"shirt_blue"; + break; + + case TEX_LOWER_PANTS: + param_name[0] = 806; //"pants_red"; + param_name[1] = 807; //"pants_green"; + param_name[2] = 808; //"pants_blue"; + break; + + case TEX_LOWER_SHOES: + param_name[0] = 812; //"shoes_red"; + param_name[1] = 813; //"shoes_green"; + param_name[2] = 817; //"shoes_blue"; + break; + + case TEX_LOWER_SOCKS: + param_name[0] = 818; //"socks_red"; + param_name[1] = 819; //"socks_green"; + param_name[2] = 820; //"socks_blue"; + break; + + case TEX_UPPER_JACKET: + case TEX_LOWER_JACKET: + param_name[0] = 834; //"jacket_red"; + param_name[1] = 835; //"jacket_green"; + param_name[2] = 836; //"jacket_blue"; + break; + + case TEX_UPPER_GLOVES: + param_name[0] = 827; //"gloves_red"; + param_name[1] = 829; //"gloves_green"; + param_name[2] = 830; //"gloves_blue"; + break; + + case TEX_UPPER_UNDERSHIRT: + param_name[0] = 821; //"undershirt_red"; + param_name[1] = 822; //"undershirt_green"; + param_name[2] = 823; //"undershirt_blue"; + break; + + case TEX_LOWER_UNDERPANTS: + param_name[0] = 824; //"underpants_red"; + param_name[1] = 825; //"underpants_green"; + param_name[2] = 826; //"underpants_blue"; + break; + + case TEX_SKIRT: + param_name[0] = 921; //"skirt_red"; + param_name[1] = 922; //"skirt_green"; + param_name[2] = 923; //"skirt_blue"; + break; + + case TEX_HEAD_TATTOO: + case TEX_LOWER_TATTOO: + case TEX_UPPER_TATTOO: + param_name[0] = 1071; //"tattoo_red"; + param_name[1] = 1072; //"tattoo_green"; + param_name[2] = 1073; //"tattoo_blue"; + break; + + default: + llassert(0); + return FALSE; + } + + return TRUE; +} + +void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake ) +{ + U32 param_name[3]; + if( teToColorParams( te, param_name ) ) + { + setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake ); + setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake ); + setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake ); + } +} + +LLColor4 LLAvatarAppearance::getClothesColor( ETextureIndex te ) +{ + LLColor4 color; + U32 param_name[3]; + if( teToColorParams( te, param_name ) ) + { + color.mV[VX] = getVisualParamWeight( param_name[0] ); + color.mV[VY] = getVisualParamWeight( param_name[1] ); + color.mV[VZ] = getVisualParamWeight( param_name[2] ); + } + return color; +} + +// static +LLColor4 LLAvatarAppearance::getDummyColor() +{ + return DUMMY_COLOR; +} + +LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) const +{ + if (color_name=="skin_color" && mTexSkinColor) + { + return mTexSkinColor->getColor(); + } + else if(color_name=="hair_color" && mTexHairColor) + { + return mTexHairColor->getColor(); + } + if(color_name=="eye_color" && mTexEyeColor) + { + return mTexEyeColor->getColor(); + } + else + { +// return LLColor4( .5f, .5f, .5f, .5f ); + return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color + } +} + + + diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h new file mode 100644 index 0000000000..cb2ae7aeef --- /dev/null +++ b/indra/llappearance/llavatarappearance.h @@ -0,0 +1,128 @@ +/** + * @file llavatarappearance.h + * @brief Declaration of LLAvatarAppearance class + * + * $LicenseInfo:firstyear=2012&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_AVATAR_APPEARANCE_H +#define LL_AVATAR_APPEARANCE_H + +#include "llcharacter.h" +#include "llframetimer.h" +#include "llvoavatardefines.h" + +class LLTexGlobalColor; +class LLTexLayerSet; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLAvatarAppearance +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLAvatarAppearance : public LLCharacter +{ + LOG_CLASS(LLAvatarAppearance); + +public: + LLAvatarAppearance(); + + //-------------------------------------------------------------------- + // Clothing colors (convenience functions to access visual parameters) + //-------------------------------------------------------------------- +public: + void setClothesColor(LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); + LLColor4 getClothesColor(LLVOAvatarDefines::ETextureIndex te); + static BOOL teToColorParams(LLVOAvatarDefines::ETextureIndex te, U32 *param_name); + + //-------------------------------------------------------------------- + // Global colors + //-------------------------------------------------------------------- +public: + LLColor4 getGlobalColor(const std::string& color_name ) const; + virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0; +protected: + LLTexGlobalColor* mTexSkinColor; + LLTexGlobalColor* mTexHairColor; + LLTexGlobalColor* mTexEyeColor; + + //-------------------------------------------------------------------- + // Morph masks + //-------------------------------------------------------------------- +public: + virtual void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES) = 0; + + //-------------------------------------------------------------------- + // Composites + //-------------------------------------------------------------------- +public: + virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0; + +/******************************************************************************** + ** ** + ** MESHES + **/ + virtual void dirtyMesh() = 0; // Dirty the avatar mesh + virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority + +/******************************************************************************** + ** ** + ** RENDERING + **/ + BOOL mIsDummy; // for special views + +/******************************************************************************** + ** ** + ** STATE + **/ +public: + virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent + virtual BOOL isUsingBakedTextures() const = 0; + +/******************************************************************************** + ** ** + ** WEARABLES + **/ +public: + virtual U32 getWearableCount(const LLWearableType::EType type) const = 0; + virtual U32 getWearableCount(const U32 tex_index) const = 0; + + virtual LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) = 0; + virtual const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const = 0; + + virtual BOOL isWearingWearableType(LLWearableType::EType type ) const = 0; + + //-------------------------------------------------------------------- + // Avatar Rez Metrics + //-------------------------------------------------------------------- +public: + F32 debugGetExistenceTimeElapsedF32() const { return mDebugExistenceTimer.getElapsedTimeF32(); } + +protected: + LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory. + +public: + static LLColor4 getDummyColor(); + virtual void updateMeshTextures() = 0; +}; + +#endif // LL_AVATAR_APPEARANCE_H diff --git a/indra/llappearance/llinventoryicon.cpp b/indra/llappearance/llinventoryicon.cpp new file mode 100644 index 0000000000..62261058ef --- /dev/null +++ b/indra/llappearance/llinventoryicon.cpp @@ -0,0 +1,184 @@ +/** + * @file llinventoryicon.cpp + * @brief Implementation of the inventory icon. + * + * $LicenseInfo:firstyear=2001&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 "linden_common.h" +#include "llinventoryicon.h" + +#include "lldictionary.h" +#include "llinventorydefines.h" +#include "llui.h" +#include "llwearabletype.h" + +struct IconEntry : public LLDictionaryEntry +{ + IconEntry(const std::string &item_name) + : + LLDictionaryEntry(item_name) + {} +}; + +class LLIconDictionary : public LLSingleton, + public LLDictionary +{ +public: + LLIconDictionary(); +}; + +LLIconDictionary::LLIconDictionary() +{ + addEntry(LLInventoryIcon::ICONNAME_TEXTURE, new IconEntry("Inv_Texture")); + addEntry(LLInventoryIcon::ICONNAME_SOUND, new IconEntry("Inv_Sound")); + addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_ONLINE, new IconEntry("Inv_CallingCard")); + addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_OFFLINE, new IconEntry("Inv_CallingCard")); + addEntry(LLInventoryIcon::ICONNAME_LANDMARK, new IconEntry("Inv_Landmark")); + addEntry(LLInventoryIcon::ICONNAME_LANDMARK_VISITED, new IconEntry("Inv_Landmark")); + addEntry(LLInventoryIcon::ICONNAME_SCRIPT, new IconEntry("Inv_Script")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING, new IconEntry("Inv_Clothing")); + addEntry(LLInventoryIcon::ICONNAME_OBJECT, new IconEntry("Inv_Object")); + addEntry(LLInventoryIcon::ICONNAME_OBJECT_MULTI, new IconEntry("Inv_Object_Multi")); + addEntry(LLInventoryIcon::ICONNAME_NOTECARD, new IconEntry("Inv_Notecard")); + addEntry(LLInventoryIcon::ICONNAME_BODYPART, new IconEntry("Inv_Skin")); + addEntry(LLInventoryIcon::ICONNAME_SNAPSHOT, new IconEntry("Inv_Snapshot")); + + addEntry(LLInventoryIcon::ICONNAME_BODYPART_SHAPE, new IconEntry("Inv_BodyShape")); + addEntry(LLInventoryIcon::ICONNAME_BODYPART_SKIN, new IconEntry("Inv_Skin")); + addEntry(LLInventoryIcon::ICONNAME_BODYPART_HAIR, new IconEntry("Inv_Hair")); + addEntry(LLInventoryIcon::ICONNAME_BODYPART_EYES, new IconEntry("Inv_Eye")); + + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SHIRT, new IconEntry("Inv_Shirt")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_PANTS, new IconEntry("Inv_Pants")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SHOES, new IconEntry("Inv_Shoe")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SOCKS, new IconEntry("Inv_Socks")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_JACKET, new IconEntry("Inv_Jacket")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_GLOVES, new IconEntry("Inv_Gloves")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT, new IconEntry("Inv_Undershirt")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS, new IconEntry("Inv_Underpants")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SKIRT, new IconEntry("Inv_Skirt")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_ALPHA, new IconEntry("Inv_Alpha")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_TATTOO, new IconEntry("Inv_Tattoo")); + addEntry(LLInventoryIcon::ICONNAME_ANIMATION, new IconEntry("Inv_Animation")); + addEntry(LLInventoryIcon::ICONNAME_GESTURE, new IconEntry("Inv_Gesture")); + + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, new IconEntry("Inv_Physics")); + + addEntry(LLInventoryIcon::ICONNAME_LINKITEM, new IconEntry("Inv_LinkItem")); + addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, new IconEntry("Inv_LinkFolder")); + addEntry(LLInventoryIcon::ICONNAME_MESH, new IconEntry("Inv_Mesh")); + + addEntry(LLInventoryIcon::ICONNAME_INVALID, new IconEntry("Inv_Invalid")); + + addEntry(LLInventoryIcon::ICONNAME_NONE, new IconEntry("NONE")); +} + +LLUIImagePtr LLInventoryIcon::getIcon(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 misc_flag, + BOOL item_is_multi) +{ + const std::string& icon_name = getIconName(asset_type, inventory_type, misc_flag, item_is_multi); + return LLUI::getUIImage(icon_name); +} + +LLUIImagePtr LLInventoryIcon::getIcon(EIconName idx) +{ + return LLUI::getUIImage(getIconName(idx)); +} + +const std::string& LLInventoryIcon::getIconName(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 misc_flag, + BOOL item_is_multi) +{ + EIconName idx = ICONNAME_OBJECT; + if (item_is_multi) + { + idx = ICONNAME_OBJECT_MULTI; + return getIconName(idx); + } + + switch(asset_type) + { + case LLAssetType::AT_TEXTURE: + idx = (inventory_type == LLInventoryType::IT_SNAPSHOT) ? ICONNAME_SNAPSHOT : ICONNAME_TEXTURE; + break; + case LLAssetType::AT_SOUND: + idx = ICONNAME_SOUND; + break; + case LLAssetType::AT_CALLINGCARD: + idx = (misc_flag != 0) ? ICONNAME_CALLINGCARD_ONLINE : ICONNAME_CALLINGCARD_OFFLINE; + break; + case LLAssetType::AT_LANDMARK: + idx = (misc_flag != 0) ? ICONNAME_LANDMARK_VISITED : ICONNAME_LANDMARK; + break; + case LLAssetType::AT_SCRIPT: + case LLAssetType::AT_LSL_TEXT: + case LLAssetType::AT_LSL_BYTECODE: + idx = ICONNAME_SCRIPT; + break; + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + idx = assignWearableIcon(misc_flag); + break; + case LLAssetType::AT_NOTECARD: + idx = ICONNAME_NOTECARD; + break; + case LLAssetType::AT_ANIMATION: + idx = ICONNAME_ANIMATION; + break; + case LLAssetType::AT_GESTURE: + idx = ICONNAME_GESTURE; + break; + case LLAssetType::AT_LINK: + idx = ICONNAME_LINKITEM; + break; + case LLAssetType::AT_LINK_FOLDER: + idx = ICONNAME_LINKFOLDER; + break; + case LLAssetType::AT_OBJECT: + idx = ICONNAME_OBJECT; + break; + case LLAssetType::AT_MESH: + idx = ICONNAME_MESH; + default: + break; + } + + return getIconName(idx); +} + + +const std::string& LLInventoryIcon::getIconName(EIconName idx) +{ + const IconEntry *entry = LLIconDictionary::instance().lookup(idx); + return entry->mName; +} + +LLInventoryIcon::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag) +{ + const LLWearableType::EType wearable_type = LLWearableType::EType(LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK & misc_flag); + return LLWearableType::getIconName(wearable_type); +} diff --git a/indra/llappearance/llinventoryicon.h b/indra/llappearance/llinventoryicon.h new file mode 100644 index 0000000000..c7e2998a20 --- /dev/null +++ b/indra/llappearance/llinventoryicon.h @@ -0,0 +1,102 @@ +/** + * @file llinventoryfunctions.h + * @brief Miscellaneous inventory-related functions and classes + * class definition + * + * $LicenseInfo:firstyear=2001&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_LLINVENTORYICON_H +#define LL_LLINVENTORYICON_H + +#include "llassettype.h" +#include "llinventorytype.h" +#include "lluiimage.h" + +class LLInventoryIcon +{ +public: + enum EIconName + { + ICONNAME_TEXTURE, + ICONNAME_SOUND, + ICONNAME_CALLINGCARD_ONLINE, + ICONNAME_CALLINGCARD_OFFLINE, + ICONNAME_LANDMARK, + ICONNAME_LANDMARK_VISITED, + ICONNAME_SCRIPT, + ICONNAME_CLOTHING, + ICONNAME_OBJECT, + ICONNAME_OBJECT_MULTI, + ICONNAME_NOTECARD, + ICONNAME_BODYPART, + ICONNAME_SNAPSHOT, + + ICONNAME_BODYPART_SHAPE, + ICONNAME_BODYPART_SKIN, + ICONNAME_BODYPART_HAIR, + ICONNAME_BODYPART_EYES, + ICONNAME_CLOTHING_SHIRT, + ICONNAME_CLOTHING_PANTS, + ICONNAME_CLOTHING_SHOES, + ICONNAME_CLOTHING_SOCKS, + ICONNAME_CLOTHING_JACKET, + ICONNAME_CLOTHING_GLOVES, + ICONNAME_CLOTHING_UNDERSHIRT, + ICONNAME_CLOTHING_UNDERPANTS, + ICONNAME_CLOTHING_SKIRT, + ICONNAME_CLOTHING_ALPHA, + ICONNAME_CLOTHING_TATTOO, + + ICONNAME_ANIMATION, + ICONNAME_GESTURE, + + ICONNAME_CLOTHING_PHYSICS, + + ICONNAME_LINKITEM, + ICONNAME_LINKFOLDER, + ICONNAME_MESH, + + ICONNAME_INVALID, + ICONNAME_COUNT, + ICONNAME_NONE = -1 + }; + + static const std::string& getIconName(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type = LLInventoryType::IT_NONE, + U32 misc_flag = 0, // different meanings depending on item type + BOOL item_is_multi = FALSE); + static const std::string& getIconName(EIconName idx); + + static LLUIImagePtr getIcon(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type = LLInventoryType::IT_NONE, + U32 misc_flag = 0, // different meanings depending on item type + BOOL item_is_multi = FALSE); + static LLUIImagePtr getIcon(EIconName idx); + +protected: + static EIconName assignWearableIcon(U32 misc_flag); +}; +#endif // LL_LLINVENTORYICON_H + + + diff --git a/indra/llappearance/lljointpickname.h b/indra/llappearance/lljointpickname.h new file mode 100644 index 0000000000..17181520e3 --- /dev/null +++ b/indra/llappearance/lljointpickname.h @@ -0,0 +1,46 @@ +/** + * @file lljointpickname.h + * @brief Defines OpenGL seleciton stack names + * + * $LicenseInfo:firstyear=2001&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_LLJOINTPICKNAME_H +#define LL_LLJOINTPICKNAME_H + + +// Sets the OpenGL selection stack name that is pushed and popped +// with this joint state. The default value indicates that no name +// should be pushed/popped. +enum LLJointPickName +{ + PN_DEFAULT = -1, + PN_0 = 0, + PN_1 = 1, + PN_2 = 2, + PN_3 = 3, + PN_4 = 4, + PN_5 = 5 +}; + +#endif // LL_LLJOINTPICKNAME_H diff --git a/indra/llappearance/lllocaltextureobject.cpp b/indra/llappearance/lllocaltextureobject.cpp new file mode 100644 index 0000000000..0e77444f49 --- /dev/null +++ b/indra/llappearance/lllocaltextureobject.cpp @@ -0,0 +1,213 @@ +/** + * @file lllocaltextureobject.cpp + * + * $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 "linden_common.h" + +#include "lllocaltextureobject.h" + +#include "llimage.h" +#include "llrender.h" +#include "lltexlayer.h" +#include "lltexture.h" +#include "lluuid.h" +#include "llwearable.h" + + +LLLocalTextureObject::LLLocalTextureObject() : + mIsBakedReady(FALSE), + mDiscard(MAX_DISCARD_LEVEL+1) +{ + mImage = NULL; +} + +LLLocalTextureObject::LLLocalTextureObject(LLTexture* image, const LLUUID& id) : + mIsBakedReady(FALSE), + mDiscard(MAX_DISCARD_LEVEL+1) +{ + mImage = image; + gGL.getTexUnit(0)->bind(mImage); + mID = id; +} + +LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) : + mImage(lto.mImage), + mID(lto.mID), + mIsBakedReady(lto.mIsBakedReady), + mDiscard(lto.mDiscard) +{ + U32 num_layers = lto.getNumTexLayers(); + mTexLayers.reserve(num_layers); + for (U32 index = 0; index < num_layers; index++) + { + LLTexLayer* original_layer = lto.getTexLayer(index); + if (!original_layer) + { + llerrs << "could not clone Local Texture Object: unable to extract texlayer!" << llendl; + continue; + } + + LLTexLayer* new_layer = new LLTexLayer(*original_layer); + new_layer->setLTO(this); + mTexLayers.push_back(new_layer); + } +} + +LLLocalTextureObject::~LLLocalTextureObject() +{ +} + +LLTexture* LLLocalTextureObject::getImage() const +{ + return mImage; +} + +LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const +{ + if (index >= getNumTexLayers()) + { + return NULL; + } + + return mTexLayers[index]; +} + +LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name) +{ + for( tex_layer_vec_t::iterator iter = mTexLayers.begin(); iter != mTexLayers.end(); iter++) + { + LLTexLayer *layer = *iter; + if (layer->getName().compare(name) == 0) + { + return layer; + } + } + + return NULL; +} + +U32 LLLocalTextureObject::getNumTexLayers() const +{ + return mTexLayers.size(); +} + +LLUUID LLLocalTextureObject::getID() const +{ + return mID; +} + +S32 LLLocalTextureObject::getDiscard() const +{ + return mDiscard; +} + +BOOL LLLocalTextureObject::getBakedReady() const +{ + return mIsBakedReady; +} + +void LLLocalTextureObject::setImage(LLTexture* new_image) +{ + mImage = new_image; +} + +BOOL LLLocalTextureObject::setTexLayer(LLTexLayer *new_tex_layer, U32 index) +{ + if (index >= getNumTexLayers() ) + { + return FALSE; + } + + if (new_tex_layer == NULL) + { + return removeTexLayer(index); + } + + LLTexLayer *layer = new LLTexLayer(*new_tex_layer); + layer->setLTO(this); + + if (mTexLayers[index]) + { + delete mTexLayers[index]; + } + mTexLayers[index] = layer; + + return TRUE; +} + +BOOL LLLocalTextureObject::addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable) +{ + if (new_tex_layer == NULL) + { + return FALSE; + } + + LLTexLayer *layer = new LLTexLayer(*new_tex_layer, wearable); + layer->setLTO(this); + mTexLayers.push_back(layer); + return TRUE; +} + +BOOL LLLocalTextureObject::addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable) +{ + if (new_tex_layer == NULL) + { + return FALSE; + } + + LLTexLayer *layer = new LLTexLayer(*new_tex_layer, this, wearable); + layer->setLTO(this); + mTexLayers.push_back(layer); + return TRUE; +} + +BOOL LLLocalTextureObject::removeTexLayer(U32 index) +{ + if (index >= getNumTexLayers()) + { + return FALSE; + } + tex_layer_vec_t::iterator iter = mTexLayers.begin(); + iter += index; + + delete *iter; + mTexLayers.erase(iter); + return TRUE; +} + +void LLLocalTextureObject::setID(LLUUID new_id) +{ + mID = new_id; +} + +void LLLocalTextureObject::setDiscard(S32 new_discard) +{ + mDiscard = new_discard; +} + +void LLLocalTextureObject::setBakedReady(BOOL ready) +{ + mIsBakedReady = ready; +} + diff --git a/indra/llappearance/lllocaltextureobject.h b/indra/llappearance/lllocaltextureobject.h new file mode 100644 index 0000000000..8f868eb412 --- /dev/null +++ b/indra/llappearance/lllocaltextureobject.h @@ -0,0 +1,87 @@ +/** + * @file lllocaltextureobject.h + * @brief LLLocalTextureObject class header file + * + * $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_LOCALTEXTUREOBJECT_H +#define LL_LOCALTEXTUREOBJECT_H + +#include + +#include "llpointer.h" +#include "lltexture.h" + +class LLUUID; +class LLTexLayer; +class LLTexLayerTemplate; +class LLWearable; + +// Stores all relevant information for a single texture +// assumed to have ownership of all objects referred to - +// will delete objects when being replaced or if object is destroyed. +class LLLocalTextureObject +{ +public: + LLLocalTextureObject(); + LLLocalTextureObject(LLTexture* image, const LLUUID& id); + LLLocalTextureObject(const LLLocalTextureObject& lto); + ~LLLocalTextureObject(); + + LLTexture* getImage() const; + LLTexLayer* getTexLayer(U32 index) const; + LLTexLayer* getTexLayer(const std::string &name); + U32 getNumTexLayers() const; + LLUUID getID() const; + S32 getDiscard() const; + BOOL getBakedReady() const; + + void setImage(LLTexture* new_image); + BOOL setTexLayer(LLTexLayer *new_tex_layer, U32 index); + BOOL addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable); + BOOL addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable); + BOOL removeTexLayer(U32 index); + + void setID(LLUUID new_id); + void setDiscard(S32 new_discard); + void setBakedReady(BOOL ready); + +protected: + +private: + + LLPointer mImage; + // NOTE: LLLocalTextureObject should be the exclusive owner of mTexEntry and mTexLayer + // using shared pointers here only for smart assignment & cleanup + // do NOT create new shared pointers to these objects, or keep pointers to them around + typedef std::vector tex_layer_vec_t; + tex_layer_vec_t mTexLayers; + + LLUUID mID; + + BOOL mIsBakedReady; + S32 mDiscard; +}; + + #endif // LL_LOCALTEXTUREOBJECT_H + diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp new file mode 100644 index 0000000000..d9c6150fc6 --- /dev/null +++ b/indra/llappearance/lltexglobalcolor.cpp @@ -0,0 +1,154 @@ +/** + * @file lltexlayerglobalcolor.cpp + * @brief Color for texture layers. + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llavatarappearance.h" +#include "lltexlayer.h" +//#include "llwearable.h" +#include "lltexglobalcolor.h" + +class LLWearable; + +//----------------------------------------------------------------------------- +// LLTexGlobalColor +//----------------------------------------------------------------------------- + +LLTexGlobalColor::LLTexGlobalColor(LLAvatarAppearance* appearance) + : + mAvatarAppearance(appearance), + mInfo(NULL) +{ +} + +LLTexGlobalColor::~LLTexGlobalColor() +{ + // mParamColorList are LLViewerVisualParam's and get deleted with ~LLCharacter() + //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer()); +} + +BOOL LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info) +{ + llassert(mInfo == NULL); + mInfo = info; + //mID = info->mID; // No ID + + mParamGlobalColorList.reserve(mInfo->mParamColorInfoList.size()); + for (param_color_info_list_t::iterator iter = mInfo->mParamColorInfoList.begin(); + iter != mInfo->mParamColorInfoList.end(); + iter++) + { + LLTexParamGlobalColor* param_color = new LLTexParamGlobalColor(this); + if (!param_color->setInfo(*iter, TRUE)) + { + mInfo = NULL; + return FALSE; + } + mParamGlobalColorList.push_back(param_color); + } + + return TRUE; +} + +LLColor4 LLTexGlobalColor::getColor() const +{ + // Sum of color params + if (mParamGlobalColorList.empty()) + return LLColor4(1.f, 1.f, 1.f, 1.f); + + LLColor4 net_color(0.f, 0.f, 0.f, 0.f); + LLTexLayer::calculateTexLayerColor(mParamGlobalColorList, net_color); + return net_color; +} + +const std::string& LLTexGlobalColor::getName() const +{ + return mInfo->mName; +} + +//----------------------------------------------------------------------------- +// LLTexParamGlobalColor +//----------------------------------------------------------------------------- +LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) : + LLTexLayerParamColor(tex_global_color->getAvatarAppearance()), + mTexGlobalColor(tex_global_color) +{ +} + +/*virtual*/ LLViewerVisualParam* LLTexParamGlobalColor::cloneParam(LLWearable* wearable) const +{ + LLTexParamGlobalColor *new_param = new LLTexParamGlobalColor(mTexGlobalColor); + *new_param = *this; + return new_param; +} + +void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake) +{ + mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake); +} + +//----------------------------------------------------------------------------- +// LLTexGlobalColorInfo +//----------------------------------------------------------------------------- + +LLTexGlobalColorInfo::LLTexGlobalColorInfo() +{ +} + + +LLTexGlobalColorInfo::~LLTexGlobalColorInfo() +{ + for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer()); +} + +BOOL LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node) +{ + // name attribute + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!node->getFastAttributeString(name_string, mName)) + { + llwarns << " element is missing name attribute." << llendl; + return FALSE; + } + // sub-element + for (LLXmlTreeNode* child = node->getChildByName("param"); + child; + child = node->getNextNamedChild()) + { + if (child->getChildByName("param_color")) + { + // + LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo(); + if (!info->parseXml(child)) + { + delete info; + return FALSE; + } + mParamColorInfoList.push_back(info); + } + } + return TRUE; +} diff --git a/indra/llappearance/lltexglobalcolor.h b/indra/llappearance/lltexglobalcolor.h new file mode 100644 index 0000000000..2867479876 --- /dev/null +++ b/indra/llappearance/lltexglobalcolor.h @@ -0,0 +1,83 @@ +/** + * @file lltexglobalcolor.h + * @brief This is global texture color info used by llavatarappearance. + * + * $LicenseInfo:firstyear=2008&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_LLTEXGLOBALCOLOR_H +#define LL_LLTEXGLOBALCOLOR_H + +#include "lltexlayer.h" +#include "lltexlayerparams.h" + +class LLAvatarAppearance; +class LLWearable; +class LLTexGlobalColorInfo; + +class LLTexGlobalColor +{ +public: + LLTexGlobalColor( LLAvatarAppearance* appearance ); + ~LLTexGlobalColor(); + + LLTexGlobalColorInfo* getInfo() const { return mInfo; } + // This sets mInfo and calls initialization functions + BOOL setInfo(LLTexGlobalColorInfo *info); + + LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } + LLColor4 getColor() const; + const std::string& getName() const; + +private: + param_color_list_t mParamGlobalColorList; + LLAvatarAppearance* mAvatarAppearance; // just backlink, don't LLPointer + LLTexGlobalColorInfo *mInfo; +}; + +// Used by llavatarappearance to determine skin/eye/hair color. +class LLTexGlobalColorInfo +{ + friend class LLTexGlobalColor; +public: + LLTexGlobalColorInfo(); + ~LLTexGlobalColorInfo(); + + BOOL parseXml(LLXmlTreeNode* node); + +private: + param_color_info_list_t mParamColorInfoList; + std::string mName; +}; + +class LLTexParamGlobalColor : public LLTexLayerParamColor +{ +public: + LLTexParamGlobalColor(LLTexGlobalColor *tex_color); + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; +protected: + /*virtual*/ void onGlobalColorChanged(bool upload_bake); +private: + LLTexGlobalColor* mTexGlobalColor; +}; + +#endif diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp new file mode 100644 index 0000000000..3bb31d3721 --- /dev/null +++ b/indra/llappearance/lltexlayer.cpp @@ -0,0 +1,1778 @@ +/** + * @file lltexlayer.cpp + * @brief A texture layer. Used for avatars. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltexlayer.h" + +#include "llavatarappearance.h" +#include "llcrc.h" +#include "imageids.h" +#include "llimagej2c.h" +#include "llimagetga.h" +//#include "llnotificationsutil.h" +#include "lldir.h" +#include "llvfile.h" +#include "llvfs.h" +//#include "llviewerstats.h" +//#include "llviewerregion.h" +//#include "pipeline.h" +#include "lltexlayerparams.h" +#include "lltexturemanagerbridge.h" +#include "llui.h" +//#include "llagentwearables.h" +#include "llwearable.h" +//#include "llviewercontrol.h" +//#include "llviewershadermgr.h" +#include "llviewervisualparam.h" + +//#include "../tools/imdebug/imdebug.h" + +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; + friend class LLTexLayerTemplate; + friend class LLTexLayerInterface; +public: + LLTexLayerInfo(); + ~LLTexLayerInfo(); + + BOOL parseXml(LLXmlTreeNode* node); + BOOL createVisualParams(LLAvatarAppearance *appearance); + BOOL isUserSettable() { return mLocalTexture != -1; } + S32 getLocalTexture() const { return mLocalTexture; } + BOOL getOnlyAlpha() const { return mUseLocalTextureAlphaOnly; } + std::string getName() const { return mName; } + +private: + std::string mName; + + BOOL mWriteAllChannels; // Don't use masking. Just write RGBA into buffer, + LLTexLayerInterface::ERenderPass mRenderPass; + + std::string mGlobalColor; + LLColor4 mFixedColor; + + S32 mLocalTexture; + std::string mStaticImageFileName; + BOOL mStaticImageIsMask; + BOOL mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask + BOOL mIsVisibilityMask; + + typedef std::vector< std::pair< std::string,BOOL > > morph_name_list_t; + morph_name_list_t mMorphNameList; + param_color_info_list_t mParamColorInfoList; + param_alpha_info_list_t mParamAlphaInfoList; +}; + + +//----------------------------------------------------------------------------- +// LLTexLayerSetInfo +// An ordered set of texture layers that get composited into a single texture. +//----------------------------------------------------------------------------- + +LLTexLayerSetInfo::LLTexLayerSetInfo() : + mBodyRegion( "" ), + mWidth( 512 ), + mHeight( 512 ), + mClearAlpha( TRUE ) +{ +} + +LLTexLayerSetInfo::~LLTexLayerSetInfo( ) +{ + std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer()); +} + +BOOL LLTexLayerSetInfo::parseXml(LLXmlTreeNode* node) +{ + llassert( node->hasName( "layer_set" ) ); + if( !node->hasName( "layer_set" ) ) + { + return FALSE; + } + + // body_region + static LLStdStringHandle body_region_string = LLXmlTree::addAttributeString("body_region"); + if( !node->getFastAttributeString( body_region_string, mBodyRegion ) ) + { + llwarns << " is missing body_region attribute" << llendl; + return FALSE; + } + + // width, height + static LLStdStringHandle width_string = LLXmlTree::addAttributeString("width"); + if( !node->getFastAttributeS32( width_string, mWidth ) ) + { + return FALSE; + } + + static LLStdStringHandle height_string = LLXmlTree::addAttributeString("height"); + if( !node->getFastAttributeS32( height_string, mHeight ) ) + { + return FALSE; + } + + // Optional alpha component to apply after all compositing is complete. + static LLStdStringHandle alpha_tga_file_string = LLXmlTree::addAttributeString("alpha_tga_file"); + node->getFastAttributeString( alpha_tga_file_string, mStaticAlphaFileName ); + + static LLStdStringHandle clear_alpha_string = LLXmlTree::addAttributeString("clear_alpha"); + node->getFastAttributeBOOL( clear_alpha_string, mClearAlpha ); + + // + for (LLXmlTreeNode* child = node->getChildByName( "layer" ); + child; + child = node->getNextNamedChild()) + { + LLTexLayerInfo* info = new LLTexLayerInfo(); + if( !info->parseXml( child )) + { + delete info; + return FALSE; + } + mLayerInfoList.push_back( info ); + } + return TRUE; +} + +// creates visual params without generating layersets or layers +void LLTexLayerSetInfo::createVisualParams(LLAvatarAppearance *appearance) +{ + //layer_info_list_t mLayerInfoList; + for (layer_info_list_t::iterator layer_iter = mLayerInfoList.begin(); + layer_iter != mLayerInfoList.end(); + layer_iter++) + { + LLTexLayerInfo *layer_info = *layer_iter; + layer_info->createVisualParams(appearance); + } +} + +//----------------------------------------------------------------------------- +// LLTexLayerSet +// An ordered set of texture layers that get composited into a single texture. +//----------------------------------------------------------------------------- + +BOOL LLTexLayerSet::sHasCaches = FALSE; + +LLTexLayerSet::LLTexLayerSet(LLAvatarAppearance* const appearance) : + mAvatarAppearance( appearance ), + mIsVisible( TRUE ), + mBakedTexIndex(LLVOAvatarDefines::BAKED_HEAD), + mInfo( NULL ) +{ +} + +// virtual +LLTexLayerSet::~LLTexLayerSet() +{ + deleteCaches(); + std::for_each(mLayerList.begin(), mLayerList.end(), DeletePointer()); + std::for_each(mMaskLayerList.begin(), mMaskLayerList.end(), DeletePointer()); +} + +//----------------------------------------------------------------------------- +// setInfo +//----------------------------------------------------------------------------- + +BOOL LLTexLayerSet::setInfo(const LLTexLayerSetInfo *info) +{ + llassert(mInfo == NULL); + mInfo = info; + //mID = info->mID; // No ID + + mLayerList.reserve(info->mLayerInfoList.size()); + for (LLTexLayerSetInfo::layer_info_list_t::const_iterator iter = info->mLayerInfoList.begin(); + iter != info->mLayerInfoList.end(); + iter++) + { + LLTexLayerInterface *layer = NULL; + if ( (*iter)->isUserSettable() ) + { + layer = new LLTexLayerTemplate( this, getAvatarAppearance() ); + } + else + { + layer = new LLTexLayer(this); + } + // this is the first time this layer (of either type) is being created - make sure you add the parameters to the avatar appearance + if (!layer->setInfo(*iter, NULL)) + { + mInfo = NULL; + return FALSE; + } + if (!layer->isVisibilityMask()) + { + mLayerList.push_back( layer ); + } + else + { + mMaskLayerList.push_back(layer); + } + } + + requestUpdate(); + + stop_glerror(); + + return TRUE; +} + +#if 0 // obsolete +//----------------------------------------------------------------------------- +// parseData +//----------------------------------------------------------------------------- + +BOOL LLTexLayerSet::parseData(LLXmlTreeNode* node) +{ + LLTexLayerSetInfo *info = new LLTexLayerSetInfo; + + if (!info->parseXml(node)) + { + delete info; + return FALSE; + } + if (!setInfo(info)) + { + delete info; + return FALSE; + } + return TRUE; +} +#endif + +void LLTexLayerSet::deleteCaches() +{ + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + layer->deleteCaches(); + } + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + { + LLTexLayerInterface* layer = *iter; + layer->deleteCaches(); + } +} + + +BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) +{ + BOOL success = TRUE; + mIsVisible = TRUE; + + if (mMaskLayerList.size() > 0) + { + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + { + LLTexLayerInterface* layer = *iter; + if (layer->isInvisibleAlphaMask()) + { + mIsVisible = FALSE; + } + } + } + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + LLGLSUIDefault gls_ui; + LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE); + gGL.setColorMask(true, true); + + // clear buffer area to ensure we don't pick up UI elements + { + gGL.flush(); + LLGLDisable no_alpha(GL_ALPHA_TEST); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.0f); + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4f( 0.f, 0.f, 0.f, 1.f ); + + gl_rect_2d_simple( width, height ); + + gGL.flush(); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + } + + if (mIsVisible) + { + // composite color layers + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + if (layer->getRenderPass() == LLTexLayer::RP_COLOR) + { + gGL.flush(); + success &= layer->render(x, y, width, height); + gGL.flush(); + } + } + + renderAlphaMaskTextures(x, y, width, height, false); + + stop_glerror(); + } + else + { + gGL.flush(); + + gGL.setSceneBlendType(LLRender::BT_REPLACE); + LLGLDisable no_alpha(GL_ALPHA_TEST); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4f( 0.f, 0.f, 0.f, 0.f ); + + gl_rect_2d_simple( width, height ); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + gGL.flush(); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + } + + return success; +} + + +BOOL LLTexLayerSet::isBodyRegion(const std::string& region) const +{ + return mInfo->mBodyRegion == region; +} + +const std::string LLTexLayerSet::getBodyRegionName() const +{ + return mInfo->mBodyRegion; +} + + +void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear) +{ + const LLTexLayerSetInfo *info = getInfo(); + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + gGL.setColorMask(false, true); + gGL.setSceneBlendType(LLRender::BT_REPLACE); + + // (Optionally) replace alpha with a single component image from a tga file. + if (!info->mStaticAlphaFileName.empty()) + { + gGL.flush(); + { + LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(info->mStaticAlphaFileName, TRUE); + if( tex ) + { + LLGLSUIDefault gls_ui; + gGL.getTexUnit(0)->bind(tex); + gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); + gl_rect_2d_simple_tex( width, height ); + } + } + gGL.flush(); + } + else if (forceClear || info->mClearAlpha || (mMaskLayerList.size() > 0)) + { + // Set the alpha channel to one (clean up after previous blending) + gGL.flush(); + LLGLDisable no_alpha(GL_ALPHA_TEST); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4f( 0.f, 0.f, 0.f, 1.f ); + + gl_rect_2d_simple( width, height ); + + gGL.flush(); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + } + + // (Optional) Mask out part of the baked texture with alpha masks + // will still have an effect even if mClearAlpha is set or the alpha component was replaced + if (mMaskLayerList.size() > 0) + { + gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA); + gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + { + LLTexLayerInterface* layer = *iter; + gGL.flush(); + layer->blendAlphaTexture(x,y,width, height); + gGL.flush(); + } + + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + gGL.setColorMask(true, true); + gGL.setSceneBlendType(LLRender::BT_ALPHA); +} + +void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components) +{ + mAvatarAppearance->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex); +} + +BOOL LLTexLayerSet::isMorphValid() const +{ + for(layer_list_t::const_iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + const LLTexLayerInterface* layer = *iter; + if (layer && !layer->isMorphValid()) + { + return FALSE; + } + } + return TRUE; +} + +void LLTexLayerSet::invalidateMorphMasks() +{ + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + if (layer) + { + layer->invalidateMorphMasks(); + } + } +} + + +//----------------------------------------------------------------------------- +// LLTexLayerInfo +//----------------------------------------------------------------------------- +LLTexLayerInfo::LLTexLayerInfo() : + mWriteAllChannels( FALSE ), + mRenderPass(LLTexLayer::RP_COLOR), + mFixedColor( 0.f, 0.f, 0.f, 0.f ), + mLocalTexture( -1 ), + mStaticImageIsMask( FALSE ), + mUseLocalTextureAlphaOnly(FALSE), + mIsVisibilityMask(FALSE) +{ +} + +LLTexLayerInfo::~LLTexLayerInfo( ) +{ + std::for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer()); + std::for_each(mParamAlphaInfoList.begin(), mParamAlphaInfoList.end(), DeletePointer()); +} + +BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) +{ + llassert( node->hasName( "layer" ) ); + + // name attribute + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if( !node->getFastAttributeString( name_string, mName ) ) + { + return FALSE; + } + + static LLStdStringHandle write_all_channels_string = LLXmlTree::addAttributeString("write_all_channels"); + node->getFastAttributeBOOL( write_all_channels_string, mWriteAllChannels ); + + std::string render_pass_name; + static LLStdStringHandle render_pass_string = LLXmlTree::addAttributeString("render_pass"); + if( node->getFastAttributeString( render_pass_string, render_pass_name ) ) + { + if( render_pass_name == "bump" ) + { + mRenderPass = LLTexLayer::RP_BUMP; + } + } + + // Note: layers can have either a "global_color" attrib, a "fixed_color" attrib, or a child. + // global color attribute (optional) + static LLStdStringHandle global_color_string = LLXmlTree::addAttributeString("global_color"); + node->getFastAttributeString( global_color_string, mGlobalColor ); + + // Visibility mask (optional) + BOOL is_visibility; + static LLStdStringHandle visibility_mask_string = LLXmlTree::addAttributeString("visibility_mask"); + if (node->getFastAttributeBOOL(visibility_mask_string, is_visibility)) + { + mIsVisibilityMask = is_visibility; + } + + // color attribute (optional) + LLColor4U color4u; + static LLStdStringHandle fixed_color_string = LLXmlTree::addAttributeString("fixed_color"); + if( node->getFastAttributeColor4U( fixed_color_string, color4u ) ) + { + mFixedColor.setVec( color4u ); + } + + // optional sub-element + for (LLXmlTreeNode* texture_node = node->getChildByName( "texture" ); + texture_node; + texture_node = node->getNextNamedChild()) + { + std::string local_texture_name; + static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file"); + static LLStdStringHandle local_texture_string = LLXmlTree::addAttributeString("local_texture"); + static LLStdStringHandle file_is_mask_string = LLXmlTree::addAttributeString("file_is_mask"); + static LLStdStringHandle local_texture_alpha_only_string = LLXmlTree::addAttributeString("local_texture_alpha_only"); + if( texture_node->getFastAttributeString( tga_file_string, mStaticImageFileName ) ) + { + texture_node->getFastAttributeBOOL( file_is_mask_string, mStaticImageIsMask ); + } + else if (texture_node->getFastAttributeString(local_texture_string, local_texture_name)) + { + texture_node->getFastAttributeBOOL( local_texture_alpha_only_string, mUseLocalTextureAlphaOnly ); + + /* if ("upper_shirt" == local_texture_name) + mLocalTexture = TEX_UPPER_SHIRT; */ + mLocalTexture = TEX_NUM_INDICES; + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + iter++) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (local_texture_name == texture_dict->mName) + { + mLocalTexture = iter->first; + break; + } + } + if (mLocalTexture == TEX_NUM_INDICES) + { + llwarns << " element has invalid local_texture attribute: " << mName << " " << local_texture_name << llendl; + return FALSE; + } + } + else + { + llwarns << " element is missing a required attribute. " << mName << llendl; + return FALSE; + } + } + + for (LLXmlTreeNode* maskNode = node->getChildByName( "morph_mask" ); + maskNode; + maskNode = node->getNextNamedChild()) + { + std::string morph_name; + static LLStdStringHandle morph_name_string = LLXmlTree::addAttributeString("morph_name"); + if (maskNode->getFastAttributeString(morph_name_string, morph_name)) + { + BOOL invert = FALSE; + static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert"); + maskNode->getFastAttributeBOOL(invert_string, invert); + mMorphNameList.push_back(std::pair(morph_name,invert)); + } + } + + // optional sub-element (color or alpha params) + for (LLXmlTreeNode* child = node->getChildByName( "param" ); + child; + child = node->getNextNamedChild()) + { + if( child->getChildByName( "param_color" ) ) + { + // + LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo(); + if (!info->parseXml(child)) + { + delete info; + return FALSE; + } + mParamColorInfoList.push_back(info); + } + else if( child->getChildByName( "param_alpha" ) ) + { + // + LLTexLayerParamAlphaInfo* info = new LLTexLayerParamAlphaInfo( ); + if (!info->parseXml(child)) + { + delete info; + return FALSE; + } + mParamAlphaInfoList.push_back(info); + } + } + + return TRUE; +} + +BOOL LLTexLayerInfo::createVisualParams(LLAvatarAppearance *appearance) +{ + BOOL success = TRUE; + for (param_color_info_list_t::iterator color_info_iter = mParamColorInfoList.begin(); + color_info_iter != mParamColorInfoList.end(); + color_info_iter++) + { + LLTexLayerParamColorInfo * color_info = *color_info_iter; + LLTexLayerParamColor* param_color = new LLTexLayerParamColor(appearance); + if (!param_color->setInfo(color_info, TRUE)) + { + llwarns << "NULL TexLayer Color Param could not be added to visual param list. Deleting." << llendl; + delete param_color; + success = FALSE; + } + } + + for (param_alpha_info_list_t::iterator alpha_info_iter = mParamAlphaInfoList.begin(); + alpha_info_iter != mParamAlphaInfoList.end(); + alpha_info_iter++) + { + LLTexLayerParamAlphaInfo * alpha_info = *alpha_info_iter; + LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha(appearance); + if (!param_alpha->setInfo(alpha_info, TRUE)) + { + llwarns << "NULL TexLayer Alpha Param could not be added to visual param list. Deleting." << llendl; + delete param_alpha; + success = FALSE; + } + } + + return success; +} + +LLTexLayerInterface::LLTexLayerInterface(LLTexLayerSet* const layer_set): + mTexLayerSet( layer_set ), + mMorphMasksValid( FALSE ), + mInfo(NULL), + mHasMorph(FALSE) +{ +} + +LLTexLayerInterface::LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable): + mTexLayerSet( layer.mTexLayerSet ), + mInfo(NULL) +{ + // don't add visual params for cloned layers + setInfo(layer.getInfo(), wearable); + + mHasMorph = layer.mHasMorph; +} + +BOOL LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearable ) // This sets mInfo and calls initialization functions +{ + // setInfo should only be called once. Code is not robust enough to handle redefinition of a texlayer. + // Not a critical warning, but could be useful for debugging later issues. -Nyx + if (mInfo != NULL) + { + llwarns << "mInfo != NULL" << llendl; + } + mInfo = info; + //mID = info->mID; // No ID + + mParamColorList.reserve(mInfo->mParamColorInfoList.size()); + for (param_color_info_list_t::const_iterator iter = mInfo->mParamColorInfoList.begin(); + iter != mInfo->mParamColorInfoList.end(); + iter++) + { + LLTexLayerParamColor* param_color; + if (!wearable) + { + param_color = new LLTexLayerParamColor(this); + if (!param_color->setInfo(*iter, TRUE)) + { + mInfo = NULL; + return FALSE; + } + } + else + { + param_color = (LLTexLayerParamColor*)wearable->getVisualParam((*iter)->getID()); + if (!param_color) + { + mInfo = NULL; + return FALSE; + } + } + mParamColorList.push_back( param_color ); + } + + mParamAlphaList.reserve(mInfo->mParamAlphaInfoList.size()); + for (param_alpha_info_list_t::const_iterator iter = mInfo->mParamAlphaInfoList.begin(); + iter != mInfo->mParamAlphaInfoList.end(); + iter++) + { + LLTexLayerParamAlpha* param_alpha; + if (!wearable) + { + param_alpha = new LLTexLayerParamAlpha( this ); + if (!param_alpha->setInfo(*iter, TRUE)) + { + mInfo = NULL; + return FALSE; + } + } + else + { + param_alpha = (LLTexLayerParamAlpha*) wearable->getVisualParam((*iter)->getID()); + if (!param_alpha) + { + mInfo = NULL; + return FALSE; + } + } + mParamAlphaList.push_back( param_alpha ); + } + + return TRUE; +} + +/*virtual*/ void LLTexLayerInterface::requestUpdate() +{ + mTexLayerSet->requestUpdate(); +} + +const std::string& LLTexLayerInterface::getName() const +{ + return mInfo->mName; +} + +LLTexLayerInterface::ERenderPass LLTexLayerInterface::getRenderPass() const +{ + return mInfo->mRenderPass; +} + +const std::string& LLTexLayerInterface::getGlobalColor() const +{ + return mInfo->mGlobalColor; +} + +BOOL LLTexLayerInterface::isVisibilityMask() const +{ + return mInfo->mIsVisibilityMask; +} + +void LLTexLayerInterface::invalidateMorphMasks() +{ + mMorphMasksValid = FALSE; +} + +LLViewerVisualParam* LLTexLayerInterface::getVisualParamPtr(S32 index) const +{ + LLViewerVisualParam *result = NULL; + for (param_color_list_t::const_iterator color_iter = mParamColorList.begin(); color_iter != mParamColorList.end() && !result; ++color_iter) + { + if ((*color_iter)->getID() == index) + { + result = *color_iter; + } + } + for (param_alpha_list_t::const_iterator alpha_iter = mParamAlphaList.begin(); alpha_iter != mParamAlphaList.end() && !result; ++alpha_iter) + { + if ((*alpha_iter)->getID() == index) + { + result = *alpha_iter; + } + } + + return result; +} + +//----------------------------------------------------------------------------- +// LLTexLayer +// A single texture layer, consisting of: +// * color, consisting of either +// * one or more color parameters (weighted colors) +// * a reference to a global color +// * a fixed color with non-zero alpha +// * opaque white (the default) +// * (optional) a texture defined by either +// * a GUID +// * a texture entry index (TE) +// * (optional) one or more alpha parameters (weighted alpha textures) +//----------------------------------------------------------------------------- +LLTexLayer::LLTexLayer(LLTexLayerSet* const layer_set) : + LLTexLayerInterface( layer_set ), + mLocalTextureObject(NULL) +{ +} + +LLTexLayer::LLTexLayer(const LLTexLayer &layer, LLWearable *wearable) : + LLTexLayerInterface( layer, wearable ), + mLocalTextureObject(NULL) +{ +} + +LLTexLayer::LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable) : + LLTexLayerInterface( layer_template, wearable ), + mLocalTextureObject(lto) +{ +} + +LLTexLayer::~LLTexLayer() +{ + // mParamAlphaList and mParamColorList are LLViewerVisualParam's and get + // deleted with ~LLCharacter() + //std::for_each(mParamAlphaList.begin(), mParamAlphaList.end(), DeletePointer()); + //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer()); + + for( alpha_cache_t::iterator iter = mAlphaCache.begin(); + iter != mAlphaCache.end(); iter++ ) + { + U8* alpha_data = iter->second; + delete [] alpha_data; + } + +} + +//----------------------------------------------------------------------------- +// setInfo +//----------------------------------------------------------------------------- + +BOOL LLTexLayer::setInfo(const LLTexLayerInfo* info, LLWearable* wearable ) +{ + return LLTexLayerInterface::setInfo(info, wearable); +} + +//static +void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color) +{ + for (param_color_list_t::const_iterator iter = param_list.begin(); + iter != param_list.end(); iter++) + { + const LLTexLayerParamColor* param = *iter; + LLColor4 param_net = param->getNetColor(); + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)param->getInfo(); + switch(info->getOperation()) + { + case LLTexLayerParamColor::OP_ADD: + net_color += param_net; + break; + case LLTexLayerParamColor::OP_MULTIPLY: + net_color = net_color * param_net; + break; + case LLTexLayerParamColor::OP_BLEND: + net_color = lerp(net_color, param_net, param->getWeight()); + break; + default: + llassert(0); + break; + } + } + net_color.clamp(); +} + +/*virtual*/ void LLTexLayer::deleteCaches() +{ + // Only need to delete caches for alpha params. Color params don't hold extra memory + for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); + iter != mParamAlphaList.end(); iter++ ) + { + LLTexLayerParamAlpha* param = *iter; + param->deleteCaches(); + } +} + +BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) +{ + LLGLEnable color_mat(GL_COLOR_MATERIAL); + // *TODO: Is this correct? + //gPipeline.disableLights(); + stop_glerror(); + glDisable(GL_LIGHTING); + stop_glerror(); + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + LLColor4 net_color; + BOOL color_specified = findNetColor(&net_color); + + if (mTexLayerSet->getAvatarAppearance()->mIsDummy) + { + color_specified = true; + net_color = LLAvatarAppearance::getDummyColor(); + } + + BOOL success = TRUE; + + // If you can't see the layer, don't render it. + if( is_approx_zero( net_color.mV[VW] ) ) + { + return success; + } + + BOOL alpha_mask_specified = FALSE; + param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); + if( iter != mParamAlphaList.end() ) + { + // If we have alpha masks, but we're skipping all of them, skip the whole layer. + // However, we can't do this optimization if we have morph masks that need updating. +/* if (!mHasMorph) + { + BOOL skip_layer = TRUE; + + while( iter != mParamAlphaList.end() ) + { + const LLTexLayerParamAlpha* param = *iter; + + if( !param->getSkip() ) + { + skip_layer = FALSE; + break; + } + + iter++; + } + + if( skip_layer ) + { + return success; + } + }//*/ + + renderMorphMasks(x, y, width, height, net_color); + alpha_mask_specified = TRUE; + gGL.flush(); + gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ONE_MINUS_DEST_ALPHA); + } + + gGL.color4fv( net_color.mV); + + if( getInfo()->mWriteAllChannels ) + { + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_REPLACE); + } + + if( (getInfo()->mLocalTexture != -1) && !getInfo()->mUseLocalTextureAlphaOnly ) + { + { + LLTexture* tex = NULL; + if (mLocalTextureObject && mLocalTextureObject->getImage()) + { + tex = mLocalTextureObject->getImage(); + if (mLocalTextureObject->getID() == IMG_DEFAULT_AVATAR) + { + tex = NULL; + } + } + else + { + llinfos << "lto not defined or image not defined: " << getInfo()->getLocalTexture() << " lto: " << mLocalTextureObject << llendl; + } +// if( mTexLayerSet->getAvatarAppearance()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &image_gl ) ) + { + if( tex ) + { + bool no_alpha_test = getInfo()->mWriteAllChannels; + LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0); + if (use_shaders && no_alpha_test) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + + LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); + + gGL.getTexUnit(0)->bind(tex, TRUE); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + + gl_rect_2d_simple_tex( width, height ); + + gGL.getTexUnit(0)->setTextureAddressMode(old_mode); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + if (use_shaders && no_alpha_test) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + + } + } +// else +// { +// success = FALSE; +// } + } + } + + if( !getInfo()->mStaticImageFileName.empty() ) + { + { + LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + if( tex ) + { + gGL.getTexUnit(0)->bind(tex, TRUE); + gl_rect_2d_simple_tex( width, height ); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + else + { + success = FALSE; + } + } + } + + if(((-1 == getInfo()->mLocalTexture) || + getInfo()->mUseLocalTextureAlphaOnly) && + getInfo()->mStaticImageFileName.empty() && + color_specified ) + { + LLGLDisable no_alpha(GL_ALPHA_TEST); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4fv( net_color.mV ); + gl_rect_2d_simple( width, height ); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + } + + if( alpha_mask_specified || getInfo()->mWriteAllChannels ) + { + // Restore standard blend func value + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + stop_glerror(); + } + + if( !success ) + { + llinfos << "LLTexLayer::render() partial: " << getInfo()->mName << llendl; + } + return success; +} + +const U8* LLTexLayer::getAlphaData() const +{ + LLCRC alpha_mask_crc; + const LLUUID& uuid = getUUID(); + alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); + + for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) + { + const LLTexLayerParamAlpha* param = *iter; + // MULTI-WEARABLE: verify visual parameters used here + F32 param_weight = param->getWeight(); + alpha_mask_crc.update((U8*)¶m_weight, sizeof(F32)); + } + + U32 cache_index = alpha_mask_crc.getCRC(); + + alpha_cache_t::const_iterator iter2 = mAlphaCache.find(cache_index); + return (iter2 == mAlphaCache.end()) ? 0 : iter2->second; +} + +BOOL LLTexLayer::findNetColor(LLColor4* net_color) const +{ + // Color is either: + // * one or more color parameters (weighted colors) (which may make use of a global color or fixed color) + // * a reference to a global color + // * a fixed color with non-zero alpha + // * opaque white (the default) + + if( !mParamColorList.empty() ) + { + if( !getGlobalColor().empty() ) + { + net_color->setVec( mTexLayerSet->getAvatarAppearance()->getGlobalColor( getInfo()->mGlobalColor ) ); + } + else if (getInfo()->mFixedColor.mV[VW]) + { + net_color->setVec( getInfo()->mFixedColor ); + } + else + { + net_color->setVec( 0.f, 0.f, 0.f, 0.f ); + } + + calculateTexLayerColor(mParamColorList, *net_color); + return TRUE; + } + + if( !getGlobalColor().empty() ) + { + net_color->setVec( mTexLayerSet->getAvatarAppearance()->getGlobalColor( getGlobalColor() ) ); + return TRUE; + } + + if( getInfo()->mFixedColor.mV[VW] ) + { + net_color->setVec( getInfo()->mFixedColor ); + return TRUE; + } + + net_color->setToWhite(); + + return FALSE; // No need to draw a separate colored polygon +} + +BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) +{ + BOOL success = TRUE; + + gGL.flush(); + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + if( !getInfo()->mStaticImageFileName.empty() ) + { + LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); + if( tex ) + { + LLGLSNoAlphaTest gls_no_alpha_test; + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + gGL.getTexUnit(0)->bind(tex, TRUE); + gl_rect_2d_simple_tex( width, height ); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + } + else + { + success = FALSE; + } + } + else + { + if (getInfo()->mLocalTexture >=0 && getInfo()->mLocalTexture < TEX_NUM_INDICES) + { + LLTexture* tex = mLocalTextureObject->getImage(); + if (tex) + { + LLGLSNoAlphaTest gls_no_alpha_test; + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + gGL.getTexUnit(0)->bind(tex); + gl_rect_2d_simple_tex( width, height ); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + success = TRUE; + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + } + } + } + + return success; +} + +/*virtual*/ void LLTexLayer::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) +{ + addAlphaMask(data, originX, originY, width, height); +} + +BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color) +{ + BOOL success = TRUE; + + llassert( !mParamAlphaList.empty() ); + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + + gGL.setColorMask(false, true); + + LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin(); + // Note: if the first param is a mulitply, multiply against the current buffer's alpha + if( !first_param || !first_param->getMultiplyBlend() ) + { + LLGLDisable no_alpha(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // Clear the alpha + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_REPLACE); + + gGL.color4f( 0.f, 0.f, 0.f, 0.f ); + gl_rect_2d_simple( width, height ); + } + + // Accumulate alphas + LLGLSNoAlphaTest gls_no_alpha_test; + gGL.color4f( 1.f, 1.f, 1.f, 1.f ); + for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) + { + LLTexLayerParamAlpha* param = *iter; + success &= param->render( x, y, width, height ); + } + + // Approximates a min() function + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA); + + // Accumulate the alpha component of the texture + if( getInfo()->mLocalTexture != -1 ) + { + LLTexture* tex = mLocalTextureObject->getImage(); + if( tex && (tex->getComponents() == 4) ) + { + LLGLSNoAlphaTest gls_no_alpha_test; + LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); + + gGL.getTexUnit(0)->bind(tex, TRUE); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + + gl_rect_2d_simple_tex( width, height ); + + gGL.getTexUnit(0)->setTextureAddressMode(old_mode); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + } + + if( !getInfo()->mStaticImageFileName.empty() ) + { + LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + if( tex ) + { + if( (tex->getComponents() == 4) || + ( (tex->getComponents() == 1) && getInfo()->mStaticImageIsMask ) ) + { + LLGLSNoAlphaTest gls_no_alpha_test; + gGL.getTexUnit(0)->bind(tex, TRUE); + gl_rect_2d_simple_tex( width, height ); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + } + } + + // Draw a rectangle with the layer color to multiply the alpha by that color's alpha. + // Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO ); + if (layer_color.mV[VW] != 1.f) + { + LLGLDisable no_alpha(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4fv(layer_color.mV); + gl_rect_2d_simple( width, height ); + } + + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + + LLGLSUIDefault gls_ui; + + gGL.setColorMask(true, true); + + if (hasMorph() && success) + { + LLCRC alpha_mask_crc; + const LLUUID& uuid = getUUID(); + alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); + + for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) + { + const LLTexLayerParamAlpha* param = *iter; + F32 param_weight = param->getWeight(); + alpha_mask_crc.update((U8*)¶m_weight, sizeof(F32)); + } + + U32 cache_index = alpha_mask_crc.getCRC(); + U8* alpha_data = get_if_there(mAlphaCache,cache_index,(U8*)NULL); + if (!alpha_data) + { + // clear out a slot if we have filled our cache + S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1; + while ((S32)mAlphaCache.size() >= max_cache_entries) + { + alpha_cache_t::iterator iter2 = mAlphaCache.begin(); // arbitrarily grab the first entry + alpha_data = iter2->second; + delete [] alpha_data; + mAlphaCache.erase(iter2); + } + alpha_data = new U8[width * height]; + mAlphaCache[cache_index] = alpha_data; + glReadPixels(x, y, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, alpha_data); + } + + getTexLayerSet()->getAvatarAppearance()->dirtyMesh(); + + mMorphMasksValid = TRUE; + getTexLayerSet()->applyMorphMask(alpha_data, width, height, 1); + } + + return success; +} + +void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height) +{ + S32 size = width * height; + const U8* alphaData = getAlphaData(); + if (!alphaData && hasAlphaParams()) + { + LLColor4 net_color; + findNetColor( &net_color ); + // TODO: eliminate need for layer morph mask valid flag + invalidateMorphMasks(); + renderMorphMasks(originX, originY, width, height, net_color); + alphaData = getAlphaData(); + } + if (alphaData) + { + for( S32 i = 0; i < size; i++ ) + { + U8 curAlpha = data[i]; + U16 resultAlpha = curAlpha; + resultAlpha *= (alphaData[i] + 1); + resultAlpha = resultAlpha >> 8; + data[i] = (U8)resultAlpha; + } + } +} + +/*virtual*/ BOOL LLTexLayer::isInvisibleAlphaMask() const +{ + if (mLocalTextureObject) + { + if (mLocalTextureObject->getID() == IMG_INVISIBLE) + { + return TRUE; + } + } + + return FALSE; +} + +LLUUID LLTexLayer::getUUID() const +{ + LLUUID uuid; + if( getInfo()->mLocalTexture != -1 ) + { + LLTexture* tex = mLocalTextureObject->getImage(); + if (tex) + { + uuid = mLocalTextureObject->getID(); + } + } + if( !getInfo()->mStaticImageFileName.empty() ) + { + LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + if( tex ) + { + uuid = tex->getID(); + } + } + return uuid; +} + + +//----------------------------------------------------------------------------- +// LLTexLayerTemplate +// A single texture layer, consisting of: +// * color, consisting of either +// * one or more color parameters (weighted colors) +// * a reference to a global color +// * a fixed color with non-zero alpha +// * opaque white (the default) +// * (optional) a texture defined by either +// * a GUID +// * a texture entry index (TE) +// * (optional) one or more alpha parameters (weighted alpha textures) +//----------------------------------------------------------------------------- +LLTexLayerTemplate::LLTexLayerTemplate(LLTexLayerSet* layer_set, LLAvatarAppearance* const appearance) : + LLTexLayerInterface(layer_set), + mAvatarAppearance( appearance ) +{ +} + +LLTexLayerTemplate::LLTexLayerTemplate(const LLTexLayerTemplate &layer) : + LLTexLayerInterface(layer), + mAvatarAppearance(layer.getAvatarAppearance()) +{ +} + +LLTexLayerTemplate::~LLTexLayerTemplate() +{ +} + +//----------------------------------------------------------------------------- +// setInfo +//----------------------------------------------------------------------------- + +/*virtual*/ BOOL LLTexLayerTemplate::setInfo(const LLTexLayerInfo* info, LLWearable* wearable ) +{ + return LLTexLayerInterface::setInfo(info, wearable); +} + +U32 LLTexLayerTemplate::updateWearableCache() const +{ + mWearableCache.clear(); + + S32 te = mInfo->mLocalTexture; + if (te == -1) + { + //this isn't a cloneable layer + return 0; + } + LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te); + U32 num_wearables = getAvatarAppearance()->getWearableCount(wearable_type); + U32 added = 0; + for (U32 i = 0; i < num_wearables; i++) + { + LLWearable* wearable = getAvatarAppearance()->getWearable(wearable_type, i); + if (!wearable) + { + continue; + } + mWearableCache.push_back(wearable); + added++; + } + return added; +} +LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const +{ + if (mWearableCache.size() <= i) + { + return NULL; + } + LLWearable *wearable = mWearableCache[i]; + LLLocalTextureObject *lto = NULL; + LLTexLayer *layer = NULL; + if (wearable) + { + lto = wearable->getLocalTextureObject(mInfo->mLocalTexture); + } + if (lto) + { + layer = lto->getTexLayer(getName()); + } + return layer; +} + +/*virtual*/ BOOL LLTexLayerTemplate::render(S32 x, S32 y, S32 width, S32 height) +{ + if(!mInfo) + { + return FALSE ; + } + + BOOL success = TRUE; + updateWearableCache(); + for (wearable_cache_t::const_iterator iter = mWearableCache.begin(); iter!= mWearableCache.end(); iter++) + { + LLWearable* wearable = NULL; + LLLocalTextureObject *lto = NULL; + LLTexLayer *layer = NULL; + wearable = *iter; + if (wearable) + { + lto = wearable->getLocalTextureObject(mInfo->mLocalTexture); + } + if (lto) + { + layer = lto->getTexLayer(getName()); + } + if (layer) + { + wearable->writeToAvatar(); + layer->setLTO(lto); + success &= layer->render(x,y,width,height); + } + } + + return success; +} + +/*virtual*/ BOOL LLTexLayerTemplate::blendAlphaTexture( S32 x, S32 y, S32 width, S32 height) // Multiplies a single alpha texture against the frame buffer +{ + BOOL success = TRUE; + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) + { + LLTexLayer *layer = getLayer(i); + if (layer) + { + success &= layer->blendAlphaTexture(x,y,width,height); + } + } + return success; +} + +/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) +{ + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) + { + LLTexLayer *layer = getLayer(i); + if (layer) + { + layer->addAlphaMask(data, originX, originY, width, height); + } + } +} + +/*virtual*/ void LLTexLayerTemplate::setHasMorph(BOOL newval) +{ + mHasMorph = newval; + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) + { + LLTexLayer *layer = getLayer(i); + if (layer) + { + layer->setHasMorph(newval); + } + } +} + +/*virtual*/ void LLTexLayerTemplate::deleteCaches() +{ + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) + { + LLTexLayer *layer = getLayer(i); + if (layer) + { + layer->deleteCaches(); + } + } +} + +/*virtual*/ BOOL LLTexLayerTemplate::isInvisibleAlphaMask() const +{ + U32 num_wearables = updateWearableCache(); + for (U32 i = 0; i < num_wearables; i++) + { + LLTexLayer *layer = getLayer(i); + if (layer) + { + if (layer->isInvisibleAlphaMask()) + { + return TRUE; + } + } + } + + return FALSE; +} + + +//----------------------------------------------------------------------------- +// finds a specific layer based on a passed in name +//----------------------------------------------------------------------------- +LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name) +{ + for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + if (layer->getName() == name) + { + return layer; + } + } + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + if (layer->getName() == name) + { + return layer; + } + } + return NULL; +} + +void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable *wearable) +{ + // initialize all texlayers with this texture type for this LTO + for( LLTexLayerSet::layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerTemplate* layer = (LLTexLayerTemplate*)*iter; + if (layer->getInfo()->getLocalTexture() == (S32) tex_index) + { + lto->addTexLayer(layer, wearable); + } + } + for( LLTexLayerSet::layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ ) + { + LLTexLayerTemplate* layer = (LLTexLayerTemplate*)*iter; + if (layer->getInfo()->getLocalTexture() == (S32) tex_index) + { + lto->addTexLayer(layer, wearable); + } + } +} +//----------------------------------------------------------------------------- +// LLTexLayerStaticImageList +//----------------------------------------------------------------------------- + +LLTexLayerStaticImageList::LLTexLayerStaticImageList() : + mGLBytes(0), + mTGABytes(0), + mImageNames(16384) +{ +} + +LLTexLayerStaticImageList::~LLTexLayerStaticImageList() +{ + deleteCachedImages(); +} + +void LLTexLayerStaticImageList::dumpByteCount() const +{ + llinfos << "Avatar Static Textures " << + "KB GL:" << (mGLBytes / 1024) << + "KB TGA:" << (mTGABytes / 1024) << "KB" << llendl; +} + +void LLTexLayerStaticImageList::deleteCachedImages() +{ + if( mGLBytes || mTGABytes ) + { + llinfos << "Clearing Static Textures " << + "KB GL:" << (mGLBytes / 1024) << + "KB TGA:" << (mTGABytes / 1024) << "KB" << llendl; + + //mStaticImageLists uses LLPointers, clear() will cause deletion + + mStaticImageListTGA.clear(); + mStaticImageList.clear(); + + mGLBytes = 0; + mTGABytes = 0; + } +} + +// Note: in general, for a given image image we'll call either getImageTga() or getTexture(). +// We call getImageTga() if the image is used as an alpha gradient. +// Otherwise, we call getTexture() + +// Returns an LLImageTGA that contains the encoded data from a tga file named file_name. +// Caches the result to speed identical subsequent requests. +LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) +{ + const char *namekey = mImageNames.addString(file_name); + image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey); + if( iter != mStaticImageListTGA.end() ) + { + return iter->second; + } + else + { + std::string path; + path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name); + LLPointer image_tga = new LLImageTGA( path ); + if( image_tga->getDataSize() > 0 ) + { + mStaticImageListTGA[ namekey ] = image_tga; + mTGABytes += image_tga->getDataSize(); + return image_tga; + } + else + { + return NULL; + } + } +} + +// Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name. +// Caches the result to speed identical subsequent requests. +LLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) +{ + LLPointer tex; + const char *namekey = mImageNames.addString(file_name); + + texture_map_t::const_iterator iter = mStaticImageList.find(namekey); + if( iter != mStaticImageList.end() ) + { + tex = iter->second; + } + else + { + llassert(gTextureManagerBridgep); + tex = gTextureManagerBridgep->getLocalTexture( FALSE ); + LLPointer image_raw = new LLImageRaw; + if( loadImageRaw( file_name, image_raw ) ) + { + if( (image_raw->getComponents() == 1) && is_mask ) + { + // Note: these are static, unchanging images so it's ok to assume + // that once an image is a mask it's always a mask. + tex->setExplicitFormat( GL_ALPHA8, GL_ALPHA ); + } + tex->createGLTexture(0, image_raw, 0, TRUE, LLTexture::LOCAL); + + gGL.getTexUnit(0)->bind(tex); + tex->setAddressMode(LLTexUnit::TAM_CLAMP); + + mStaticImageList [ namekey ] = tex; + mGLBytes += (S32)tex->getWidth() * tex->getHeight() * tex->getComponents(); + } + else + { + tex = NULL; + } + } + + return tex; +} + +// Reads a .tga file, decodes it, and puts the decoded data in image_raw. +// Returns TRUE if successful. +BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw) +{ + BOOL success = FALSE; + std::string path; + path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name); + LLPointer image_tga = new LLImageTGA( path ); + if( image_tga->getDataSize() > 0 ) + { + // Copy data from tga to raw. + success = image_tga->decode( image_raw ); + } + + return success; +} + diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h new file mode 100644 index 0000000000..5ee08e67ec --- /dev/null +++ b/indra/llappearance/lltexlayer.h @@ -0,0 +1,269 @@ +/** + * @file lltexlayer.h + * @brief Texture layer classes. Used for avatars. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTEXLAYER_H +#define LL_LLTEXLAYER_H + +#include +#include "lltexture.h" +#include "llframetimer.h" +#include "llvoavatardefines.h" +#include "lltexlayerparams.h" + +class LLAvatarAppearance; +class LLImageTGA; +class LLImageRaw; +class LLXmlTreeNode; +class LLTexLayerSet; +class LLTexLayerSetInfo; +class LLTexLayerInfo; +class LLWearable; +class LLViewerVisualParam; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerInterface +// +// Interface class to generalize functionality shared by LLTexLayer +// and LLTexLayerTemplate. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerInterface +{ +public: + enum ERenderPass + { + RP_COLOR, + RP_BUMP, + RP_SHINE + }; + + LLTexLayerInterface(LLTexLayerSet* const layer_set); + LLTexLayerInterface(const LLTexLayerInterface &layer, LLWearable *wearable); + virtual ~LLTexLayerInterface() {} + + virtual BOOL render(S32 x, S32 y, S32 width, S32 height) = 0; + virtual void deleteCaches() = 0; + virtual BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) = 0; + virtual BOOL isInvisibleAlphaMask() const = 0; + + const LLTexLayerInfo* getInfo() const { return mInfo; } + virtual BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // sets mInfo, calls initialization functions + + const std::string& getName() const; + const LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; } + LLTexLayerSet* const getTexLayerSet() { return mTexLayerSet; } + + void invalidateMorphMasks(); + virtual void setHasMorph(BOOL newval) { mHasMorph = newval; } + BOOL hasMorph() const { return mHasMorph; } + BOOL isMorphValid() const { return mMorphMasksValid; } + + void requestUpdate(); + virtual void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) = 0; + BOOL hasAlphaParams() const { return !mParamAlphaList.empty(); } + + ERenderPass getRenderPass() const; + BOOL isVisibilityMask() const; + +protected: + const std::string& getGlobalColor() const; + LLViewerVisualParam* getVisualParamPtr(S32 index) const; + +protected: + LLTexLayerSet* const mTexLayerSet; + const LLTexLayerInfo* mInfo; + BOOL mMorphMasksValid; + BOOL mHasMorph; + + // Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order. + param_color_list_t mParamColorList; + param_alpha_list_t mParamAlphaList; + // mGlobalColor name stored in mInfo + // mFixedColor value stored in mInfo +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerTemplate +// +// Only exists for llvoavatarself. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerTemplate : public LLTexLayerInterface +{ +public: + LLTexLayerTemplate(LLTexLayerSet* const layer_set, LLAvatarAppearance* const appearance); + LLTexLayerTemplate(const LLTexLayerTemplate &layer); + /*virtual*/ ~LLTexLayerTemplate(); + /*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height); + /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions + /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer + /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height); + /*virtual*/ void setHasMorph(BOOL newval); + /*virtual*/ void deleteCaches(); + /*virtual*/ BOOL isInvisibleAlphaMask() const; +protected: + U32 updateWearableCache() const; + LLTexLayer* getLayer(U32 i) const; + LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } +private: + LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer. + typedef std::vector wearable_cache_t; + mutable wearable_cache_t mWearableCache; // mutable b/c most get- require updating this cache +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayer +// +// A single texture layer. Only exists for llvoavatarself. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayer : public LLTexLayerInterface +{ +public: + LLTexLayer(LLTexLayerSet* const layer_set); + LLTexLayer(const LLTexLayer &layer, LLWearable *wearable); + LLTexLayer(const LLTexLayerTemplate &layer_template, LLLocalTextureObject *lto, LLWearable *wearable); + /*virtual*/ ~LLTexLayer(); + + /*virtual*/ BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // This sets mInfo and calls initialization functions + /*virtual*/ BOOL render(S32 x, S32 y, S32 width, S32 height); + + /*virtual*/ void deleteCaches(); + const U8* getAlphaData() const; + + BOOL findNetColor(LLColor4* color) const; + /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer + /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height); + BOOL renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color); + void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height); + /*virtual*/ BOOL isInvisibleAlphaMask() const; + + void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; } + LLLocalTextureObject* getLTO() { return mLocalTextureObject; } + + static void calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color); +protected: + LLUUID getUUID() const; +private: + typedef std::map alpha_cache_t; + alpha_cache_t mAlphaCache; + LLLocalTextureObject* mLocalTextureObject; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerSet +// +// An ordered set of texture layers that gets composited into a single texture. +// Only exists for llvoavatarself. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerSet +{ +public: + LLTexLayerSet(LLAvatarAppearance* const appearance); + virtual ~LLTexLayerSet(); + + const LLTexLayerSetInfo* getInfo() const { return mInfo; } + BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions + + BOOL render(S32 x, S32 y, S32 width, S32 height); + void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear = false); + + BOOL isBodyRegion(const std::string& region) const; + void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); + BOOL isMorphValid() const; + virtual void requestUpdate() = 0; + void invalidateMorphMasks(); + void deleteCaches(); + LLTexLayerInterface* findLayerByName(const std::string& name); + void cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable* wearable); + + LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } + const std::string getBodyRegionName() const; + LLVOAvatarDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; } + void setBakedTexIndex(LLVOAvatarDefines::EBakedTextureIndex index) { mBakedTexIndex = index; } + BOOL isVisible() const { return mIsVisible; } + + static BOOL sHasCaches; + +protected: + typedef std::vector layer_list_t; + layer_list_t mLayerList; + layer_list_t mMaskLayerList; + LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer. + BOOL mIsVisible; + + LLVOAvatarDefines::EBakedTextureIndex mBakedTexIndex; + const LLTexLayerSetInfo* mInfo; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerSetInfo +// +// Contains shared layer set data. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerSetInfo +{ + friend class LLTexLayerSet; +public: + LLTexLayerSetInfo(); + ~LLTexLayerSetInfo(); + BOOL parseXml(LLXmlTreeNode* node); + void createVisualParams(LLAvatarAppearance *appearance); + S32 getWidth() const { return mWidth; } + S32 getHeight() const { return mHeight; } +protected: + std::string mBodyRegion; + S32 mWidth; + S32 mHeight; + std::string mStaticAlphaFileName; + BOOL mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName) + typedef std::vector layer_info_list_t; + layer_info_list_t mLayerInfoList; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerStaticImageList +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerStaticImageList : public LLSingleton +{ +public: + LLTexLayerStaticImageList(); + ~LLTexLayerStaticImageList(); + LLTexture* getTexture(const std::string& file_name, BOOL is_mask); + LLImageTGA* getImageTGA(const std::string& file_name); + void deleteCachedImages(); + void dumpByteCount() const; +protected: + BOOL loadImageRaw(const std::string& file_name, LLImageRaw* image_raw); +private: + LLStringTable mImageNames; + typedef std::map > texture_map_t; + texture_map_t mStaticImageList; + typedef std::map > image_tga_map_t; + image_tga_map_t mStaticImageListTGA; + S32 mGLBytes; + S32 mTGABytes; +}; + +#endif // LL_LLTEXLAYER_H diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp new file mode 100644 index 0000000000..c843367357 --- /dev/null +++ b/indra/llappearance/lltexlayerparams.cpp @@ -0,0 +1,571 @@ +/** + * @file lltexlayerparams.cpp + * @brief Texture layer parameters + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltexlayerparams.h" + +#include "llavatarappearance.h" +//#include "llagentcamera.h" +#include "llimagetga.h" +#include "llquantize.h" +#include "lltexlayer.h" +#include "lltexturemanagerbridge.h" +#include "llwearable.h" +#include "llui.h" + +//----------------------------------------------------------------------------- +// LLTexLayerParam +//----------------------------------------------------------------------------- +LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) : + mTexLayer(layer), + mAvatarAppearance(NULL) +{ + if (mTexLayer != NULL) + { + mAvatarAppearance = mTexLayer->getTexLayerSet()->getAvatarAppearance(); + } + else + { + llerrs << "LLTexLayerParam constructor passed with NULL reference for layer!" << llendl; + } +} + +LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance) : + mTexLayer(NULL), + mAvatarAppearance(appearance) +{ +} + + +BOOL LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, BOOL add_to_appearance) +{ + LLViewerVisualParam::setInfo(info); + + if (add_to_appearance) + { + mAvatarAppearance->addVisualParam( this); + } + + return TRUE; +} + + +//----------------------------------------------------------------------------- +// LLTexLayerParamAlpha +//----------------------------------------------------------------------------- + +// static +LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances; + +// static +void LLTexLayerParamAlpha::dumpCacheByteCount() +{ + S32 gl_bytes = 0; + getCacheByteCount( &gl_bytes); + llinfos << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << llendl; +} + +// static +void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes) +{ + *gl_bytes = 0; + + for (param_alpha_ptr_list_t::iterator iter = sInstances.begin(); + iter != sInstances.end(); iter++) + { + LLTexLayerParamAlpha* instance = *iter; + LLTexture* tex = instance->mCachedProcessedTexture; + if (tex) + { + S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents(); + + if (tex->hasGLTexture()) + { + *gl_bytes += bytes; + } + } + } +} + +LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) : + LLTexLayerParam(layer), + mCachedProcessedTexture(NULL), + mNeedsCreateTexture(FALSE), + mStaticImageInvalid(FALSE), + mAvgDistortionVec(1.f, 1.f, 1.f), + mCachedEffectiveWeight(0.f) +{ + sInstances.push_front(this); +} + +LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) : + LLTexLayerParam(appearance), + mCachedProcessedTexture(NULL), + mNeedsCreateTexture(FALSE), + mStaticImageInvalid(FALSE), + mAvgDistortionVec(1.f, 1.f, 1.f), + mCachedEffectiveWeight(0.f) +{ + sInstances.push_front(this); +} + + +LLTexLayerParamAlpha::~LLTexLayerParamAlpha() +{ + deleteCaches(); + sInstances.remove(this); +} + +/*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const +{ + LLTexLayerParamAlpha *new_param = new LLTexLayerParamAlpha(mTexLayer); + *new_param = *this; + return new_param; +} + +void LLTexLayerParamAlpha::deleteCaches() +{ + mStaticImageTGA = NULL; // deletes image + mCachedProcessedTexture = NULL; + mStaticImageRaw = NULL; + mNeedsCreateTexture = FALSE; +} + +BOOL LLTexLayerParamAlpha::getMultiplyBlend() const +{ + return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend; +} + +void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) +{ + if (mIsAnimating || mTexLayer == NULL) + { + return; + } + F32 min_weight = getMinWeight(); + F32 max_weight = getMaxWeight(); + F32 new_weight = llclamp(weight, min_weight, max_weight); + U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight); + U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight); + if (cur_u8 != new_u8) + { + mCurWeight = new_weight; + + if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. + { + if (!mAvatarAppearance->isUsingBakedTextures()) + { + upload_bake = FALSE; + } + mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake); + mTexLayer->invalidateMorphMasks(); + } + } +} + +void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL upload_bake) +{ + // do not animate dummy parameters + if (mIsDummy) + { + setWeight(target_value, upload_bake); + return; + } + + mTargetWeight = target_value; + setWeight(target_value, upload_bake); + mIsAnimating = TRUE; + if (mNext) + { + mNext->setAnimationTarget(target_value, upload_bake); + } +} + +void LLTexLayerParamAlpha::animate(F32 delta, BOOL upload_bake) +{ + if (mNext) + { + mNext->animate(delta, upload_bake); + } +} + +BOOL LLTexLayerParamAlpha::getSkip() const +{ + if (!mTexLayer) + { + return TRUE; + } + + const LLAvatarAppearance *appearance = mTexLayer->getTexLayerSet()->getAvatarAppearance(); + + if (((LLTexLayerParamAlphaInfo *)getInfo())->mSkipIfZeroWeight) + { + F32 effective_weight = (appearance->getSex() & getSex()) ? mCurWeight : getDefaultWeight(); + if (is_approx_zero(effective_weight)) + { + return TRUE; + } + } + + LLWearableType::EType type = (LLWearableType::EType)getWearableType(); + if ((type != LLWearableType::WT_INVALID) && !appearance->isWearingWearableType(type)) + { + return TRUE; + } + + return FALSE; +} + + +BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) +{ + BOOL success = TRUE; + + if (!mTexLayer) + { + return success; + } + + F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatarAppearance()->getSex() & getSex()) ? mCurWeight : getDefaultWeight(); + BOOL weight_changed = effective_weight != mCachedEffectiveWeight; + if (getSkip()) + { + return success; + } + + LLTexLayerParamAlphaInfo *info = (LLTexLayerParamAlphaInfo *)getInfo(); + gGL.flush(); + if (info->mMultiplyBlend) + { + gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); // Multiplication: approximates a min() function + } + else + { + gGL.setSceneBlendType(LLRender::BT_ADD); // Addition: approximates a max() function + } + + if (!info->mStaticImageFileName.empty() && !mStaticImageInvalid) + { + if (mStaticImageTGA.isNull()) + { + // Don't load the image file until we actually need it the first time. Like now. + mStaticImageTGA = LLTexLayerStaticImageList::getInstance()->getImageTGA(info->mStaticImageFileName); + // We now have something in one of our caches + LLTexLayerSet::sHasCaches |= mStaticImageTGA.notNull() ? TRUE : FALSE; + + if (mStaticImageTGA.isNull()) + { + llwarns << "Unable to load static file: " << info->mStaticImageFileName << llendl; + mStaticImageInvalid = TRUE; // don't try again. + return FALSE; + } + } + + const S32 image_tga_width = mStaticImageTGA->getWidth(); + const S32 image_tga_height = mStaticImageTGA->getHeight(); + if (!mCachedProcessedTexture || + (mCachedProcessedTexture->getWidth() != image_tga_width) || + (mCachedProcessedTexture->getHeight() != image_tga_height) || + (weight_changed)) + { +// llinfos << "Building Cached Alpha: " << mName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << effective_weight << llendl; + mCachedEffectiveWeight = effective_weight; + + if (!mCachedProcessedTexture) + { + llassert(gTextureManagerBridgep); + mCachedProcessedTexture = gTextureManagerBridgep->getLocalTexture(image_tga_width, image_tga_height, 1, FALSE); + + // We now have something in one of our caches + LLTexLayerSet::sHasCaches |= mCachedProcessedTexture ? TRUE : FALSE; + + mCachedProcessedTexture->setExplicitFormat(GL_ALPHA8, GL_ALPHA); + } + + // Applies domain and effective weight to data as it is decoded. Also resizes the raw image if needed. + mStaticImageRaw = NULL; + mStaticImageRaw = new LLImageRaw; + mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight); + mNeedsCreateTexture = TRUE; + } + + if (mCachedProcessedTexture) + { + { + // Create the GL texture, and then hang onto it for future use. + if (mNeedsCreateTexture) + { + mCachedProcessedTexture->createGLTexture(0, mStaticImageRaw); + mNeedsCreateTexture = FALSE; + gGL.getTexUnit(0)->bind(mCachedProcessedTexture); + mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP); + } + + LLGLSNoAlphaTest gls_no_alpha_test; + gGL.getTexUnit(0)->bind(mCachedProcessedTexture); + gl_rect_2d_simple_tex(width, height); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + stop_glerror(); + } + } + + // Don't keep the cache for other people's avatars + // (It's not really a "cache" in that case, but the logic is the same) + if (!mAvatarAppearance->isSelf()) + { + mCachedProcessedTexture = NULL; + } + } + else + { + LLGLDisable no_alpha(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4f(0.f, 0.f, 0.f, effective_weight); + gl_rect_2d_simple(width, height); + } + + return success; +} + +//----------------------------------------------------------------------------- +// LLTexLayerParamAlphaInfo +//----------------------------------------------------------------------------- +LLTexLayerParamAlphaInfo::LLTexLayerParamAlphaInfo() : + mMultiplyBlend(FALSE), + mSkipIfZeroWeight(FALSE), + mDomain(0.f) +{ +} + +BOOL LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node) +{ + llassert(node->hasName("param") && node->getChildByName("param_alpha")); + + if (!LLViewerVisualParamInfo::parseXml(node)) + return FALSE; + + LLXmlTreeNode* param_alpha_node = node->getChildByName("param_alpha"); + if (!param_alpha_node) + { + return FALSE; + } + + static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file"); + if (param_alpha_node->getFastAttributeString(tga_file_string, mStaticImageFileName)) + { + // Don't load the image file until it's actually needed. + } +// else +// { +// llwarns << " element is missing tga_file attribute." << llendl; +// } + + static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend"); + param_alpha_node->getFastAttributeBOOL(multiply_blend_string, mMultiplyBlend); + + static LLStdStringHandle skip_if_zero_string = LLXmlTree::addAttributeString("skip_if_zero"); + param_alpha_node->getFastAttributeBOOL(skip_if_zero_string, mSkipIfZeroWeight); + + static LLStdStringHandle domain_string = LLXmlTree::addAttributeString("domain"); + param_alpha_node->getFastAttributeF32(domain_string, mDomain); + + return TRUE; +} + + + + +LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer) : + LLTexLayerParam(layer), + mAvgDistortionVec(1.f, 1.f, 1.f) +{ +} + +LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance) : + LLTexLayerParam(appearance), + mAvgDistortionVec(1.f, 1.f, 1.f) +{ +} + +LLTexLayerParamColor::~LLTexLayerParamColor() +{ +} + +/*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const +{ + LLTexLayerParamColor *new_param = new LLTexLayerParamColor(mTexLayer); + *new_param = *this; + return new_param; +} + +LLColor4 LLTexLayerParamColor::getNetColor() const +{ + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); + + llassert(info->mNumColors >= 1); + + F32 effective_weight = (mAvatarAppearance && (mAvatarAppearance->getSex() & getSex())) ? mCurWeight : getDefaultWeight(); + + S32 index_last = info->mNumColors - 1; + F32 scaled_weight = effective_weight * index_last; + S32 index_start = (S32) scaled_weight; + S32 index_end = index_start + 1; + if (index_start == index_last) + { + return info->mColors[index_last]; + } + else + { + F32 weight = scaled_weight - index_start; + const LLColor4 *start = &info->mColors[ index_start ]; + const LLColor4 *end = &info->mColors[ index_end ]; + return LLColor4((1.f - weight) * start->mV[VX] + weight * end->mV[VX], + (1.f - weight) * start->mV[VY] + weight * end->mV[VY], + (1.f - weight) * start->mV[VZ] + weight * end->mV[VZ], + (1.f - weight) * start->mV[VW] + weight * end->mV[VW]); + } +} + +void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake) +{ + if (mIsAnimating) + { + return; + } + + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); + F32 min_weight = getMinWeight(); + F32 max_weight = getMaxWeight(); + F32 new_weight = llclamp(weight, min_weight, max_weight); + U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight); + U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight); + if (cur_u8 != new_u8) + { + mCurWeight = new_weight; + + if (info->mNumColors <= 0) + { + // This will happen when we set the default weight the first time. + return; + } + + if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. + { + onGlobalColorChanged(upload_bake); + if (mTexLayer) + { + mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake); + } + } + +// llinfos << "param " << mName << " = " << new_weight << llendl; + } +} + +void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL upload_bake) +{ + // set value first then set interpolating flag to ignore further updates + mTargetWeight = target_value; + setWeight(target_value, upload_bake); + mIsAnimating = TRUE; + if (mNext) + { + mNext->setAnimationTarget(target_value, upload_bake); + } +} + +void LLTexLayerParamColor::animate(F32 delta, BOOL upload_bake) +{ + if (mNext) + { + mNext->animate(delta, upload_bake); + } +} + +//----------------------------------------------------------------------------- +// LLTexLayerParamColorInfo +//----------------------------------------------------------------------------- +LLTexLayerParamColorInfo::LLTexLayerParamColorInfo() : + mOperation(LLTexLayerParamColor::OP_ADD), + mNumColors(0) +{ +} + +BOOL LLTexLayerParamColorInfo::parseXml(LLXmlTreeNode *node) +{ + llassert(node->hasName("param") && node->getChildByName("param_color")); + + if (!LLViewerVisualParamInfo::parseXml(node)) + return FALSE; + + LLXmlTreeNode* param_color_node = node->getChildByName("param_color"); + if (!param_color_node) + { + return FALSE; + } + + std::string op_string; + static LLStdStringHandle operation_string = LLXmlTree::addAttributeString("operation"); + if (param_color_node->getFastAttributeString(operation_string, op_string)) + { + LLStringUtil::toLower(op_string); + if (op_string == "add") mOperation = LLTexLayerParamColor::OP_ADD; + else if (op_string == "multiply") mOperation = LLTexLayerParamColor::OP_MULTIPLY; + else if (op_string == "blend") mOperation = LLTexLayerParamColor::OP_BLEND; + } + + mNumColors = 0; + + LLColor4U color4u; + for (LLXmlTreeNode* child = param_color_node->getChildByName("value"); + child; + child = param_color_node->getNextNamedChild()) + { + if ((mNumColors < MAX_COLOR_VALUES)) + { + static LLStdStringHandle color_string = LLXmlTree::addAttributeString("color"); + if (child->getFastAttributeColor4U(color_string, color4u)) + { + mColors[ mNumColors ].setVec(color4u); + mNumColors++; + } + } + } + if (!mNumColors) + { + llwarns << " is missing sub-elements" << llendl; + return FALSE; + } + + if ((mOperation == LLTexLayerParamColor::OP_BLEND) && (mNumColors != 1)) + { + llwarns << " with operation\"blend\" must have exactly one " << llendl; + return FALSE; + } + + return TRUE; +} diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h new file mode 100644 index 0000000000..dbffd15751 --- /dev/null +++ b/indra/llappearance/lltexlayerparams.h @@ -0,0 +1,195 @@ +/** + * @file lltexlayerparams.h + * @brief Texture layer parameters, used by lltexlayer. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTEXLAYERPARAMS_H +#define LL_LLTEXLAYERPARAMS_H + +#include "llpointer.h" +#include "v4color.h" +#include "llviewervisualparam.h" + +class LLAvatarAppearance; +class LLImageRaw; +class LLImageTGA; +class LLTexLayer; +class LLTexLayerInterface; +class LLTexture; +class LLWearable; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerParam +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerParam : public LLViewerVisualParam +{ +public: + LLTexLayerParam(LLTexLayerInterface *layer); + LLTexLayerParam(LLAvatarAppearance *appearance); + /*virtual*/ BOOL setInfo(LLViewerVisualParamInfo *info, BOOL add_to_appearance); + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0; + +protected: + LLTexLayerInterface* mTexLayer; + LLAvatarAppearance* mAvatarAppearance; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerParamAlpha +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerParamAlpha : public LLTexLayerParam +{ +public: + LLTexLayerParamAlpha( LLTexLayerInterface* layer ); + LLTexLayerParamAlpha( LLAvatarAppearance* appearance ); + /*virtual*/ ~LLTexLayerParamAlpha(); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ void apply( ESex avatar_sex ) {} + /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); + /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake); + /*virtual*/ void animate(F32 delta, BOOL upload_bake); + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion() { return 1.f; } + /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; } + /*virtual*/ F32 getMaxDistortion() { return 3.f; } + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f);} + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + + // New functions + BOOL render( S32 x, S32 y, S32 width, S32 height ); + BOOL getSkip() const; + void deleteCaches(); + BOOL getMultiplyBlend() const; + +private: + LLPointer mCachedProcessedTexture; + LLPointer mStaticImageTGA; + LLPointer mStaticImageRaw; + BOOL mNeedsCreateTexture; + BOOL mStaticImageInvalid; + LLVector4a mAvgDistortionVec; + F32 mCachedEffectiveWeight; + +public: + // Global list of instances for gathering statistics + static void dumpCacheByteCount(); + static void getCacheByteCount( S32* gl_bytes ); + + typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t; + static param_alpha_ptr_list_t sInstances; +}; +class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo +{ + friend class LLTexLayerParamAlpha; +public: + LLTexLayerParamAlphaInfo(); + /*virtual*/ ~LLTexLayerParamAlphaInfo() {}; + + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + +private: + std::string mStaticImageFileName; + BOOL mMultiplyBlend; + BOOL mSkipIfZeroWeight; + F32 mDomain; +}; +// +// LLTexLayerParamAlpha +//----------------------------------------------------------------------------- + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerParamColor +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerParamColor : public LLTexLayerParam +{ +public: + enum EColorOperation + { + OP_ADD = 0, + OP_MULTIPLY = 1, + OP_BLEND = 2, + OP_COUNT = 3 // Number of operations + }; + + LLTexLayerParamColor( LLTexLayerInterface* layer ); + LLTexLayerParamColor( LLAvatarAppearance* appearance ); + /* virtual */ ~LLTexLayerParamColor(); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ void apply( ESex avatar_sex ) {} + /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); + /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake); + /*virtual*/ void animate(F32 delta, BOOL upload_bake); + + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion() { return 1.f; } + /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; } + /*virtual*/ F32 getMaxDistortion() { return 3.f; } + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f); } + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + + // New functions + LLColor4 getNetColor() const; +protected: + virtual void onGlobalColorChanged(bool upload_bake) {} +private: + LLVector4a mAvgDistortionVec; +}; + +class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo +{ + friend class LLTexLayerParamColor; + +public: + LLTexLayerParamColorInfo(); + virtual ~LLTexLayerParamColorInfo() {}; + BOOL parseXml( LLXmlTreeNode* node ); + LLTexLayerParamColor::EColorOperation getOperation() const { return mOperation; } +private: + enum { MAX_COLOR_VALUES = 20 }; + LLTexLayerParamColor::EColorOperation mOperation; + LLColor4 mColors[MAX_COLOR_VALUES]; + S32 mNumColors; +}; + +typedef std::vector param_color_list_t; +typedef std::vector param_alpha_list_t; +typedef std::vector param_color_info_list_t; +typedef std::vector param_alpha_info_list_t; + +#endif diff --git a/indra/llappearance/lltexturemanagerbridge.cpp b/indra/llappearance/lltexturemanagerbridge.cpp new file mode 100644 index 0000000000..33f2185e4f --- /dev/null +++ b/indra/llappearance/lltexturemanagerbridge.cpp @@ -0,0 +1,32 @@ + /** + * @file lltexturemanagerbridge.cpp + * @brief Defined a null texture manager bridge. Applications must provide their own bridge implementaton. + * + * $LicenseInfo:firstyear=2012&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 "lltexturemanagerbridge.h" + +// Define a null texture manager bridge. Applications must provide their own bridge implementaton. +LLTextureManagerBridge* gTextureManagerBridgep = NULL; + + diff --git a/indra/llappearance/lltexturemanagerbridge.h b/indra/llappearance/lltexturemanagerbridge.h new file mode 100644 index 0000000000..20f5d0fd3c --- /dev/null +++ b/indra/llappearance/lltexturemanagerbridge.h @@ -0,0 +1,45 @@ +/** + * @file lltexturemanagerbridge.h + * @brief Bridge to an application-specific texture manager. + * + * $LicenseInfo:firstyear=2012&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_TEXTUREMANAGERBRIDGE_H +#define LL_TEXTUREMANAGERBRIDGE_H + +#include "llpointer.h" +#include "lltexture.h" + +// Abstract bridge interface +class LLTextureManagerBridge +{ +public: + virtual LLPointer getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE) = 0; + virtual LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) = 0; + virtual LLTexture* getFetchedTexture(const LLUUID &image_id) = 0; +}; + +extern LLTextureManagerBridge* gTextureManagerBridgep; + +#endif // LL_TEXTUREMANAGERBRIDGE_H + diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp new file mode 100644 index 0000000000..e1ddeeeff0 --- /dev/null +++ b/indra/llappearance/llviewervisualparam.cpp @@ -0,0 +1,165 @@ +/** + * @file llviewervisualparam.cpp + * @brief Implementation of LLViewerVisualParam class + * + * $LicenseInfo:firstyear=2001&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$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +//#include "llviewerprecompiledheaders.h" +#include "linden_common.h" + +#include "llviewervisualparam.h" +#include "llxmltree.h" +#include "llui.h" +#include "llwearable.h" + +//----------------------------------------------------------------------------- +// LLViewerVisualParamInfo() +//----------------------------------------------------------------------------- +LLViewerVisualParamInfo::LLViewerVisualParamInfo() + : + mWearableType( LLWearableType::WT_INVALID ), + mCrossWearable(FALSE), + mCamDist( 0.5f ), + mCamAngle( 0.f ), + mCamElevation( 0.f ), + mEditGroupDisplayOrder( 0 ), + mShowSimple(FALSE), + mSimpleMin(0.f), + mSimpleMax(100.f) +{ +} + +LLViewerVisualParamInfo::~LLViewerVisualParamInfo() +{ +} + +//----------------------------------------------------------------------------- +// parseXml() +//----------------------------------------------------------------------------- +BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node) +{ + llassert( node->hasName( "param" ) ); + + if (!LLVisualParamInfo::parseXml(node)) + return FALSE; + + // VIEWER SPECIFIC PARAMS + + std::string wearable; + static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable"); + if( node->getFastAttributeString( wearable_string, wearable) ) + { + mWearableType = LLWearableType::typeNameToType( wearable ); + } + + static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group"); + if (!node->getFastAttributeString( edit_group_string, mEditGroup)) + { + mEditGroup = ""; + } + + static LLStdStringHandle cross_wearable_string = LLXmlTree::addAttributeString("cross_wearable"); + if (!node->getFastAttributeBOOL(cross_wearable_string, mCrossWearable)) + { + mCrossWearable = FALSE; + } + + // Optional camera offsets from the current joint center. Used for generating "hints" (thumbnails). + static LLStdStringHandle camera_distance_string = LLXmlTree::addAttributeString("camera_distance"); + node->getFastAttributeF32( camera_distance_string, mCamDist ); + static LLStdStringHandle camera_angle_string = LLXmlTree::addAttributeString("camera_angle"); + node->getFastAttributeF32( camera_angle_string, mCamAngle ); // in degrees + static LLStdStringHandle camera_elevation_string = LLXmlTree::addAttributeString("camera_elevation"); + node->getFastAttributeF32( camera_elevation_string, mCamElevation ); + + mCamAngle += 180; + + static S32 params_loaded = 0; + + // By default, parameters are displayed in the order in which they appear in the xml file. + // "edit_group_order" overriddes. + static LLStdStringHandle edit_group_order_string = LLXmlTree::addAttributeString("edit_group_order"); + if( !node->getFastAttributeF32( edit_group_order_string, mEditGroupDisplayOrder ) ) + { + mEditGroupDisplayOrder = (F32)params_loaded; + } + + params_loaded++; + + return TRUE; +} + +/*virtual*/ void LLViewerVisualParamInfo::toStream(std::ostream &out) +{ + LLVisualParamInfo::toStream(out); + + out << mWearableType << "\t"; + out << mEditGroup << "\t"; + out << mEditGroupDisplayOrder << "\t"; +} + +//----------------------------------------------------------------------------- +// LLViewerVisualParam() +//----------------------------------------------------------------------------- +LLViewerVisualParam::LLViewerVisualParam() +{ +} + +//----------------------------------------------------------------------------- +// setInfo() +//----------------------------------------------------------------------------- + +BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info) +{ + llassert(mInfo == NULL); + if (info->mID < 0) + return FALSE; + mInfo = info; + mID = info->mID; + setWeight(getDefaultWeight(), FALSE ); + return TRUE; +} + +/* +//============================================================================= +// These virtual functions should always be overridden, +// but are included here for use as templates +//============================================================================= + +//----------------------------------------------------------------------------- +// parseData() +//----------------------------------------------------------------------------- +BOOL LLViewerVisualParam::parseData(LLXmlTreeNode *node) +{ + LLViewerVisualParamInfo* info = new LLViewerVisualParamInfo; + + info->parseXml(node); + if (!setInfo(info)) + return FALSE; + + return TRUE; +} +*/ diff --git a/indra/llappearance/llviewervisualparam.h b/indra/llappearance/llviewervisualparam.h new file mode 100644 index 0000000000..3bc95cbfbf --- /dev/null +++ b/indra/llappearance/llviewervisualparam.h @@ -0,0 +1,109 @@ +/** + * @file llviewervisualparam.h + * @brief viewer side visual params (with data file parsing) + * + * $LicenseInfo:firstyear=2001&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_LLViewerVisualParam_H +#define LL_LLViewerVisualParam_H + +#include "v3math.h" +#include "llstring.h" +#include "llvisualparam.h" + +class LLWearable; + +//----------------------------------------------------------------------------- +// LLViewerVisualParamInfo +//----------------------------------------------------------------------------- +class LLViewerVisualParamInfo : public LLVisualParamInfo +{ + friend class LLViewerVisualParam; +public: + LLViewerVisualParamInfo(); + /*virtual*/ ~LLViewerVisualParamInfo(); + + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + + /*virtual*/ void toStream(std::ostream &out); + +protected: + S32 mWearableType; + BOOL mCrossWearable; + std::string mEditGroup; + F32 mCamDist; + F32 mCamAngle; // degrees + F32 mCamElevation; + F32 mEditGroupDisplayOrder; + BOOL mShowSimple; // show edit controls when in "simple ui" mode? + F32 mSimpleMin; // when in simple UI, apply this minimum, range 0.f to 100.f + F32 mSimpleMax; // when in simple UI, apply this maximum, range 0.f to 100.f +}; + +//----------------------------------------------------------------------------- +// LLViewerVisualParam +// VIRTUAL CLASS +// a viewer side interface class for a generalized parametric modification of the avatar mesh +//----------------------------------------------------------------------------- +class LLViewerVisualParam : public LLVisualParam +{ +public: + LLViewerVisualParam(); + /*virtual*/ ~LLViewerVisualParam(){}; + + // Special: These functions are overridden by child classes + LLViewerVisualParamInfo *getInfo() const { return (LLViewerVisualParamInfo*)mInfo; }; + // This sets mInfo and calls initialization functions + BOOL setInfo(LLViewerVisualParamInfo *info); + + virtual LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0; + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + + // New Virtual functions + virtual F32 getTotalDistortion() = 0; + virtual const LLVector4a& getAvgDistortion() = 0; + virtual F32 getMaxDistortion() = 0; + virtual LLVector4a getVertexDistortion(S32 index, LLPolyMesh *mesh) = 0; + virtual const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **mesh) = 0; + virtual const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0; + + // interface methods + F32 getDisplayOrder() const { return getInfo()->mEditGroupDisplayOrder; } + S32 getWearableType() const { return getInfo()->mWearableType; } + const std::string& getEditGroup() const { return getInfo()->mEditGroup; } + + F32 getCameraDistance() const { return getInfo()->mCamDist; } + F32 getCameraAngle() const { return getInfo()->mCamAngle; } // degrees + F32 getCameraElevation() const { return getInfo()->mCamElevation; } + + BOOL getShowSimple() const { return getInfo()->mShowSimple; } + F32 getSimpleMin() const { return getInfo()->mSimpleMin; } + F32 getSimpleMax() const { return getInfo()->mSimpleMax; } + + BOOL getCrossWearable() const { return getInfo()->mCrossWearable; } + +}; + +#endif // LL_LLViewerVisualParam_H diff --git a/indra/llappearance/llvoavatardefines.cpp b/indra/llappearance/llvoavatardefines.cpp new file mode 100644 index 0000000000..48ef63ab64 --- /dev/null +++ b/indra/llappearance/llvoavatardefines.cpp @@ -0,0 +1,249 @@ +/** + * @file llvoavatardefines.cpp + * @brief Implementation of LLVOAvatarDefines::LLVOAvatarDictionary + * + * $LicenseInfo:firstyear=2001&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 "linden_common.h" + +#include "llvoavatardefines.h" +//#include "llviewercontrol.h" // gSavedSettings + +const S32 LLVOAvatarDefines::SCRATCH_TEX_WIDTH = 512; +const S32 LLVOAvatarDefines::SCRATCH_TEX_HEIGHT = 512; +const S32 LLVOAvatarDefines::IMPOSTOR_PERIOD = 2; + +using namespace LLVOAvatarDefines; + +/********************************************************************************* + * Edit this function to add/remove/change textures and mesh definitions for avatars. + */ + +LLVOAvatarDictionary::Textures::Textures() +{ + addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); + addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", LLWearableType::WT_SHIRT)); + addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", LLWearableType::WT_PANTS)); + addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", TRUE, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", LLWearableType::WT_EYES)); + addEntry(TEX_HAIR, new TextureEntry("hair_grain", TRUE, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", LLWearableType::WT_HAIR)); + addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); + addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); + addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", LLWearableType::WT_SHOES)); + addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", LLWearableType::WT_SOCKS)); + addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET)); + addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET)); + addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", TRUE, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", LLWearableType::WT_GLOVES)); + addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERSHIRT)); + addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERPANTS)); + addEntry(TEX_SKIRT, new TextureEntry("skirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", LLWearableType::WT_SKIRT)); + + addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + + addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); + addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); + addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); + + addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD, "head")); + addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER, "upper")); + addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", FALSE, BAKED_LOWER, "lower")); + addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", FALSE, BAKED_EYES, "eyes")); + addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", FALSE, BAKED_HAIR, "hair")); + addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", FALSE, BAKED_SKIRT, "skirt")); +} + +LLVOAvatarDictionary::BakedTextures::BakedTextures() +{ + // Baked textures + addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED, + "head", "a4b9dc38-e13b-4df9-b284-751efb0566ff", + 3, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, + 5, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED, + "upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4", + 7, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET, + TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, + 8, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED, + "lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d", + 8, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS, + TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, + 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED, + "eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788", + 2, TEX_EYES_IRIS, TEX_EYES_ALPHA, + 2, LLWearableType::WT_EYES, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED, + "skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63", + 1, TEX_SKIRT, + 1, LLWearableType::WT_SKIRT)); + + addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED, + "hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61", + 2, TEX_HAIR, TEX_HAIR_ALPHA, + 2, LLWearableType::WT_HAIR, LLWearableType::WT_ALPHA)); +} + +LLVOAvatarDictionary::Meshes::Meshes() +{ + // Meshes + addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, PN_4)); + addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, PN_5)); + addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, PN_0)); // no baked mesh associated currently + addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, PN_1)); + addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, PN_2)); + addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, PN_3)); + addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, PN_3)); + addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, PN_5)); +} + +/* + * + *********************************************************************************/ + +LLVOAvatarDictionary::LLVOAvatarDictionary() +{ + createAssociations(); +} + +//virtual +LLVOAvatarDictionary::~LLVOAvatarDictionary() +{ +} + +// Baked textures are composites of textures; for each such composited texture, +// map it to the baked texture. +void LLVOAvatarDictionary::createAssociations() +{ + for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); iter++) + { + const EBakedTextureIndex baked_index = (iter->first); + const BakedEntry *dict = (iter->second); + + // For each texture that this baked texture index affects, associate those textures + // with this baked texture index. + for (texture_vec_t::const_iterator local_texture_iter = dict->mLocalTextures.begin(); + local_texture_iter != dict->mLocalTextures.end(); + local_texture_iter++) + { + const ETextureIndex local_texture_index = (ETextureIndex) *local_texture_iter; + mTextures[local_texture_index]->mIsUsedByBakedTexture = true; + mTextures[local_texture_index]->mBakedTextureIndex = baked_index; + } + } + +} + +LLVOAvatarDictionary::TextureEntry::TextureEntry(const std::string &name, + bool is_local_texture, + EBakedTextureIndex baked_texture_index, + const std::string &default_image_name, + LLWearableType::EType wearable_type) : + LLDictionaryEntry(name), + mIsLocalTexture(is_local_texture), + mIsBakedTexture(!is_local_texture), + mIsUsedByBakedTexture(baked_texture_index != BAKED_NUM_INDICES), + mBakedTextureIndex(baked_texture_index), + mDefaultImageName(default_image_name), + mWearableType(wearable_type) +{ +} + +LLVOAvatarDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index, + const std::string &name, + U8 level, + LLJointPickName pick) : + LLDictionaryEntry(name), + mBakedID(baked_index), + mLOD(level), + mPickName(pick) +{ +} +LLVOAvatarDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index, + const std::string &name, + const std::string &hash_name, + U32 num_local_textures, + ... ) : + LLDictionaryEntry(name), + mWearablesHashID(LLUUID(hash_name)), + mTextureIndex(tex_index) +{ + va_list argp; + + va_start(argp, num_local_textures); + + // Read in local textures + for (U8 i=0; i < num_local_textures; i++) + { + ETextureIndex t = (ETextureIndex)va_arg(argp,int); + mLocalTextures.push_back(t); + } + + // Read in number of wearables + const U32 num_wearables = (U32)va_arg(argp,int); + // Read in wearables + for (U8 i=0; i < num_wearables; i++) + { + LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int); + mWearables.push_back(t); + } +} + +// static +ETextureIndex LLVOAvatarDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) +{ + return LLVOAvatarDictionary::getInstance()->getBakedTexture(index)->mTextureIndex; +} + +//static +EBakedTextureIndex LLVOAvatarDictionary::findBakedByRegionName(std::string name) +{ + U8 index = 0; + while (index < BAKED_NUM_INDICES) + { + const BakedEntry *be = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index); + if (be && be->mName.compare(name) == 0) + { + // baked texture found + return (EBakedTextureIndex) index; + } + index++; + } + // baked texture could not be found + return BAKED_NUM_INDICES; +} + +// static +LLWearableType::EType LLVOAvatarDictionary::getTEWearableType(ETextureIndex index ) +{ + return getInstance()->getTexture(index)->mWearableType; +} + diff --git a/indra/llappearance/llvoavatardefines.h b/indra/llappearance/llvoavatardefines.h new file mode 100644 index 0000000000..7b0442bffb --- /dev/null +++ b/indra/llappearance/llvoavatardefines.h @@ -0,0 +1,226 @@ +/** + * @file llvoavatardefines.h + * @brief Various LLAvatarAppearance related definitions + * LLViewerObject + * + * $LicenseInfo:firstyear=2001&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 LLVOAVATAR_DEFINES_H +#define LLVOAVATAR_DEFINES_H + +#include +#include "lljointpickname.h" +#include "llwearable.h" +#include "lldictionary.h" + +namespace LLVOAvatarDefines +{ + +extern const S32 SCRATCH_TEX_WIDTH; +extern const S32 SCRATCH_TEX_HEIGHT; +extern const S32 IMPOSTOR_PERIOD; + +//-------------------------------------------------------------------- +// Enums +//-------------------------------------------------------------------- +enum ETextureIndex +{ + TEX_HEAD_BODYPAINT = 0, + TEX_UPPER_SHIRT, + TEX_LOWER_PANTS, + TEX_EYES_IRIS, + TEX_HAIR, + TEX_UPPER_BODYPAINT, + TEX_LOWER_BODYPAINT, + TEX_LOWER_SHOES, + TEX_HEAD_BAKED, // Pre-composited + TEX_UPPER_BAKED, // Pre-composited + TEX_LOWER_BAKED, // Pre-composited + TEX_EYES_BAKED, // Pre-composited + TEX_LOWER_SOCKS, + TEX_UPPER_JACKET, + TEX_LOWER_JACKET, + TEX_UPPER_GLOVES, + TEX_UPPER_UNDERSHIRT, + TEX_LOWER_UNDERPANTS, + TEX_SKIRT, + TEX_SKIRT_BAKED, // Pre-composited + TEX_HAIR_BAKED, // Pre-composited + TEX_LOWER_ALPHA, + TEX_UPPER_ALPHA, + TEX_HEAD_ALPHA, + TEX_EYES_ALPHA, + TEX_HAIR_ALPHA, + TEX_HEAD_TATTOO, + TEX_UPPER_TATTOO, + TEX_LOWER_TATTOO, + TEX_NUM_INDICES +}; + +enum EBakedTextureIndex +{ + BAKED_HEAD = 0, + BAKED_UPPER, + BAKED_LOWER, + BAKED_EYES, + BAKED_SKIRT, + BAKED_HAIR, + BAKED_NUM_INDICES +}; + +// Reference IDs for each mesh. Used as indices for vector of joints +enum EMeshIndex +{ + MESH_ID_HAIR = 0, + MESH_ID_HEAD, + MESH_ID_EYELASH, + MESH_ID_UPPER_BODY, + MESH_ID_LOWER_BODY, + MESH_ID_EYEBALL_LEFT, + MESH_ID_EYEBALL_RIGHT, + MESH_ID_SKIRT, + MESH_ID_NUM_INDICES +}; + +//-------------------------------------------------------------------- +// Vector Types +//-------------------------------------------------------------------- +typedef std::vector texture_vec_t; +typedef std::vector bakedtexture_vec_t; +typedef std::vector mesh_vec_t; +typedef std::vector wearables_vec_t; + +//------------------------------------------------------------------------ +// LLVOAvatarDictionary +// +// Holds dictionary static entries for textures, baked textures, meshes, etc.; i.e. +// information that is common to all avatars. +// +// This holds const data - it is initialized once and the contents never change after that. +//------------------------------------------------------------------------ +class LLVOAvatarDictionary : public LLSingleton +{ + //-------------------------------------------------------------------- + // Constructors and Destructors + //-------------------------------------------------------------------- +public: + LLVOAvatarDictionary(); + virtual ~LLVOAvatarDictionary(); +private: + void createAssociations(); + + //-------------------------------------------------------------------- + // Local and baked textures + //-------------------------------------------------------------------- +public: + struct TextureEntry : public LLDictionaryEntry + { + TextureEntry(const std::string &name, // this must match the xml name used by LLTexLayerInfo::parseXml + bool is_local_texture, + EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES, + const std::string& default_image_name = "", + LLWearableType::EType wearable_type = LLWearableType::WT_INVALID); + const std::string mDefaultImageName; + const LLWearableType::EType mWearableType; + // It's either a local texture xor baked + BOOL mIsLocalTexture; + BOOL mIsBakedTexture; + // If it's a local texture, it may be used by a baked texture + BOOL mIsUsedByBakedTexture; + EBakedTextureIndex mBakedTextureIndex; + }; + + struct Textures : public LLDictionary + { + Textures(); + } mTextures; + const TextureEntry* getTexture(ETextureIndex index) const { return mTextures.lookup(index); } + const Textures& getTextures() const { return mTextures; } + + //-------------------------------------------------------------------- + // Meshes + //-------------------------------------------------------------------- +public: + struct MeshEntry : public LLDictionaryEntry + { + MeshEntry(EBakedTextureIndex baked_index, + const std::string &name, // names of mesh types as they are used in avatar_lad.xml + U8 level, + LLJointPickName pick); + // Levels of Detail for each mesh. Must match levels of detail present in avatar_lad.xml + // Otherwise meshes will be unable to be found, or levels of detail will be ignored + const U8 mLOD; + const EBakedTextureIndex mBakedID; + const LLJointPickName mPickName; + }; + + struct Meshes : public LLDictionary + { + Meshes(); + } mMeshes; + const MeshEntry* getMesh(EMeshIndex index) const { return mMeshes.lookup(index); } + const Meshes& getMeshes() const { return mMeshes; } + + //-------------------------------------------------------------------- + // Baked Textures + //-------------------------------------------------------------------- +public: + struct BakedEntry : public LLDictionaryEntry + { + BakedEntry(ETextureIndex tex_index, + const std::string &name, // unused, but necessary for templating. + const std::string &hash_name, + U32 num_local_textures, ... ); // # local textures, local texture list, # wearables, wearable list + // Local Textures + const ETextureIndex mTextureIndex; + texture_vec_t mLocalTextures; + // Wearables + const LLUUID mWearablesHashID; + wearables_vec_t mWearables; + }; + + struct BakedTextures: public LLDictionary + { + BakedTextures(); + } mBakedTextures; + const BakedEntry* getBakedTexture(EBakedTextureIndex index) const { return mBakedTextures.lookup(index); } + const BakedTextures& getBakedTextures() const { return mBakedTextures; } + + //-------------------------------------------------------------------- + // Convenience Functions + //-------------------------------------------------------------------- +public: + // Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED + static ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t); + + // find a baked texture index based on its name + static EBakedTextureIndex findBakedByRegionName(std::string name); + + // Given a texture entry, determine which wearable type owns it. + static LLWearableType::EType getTEWearableType(ETextureIndex index); + +}; // End LLVOAvatarDictionary + +} // End namespace LLVOAvatarDefines + +#endif //LL_VO_AVATARDEFINES_H diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index d72999d8c7..64bd921ec5 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -24,14 +24,13 @@ * $/LicenseInfo$ */ -//#include "llviewerprecompiledheaders.h" +#include "linden_common.h" -//#include "llagent.h" -//#include "llagentcamera.h" -#include "llagentwearables.h" +#include "llavatarappearance.h" +//#include "llagentwearables.h" //#include "lldictionary.h" //#include "llfloatersidepanelcontainer.h" -//#include "lllocaltextureobject.h" +#include "lllocaltextureobject.h" //#include "llnotificationsutil.h" //#include "llviewertexturelist.h" //#include "llinventorymodel.h" @@ -39,12 +38,11 @@ //#include "llsidepanelappearance.h" #include "lltexlayer.h" //#include "lltexglobalcolor.h" +#include "lltexturemanagerbridge.h" //#include "lltrans.h" //#include "llviewerregion.h" #include "llvisualparam.h" -//#include "llvoavatar.h" -//#include "llvoavatarself.h" -//#include "llvoavatardefines.h" +#include "llvoavatardefines.h" #include "llwearable.h" //#include "llviewercontrol.h" @@ -53,52 +51,10 @@ using namespace LLVOAvatarDefines; // static S32 LLWearable::sCurrentDefinitionVersion = 1; -// support class - remove for 2.1 (hackity hack hack) -class LLOverrideBakedTextureUpdate -{ -public: - LLOverrideBakedTextureUpdate(bool temp_state) - { - U32 num_bakes = (U32) LLVOAvatarDefines::BAKED_NUM_INDICES; - for( U32 index = 0; index < num_bakes; ++index ) - { - composite_enabled[index] = gAgentAvatarp->isCompositeUpdateEnabled(index); - } - gAgentAvatarp->setCompositeUpdatesEnabled(temp_state); - } - - ~LLOverrideBakedTextureUpdate() - { - U32 num_bakes = (U32)LLVOAvatarDefines::BAKED_NUM_INDICES; - for( U32 index = 0; index < num_bakes; ++index ) - { - gAgentAvatarp->setCompositeUpdatesEnabled(index, composite_enabled[index]); - } - } -private: - bool composite_enabled[LLVOAvatarDefines::BAKED_NUM_INDICES]; -}; - // Private local functions static std::string terse_F32_to_string(F32 f); -static std::string asset_id_to_filename(const LLUUID &asset_id); - -LLWearable::LLWearable(const LLTransactionID& transaction_id) : - mDefinitionVersion(LLWearable::sCurrentDefinitionVersion), - mType(LLWearableType::WT_INVALID) -{ - mTransactionID = transaction_id; - mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); -} - -LLWearable::LLWearable(const LLAssetID& asset_id) : - mDefinitionVersion( LLWearable::sCurrentDefinitionVersion ), - mType(LLWearableType::WT_INVALID) -{ - mAssetID = asset_id; - mTransactionID.setNull(); -} +// virtual LLWearable::~LLWearable() { } @@ -118,6 +74,7 @@ LLAssetType::EType LLWearable::getAssetType() const return LLWearableType::getAssetType(mType); } +// virtual BOOL LLWearable::exportFile(LLFILE* file) const { // header and version @@ -178,16 +135,16 @@ BOOL LLWearable::exportFile(LLFILE* file) const } // texture entries - S32 num_textures = mTEMap.size(); + S32 num_textures = mTextureIDMap.size(); if( fprintf( file, "textures %d\n", num_textures ) < 0 ) { return FALSE; } - for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter) + for (texture_id_map_t::const_iterator iter = mTextureIDMap.begin(); iter != mTextureIDMap.end(); ++iter) { S32 te = iter->first; - const LLUUID& image_id = iter->second->getID(); + const LLUUID& image_id = iter->second; if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 ) { return FALSE; @@ -197,40 +154,8 @@ BOOL LLWearable::exportFile(LLFILE* file) const } -void LLWearable::createVisualParams() -{ - for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); - param; - param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam()) - { - if (param->getWearableType() == mType) - { - addVisualParam(param->cloneParam(this)); - } - } - - // resync driver parameters to point to the newly cloned driven parameters - for (visual_param_index_map_t::iterator param_iter = mVisualParamIndexMap.begin(); - param_iter != mVisualParamIndexMap.end(); - ++param_iter) - { - LLVisualParam* param = param_iter->second; - LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam; - // need this line to disambiguate between versions of LLCharacter::getVisualParam() - LLVisualParam*(LLVOAvatarSelf::*avatar_function)(S32)const = &LLVOAvatarSelf::getVisualParam; - param->resetDrivenParams(); - if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false)) - { - if( !param->linkDrivenParams(boost::bind(avatar_function,gAgentAvatarp.get(),_1 ), true)) - { - llwarns << "could not link driven params for wearable " << getName() << " id: " << param->getID() << llendl; - continue; - } - } - } -} - -BOOL LLWearable::importFile( LLFILE* file ) +// virtual +LLWearable::EImportResult LLWearable::importFile( LLFILE* file ) { // *NOTE: changing the type or size of this buffer will require // changes in the fscanf() code below. You would be better off @@ -238,23 +163,14 @@ BOOL LLWearable::importFile( LLFILE* file ) char text_buffer[2048]; /* Flawfinder: ignore */ S32 fields_read = 0; - // suppress texlayerset updates while wearables are being imported. Layersets will be updated - // when the wearables are "worn", not loaded. Note state will be restored when this object is destroyed. - LLOverrideBakedTextureUpdate stop_bakes(false); - // read header and version fields_read = fscanf( file, "LLWearable version %d\n", &mDefinitionVersion ); if( fields_read != 1 ) { - // Shouldn't really log the asset id for security reasons, but - // we need it in this case. - llwarns << "Bad Wearable asset header: " << mAssetID << llendl; - //gVFS->dumpMap(); - return FALSE; + return LLWearable::BAD_HEADER; } - - // Temoprary hack to allow wearables with definition version 24 to still load. + // Temporary hack to allow wearables with definition version 24 to still load. // This should only affect lindens and NDA'd testers who have saved wearables in 2.0 // the extra check for version == 24 can be removed before release, once internal testers // have loaded these wearables again. See hack pt 2 at bottom of function to ensure that @@ -262,7 +178,7 @@ BOOL LLWearable::importFile( LLFILE* file ) if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 ) { llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; - return FALSE; + return LLWearable::FAILURE; } // name @@ -282,10 +198,9 @@ BOOL LLWearable::importFile( LLFILE* file ) if( (1 != fields_read) || (fgetc( file ) != '\n') ) /* Flawfinder: ignore */ { llwarns << "Bad Wearable asset: early end of file" << llendl; - return FALSE; + return LLWearable::FAILURE; } mName = text_buffer; - LLStringUtil::truncate(mName, DB_INV_ITEM_NAME_STR_LEN ); } // description @@ -305,10 +220,9 @@ BOOL LLWearable::importFile( LLFILE* file ) if( (1 != fields_read) || (fgetc( file ) != '\n') ) /* Flawfinder: ignore */ { llwarns << "Bad Wearable asset: early end of file" << llendl; - return FALSE; + return LLWearable::FAILURE; } mDescription = text_buffer; - LLStringUtil::truncate(mDescription, DB_INV_ITEM_DESC_STR_LEN ); } // permissions @@ -317,11 +231,11 @@ BOOL LLWearable::importFile( LLFILE* file ) if( (fields_read != 1) || (perm_version != 0) ) { llwarns << "Bad Wearable asset: missing permissions" << llendl; - return FALSE; + return LLWearable::FAILURE; } if( !mPermissions.importFile( file ) ) { - return FALSE; + return LLWearable::FAILURE; } // sale info @@ -330,7 +244,7 @@ BOOL LLWearable::importFile( LLFILE* file ) if( (fields_read != 1) || (sale_info_version != 0) ) { llwarns << "Bad Wearable asset: missing sale_info" << llendl; - return FALSE; + return LLWearable::FAILURE; } // Sale info used to contain next owner perm. It is now in the // permissions. Thus, we read that out, and fix legacy @@ -340,7 +254,7 @@ BOOL LLWearable::importFile( LLFILE* file ) U32 perm_mask = 0; if( !mSaleInfo.importFile(file, has_perm_mask, perm_mask) ) { - return FALSE; + return LLWearable::FAILURE; } if(has_perm_mask) { @@ -358,7 +272,7 @@ BOOL LLWearable::importFile( LLFILE* file ) if( fields_read != 1 ) { llwarns << "Bad Wearable asset: bad type" << llendl; - return FALSE; + return LLWearable::FAILURE; } if( 0 <= type && type < LLWearableType::WT_COUNT ) { @@ -368,7 +282,7 @@ BOOL LLWearable::importFile( LLFILE* file ) { mType = LLWearableType::WT_COUNT; llwarns << "Bad Wearable asset: bad type #" << type << llendl; - return FALSE; + return LLWearable::FAILURE; } // parameters header @@ -377,7 +291,7 @@ BOOL LLWearable::importFile( LLFILE* file ) if( fields_read != 1 ) { llwarns << "Bad Wearable asset: missing parameters block" << llendl; - return FALSE; + return LLWearable::FAILURE; } if( num_parameters != mVisualParamIndexMap.size() ) @@ -395,7 +309,7 @@ BOOL LLWearable::importFile( LLFILE* file ) if( fields_read != 2 ) { llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl; - return FALSE; + return LLWearable::FAILURE; } mSavedVisualParamMap[param_id] = param_weight; } @@ -406,10 +320,11 @@ BOOL LLWearable::importFile( LLFILE* file ) if( fields_read != 1 ) { llwarns << "Bad Wearable asset: missing textures block" << llendl; - return FALSE; + return LLWearable::FAILURE; } // textures + mTextureIDMap.clear(); for( i = 0; i < num_textures; i++ ) { S32 te = 0; @@ -420,367 +335,21 @@ BOOL LLWearable::importFile( LLFILE* file ) if( fields_read != 2 ) { llwarns << "Bad Wearable asset: bad texture, #" << i << llendl; - return FALSE; + return LLWearable::FAILURE; } if( !LLUUID::validate( text_buffer ) ) { llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl; - return FALSE; + return LLWearable::FAILURE; } LLUUID id = LLUUID(text_buffer); - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( id ); - if( mTEMap.find(te) != mTEMap.end() ) - { - delete mTEMap[te]; - } - if( mSavedTEMap.find(te) != mSavedTEMap.end() ) - { - delete mSavedTEMap[te]; - } - - if(gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime")) - { - image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te), NULL); - } - LLUUID textureid(text_buffer); - mTEMap[te] = new LLLocalTextureObject(image, textureid); - mSavedTEMap[te] = new LLLocalTextureObject(image, textureid); - createLayers(te); - } - - // copy all saved param values to working params - revertValues(); - - return TRUE; -} - - -// Avatar parameter and texture definitions can change over time. -// This function returns true if parameters or textures have been added or removed -// since this wearable was created. -BOOL LLWearable::isOldVersion() const -{ - if (!isAgentAvatarValid()) return FALSE; - - if( LLWearable::sCurrentDefinitionVersion < mDefinitionVersion ) - { - llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; - llassert(0); - } - - if( LLWearable::sCurrentDefinitionVersion != mDefinitionVersion ) - { - return TRUE; - } - - S32 param_count = 0; - for( LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); - param; - param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam() ) - { - if( (param->getWearableType() == mType) && (param->isTweakable() ) ) - { - param_count++; - if( !is_in_map(mVisualParamIndexMap, param->getID() ) ) - { - return TRUE; - } - } - } - if( param_count != mVisualParamIndexMap.size() ) - { - return TRUE; - } - - - S32 te_count = 0; - for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) - { - if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) - { - te_count++; - if( !is_in_map(mTEMap, te ) ) - { - return TRUE; - } - } - } - if( te_count != mTEMap.size() ) - { - return TRUE; - } - - return FALSE; -} - -// Avatar parameter and texture definitions can change over time. -// * If parameters or textures have been REMOVED since the wearable was created, -// they're just ignored, so we consider the wearable clean even though isOldVersion() -// will return true. -// * If parameters or textures have been ADDED since the wearable was created, -// they are taken to have default values, so we consider the wearable clean -// only if those values are the same as the defaults. -BOOL LLWearable::isDirty() const -{ - if (!isAgentAvatarValid()) return FALSE; - - for( LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); - param; - param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam() ) - { - if( (param->getWearableType() == mType) - && (param->isTweakable() ) - && !param->getCrossWearable()) - { - F32 current_weight = getVisualParamWeight(param->getID()); - current_weight = llclamp( current_weight, param->getMinWeight(), param->getMaxWeight() ); - F32 saved_weight = get_if_there(mSavedVisualParamMap, param->getID(), param->getDefaultWeight()); - saved_weight = llclamp( saved_weight, param->getMinWeight(), param->getMaxWeight() ); - - U8 a = F32_to_U8( saved_weight, param->getMinWeight(), param->getMaxWeight() ); - U8 b = F32_to_U8( current_weight, param->getMinWeight(), param->getMaxWeight() ); - if( a != b ) - { - return TRUE; - } - } - } - - for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) - { - if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) - { - te_map_t::const_iterator current_iter = mTEMap.find(te); - if(current_iter != mTEMap.end()) - { - const LLUUID& current_image_id = current_iter->second->getID(); - te_map_t::const_iterator saved_iter = mSavedTEMap.find(te); - if(saved_iter != mSavedTEMap.end()) - { - const LLUUID& saved_image_id = saved_iter->second->getID(); - if (saved_image_id != current_image_id) - { - // saved vs current images are different, wearable is dirty - return TRUE; - } - } - else - { - // image found in current image list but not saved image list - return TRUE; - } - } - } - } - - return FALSE; -} - - -void LLWearable::setParamsToDefaults() -{ - if (!isAgentAvatarValid()) return; - - for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam() ) - { - if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) ) - { - setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE); - } - } -} - -void LLWearable::setTexturesToDefaults() -{ - for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) - { - if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) - { - LLUUID id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); - LLViewerFetchedTexture * image = LLViewerTextureManager::getFetchedTexture( id ); - if( mTEMap.find(te) == mTEMap.end() ) - { - mTEMap[te] = new LLLocalTextureObject(image, id); - createLayers(te); - } - else - { - // Local Texture Object already created, just set image and UUID - LLLocalTextureObject *lto = mTEMap[te]; - lto->setID(id); - lto->setImage(image); - } - } - } -} - -// Updates the user's avatar's appearance -void LLWearable::writeToAvatar() -{ - if (!isAgentAvatarValid()) return; - - ESex old_sex = gAgentAvatarp->getSex(); - - // Pull params - for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam() ) - { - // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the - // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way. - if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) ) - { - S32 param_id = param->getID(); - F32 weight = getVisualParamWeight(param_id); - - gAgentAvatarp->setVisualParamWeight( param_id, weight, FALSE ); - } - } - - // Pull texture entries - for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) - { - if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) - { - te_map_t::const_iterator iter = mTEMap.find(te); - LLUUID image_id; - if(iter != mTEMap.end()) - { - image_id = iter->second->getID(); - } - else - { - image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); - } - LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE ); - // MULTI-WEARABLE: assume index 0 will be used when writing to avatar. TODO: eliminate the need for this. - gAgentAvatarp->setLocalTextureTE(te, image, 0); - } - } - - ESex new_sex = gAgentAvatarp->getSex(); - if( old_sex != new_sex ) - { - gAgentAvatarp->updateSexDependentLayerSets( FALSE ); - } - -// if( upload_bake ) -// { -// gAgent.sendAgentSetAppearance(); -// } -} - - -// Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values. -// static -void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ) -{ - if (!isAgentAvatarValid()) return; - - // You can't just remove body parts. - if( (type == LLWearableType::WT_SHAPE) || - (type == LLWearableType::WT_SKIN) || - (type == LLWearableType::WT_HAIR) || - (type == LLWearableType::WT_EYES) ) - { - return; - } - - // Pull params - for( LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam() ) - { - if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable() ) ) - { - S32 param_id = param->getID(); - gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight(), upload_bake ); - } - } - - if(gAgentCamera.cameraCustomizeAvatar()) - { - LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit")); - } - - gAgentAvatarp->updateVisualParams(); - gAgentAvatarp->wearableUpdated(type, FALSE); - -// if( upload_bake ) -// { -// gAgent.sendAgentSetAppearance(); -// } -} - -// Does not copy mAssetID. -// Definition version is current: removes obsolete enties and creates default values for new ones. -void LLWearable::copyDataFrom(const LLWearable* src) -{ - if (!isAgentAvatarValid()) return; - - mDefinitionVersion = LLWearable::sCurrentDefinitionVersion; - - mName = src->mName; - mDescription = src->mDescription; - mPermissions = src->mPermissions; - mSaleInfo = src->mSaleInfo; - - setType(src->mType); - - mSavedVisualParamMap.clear(); - // Deep copy of mVisualParamMap (copies only those params that are current, filling in defaults where needed) - for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); - param; - param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam() ) - { - if( (param->getWearableType() == mType) ) - { - S32 id = param->getID(); - F32 weight = src->getVisualParamWeight(id); - mSavedVisualParamMap[id] = weight; - } - } - - destroyTextures(); - // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) - for (S32 te = 0; te < TEX_NUM_INDICES; te++) - { - if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) - { - te_map_t::const_iterator iter = src->mTEMap.find(te); - LLUUID image_id; - LLViewerFetchedTexture *image = NULL; - if(iter != src->mTEMap.end()) - { - image = src->getLocalTextureObject(te)->getImage(); - image_id = src->getLocalTextureObject(te)->getID(); - mTEMap[te] = new LLLocalTextureObject(image, image_id); - mSavedTEMap[te] = new LLLocalTextureObject(image, image_id); - mTEMap[te]->setBakedReady(src->getLocalTextureObject(te)->getBakedReady()); - mTEMap[te]->setDiscard(src->getLocalTextureObject(te)->getDiscard()); - } - else - { - image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); - image = LLViewerTextureManager::getFetchedTexture( image_id ); - mTEMap[te] = new LLLocalTextureObject(image, image_id); - mSavedTEMap[te] = new LLLocalTextureObject(image, image_id); - } - createLayers(te); - } + mTextureIDMap[te] = id; } - // Probably reduntant, but ensure that the newly created wearable is not dirty by setting current value of params in new wearable - // to be the same as the saved values (which were loaded from src at param->cloneParam(this)) - revertValues(); + return LLWearable::SUCCESS; } -void LLWearable::setItemID(const LLUUID& item_id) -{ - mItemID = item_id; -} - -const LLUUID& LLWearable::getItemID() const -{ - return mItemID; -} void LLWearable::setType(LLWearableType::EType type) { @@ -788,51 +357,6 @@ void LLWearable::setType(LLWearableType::EType type) createVisualParams(); } -LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) -{ - te_map_t::iterator iter = mTEMap.find(index); - if( iter != mTEMap.end() ) - { - LLLocalTextureObject* lto = iter->second; - return lto; - } - return NULL; -} - -const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const -{ - te_map_t::const_iterator iter = mTEMap.find(index); - if( iter != mTEMap.end() ) - { - const LLLocalTextureObject* lto = iter->second; - return lto; - } - return NULL; -} - -std::vector LLWearable::getLocalTextureListSeq() -{ - std::vector result; - - for(te_map_t::const_iterator iter = mTEMap.begin(); - iter != mTEMap.end(); iter++) - { - LLLocalTextureObject* lto = iter->second; - result.push_back(lto); - } - - return result; -} - -void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject <o) -{ - if( mTEMap.find(index) != mTEMap.end() ) - { - mTEMap.erase(index); - } - mTEMap[index] = new LLLocalTextureObject(lto); -} - void LLWearable::addVisualParam(LLVisualParam *param) { @@ -845,17 +369,6 @@ void LLWearable::addVisualParam(LLVisualParam *param) mSavedVisualParamMap[param->getID()] = param->getDefaultWeight(); } -void LLWearable::setVisualParams() -{ - for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); iter++) - { - S32 id = iter->first; - LLVisualParam *wearable_param = iter->second; - F32 value = wearable_param->getWeight(); - gAgentAvatarp->setVisualParamWeight(id, value, FALSE); - } -} - void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake) { @@ -918,7 +431,7 @@ LLColor4 LLWearable::getClothesColor(S32 te) const { LLColor4 color; U32 param_name[3]; - if( LLVOAvatar::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) + if( LLAvatarAppearance::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) { for( U8 index = 0; index < 3; index++ ) { @@ -931,7 +444,7 @@ LLColor4 LLWearable::getClothesColor(S32 te) const void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ) { U32 param_name[3]; - if( LLVOAvatar::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) + if( LLAvatarAppearance::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) { for( U8 index = 0; index < 3; index++ ) { @@ -940,312 +453,6 @@ void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload } } -void LLWearable::revertValues() -{ - //update saved settings so wearable is no longer dirty - // non-driver params first - for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) - { - S32 id = iter->first; - F32 value = iter->second; - LLVisualParam *param = getVisualParam(id); - if(param && !dynamic_cast(param) ) - { - setVisualParamWeight(id, value, TRUE); - } - } - - //then driver params - for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) - { - S32 id = iter->first; - F32 value = iter->second; - LLVisualParam *param = getVisualParam(id); - if(param && dynamic_cast(param) ) - { - setVisualParamWeight(id, value, TRUE); - } - } - - // make sure that saved values are sane - for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) - { - S32 id = iter->first; - LLVisualParam *param = getVisualParam(id); - if( param ) - { - mSavedVisualParamMap[id] = param->getWeight(); - } - } - - syncImages(mSavedTEMap, mTEMap); - - - LLSidepanelAppearance *panel = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); - if( panel ) - { - panel->updateScrollingPanelList(); - } -} - -BOOL LLWearable::isOnTop() const -{ - return (this == gAgentWearables.getTopWearable(mType)); -} - -void LLWearable::createLayers(S32 te) -{ - LLTexLayerSet *layer_set = gAgentAvatarp->getLayerSet((ETextureIndex)te); - if (layer_set) - { - layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this); - } - else - { - llerrs << "could not find layerset for LTO in wearable!" << llendl; - } -} - -void LLWearable::saveValues() -{ - //update saved settings so wearable is no longer dirty - mSavedVisualParamMap.clear(); - for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter) - { - S32 id = iter->first; - LLVisualParam *wearable_param = iter->second; - F32 value = wearable_param->getWeight(); - mSavedVisualParamMap[id] = value; - } - - // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) - syncImages(mTEMap, mSavedTEMap); - - - LLSidepanelAppearance *panel = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); - if( panel ) - { - panel->updateScrollingPanelList(); - } -} - -void LLWearable::syncImages(te_map_t &src, te_map_t &dst) -{ - // Deep copy of src (copies only those tes that are current, filling in defaults where needed) - for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) - { - if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) - { - te_map_t::const_iterator iter = src.find(te); - LLUUID image_id; - LLViewerFetchedTexture *image = NULL; - LLLocalTextureObject *lto = NULL; - if(iter != src.end()) - { - // there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map. - lto = iter->second; - image = lto->getImage(); - image_id = lto->getID(); - } - else - { - // there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map. - image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); - image = LLViewerTextureManager::getFetchedTexture( image_id ); - } - - if( dst.find(te) != dst.end() ) - { - // there's already an entry in the destination map for the texture. Just update its values. - dst[te]->setImage(image); - dst[te]->setID(image_id); - } - else - { - // no entry found in the destination map, we need to create a new Local Texture Object - dst[te] = new LLLocalTextureObject(image, image_id); - } - - if( lto ) - { - // If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map. - dst[te]->setBakedReady(lto->getBakedReady()); - dst[te]->setDiscard(lto->getDiscard()); - } - } - } -} - -void LLWearable::destroyTextures() -{ - for( te_map_t::iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter ) - { - LLLocalTextureObject *lto = iter->second; - delete lto; - } - mTEMap.clear(); - for( te_map_t::iterator iter = mSavedTEMap.begin(); iter != mSavedTEMap.end(); ++iter ) - { - LLLocalTextureObject *lto = iter->second; - delete lto; - } - mSavedTEMap.clear(); -} - -void LLWearable::pullCrossWearableValues() -{ - // scan through all of the avatar's visual parameters - for (LLViewerVisualParam* param = (LLViewerVisualParam*) gAgentAvatarp->getFirstVisualParam(); - param; - param = (LLViewerVisualParam*) gAgentAvatarp->getNextVisualParam()) - { - if( param ) - { - LLDriverParam *driver_param = dynamic_cast(param); - if(driver_param) - { - // parameter is a driver parameter, have it update its - driver_param->updateCrossDrivenParams(getType()); - } - } - } -} - - -void LLWearable::setLabelUpdated() const -{ - gInventory.addChangedMask(LLInventoryObserver::LABEL, getItemID()); -} - -void LLWearable::refreshName() -{ - LLUUID item_id = getItemID(); - LLInventoryItem* item = gInventory.getItem(item_id); - if( item ) - { - mName = item->getName(); - } -} - -struct LLWearableSaveData -{ - LLWearableType::EType mType; -}; - -void LLWearable::saveNewAsset() const -{ -// llinfos << "LLWearable::saveNewAsset() type: " << getTypeName() << llendl; - //llinfos << *this << llendl; - - const std::string filename = asset_id_to_filename(mAssetID); - LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ - BOOL successful_save = FALSE; - if(fp && exportFile(fp)) - { - successful_save = TRUE; - } - if(fp) - { - fclose(fp); - fp = NULL; - } - if(!successful_save) - { - std::string buffer = llformat("Unable to save '%s' to wearable file.", mName.c_str()); - llwarns << buffer << llendl; - - LLSD args; - args["NAME"] = mName; - LLNotificationsUtil::add("CannotSaveWearableOutOfSpace", args); - return; - } - - // save it out to database - if( gAssetStorage ) - { - /* - std::string url = gAgent.getRegion()->getCapability("NewAgentInventory"); - if (!url.empty()) - { - llinfos << "Update Agent Inventory via capability" << llendl; - LLSD body; - body["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::assetToFolderType(getAssetType())); - body["asset_type"] = LLAssetType::lookup(getAssetType()); - body["inventory_type"] = LLInventoryType::lookup(LLInventoryType::IT_WEARABLE); - body["name"] = getName(); - body["description"] = getDescription(); - LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, filename)); - } - else - { - } - */ - LLWearableSaveData* data = new LLWearableSaveData; - data->mType = mType; - gAssetStorage->storeAssetData(filename, mTransactionID, getAssetType(), - &LLWearable::onSaveNewAssetComplete, - (void*)data); - } -} - -// static -void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userdata, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLWearableSaveData* data = (LLWearableSaveData*)userdata; - const std::string& type_name = LLWearableType::getTypeName(data->mType); - if(0 == status) - { - // Success - llinfos << "Saved wearable " << type_name << llendl; - } - else - { - std::string buffer = llformat("Unable to save %s to central asset store.", type_name.c_str()); - llwarns << buffer << " Status: " << status << llendl; - LLSD args; - args["NAME"] = type_name; - LLNotificationsUtil::add("CannotSaveToAssetStore", args); - } - - // Delete temp file - const std::string src_filename = asset_id_to_filename(new_asset_id); - LLFile::remove(src_filename); - - // delete the context data - delete data; - -} - -std::ostream& operator<<(std::ostream &s, const LLWearable &w) -{ - s << "wearable " << LLWearableType::getTypeName(w.mType) << "\n"; - s << " Name: " << w.mName << "\n"; - s << " Desc: " << w.mDescription << "\n"; - //w.mPermissions - //w.mSaleInfo - - s << " Params:" << "\n"; - for (LLWearable::visual_param_index_map_t::const_iterator iter = w.mVisualParamIndexMap.begin(); - iter != w.mVisualParamIndexMap.end(); ++iter) - { - S32 param_id = iter->first; - LLVisualParam *wearable_param = iter->second; - F32 param_weight = wearable_param->getWeight(); - s << " " << param_id << " " << param_weight << "\n"; - } - - s << " Textures:" << "\n"; - for (LLWearable::te_map_t::const_iterator iter = w.mTEMap.begin(); - iter != w.mTEMap.end(); ++iter) - { - S32 te = iter->first; - const LLUUID& image_id = iter->second->getID(); - s << " " << te << " " << image_id << "\n"; - } - return s; -} - - std::string terse_F32_to_string(F32 f) { std::string r = llformat("%.2f", f); @@ -1276,10 +483,3 @@ std::string terse_F32_to_string(F32 f) return r; } -std::string asset_id_to_filename(const LLUUID &asset_id) -{ - std::string asset_id_string; - asset_id.toString(asset_id_string); - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id_string) + ".wbl"; - return filename; -} diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index c8f9ef1fb9..56c931e43b 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -27,31 +27,25 @@ #ifndef LL_LLWEARABLE_H #define LL_LLWEARABLE_H +#include "llextendedstatus.h" //#include "lluuid.h" //#include "llstring.h" -//#include "llpermissions.h" -//#include "llsaleinfo.h" +#include "llpermissions.h" +#include "llsaleinfo.h" //#include "llassetstorage.h" -//#include "llwearabletype.h" +#include "llwearabletype.h" //#include "llfile.h" -//#include "lllocaltextureobject.h" +#include "lllocaltextureobject.h" -class LLViewerInventoryItem; class LLVisualParam; class LLTexGlobalColorInfo; class LLTexGlobalColor; class LLWearable { - friend class LLWearableList; - //-------------------------------------------------------------------- // Constructors and destructors //-------------------------------------------------------------------- -private: - // Private constructors used by LLWearableList - LLWearable(const LLTransactionID& transactionID); - LLWearable(const LLAssetID& assetID); public: virtual ~LLWearable(); @@ -59,10 +53,7 @@ public: // Accessors //-------------------------------------------------------------------- public: - const LLUUID& getItemID() const; - const LLAssetID& getAssetID() const { return mAssetID; } - const LLTransactionID& getTransactionID() const { return mTransactionID; } - LLWearableType::EType getType() const { return mType; } + LLWearableType::EType getType() const { return mType; } void setType(LLWearableType::EType type); const std::string& getName() const { return mName; } void setName(const std::string& name) { mName = name; } @@ -81,36 +72,22 @@ public: public: typedef std::vector visual_param_vec_t; - BOOL isDirty() const; - BOOL isOldVersion() const; - - void writeToAvatar(); - void removeFromAvatar( BOOL upload_bake ) { LLWearable::removeFromAvatar( mType, upload_bake ); } - static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ); - - BOOL exportFile(LLFILE* file) const; - BOOL importFile(LLFILE* file); - - void setParamsToDefaults(); - void setTexturesToDefaults(); + enum EImportResult + { + FAILURE = 0, + SUCCESS, + BAD_HEADER + }; + virtual BOOL exportFile(LLFILE* file) const; + virtual EImportResult importFile(LLFILE* file); - void saveNewAsset() const; - static void onSaveNewAssetComplete( const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status ); + virtual LLLocalTextureObject* getLocalTextureObject(S32 index) = 0; + virtual void writeToAvatar() = 0; - void copyDataFrom(const LLWearable* src); static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; } - friend std::ostream& operator<<(std::ostream &s, const LLWearable &w); - void setItemID(const LLUUID& item_id); - - LLLocalTextureObject* getLocalTextureObject(S32 index); - const LLLocalTextureObject* getLocalTextureObject(S32 index) const; - std::vector getLocalTextureListSeq(); - - void setLocalTextureObject(S32 index, LLLocalTextureObject <o); void addVisualParam(LLVisualParam *param); - void setVisualParams(); void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); F32 getVisualParamWeight(S32 index) const; LLVisualParam* getVisualParam(S32 index) const; @@ -120,27 +97,11 @@ public: LLColor4 getClothesColor(S32 te) const; void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ); - void revertValues(); - void saveValues(); - void pullCrossWearableValues(); - - BOOL isOnTop() const; + typedef std::map texture_id_map_t; + const texture_id_map_t& getTextureIDMap() const { return mTextureIDMap; } - // Something happened that requires the wearable's label to be updated (e.g. worn/unworn). - void setLabelUpdated() const; - - // the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem, - // not the wearable asset itself. - void refreshName(); - -private: - typedef std::map te_map_t; - typedef std::map visual_param_index_map_t; - - void createLayers(S32 te); - void createVisualParams(); - void syncImages(te_map_t &src, te_map_t &dst); - void destroyTextures(); +protected: + virtual void createVisualParams() = 0; static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml. S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created. @@ -148,18 +109,16 @@ private: std::string mDescription; LLPermissions mPermissions; LLSaleInfo mSaleInfo; - LLAssetID mAssetID; - LLTransactionID mTransactionID; LLWearableType::EType mType; typedef std::map param_map_t; param_map_t mSavedVisualParamMap; // last saved version of visual params + typedef std::map visual_param_index_map_t; visual_param_index_map_t mVisualParamIndexMap; - te_map_t mTEMap; // maps TE to LocalTextureObject - te_map_t mSavedTEMap; // last saved version of TEMap - LLUUID mItemID; // ID of the inventory item in the agent's inventory + // *TODO: Lazy mutable. Find a better way? + mutable texture_id_map_t mTextureIDMap; }; #endif // LL_LLWEARABLE_H diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp new file mode 100644 index 0000000000..d47702ff4d --- /dev/null +++ b/indra/llappearance/llwearabletype.cpp @@ -0,0 +1,162 @@ +/** + * @file llwearabletype.cpp + * @brief LLWearableType class implementation + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +//#include "llviewerprecompiledheaders.h" +#include "linden_common.h" + +#include "llwearabletype.h" +//#include "llinventoryfunctions.h" +#include "llinventoryicon.h" +#include "lltrans.h" + +struct WearableEntry : public LLDictionaryEntry +{ + WearableEntry(const std::string &name, + const std::string& default_new_name, + LLAssetType::EType assetType, + LLInventoryIcon::EIconName iconName, + BOOL disable_camera_switch = FALSE, + BOOL allow_multiwear = TRUE) : + LLDictionaryEntry(name), + mAssetType(assetType), + mDefaultNewName(default_new_name), + mLabel(LLTrans::getString(name)), + mIconName(iconName), + mDisableCameraSwitch(disable_camera_switch), + mAllowMultiwear(allow_multiwear) + { + + } + const LLAssetType::EType mAssetType; + const std::string mLabel; + const std::string mDefaultNewName; //keep mLabel for backward compatibility + LLInventoryIcon::EIconName mIconName; + BOOL mDisableCameraSwitch; + BOOL mAllowMultiwear; +}; + +class LLWearableDictionary : public LLSingleton, + public LLDictionary +{ +public: + LLWearableDictionary(); +}; + +LLWearableDictionary::LLWearableDictionary() +{ + addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); + addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_EYES, FALSE, FALSE)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHOES, FALSE, TRUE)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_JACKET, FALSE, TRUE)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); + + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); + + addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE)); + addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE)); +} + +// static +LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const LLWearableType::EType wearable = dict->lookup(type_name); + return wearable; +} + +// static +const std::string& LLWearableType::getTypeName(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + if (!entry) return getTypeName(WT_INVALID); + return entry->mName; +} + +//static +const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + if (!entry) return getTypeDefaultNewName(WT_INVALID); + return entry->mDefaultNewName; +} + +// static +const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + if (!entry) return getTypeLabel(WT_INVALID); + return entry->mLabel; +} + +// static +LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + if (!entry) return getAssetType(WT_INVALID); + return entry->mAssetType; +} + +// static +LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + if (!entry) return getIconName(WT_INVALID); + return entry->mIconName; +} + +// static +BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + if (!entry) return FALSE; + return entry->mDisableCameraSwitch; +} + +// static +BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + if (!entry) return FALSE; + return entry->mAllowMultiwear; +} + diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h new file mode 100644 index 0000000000..d633b4807e --- /dev/null +++ b/indra/llappearance/llwearabletype.h @@ -0,0 +1,76 @@ +/** + * @file llwearabletype.h + * @brief LLWearableType class header file + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLWEARABLETYPE_H +#define LL_LLWEARABLETYPE_H + +#include "llassettype.h" +#include "lldictionary.h" +#include "llinventoryicon.h" +#include "llsingleton.h" + +class LLWearableType +{ +public: + enum EType + { + WT_SHAPE = 0, + WT_SKIN = 1, + WT_HAIR = 2, + WT_EYES = 3, + WT_SHIRT = 4, + WT_PANTS = 5, + WT_SHOES = 6, + WT_SOCKS = 7, + WT_JACKET = 8, + WT_GLOVES = 9, + WT_UNDERSHIRT = 10, + WT_UNDERPANTS = 11, + WT_SKIRT = 12, + WT_ALPHA = 13, + WT_TATTOO = 14, + WT_PHYSICS = 15, + WT_COUNT = 16, + + WT_INVALID = 255, + WT_NONE = -1, + }; + + static const std::string& getTypeName(EType type); + static const std::string& getTypeDefaultNewName(EType type); + static const std::string& getTypeLabel(EType type); + static LLAssetType::EType getAssetType(EType type); + static EType typeNameToType(const std::string& type_name); + static LLInventoryIcon::EIconName getIconName(EType type); + static BOOL getDisableCameraSwitch(EType type); + static BOOL getAllowMultiwear(EType type); + +protected: + LLWearableType() {} + ~LLWearableType() {} +}; + +#endif // LL_LLWEARABLETYPE_H -- cgit v1.2.3 From 1bd5fd8c50eb299ea96720db8cf0f9b25ec6e941 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 3 Sep 2012 07:00:56 +0000 Subject: Fixed typo in cmake file --- indra/llappearance/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index bc4748b87f..8d2334c566 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -59,7 +59,7 @@ set(llappearance_HEADER_FILES CMakeLists.txt llavatarappearance.h - llinventoryicon.cpp + llinventoryicon.h lljointpickname.h lllocaltextureobject.h lltexglobalcolor.h -- cgit v1.2.3 From 0c7623f628cbba999860379a2f5c302d94c1d287 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 3 Sep 2012 08:37:58 +0000 Subject: Cleanup of llappearance refactor file definition order for easier diff'ing --- indra/llappearance/llavatarappearance.cpp | 1 - indra/llappearance/llavatarappearance.h | 9 --------- indra/llappearance/lltexlayer.cpp | 7 ------- indra/llappearance/lltexlayerparams.cpp | 1 - indra/llappearance/llvoavatardefines.cpp | 3 --- indra/llappearance/llvoavatardefines.h | 2 +- indra/llappearance/llwearable.cpp | 13 +------------ indra/llappearance/llwearable.h | 10 ++++------ indra/llappearance/llwearabletype.cpp | 2 -- 9 files changed, 6 insertions(+), 42 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 1ca0161d7e..044ea8fbf0 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -38,7 +38,6 @@ LLAvatarAppearance::LLAvatarAppearance() : mTexEyeColor( NULL ), mIsDummy(FALSE) { - mDebugExistenceTimer.reset(); } using namespace LLVOAvatarDefines; diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index cb2ae7aeef..1b0e0ad270 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -111,15 +111,6 @@ public: virtual BOOL isWearingWearableType(LLWearableType::EType type ) const = 0; - //-------------------------------------------------------------------- - // Avatar Rez Metrics - //-------------------------------------------------------------------- -public: - F32 debugGetExistenceTimeElapsedF32() const { return mDebugExistenceTimer.getElapsedTimeF32(); } - -protected: - LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory. - public: static LLColor4 getDummyColor(); virtual void updateMeshTextures() = 0; diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 3bb31d3721..6522976be1 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -33,20 +33,13 @@ #include "imageids.h" #include "llimagej2c.h" #include "llimagetga.h" -//#include "llnotificationsutil.h" #include "lldir.h" #include "llvfile.h" #include "llvfs.h" -//#include "llviewerstats.h" -//#include "llviewerregion.h" -//#include "pipeline.h" #include "lltexlayerparams.h" #include "lltexturemanagerbridge.h" #include "llui.h" -//#include "llagentwearables.h" #include "llwearable.h" -//#include "llviewercontrol.h" -//#include "llviewershadermgr.h" #include "llviewervisualparam.h" //#include "../tools/imdebug/imdebug.h" diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index c843367357..4f0456f315 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -29,7 +29,6 @@ #include "lltexlayerparams.h" #include "llavatarappearance.h" -//#include "llagentcamera.h" #include "llimagetga.h" #include "llquantize.h" #include "lltexlayer.h" diff --git a/indra/llappearance/llvoavatardefines.cpp b/indra/llappearance/llvoavatardefines.cpp index 48ef63ab64..29891986f5 100644 --- a/indra/llappearance/llvoavatardefines.cpp +++ b/indra/llappearance/llvoavatardefines.cpp @@ -24,11 +24,8 @@ * $/LicenseInfo$ */ -//#include "llviewerprecompiledheaders.h" #include "linden_common.h" - #include "llvoavatardefines.h" -//#include "llviewercontrol.h" // gSavedSettings const S32 LLVOAvatarDefines::SCRATCH_TEX_WIDTH = 512; const S32 LLVOAvatarDefines::SCRATCH_TEX_HEIGHT = 512; diff --git a/indra/llappearance/llvoavatardefines.h b/indra/llappearance/llvoavatardefines.h index 7b0442bffb..7745775f9f 100644 --- a/indra/llappearance/llvoavatardefines.h +++ b/indra/llappearance/llvoavatardefines.h @@ -29,8 +29,8 @@ #define LLVOAVATAR_DEFINES_H #include -#include "lljointpickname.h" #include "llwearable.h" +#include "lljointpickname.h" #include "lldictionary.h" namespace LLVOAvatarDefines diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 64bd921ec5..77f1f27cb0 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -27,24 +27,12 @@ #include "linden_common.h" #include "llavatarappearance.h" -//#include "llagentwearables.h" -//#include "lldictionary.h" -//#include "llfloatersidepanelcontainer.h" #include "lllocaltextureobject.h" -//#include "llnotificationsutil.h" -//#include "llviewertexturelist.h" -//#include "llinventorymodel.h" -//#include "llinventoryobserver.h" -//#include "llsidepanelappearance.h" #include "lltexlayer.h" -//#include "lltexglobalcolor.h" #include "lltexturemanagerbridge.h" -//#include "lltrans.h" -//#include "llviewerregion.h" #include "llvisualparam.h" #include "llvoavatardefines.h" #include "llwearable.h" -//#include "llviewercontrol.h" using namespace LLVOAvatarDefines; @@ -170,6 +158,7 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file ) return LLWearable::BAD_HEADER; } + // Temporary hack to allow wearables with definition version 24 to still load. // This should only affect lindens and NDA'd testers who have saved wearables in 2.0 // the extra check for version == 24 can be removed before release, once internal testers diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index 56c931e43b..8a99debac8 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -28,19 +28,16 @@ #define LL_LLWEARABLE_H #include "llextendedstatus.h" -//#include "lluuid.h" -//#include "llstring.h" #include "llpermissions.h" #include "llsaleinfo.h" -//#include "llassetstorage.h" #include "llwearabletype.h" -//#include "llfile.h" #include "lllocaltextureobject.h" class LLVisualParam; class LLTexGlobalColorInfo; class LLTexGlobalColor; +// Abstract class. class LLWearable { //-------------------------------------------------------------------- @@ -72,6 +69,8 @@ public: public: typedef std::vector visual_param_vec_t; + virtual void writeToAvatar() = 0; + enum EImportResult { FAILURE = 0, @@ -81,12 +80,11 @@ public: virtual BOOL exportFile(LLFILE* file) const; virtual EImportResult importFile(LLFILE* file); - virtual LLLocalTextureObject* getLocalTextureObject(S32 index) = 0; - virtual void writeToAvatar() = 0; static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; } + virtual LLLocalTextureObject* getLocalTextureObject(S32 index) = 0; void addVisualParam(LLVisualParam *param); void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); F32 getVisualParamWeight(S32 index) const; diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index d47702ff4d..009a3b631a 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -24,11 +24,9 @@ * $/LicenseInfo$ */ -//#include "llviewerprecompiledheaders.h" #include "linden_common.h" #include "llwearabletype.h" -//#include "llinventoryfunctions.h" #include "llinventoryicon.h" #include "lltrans.h" -- cgit v1.2.3 From 21c364c4d455cc05ec176032e8c090be0cc4ed50 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Mon, 3 Sep 2012 09:10:24 +0000 Subject: Renamed LLVOAvatarDefines to LLAvatarAppearanceDefines --- indra/llappearance/CMakeLists.txt | 4 +- indra/llappearance/llavatarappearance.cpp | 2 +- indra/llappearance/llavatarappearance.h | 10 +- indra/llappearance/llavatarappearancedefines.cpp | 246 +++++++++++++++++++++++ indra/llappearance/llavatarappearancedefines.h | 226 +++++++++++++++++++++ indra/llappearance/lltexlayer.cpp | 14 +- indra/llappearance/lltexlayer.h | 10 +- indra/llappearance/llvoavatardefines.cpp | 246 ----------------------- indra/llappearance/llvoavatardefines.h | 226 --------------------- indra/llappearance/llwearable.cpp | 8 +- 10 files changed, 496 insertions(+), 496 deletions(-) create mode 100644 indra/llappearance/llavatarappearancedefines.cpp create mode 100644 indra/llappearance/llavatarappearancedefines.h delete mode 100644 indra/llappearance/llvoavatardefines.cpp delete mode 100644 indra/llappearance/llvoavatardefines.h (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index 8d2334c566..f77c7e6440 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -52,7 +52,7 @@ set(llappearance_SOURCE_FILES llwearable.cpp llwearabletype.cpp llviewervisualparam.cpp - llvoavatardefines.cpp + llavatarappearancedefines.cpp ) set(llappearance_HEADER_FILES @@ -69,7 +69,7 @@ set(llappearance_HEADER_FILES llwearable.h llwearabletype.h llviewervisualparam.h - llvoavatardefines.h + llavatarappearancedefines.h ) set_source_files_properties(${llappearance_HEADER_FILES} diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 044ea8fbf0..2cc38ae2ab 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -40,7 +40,7 @@ LLAvatarAppearance::LLAvatarAppearance() : { } -using namespace LLVOAvatarDefines; +using namespace LLAvatarAppearanceDefines; //static BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 1b0e0ad270..0ab3960e64 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -29,7 +29,7 @@ #include "llcharacter.h" #include "llframetimer.h" -#include "llvoavatardefines.h" +#include "llavatarappearancedefines.h" class LLTexGlobalColor; class LLTexLayerSet; @@ -50,9 +50,9 @@ public: // Clothing colors (convenience functions to access visual parameters) //-------------------------------------------------------------------- public: - void setClothesColor(LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); - LLColor4 getClothesColor(LLVOAvatarDefines::ETextureIndex te); - static BOOL teToColorParams(LLVOAvatarDefines::ETextureIndex te, U32 *param_name); + void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); + LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te); + static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name); //-------------------------------------------------------------------- // Global colors @@ -69,7 +69,7 @@ protected: // Morph masks //-------------------------------------------------------------------- public: - virtual void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES) = 0; + virtual void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0; //-------------------------------------------------------------------- // Composites diff --git a/indra/llappearance/llavatarappearancedefines.cpp b/indra/llappearance/llavatarappearancedefines.cpp new file mode 100644 index 0000000000..2c3cf781c1 --- /dev/null +++ b/indra/llappearance/llavatarappearancedefines.cpp @@ -0,0 +1,246 @@ +/** + * @file llavatarappearancedefines.cpp + * @brief Implementation of LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llavatarappearancedefines.h" + +const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 512; +const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 512; +const S32 LLAvatarAppearanceDefines::IMPOSTOR_PERIOD = 2; + +using namespace LLAvatarAppearanceDefines; + +/********************************************************************************* + * Edit this function to add/remove/change textures and mesh definitions for avatars. + */ + +LLAvatarAppearanceDictionary::Textures::Textures() +{ + addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); + addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", LLWearableType::WT_SHIRT)); + addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", LLWearableType::WT_PANTS)); + addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", TRUE, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", LLWearableType::WT_EYES)); + addEntry(TEX_HAIR, new TextureEntry("hair_grain", TRUE, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", LLWearableType::WT_HAIR)); + addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); + addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); + addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", LLWearableType::WT_SHOES)); + addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", LLWearableType::WT_SOCKS)); + addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET)); + addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET)); + addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", TRUE, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", LLWearableType::WT_GLOVES)); + addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERSHIRT)); + addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERPANTS)); + addEntry(TEX_SKIRT, new TextureEntry("skirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", LLWearableType::WT_SKIRT)); + + addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); + + addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); + addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); + addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); + + addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD, "head")); + addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER, "upper")); + addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", FALSE, BAKED_LOWER, "lower")); + addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", FALSE, BAKED_EYES, "eyes")); + addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", FALSE, BAKED_HAIR, "hair")); + addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", FALSE, BAKED_SKIRT, "skirt")); +} + +LLAvatarAppearanceDictionary::BakedTextures::BakedTextures() +{ + // Baked textures + addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED, + "head", "a4b9dc38-e13b-4df9-b284-751efb0566ff", + 3, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, + 5, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED, + "upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4", + 7, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET, + TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, + 8, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED, + "lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d", + 8, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS, + TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, + 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED, + "eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788", + 2, TEX_EYES_IRIS, TEX_EYES_ALPHA, + 2, LLWearableType::WT_EYES, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED, + "skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63", + 1, TEX_SKIRT, + 1, LLWearableType::WT_SKIRT)); + + addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED, + "hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61", + 2, TEX_HAIR, TEX_HAIR_ALPHA, + 2, LLWearableType::WT_HAIR, LLWearableType::WT_ALPHA)); +} + +LLAvatarAppearanceDictionary::Meshes::Meshes() +{ + // Meshes + addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, PN_4)); + addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, PN_5)); + addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, PN_0)); // no baked mesh associated currently + addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, PN_1)); + addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, PN_2)); + addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, PN_3)); + addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, PN_3)); + addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, PN_5)); +} + +/* + * + *********************************************************************************/ + +LLAvatarAppearanceDictionary::LLAvatarAppearanceDictionary() +{ + createAssociations(); +} + +//virtual +LLAvatarAppearanceDictionary::~LLAvatarAppearanceDictionary() +{ +} + +// Baked textures are composites of textures; for each such composited texture, +// map it to the baked texture. +void LLAvatarAppearanceDictionary::createAssociations() +{ + for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); iter++) + { + const EBakedTextureIndex baked_index = (iter->first); + const BakedEntry *dict = (iter->second); + + // For each texture that this baked texture index affects, associate those textures + // with this baked texture index. + for (texture_vec_t::const_iterator local_texture_iter = dict->mLocalTextures.begin(); + local_texture_iter != dict->mLocalTextures.end(); + local_texture_iter++) + { + const ETextureIndex local_texture_index = (ETextureIndex) *local_texture_iter; + mTextures[local_texture_index]->mIsUsedByBakedTexture = true; + mTextures[local_texture_index]->mBakedTextureIndex = baked_index; + } + } + +} + +LLAvatarAppearanceDictionary::TextureEntry::TextureEntry(const std::string &name, + bool is_local_texture, + EBakedTextureIndex baked_texture_index, + const std::string &default_image_name, + LLWearableType::EType wearable_type) : + LLDictionaryEntry(name), + mIsLocalTexture(is_local_texture), + mIsBakedTexture(!is_local_texture), + mIsUsedByBakedTexture(baked_texture_index != BAKED_NUM_INDICES), + mBakedTextureIndex(baked_texture_index), + mDefaultImageName(default_image_name), + mWearableType(wearable_type) +{ +} + +LLAvatarAppearanceDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index, + const std::string &name, + U8 level, + LLJointPickName pick) : + LLDictionaryEntry(name), + mBakedID(baked_index), + mLOD(level), + mPickName(pick) +{ +} +LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index, + const std::string &name, + const std::string &hash_name, + U32 num_local_textures, + ... ) : + LLDictionaryEntry(name), + mWearablesHashID(LLUUID(hash_name)), + mTextureIndex(tex_index) +{ + va_list argp; + + va_start(argp, num_local_textures); + + // Read in local textures + for (U8 i=0; i < num_local_textures; i++) + { + ETextureIndex t = (ETextureIndex)va_arg(argp,int); + mLocalTextures.push_back(t); + } + + // Read in number of wearables + const U32 num_wearables = (U32)va_arg(argp,int); + // Read in wearables + for (U8 i=0; i < num_wearables; i++) + { + LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int); + mWearables.push_back(t); + } +} + +// static +ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) +{ + return LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(index)->mTextureIndex; +} + +//static +EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name) +{ + U8 index = 0; + while (index < BAKED_NUM_INDICES) + { + const BakedEntry *be = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index); + if (be && be->mName.compare(name) == 0) + { + // baked texture found + return (EBakedTextureIndex) index; + } + index++; + } + // baked texture could not be found + return BAKED_NUM_INDICES; +} + +// static +LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index ) +{ + return getInstance()->getTexture(index)->mWearableType; +} + diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h new file mode 100644 index 0000000000..c5285ddc02 --- /dev/null +++ b/indra/llappearance/llavatarappearancedefines.h @@ -0,0 +1,226 @@ +/** + * @file llavatarappearancedefines.h + * @brief Various LLAvatarAppearance related definitions + * LLViewerObject + * + * $LicenseInfo:firstyear=2001&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_AVATARAPPEARANCE_DEFINES_H +#define LL_AVATARAPPEARANCE_DEFINES_H + +#include +#include "llwearable.h" +#include "lljointpickname.h" +#include "lldictionary.h" + +namespace LLAvatarAppearanceDefines +{ + +extern const S32 SCRATCH_TEX_WIDTH; +extern const S32 SCRATCH_TEX_HEIGHT; +extern const S32 IMPOSTOR_PERIOD; + +//-------------------------------------------------------------------- +// Enums +//-------------------------------------------------------------------- +enum ETextureIndex +{ + TEX_HEAD_BODYPAINT = 0, + TEX_UPPER_SHIRT, + TEX_LOWER_PANTS, + TEX_EYES_IRIS, + TEX_HAIR, + TEX_UPPER_BODYPAINT, + TEX_LOWER_BODYPAINT, + TEX_LOWER_SHOES, + TEX_HEAD_BAKED, // Pre-composited + TEX_UPPER_BAKED, // Pre-composited + TEX_LOWER_BAKED, // Pre-composited + TEX_EYES_BAKED, // Pre-composited + TEX_LOWER_SOCKS, + TEX_UPPER_JACKET, + TEX_LOWER_JACKET, + TEX_UPPER_GLOVES, + TEX_UPPER_UNDERSHIRT, + TEX_LOWER_UNDERPANTS, + TEX_SKIRT, + TEX_SKIRT_BAKED, // Pre-composited + TEX_HAIR_BAKED, // Pre-composited + TEX_LOWER_ALPHA, + TEX_UPPER_ALPHA, + TEX_HEAD_ALPHA, + TEX_EYES_ALPHA, + TEX_HAIR_ALPHA, + TEX_HEAD_TATTOO, + TEX_UPPER_TATTOO, + TEX_LOWER_TATTOO, + TEX_NUM_INDICES +}; + +enum EBakedTextureIndex +{ + BAKED_HEAD = 0, + BAKED_UPPER, + BAKED_LOWER, + BAKED_EYES, + BAKED_SKIRT, + BAKED_HAIR, + BAKED_NUM_INDICES +}; + +// Reference IDs for each mesh. Used as indices for vector of joints +enum EMeshIndex +{ + MESH_ID_HAIR = 0, + MESH_ID_HEAD, + MESH_ID_EYELASH, + MESH_ID_UPPER_BODY, + MESH_ID_LOWER_BODY, + MESH_ID_EYEBALL_LEFT, + MESH_ID_EYEBALL_RIGHT, + MESH_ID_SKIRT, + MESH_ID_NUM_INDICES +}; + +//-------------------------------------------------------------------- +// Vector Types +//-------------------------------------------------------------------- +typedef std::vector texture_vec_t; +typedef std::vector bakedtexture_vec_t; +typedef std::vector mesh_vec_t; +typedef std::vector wearables_vec_t; + +//------------------------------------------------------------------------ +// LLAvatarAppearanceDictionary +// +// Holds dictionary static entries for textures, baked textures, meshes, etc.; i.e. +// information that is common to all avatars. +// +// This holds const data - it is initialized once and the contents never change after that. +//------------------------------------------------------------------------ +class LLAvatarAppearanceDictionary : public LLSingleton +{ + //-------------------------------------------------------------------- + // Constructors and Destructors + //-------------------------------------------------------------------- +public: + LLAvatarAppearanceDictionary(); + virtual ~LLAvatarAppearanceDictionary(); +private: + void createAssociations(); + + //-------------------------------------------------------------------- + // Local and baked textures + //-------------------------------------------------------------------- +public: + struct TextureEntry : public LLDictionaryEntry + { + TextureEntry(const std::string &name, // this must match the xml name used by LLTexLayerInfo::parseXml + bool is_local_texture, + EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES, + const std::string& default_image_name = "", + LLWearableType::EType wearable_type = LLWearableType::WT_INVALID); + const std::string mDefaultImageName; + const LLWearableType::EType mWearableType; + // It's either a local texture xor baked + BOOL mIsLocalTexture; + BOOL mIsBakedTexture; + // If it's a local texture, it may be used by a baked texture + BOOL mIsUsedByBakedTexture; + EBakedTextureIndex mBakedTextureIndex; + }; + + struct Textures : public LLDictionary + { + Textures(); + } mTextures; + const TextureEntry* getTexture(ETextureIndex index) const { return mTextures.lookup(index); } + const Textures& getTextures() const { return mTextures; } + + //-------------------------------------------------------------------- + // Meshes + //-------------------------------------------------------------------- +public: + struct MeshEntry : public LLDictionaryEntry + { + MeshEntry(EBakedTextureIndex baked_index, + const std::string &name, // names of mesh types as they are used in avatar_lad.xml + U8 level, + LLJointPickName pick); + // Levels of Detail for each mesh. Must match levels of detail present in avatar_lad.xml + // Otherwise meshes will be unable to be found, or levels of detail will be ignored + const U8 mLOD; + const EBakedTextureIndex mBakedID; + const LLJointPickName mPickName; + }; + + struct Meshes : public LLDictionary + { + Meshes(); + } mMeshes; + const MeshEntry* getMesh(EMeshIndex index) const { return mMeshes.lookup(index); } + const Meshes& getMeshes() const { return mMeshes; } + + //-------------------------------------------------------------------- + // Baked Textures + //-------------------------------------------------------------------- +public: + struct BakedEntry : public LLDictionaryEntry + { + BakedEntry(ETextureIndex tex_index, + const std::string &name, // unused, but necessary for templating. + const std::string &hash_name, + U32 num_local_textures, ... ); // # local textures, local texture list, # wearables, wearable list + // Local Textures + const ETextureIndex mTextureIndex; + texture_vec_t mLocalTextures; + // Wearables + const LLUUID mWearablesHashID; + wearables_vec_t mWearables; + }; + + struct BakedTextures: public LLDictionary + { + BakedTextures(); + } mBakedTextures; + const BakedEntry* getBakedTexture(EBakedTextureIndex index) const { return mBakedTextures.lookup(index); } + const BakedTextures& getBakedTextures() const { return mBakedTextures; } + + //-------------------------------------------------------------------- + // Convenience Functions + //-------------------------------------------------------------------- +public: + // Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED + static ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t); + + // find a baked texture index based on its name + static EBakedTextureIndex findBakedByRegionName(std::string name); + + // Given a texture entry, determine which wearable type owns it. + static LLWearableType::EType getTEWearableType(ETextureIndex index); + +}; // End LLAvatarAppearanceDictionary + +} // End namespace LLAvatarAppearanceDefines + +#endif //LL_AVATARAPPEARANCE_DEFINES_H diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 6522976be1..bf2fd1e30d 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -44,7 +44,7 @@ //#include "../tools/imdebug/imdebug.h" -using namespace LLVOAvatarDefines; +using namespace LLAvatarAppearanceDefines; 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 @@ -183,7 +183,7 @@ BOOL LLTexLayerSet::sHasCaches = FALSE; LLTexLayerSet::LLTexLayerSet(LLAvatarAppearance* const appearance) : mAvatarAppearance( appearance ), mIsVisible( TRUE ), - mBakedTexIndex(LLVOAvatarDefines::BAKED_HEAD), + mBakedTexIndex(LLAvatarAppearanceDefines::BAKED_HEAD), mInfo( NULL ) { } @@ -567,11 +567,11 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) /* if ("upper_shirt" == local_texture_name) mLocalTexture = TEX_UPPER_SHIRT; */ mLocalTexture = TEX_NUM_INDICES; - for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); + iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); iter++) { - const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; if (local_texture_name == texture_dict->mName) { mLocalTexture = iter->first; @@ -1450,7 +1450,7 @@ U32 LLTexLayerTemplate::updateWearableCache() const //this isn't a cloneable layer return 0; } - LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te); + LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te); U32 num_wearables = getAvatarAppearance()->getWearableCount(wearable_type); U32 added = 0; for (U32 i = 0; i < num_wearables; i++) @@ -1617,7 +1617,7 @@ LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name) return NULL; } -void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable *wearable) +void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable *wearable) { // initialize all texlayers with this texture type for this LTO for( LLTexLayerSet::layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 5ee08e67ec..5a413e929f 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -30,7 +30,7 @@ #include #include "lltexture.h" #include "llframetimer.h" -#include "llvoavatardefines.h" +#include "llavatarappearancedefines.h" #include "lltexlayerparams.h" class LLAvatarAppearance; @@ -195,12 +195,12 @@ public: void invalidateMorphMasks(); void deleteCaches(); LLTexLayerInterface* findLayerByName(const std::string& name); - void cloneTemplates(LLLocalTextureObject *lto, LLVOAvatarDefines::ETextureIndex tex_index, LLWearable* wearable); + void cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable* wearable); LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } const std::string getBodyRegionName() const; - LLVOAvatarDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; } - void setBakedTexIndex(LLVOAvatarDefines::EBakedTextureIndex index) { mBakedTexIndex = index; } + LLAvatarAppearanceDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; } + void setBakedTexIndex(LLAvatarAppearanceDefines::EBakedTextureIndex index) { mBakedTexIndex = index; } BOOL isVisible() const { return mIsVisible; } static BOOL sHasCaches; @@ -212,7 +212,7 @@ protected: LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer. BOOL mIsVisible; - LLVOAvatarDefines::EBakedTextureIndex mBakedTexIndex; + LLAvatarAppearanceDefines::EBakedTextureIndex mBakedTexIndex; const LLTexLayerSetInfo* mInfo; }; diff --git a/indra/llappearance/llvoavatardefines.cpp b/indra/llappearance/llvoavatardefines.cpp deleted file mode 100644 index 29891986f5..0000000000 --- a/indra/llappearance/llvoavatardefines.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/** - * @file llvoavatardefines.cpp - * @brief Implementation of LLVOAvatarDefines::LLVOAvatarDictionary - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llvoavatardefines.h" - -const S32 LLVOAvatarDefines::SCRATCH_TEX_WIDTH = 512; -const S32 LLVOAvatarDefines::SCRATCH_TEX_HEIGHT = 512; -const S32 LLVOAvatarDefines::IMPOSTOR_PERIOD = 2; - -using namespace LLVOAvatarDefines; - -/********************************************************************************* - * Edit this function to add/remove/change textures and mesh definitions for avatars. - */ - -LLVOAvatarDictionary::Textures::Textures() -{ - addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); - addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", LLWearableType::WT_SHIRT)); - addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", LLWearableType::WT_PANTS)); - addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", TRUE, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", LLWearableType::WT_EYES)); - addEntry(TEX_HAIR, new TextureEntry("hair_grain", TRUE, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", LLWearableType::WT_HAIR)); - addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); - addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_SKIN)); - addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", LLWearableType::WT_SHOES)); - addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", LLWearableType::WT_SOCKS)); - addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET)); - addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", LLWearableType::WT_JACKET)); - addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", TRUE, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", LLWearableType::WT_GLOVES)); - addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERSHIRT)); - addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", LLWearableType::WT_UNDERPANTS)); - addEntry(TEX_SKIRT, new TextureEntry("skirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", LLWearableType::WT_SKIRT)); - - addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); - addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); - addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); - addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); - addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", LLWearableType::WT_ALPHA)); - - addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); - addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); - addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); - - addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD, "head")); - addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER, "upper")); - addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", FALSE, BAKED_LOWER, "lower")); - addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", FALSE, BAKED_EYES, "eyes")); - addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", FALSE, BAKED_HAIR, "hair")); - addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", FALSE, BAKED_SKIRT, "skirt")); -} - -LLVOAvatarDictionary::BakedTextures::BakedTextures() -{ - // Baked textures - addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED, - "head", "a4b9dc38-e13b-4df9-b284-751efb0566ff", - 3, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, - 5, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); - - addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED, - "upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4", - 7, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET, - TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, - 8, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); - - addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED, - "lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d", - 8, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS, - TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, - 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); - - addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED, - "eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788", - 2, TEX_EYES_IRIS, TEX_EYES_ALPHA, - 2, LLWearableType::WT_EYES, LLWearableType::WT_ALPHA)); - - addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED, - "skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63", - 1, TEX_SKIRT, - 1, LLWearableType::WT_SKIRT)); - - addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED, - "hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61", - 2, TEX_HAIR, TEX_HAIR_ALPHA, - 2, LLWearableType::WT_HAIR, LLWearableType::WT_ALPHA)); -} - -LLVOAvatarDictionary::Meshes::Meshes() -{ - // Meshes - addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, PN_4)); - addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, PN_5)); - addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, PN_0)); // no baked mesh associated currently - addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, PN_1)); - addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, PN_2)); - addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, PN_3)); - addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, PN_3)); - addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, PN_5)); -} - -/* - * - *********************************************************************************/ - -LLVOAvatarDictionary::LLVOAvatarDictionary() -{ - createAssociations(); -} - -//virtual -LLVOAvatarDictionary::~LLVOAvatarDictionary() -{ -} - -// Baked textures are composites of textures; for each such composited texture, -// map it to the baked texture. -void LLVOAvatarDictionary::createAssociations() -{ - for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); iter++) - { - const EBakedTextureIndex baked_index = (iter->first); - const BakedEntry *dict = (iter->second); - - // For each texture that this baked texture index affects, associate those textures - // with this baked texture index. - for (texture_vec_t::const_iterator local_texture_iter = dict->mLocalTextures.begin(); - local_texture_iter != dict->mLocalTextures.end(); - local_texture_iter++) - { - const ETextureIndex local_texture_index = (ETextureIndex) *local_texture_iter; - mTextures[local_texture_index]->mIsUsedByBakedTexture = true; - mTextures[local_texture_index]->mBakedTextureIndex = baked_index; - } - } - -} - -LLVOAvatarDictionary::TextureEntry::TextureEntry(const std::string &name, - bool is_local_texture, - EBakedTextureIndex baked_texture_index, - const std::string &default_image_name, - LLWearableType::EType wearable_type) : - LLDictionaryEntry(name), - mIsLocalTexture(is_local_texture), - mIsBakedTexture(!is_local_texture), - mIsUsedByBakedTexture(baked_texture_index != BAKED_NUM_INDICES), - mBakedTextureIndex(baked_texture_index), - mDefaultImageName(default_image_name), - mWearableType(wearable_type) -{ -} - -LLVOAvatarDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index, - const std::string &name, - U8 level, - LLJointPickName pick) : - LLDictionaryEntry(name), - mBakedID(baked_index), - mLOD(level), - mPickName(pick) -{ -} -LLVOAvatarDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index, - const std::string &name, - const std::string &hash_name, - U32 num_local_textures, - ... ) : - LLDictionaryEntry(name), - mWearablesHashID(LLUUID(hash_name)), - mTextureIndex(tex_index) -{ - va_list argp; - - va_start(argp, num_local_textures); - - // Read in local textures - for (U8 i=0; i < num_local_textures; i++) - { - ETextureIndex t = (ETextureIndex)va_arg(argp,int); - mLocalTextures.push_back(t); - } - - // Read in number of wearables - const U32 num_wearables = (U32)va_arg(argp,int); - // Read in wearables - for (U8 i=0; i < num_wearables; i++) - { - LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int); - mWearables.push_back(t); - } -} - -// static -ETextureIndex LLVOAvatarDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) -{ - return LLVOAvatarDictionary::getInstance()->getBakedTexture(index)->mTextureIndex; -} - -//static -EBakedTextureIndex LLVOAvatarDictionary::findBakedByRegionName(std::string name) -{ - U8 index = 0; - while (index < BAKED_NUM_INDICES) - { - const BakedEntry *be = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index); - if (be && be->mName.compare(name) == 0) - { - // baked texture found - return (EBakedTextureIndex) index; - } - index++; - } - // baked texture could not be found - return BAKED_NUM_INDICES; -} - -// static -LLWearableType::EType LLVOAvatarDictionary::getTEWearableType(ETextureIndex index ) -{ - return getInstance()->getTexture(index)->mWearableType; -} - diff --git a/indra/llappearance/llvoavatardefines.h b/indra/llappearance/llvoavatardefines.h deleted file mode 100644 index 7745775f9f..0000000000 --- a/indra/llappearance/llvoavatardefines.h +++ /dev/null @@ -1,226 +0,0 @@ -/** - * @file llvoavatardefines.h - * @brief Various LLAvatarAppearance related definitions - * LLViewerObject - * - * $LicenseInfo:firstyear=2001&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 LLVOAVATAR_DEFINES_H -#define LLVOAVATAR_DEFINES_H - -#include -#include "llwearable.h" -#include "lljointpickname.h" -#include "lldictionary.h" - -namespace LLVOAvatarDefines -{ - -extern const S32 SCRATCH_TEX_WIDTH; -extern const S32 SCRATCH_TEX_HEIGHT; -extern const S32 IMPOSTOR_PERIOD; - -//-------------------------------------------------------------------- -// Enums -//-------------------------------------------------------------------- -enum ETextureIndex -{ - TEX_HEAD_BODYPAINT = 0, - TEX_UPPER_SHIRT, - TEX_LOWER_PANTS, - TEX_EYES_IRIS, - TEX_HAIR, - TEX_UPPER_BODYPAINT, - TEX_LOWER_BODYPAINT, - TEX_LOWER_SHOES, - TEX_HEAD_BAKED, // Pre-composited - TEX_UPPER_BAKED, // Pre-composited - TEX_LOWER_BAKED, // Pre-composited - TEX_EYES_BAKED, // Pre-composited - TEX_LOWER_SOCKS, - TEX_UPPER_JACKET, - TEX_LOWER_JACKET, - TEX_UPPER_GLOVES, - TEX_UPPER_UNDERSHIRT, - TEX_LOWER_UNDERPANTS, - TEX_SKIRT, - TEX_SKIRT_BAKED, // Pre-composited - TEX_HAIR_BAKED, // Pre-composited - TEX_LOWER_ALPHA, - TEX_UPPER_ALPHA, - TEX_HEAD_ALPHA, - TEX_EYES_ALPHA, - TEX_HAIR_ALPHA, - TEX_HEAD_TATTOO, - TEX_UPPER_TATTOO, - TEX_LOWER_TATTOO, - TEX_NUM_INDICES -}; - -enum EBakedTextureIndex -{ - BAKED_HEAD = 0, - BAKED_UPPER, - BAKED_LOWER, - BAKED_EYES, - BAKED_SKIRT, - BAKED_HAIR, - BAKED_NUM_INDICES -}; - -// Reference IDs for each mesh. Used as indices for vector of joints -enum EMeshIndex -{ - MESH_ID_HAIR = 0, - MESH_ID_HEAD, - MESH_ID_EYELASH, - MESH_ID_UPPER_BODY, - MESH_ID_LOWER_BODY, - MESH_ID_EYEBALL_LEFT, - MESH_ID_EYEBALL_RIGHT, - MESH_ID_SKIRT, - MESH_ID_NUM_INDICES -}; - -//-------------------------------------------------------------------- -// Vector Types -//-------------------------------------------------------------------- -typedef std::vector texture_vec_t; -typedef std::vector bakedtexture_vec_t; -typedef std::vector mesh_vec_t; -typedef std::vector wearables_vec_t; - -//------------------------------------------------------------------------ -// LLVOAvatarDictionary -// -// Holds dictionary static entries for textures, baked textures, meshes, etc.; i.e. -// information that is common to all avatars. -// -// This holds const data - it is initialized once and the contents never change after that. -//------------------------------------------------------------------------ -class LLVOAvatarDictionary : public LLSingleton -{ - //-------------------------------------------------------------------- - // Constructors and Destructors - //-------------------------------------------------------------------- -public: - LLVOAvatarDictionary(); - virtual ~LLVOAvatarDictionary(); -private: - void createAssociations(); - - //-------------------------------------------------------------------- - // Local and baked textures - //-------------------------------------------------------------------- -public: - struct TextureEntry : public LLDictionaryEntry - { - TextureEntry(const std::string &name, // this must match the xml name used by LLTexLayerInfo::parseXml - bool is_local_texture, - EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES, - const std::string& default_image_name = "", - LLWearableType::EType wearable_type = LLWearableType::WT_INVALID); - const std::string mDefaultImageName; - const LLWearableType::EType mWearableType; - // It's either a local texture xor baked - BOOL mIsLocalTexture; - BOOL mIsBakedTexture; - // If it's a local texture, it may be used by a baked texture - BOOL mIsUsedByBakedTexture; - EBakedTextureIndex mBakedTextureIndex; - }; - - struct Textures : public LLDictionary - { - Textures(); - } mTextures; - const TextureEntry* getTexture(ETextureIndex index) const { return mTextures.lookup(index); } - const Textures& getTextures() const { return mTextures; } - - //-------------------------------------------------------------------- - // Meshes - //-------------------------------------------------------------------- -public: - struct MeshEntry : public LLDictionaryEntry - { - MeshEntry(EBakedTextureIndex baked_index, - const std::string &name, // names of mesh types as they are used in avatar_lad.xml - U8 level, - LLJointPickName pick); - // Levels of Detail for each mesh. Must match levels of detail present in avatar_lad.xml - // Otherwise meshes will be unable to be found, or levels of detail will be ignored - const U8 mLOD; - const EBakedTextureIndex mBakedID; - const LLJointPickName mPickName; - }; - - struct Meshes : public LLDictionary - { - Meshes(); - } mMeshes; - const MeshEntry* getMesh(EMeshIndex index) const { return mMeshes.lookup(index); } - const Meshes& getMeshes() const { return mMeshes; } - - //-------------------------------------------------------------------- - // Baked Textures - //-------------------------------------------------------------------- -public: - struct BakedEntry : public LLDictionaryEntry - { - BakedEntry(ETextureIndex tex_index, - const std::string &name, // unused, but necessary for templating. - const std::string &hash_name, - U32 num_local_textures, ... ); // # local textures, local texture list, # wearables, wearable list - // Local Textures - const ETextureIndex mTextureIndex; - texture_vec_t mLocalTextures; - // Wearables - const LLUUID mWearablesHashID; - wearables_vec_t mWearables; - }; - - struct BakedTextures: public LLDictionary - { - BakedTextures(); - } mBakedTextures; - const BakedEntry* getBakedTexture(EBakedTextureIndex index) const { return mBakedTextures.lookup(index); } - const BakedTextures& getBakedTextures() const { return mBakedTextures; } - - //-------------------------------------------------------------------- - // Convenience Functions - //-------------------------------------------------------------------- -public: - // Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED - static ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t); - - // find a baked texture index based on its name - static EBakedTextureIndex findBakedByRegionName(std::string name); - - // Given a texture entry, determine which wearable type owns it. - static LLWearableType::EType getTEWearableType(ETextureIndex index); - -}; // End LLVOAvatarDictionary - -} // End namespace LLVOAvatarDefines - -#endif //LL_VO_AVATARDEFINES_H diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 77f1f27cb0..ea14c6320f 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -31,10 +31,10 @@ #include "lltexlayer.h" #include "lltexturemanagerbridge.h" #include "llvisualparam.h" -#include "llvoavatardefines.h" +#include "llavatarappearancedefines.h" #include "llwearable.h" -using namespace LLVOAvatarDefines; +using namespace LLAvatarAppearanceDefines; // static S32 LLWearable::sCurrentDefinitionVersion = 1; @@ -420,7 +420,7 @@ LLColor4 LLWearable::getClothesColor(S32 te) const { LLColor4 color; U32 param_name[3]; - if( LLAvatarAppearance::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) + if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) ) { for( U8 index = 0; index < 3; index++ ) { @@ -433,7 +433,7 @@ LLColor4 LLWearable::getClothesColor(S32 te) const void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ) { U32 param_name[3]; - if( LLAvatarAppearance::teToColorParams( (LLVOAvatarDefines::ETextureIndex)te, param_name ) ) + if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) ) { for( U8 index = 0; index < 3; index++ ) { -- cgit v1.2.3 From 7b4385420edf3f431ddc4a7042bbc9623ffedd34 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 4 Sep 2012 04:24:47 +0000 Subject: More clean-up to closer match original file order. For llavatarappearance diffs --- indra/llappearance/llavatarappearance.h | 95 +++++++++++++++++++++--------- indra/llappearance/llinventoryicon.cpp | 1 - indra/llappearance/lltexglobalcolor.cpp | 2 - indra/llappearance/llviewervisualparam.cpp | 1 - indra/llappearance/llwearabletype.cpp | 1 - 5 files changed, 67 insertions(+), 33 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 0ab3960e64..e882868e91 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -31,8 +31,8 @@ #include "llframetimer.h" #include "llavatarappearancedefines.h" -class LLTexGlobalColor; class LLTexLayerSet; +class LLTexGlobalColor; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLAvatarAppearance @@ -43,27 +43,36 @@ class LLAvatarAppearance : public LLCharacter { LOG_CLASS(LLAvatarAppearance); +/******************************************************************************** + ** ** + ** INITIALIZATION + **/ + public: LLAvatarAppearance(); - //-------------------------------------------------------------------- - // Clothing colors (convenience functions to access visual parameters) - //-------------------------------------------------------------------- -public: - void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); - LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te); - static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name); +/** Initialization + ** ** + *******************************************************************************/ - //-------------------------------------------------------------------- - // Global colors - //-------------------------------------------------------------------- +/******************************************************************************** + ** ** + ** STATE + **/ public: - LLColor4 getGlobalColor(const std::string& color_name ) const; - virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0; -protected: - LLTexGlobalColor* mTexSkinColor; - LLTexGlobalColor* mTexHairColor; - LLTexGlobalColor* mTexEyeColor; + virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent + virtual BOOL isUsingBakedTextures() const = 0; + +/** State + ** ** + *******************************************************************************/ + + +/******************************************************************************** + ** ** + ** RENDERING + **/ + BOOL mIsDummy; // for special views //-------------------------------------------------------------------- // Morph masks @@ -71,6 +80,10 @@ protected: public: virtual void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0; +/** Rendering + ** ** + *******************************************************************************/ + //-------------------------------------------------------------------- // Composites //-------------------------------------------------------------------- @@ -81,39 +94,65 @@ public: ** ** ** MESHES **/ + +public: + virtual void updateMeshTextures() = 0; virtual void dirtyMesh() = 0; // Dirty the avatar mesh +protected: virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority -/******************************************************************************** +/** Meshes ** ** - ** RENDERING - **/ - BOOL mIsDummy; // for special views + *******************************************************************************/ /******************************************************************************** ** ** - ** STATE + ** APPEARANCE **/ + + //-------------------------------------------------------------------- + // Clothing colors (convenience functions to access visual parameters) + //-------------------------------------------------------------------- public: - virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent - virtual BOOL isUsingBakedTextures() const = 0; + void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); + LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te); + static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name); + + //-------------------------------------------------------------------- + // Global colors + //-------------------------------------------------------------------- +public: + LLColor4 getGlobalColor(const std::string& color_name ) const; + virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0; +protected: + LLTexGlobalColor* mTexSkinColor; + LLTexGlobalColor* mTexHairColor; + LLTexGlobalColor* mTexEyeColor; + + //-------------------------------------------------------------------- + // Visibility + //-------------------------------------------------------------------- +public: + static LLColor4 getDummyColor(); +/** Appearance + ** ** + *******************************************************************************/ /******************************************************************************** ** ** ** WEARABLES **/ + public: + virtual BOOL isWearingWearableType(LLWearableType::EType type ) const = 0; + virtual U32 getWearableCount(const LLWearableType::EType type) const = 0; virtual U32 getWearableCount(const U32 tex_index) const = 0; virtual LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) = 0; virtual const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const = 0; - virtual BOOL isWearingWearableType(LLWearableType::EType type ) const = 0; -public: - static LLColor4 getDummyColor(); - virtual void updateMeshTextures() = 0; }; #endif // LL_AVATAR_APPEARANCE_H diff --git a/indra/llappearance/llinventoryicon.cpp b/indra/llappearance/llinventoryicon.cpp index 62261058ef..371f60353b 100644 --- a/indra/llappearance/llinventoryicon.cpp +++ b/indra/llappearance/llinventoryicon.cpp @@ -24,7 +24,6 @@ * $/LicenseInfo$ */ -//#include "llviewerprecompiledheaders.h" #include "linden_common.h" #include "llinventoryicon.h" diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp index d9c6150fc6..f38b982104 100644 --- a/indra/llappearance/lltexglobalcolor.cpp +++ b/indra/llappearance/lltexglobalcolor.cpp @@ -25,10 +25,8 @@ */ #include "linden_common.h" - #include "llavatarappearance.h" #include "lltexlayer.h" -//#include "llwearable.h" #include "lltexglobalcolor.h" class LLWearable; diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index e1ddeeeff0..a6792d0974 100644 --- a/indra/llappearance/llviewervisualparam.cpp +++ b/indra/llappearance/llviewervisualparam.cpp @@ -27,7 +27,6 @@ //----------------------------------------------------------------------------- // Header Files //----------------------------------------------------------------------------- -//#include "llviewerprecompiledheaders.h" #include "linden_common.h" #include "llviewervisualparam.h" diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index 009a3b631a..c72a0965fe 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -25,7 +25,6 @@ */ #include "linden_common.h" - #include "llwearabletype.h" #include "llinventoryicon.h" #include "lltrans.h" -- cgit v1.2.3 From 204be2ba5261d794f8264e004b65725450bf1be9 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 4 Sep 2012 15:18:15 +0000 Subject: Split LLTexLayerSetBuffer into llappearance portion, and viewer-specific LLViewerTexLayerSetBuffer --- indra/llappearance/lltexlayer.cpp | 109 ++++++++++++++++++++++++++++++++++++++ indra/llappearance/lltexlayer.h | 37 +++++++++++++ 2 files changed, 146 insertions(+) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index bf2fd1e30d..0d3219c4e0 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -40,6 +40,7 @@ #include "lltexturemanagerbridge.h" #include "llui.h" #include "llwearable.h" +#include "llvertexbuffer.h" #include "llviewervisualparam.h" //#include "../tools/imdebug/imdebug.h" @@ -89,6 +90,92 @@ private: param_alpha_info_list_t mParamAlphaInfoList; }; +//----------------------------------------------------------------------------- +// LLTexLayerSetBuffer +// The composite image that a LLViewerTexLayerSet writes to. Each LLViewerTexLayerSet has one. +//----------------------------------------------------------------------------- + +LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* const owner) : + mTexLayerSet(owner) +{ +} + +LLTexLayerSetBuffer::~LLTexLayerSetBuffer() +{ +} + +void LLTexLayerSetBuffer::pushProjection() const +{ + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho(0.0f, getCompositeWidth(), 0.0f, getCompositeHeight(), -1.0f, 1.0f); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); +} + +void LLTexLayerSetBuffer::popProjection() const +{ + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); +} + +// virtual +void LLTexLayerSetBuffer::preRenderTexLayerSet() +{ + // Set up an ortho projection + pushProjection(); +} + +// virtual +void LLTexLayerSetBuffer::postRenderTexLayerSet(BOOL success) +{ + popProjection(); +} + +BOOL LLTexLayerSetBuffer::renderTexLayerSet() +{ + // Default color mask for tex layer render + gGL.setColorMask(true, true); + + BOOL success = TRUE; + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + if (use_shaders) + { + gAlphaMaskProgram.bind(); + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + + LLVertexBuffer::unbind(); + + // Composite the color data + LLGLSUIDefault gls_ui; + success &= mTexLayerSet->render( getCompositeOriginX(), getCompositeOriginY(), + getCompositeWidth(), getCompositeHeight() ); + gGL.flush(); + + midRenderTexLayerSet(success); + + if (use_shaders) + { + gAlphaMaskProgram.unbind(); + } + + LLVertexBuffer::unbind(); + + // reset GL state + gGL.setColorMask(true, true); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + return success; +} //----------------------------------------------------------------------------- // LLTexLayerSetInfo @@ -381,6 +468,28 @@ const std::string LLTexLayerSet::getBodyRegionName() const } +void LLTexLayerSet::destroyComposite() +{ + if( mComposite ) + { + mComposite = NULL; + } +} + +LLTexLayerSetBuffer* LLTexLayerSet::getComposite() +{ + if (!mComposite) + { + createComposite(); + } + return mComposite; +} + +const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const +{ + return mComposite; +} + void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear) { const LLTexLayerSetInfo *info = getInfo(); diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 5a413e929f..4f2ee5b045 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -40,6 +40,7 @@ class LLXmlTreeNode; class LLTexLayerSet; class LLTexLayerSetInfo; class LLTexLayerInfo; +class LLTexLayerSetBuffer; class LLWearable; class LLViewerVisualParam; @@ -178,10 +179,16 @@ private: //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLTexLayerSet { + friend class LLTexLayerSetBuffer; public: LLTexLayerSet(LLAvatarAppearance* const appearance); virtual ~LLTexLayerSet(); + LLTexLayerSetBuffer* getComposite(); + const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist. + virtual void createComposite() = 0; + void destroyComposite(); + const LLTexLayerSetInfo* getInfo() const { return mInfo; } BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions @@ -199,6 +206,7 @@ public: LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } const std::string getBodyRegionName() const; + BOOL hasComposite() const { return (mComposite.notNull()); } LLAvatarAppearanceDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; } void setBakedTexIndex(LLAvatarAppearanceDefines::EBakedTextureIndex index) { mBakedTexIndex = index; } BOOL isVisible() const { return mIsVisible; } @@ -209,6 +217,7 @@ protected: typedef std::vector layer_list_t; layer_list_t mLayerList; layer_list_t mMaskLayerList; + LLPointer mComposite; LLAvatarAppearance* const mAvatarAppearance; // note: backlink only; don't make this an LLPointer. BOOL mIsVisible; @@ -241,6 +250,34 @@ protected: layer_info_list_t mLayerInfoList; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLTexLayerSetBuffer +// +// The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLTexLayerSetBuffer : public virtual LLRefCount +{ + LOG_CLASS(LLTexLayerSetBuffer); + +public: + LLTexLayerSetBuffer(LLTexLayerSet* const owner); + virtual ~LLTexLayerSetBuffer(); + +protected: + void pushProjection() const; + void popProjection() const; + virtual void preRenderTexLayerSet(); + virtual void midRenderTexLayerSet(BOOL success) {} + virtual void postRenderTexLayerSet(BOOL success); + virtual S32 getCompositeOriginX() const = 0; + virtual S32 getCompositeOriginY() const = 0; + virtual S32 getCompositeWidth() const = 0; + virtual S32 getCompositeHeight() const = 0; + BOOL renderTexLayerSet(); + + LLTexLayerSet* const mTexLayerSet; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLTexLayerStaticImageList // -- cgit v1.2.3 From 1f6e20c5bbfd4495e6493facd2363fd133fe7fcd Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 4 Sep 2012 17:43:08 +0000 Subject: Split gl-specific LLViewerTexture implementation into llrender/LLGLViewerTexture --- indra/llappearance/lllocaltextureobject.cpp | 8 ++++---- indra/llappearance/lllocaltextureobject.h | 10 +++++----- indra/llappearance/lltexlayer.cpp | 24 ++++++++++++------------ indra/llappearance/lltexlayer.h | 6 +++--- indra/llappearance/lltexlayerparams.cpp | 2 +- indra/llappearance/lltexlayerparams.h | 4 ++-- indra/llappearance/lltexturemanagerbridge.h | 8 ++++---- 7 files changed, 31 insertions(+), 31 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lllocaltextureobject.cpp b/indra/llappearance/lllocaltextureobject.cpp index 0e77444f49..7e36a06797 100644 --- a/indra/llappearance/lllocaltextureobject.cpp +++ b/indra/llappearance/lllocaltextureobject.cpp @@ -30,7 +30,7 @@ #include "llimage.h" #include "llrender.h" #include "lltexlayer.h" -#include "lltexture.h" +#include "llgltexture.h" #include "lluuid.h" #include "llwearable.h" @@ -42,7 +42,7 @@ LLLocalTextureObject::LLLocalTextureObject() : mImage = NULL; } -LLLocalTextureObject::LLLocalTextureObject(LLTexture* image, const LLUUID& id) : +LLLocalTextureObject::LLLocalTextureObject(LLGLTexture* image, const LLUUID& id) : mIsBakedReady(FALSE), mDiscard(MAX_DISCARD_LEVEL+1) { @@ -78,7 +78,7 @@ LLLocalTextureObject::~LLLocalTextureObject() { } -LLTexture* LLLocalTextureObject::getImage() const +LLGLTexture* LLLocalTextureObject::getImage() const { return mImage; } @@ -127,7 +127,7 @@ BOOL LLLocalTextureObject::getBakedReady() const return mIsBakedReady; } -void LLLocalTextureObject::setImage(LLTexture* new_image) +void LLLocalTextureObject::setImage(LLGLTexture* new_image) { mImage = new_image; } diff --git a/indra/llappearance/lllocaltextureobject.h b/indra/llappearance/lllocaltextureobject.h index 8f868eb412..6f14448cca 100644 --- a/indra/llappearance/lllocaltextureobject.h +++ b/indra/llappearance/lllocaltextureobject.h @@ -30,7 +30,7 @@ #include #include "llpointer.h" -#include "lltexture.h" +#include "llgltexture.h" class LLUUID; class LLTexLayer; @@ -44,11 +44,11 @@ class LLLocalTextureObject { public: LLLocalTextureObject(); - LLLocalTextureObject(LLTexture* image, const LLUUID& id); + LLLocalTextureObject(LLGLTexture* image, const LLUUID& id); LLLocalTextureObject(const LLLocalTextureObject& lto); ~LLLocalTextureObject(); - LLTexture* getImage() const; + LLGLTexture* getImage() const; LLTexLayer* getTexLayer(U32 index) const; LLTexLayer* getTexLayer(const std::string &name); U32 getNumTexLayers() const; @@ -56,7 +56,7 @@ public: S32 getDiscard() const; BOOL getBakedReady() const; - void setImage(LLTexture* new_image); + void setImage(LLGLTexture* new_image); BOOL setTexLayer(LLTexLayer *new_tex_layer, U32 index); BOOL addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable); BOOL addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable); @@ -70,7 +70,7 @@ protected: private: - LLPointer mImage; + LLPointer mImage; // NOTE: LLLocalTextureObject should be the exclusive owner of mTexEntry and mTexLayer // using shared pointers here only for smart assignment & cleanup // do NOT create new shared pointers to these objects, or keep pointers to them around diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 0d3219c4e0..a741a83af7 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -504,7 +504,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, { gGL.flush(); { - LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(info->mStaticAlphaFileName, TRUE); + LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(info->mStaticAlphaFileName, TRUE); if( tex ) { LLGLSUIDefault gls_ui; @@ -1087,7 +1087,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) if( (getInfo()->mLocalTexture != -1) && !getInfo()->mUseLocalTextureAlphaOnly ) { { - LLTexture* tex = NULL; + LLGLTexture* tex = NULL; if (mLocalTextureObject && mLocalTextureObject->getImage()) { tex = mLocalTextureObject->getImage(); @@ -1137,7 +1137,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) if( !getInfo()->mStaticImageFileName.empty() ) { { - LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); if( tex ) { gGL.getTexUnit(0)->bind(tex, TRUE); @@ -1259,7 +1259,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) if( !getInfo()->mStaticImageFileName.empty() ) { - LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); + LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); if( tex ) { LLGLSNoAlphaTest gls_no_alpha_test; @@ -1284,7 +1284,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { if (getInfo()->mLocalTexture >=0 && getInfo()->mLocalTexture < TEX_NUM_INDICES) { - LLTexture* tex = mLocalTextureObject->getImage(); + LLGLTexture* tex = mLocalTextureObject->getImage(); if (tex) { LLGLSNoAlphaTest gls_no_alpha_test; @@ -1358,7 +1358,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC // Accumulate the alpha component of the texture if( getInfo()->mLocalTexture != -1 ) { - LLTexture* tex = mLocalTextureObject->getImage(); + LLGLTexture* tex = mLocalTextureObject->getImage(); if( tex && (tex->getComponents() == 4) ) { LLGLSNoAlphaTest gls_no_alpha_test; @@ -1376,7 +1376,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC if( !getInfo()->mStaticImageFileName.empty() ) { - LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); if( tex ) { if( (tex->getComponents() == 4) || @@ -1493,7 +1493,7 @@ LLUUID LLTexLayer::getUUID() const LLUUID uuid; if( getInfo()->mLocalTexture != -1 ) { - LLTexture* tex = mLocalTextureObject->getImage(); + LLGLTexture* tex = mLocalTextureObject->getImage(); if (tex) { uuid = mLocalTextureObject->getID(); @@ -1501,7 +1501,7 @@ LLUUID LLTexLayer::getUUID() const } if( !getInfo()->mStaticImageFileName.empty() ) { - LLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); if( tex ) { uuid = tex->getID(); @@ -1821,9 +1821,9 @@ LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) // Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -LLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) +LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) { - LLPointer tex; + LLPointer tex; const char *namekey = mImageNames.addString(file_name); texture_map_t::const_iterator iter = mStaticImageList.find(namekey); @@ -1844,7 +1844,7 @@ LLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, B // that once an image is a mask it's always a mask. tex->setExplicitFormat( GL_ALPHA8, GL_ALPHA ); } - tex->createGLTexture(0, image_raw, 0, TRUE, LLTexture::LOCAL); + tex->createGLTexture(0, image_raw, 0, TRUE, LLGLTexture::LOCAL); gGL.getTexUnit(0)->bind(tex); tex->setAddressMode(LLTexUnit::TAM_CLAMP); diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 4f2ee5b045..e9e1764763 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -28,7 +28,7 @@ #define LL_LLTEXLAYER_H #include -#include "lltexture.h" +#include "llgltexture.h" #include "llframetimer.h" #include "llavatarappearancedefines.h" #include "lltexlayerparams.h" @@ -287,7 +287,7 @@ class LLTexLayerStaticImageList : public LLSingleton public: LLTexLayerStaticImageList(); ~LLTexLayerStaticImageList(); - LLTexture* getTexture(const std::string& file_name, BOOL is_mask); + LLGLTexture* getTexture(const std::string& file_name, BOOL is_mask); LLImageTGA* getImageTGA(const std::string& file_name); void deleteCachedImages(); void dumpByteCount() const; @@ -295,7 +295,7 @@ protected: BOOL loadImageRaw(const std::string& file_name, LLImageRaw* image_raw); private: LLStringTable mImageNames; - typedef std::map > texture_map_t; + typedef std::map > texture_map_t; texture_map_t mStaticImageList; typedef std::map > image_tga_map_t; image_tga_map_t mStaticImageListTGA; diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 4f0456f315..06001c6b15 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -97,7 +97,7 @@ void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes) iter != sInstances.end(); iter++) { LLTexLayerParamAlpha* instance = *iter; - LLTexture* tex = instance->mCachedProcessedTexture; + LLGLTexture* tex = instance->mCachedProcessedTexture; if (tex) { S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents(); diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h index dbffd15751..1974a4f7ac 100644 --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -36,7 +36,7 @@ class LLImageRaw; class LLImageTGA; class LLTexLayer; class LLTexLayerInterface; -class LLTexture; +class LLGLTexture; class LLWearable; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -91,7 +91,7 @@ public: BOOL getMultiplyBlend() const; private: - LLPointer mCachedProcessedTexture; + LLPointer mCachedProcessedTexture; LLPointer mStaticImageTGA; LLPointer mStaticImageRaw; BOOL mNeedsCreateTexture; diff --git a/indra/llappearance/lltexturemanagerbridge.h b/indra/llappearance/lltexturemanagerbridge.h index 20f5d0fd3c..99c01755d4 100644 --- a/indra/llappearance/lltexturemanagerbridge.h +++ b/indra/llappearance/lltexturemanagerbridge.h @@ -28,15 +28,15 @@ #define LL_TEXTUREMANAGERBRIDGE_H #include "llpointer.h" -#include "lltexture.h" +#include "llgltexture.h" // Abstract bridge interface class LLTextureManagerBridge { public: - virtual LLPointer getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE) = 0; - virtual LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) = 0; - virtual LLTexture* getFetchedTexture(const LLUUID &image_id) = 0; + virtual LLPointer getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE) = 0; + virtual LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) = 0; + virtual LLGLTexture* getFetchedTexture(const LLUUID &image_id) = 0; }; extern LLTextureManagerBridge* gTextureManagerBridgep; -- cgit v1.2.3 From 41301004e13bec1c74f444f42372a3a6609cb305 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 4 Sep 2012 22:49:26 +0000 Subject: Cleanup actions from code review of llappearance with nyx --- indra/llappearance/CMakeLists.txt | 1 - indra/llappearance/llavatarappearance.cpp | 9 +++++++++ indra/llappearance/llavatarappearance.h | 3 ++- indra/llappearance/lltexlayer.h | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index f77c7e6440..0206f76546 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -4,7 +4,6 @@ project(llappearance) include(00-Common) include(LLCommon) -include(Viewer) include(LLAudio) include(LLCharacter) include(LLCommon) diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 2cc38ae2ab..75b9c1ffa5 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include "llavatarappearance.h" +#include "lldeleteutils.h" #include "lltexglobalcolor.h" const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); @@ -40,6 +41,14 @@ LLAvatarAppearance::LLAvatarAppearance() : { } +// virtual +LLAvatarAppearance::~LLAvatarAppearance() +{ + deleteAndClear(mTexSkinColor); + deleteAndClear(mTexHairColor); + deleteAndClear(mTexEyeColor); +} + using namespace LLAvatarAppearanceDefines; //static diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index e882868e91..0e746b3b9d 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -28,7 +28,7 @@ #define LL_AVATAR_APPEARANCE_H #include "llcharacter.h" -#include "llframetimer.h" +//#include "llframetimer.h" #include "llavatarappearancedefines.h" class LLTexLayerSet; @@ -50,6 +50,7 @@ class LLAvatarAppearance : public LLCharacter public: LLAvatarAppearance(); + virtual ~LLAvatarAppearance(); /** Initialization ** ** diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index e9e1764763..e6c2ece64a 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -29,7 +29,7 @@ #include #include "llgltexture.h" -#include "llframetimer.h" +//#include "llframetimer.h" #include "llavatarappearancedefines.h" #include "lltexlayerparams.h" -- cgit v1.2.3 From b146490e1b46799ccb35e156b4751eddea3a23ce Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Wed, 5 Sep 2012 17:46:11 -0400 Subject: SH-3264 Worked to move over mBakedTextureDatas from LLVOAvatar to LLAvatarAppearance. Appear to have been able to move over the parts that are common to both the backend and the viewer into LLAvatarAppearance. --- indra/llappearance/llavatarappearance.cpp | 38 ++++++++++++++++++++++++++++++ indra/llappearance/llavatarappearance.h | 39 +++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 75b9c1ffa5..81a1d3965c 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -26,7 +26,10 @@ #include "linden_common.h" + #include "llavatarappearance.h" +#include "llavatarappearancedefines.h" +#include "imageids.h" #include "lldeleteutils.h" #include "lltexglobalcolor.h" @@ -39,6 +42,16 @@ LLAvatarAppearance::LLAvatarAppearance() : mTexEyeColor( NULL ), mIsDummy(FALSE) { + mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); + for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) + { + mBakedTextureDatas[i].mLastTextureIndex = IMG_DEFAULT_AVATAR; + mBakedTextureDatas[i].mTexLayerSet = NULL; + mBakedTextureDatas[i].mIsLoaded = false; + mBakedTextureDatas[i].mIsUsed = false; + mBakedTextureDatas[i].mMaskTexName = 0; + mBakedTextureDatas[i].mTextureIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i); + } } // virtual @@ -47,10 +60,35 @@ LLAvatarAppearance::~LLAvatarAppearance() deleteAndClear(mTexSkinColor); deleteAndClear(mTexHairColor); deleteAndClear(mTexEyeColor); + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + deleteAndClear(mBakedTextureDatas[i].mTexLayerSet); + mBakedTextureDatas[i].mMeshes.clear(); + + for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin(); + iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++) + { + LLMaskedMorph* masked_morph = (*iter2); + delete masked_morph; + } + } } using namespace LLAvatarAppearanceDefines; + +// adds a morph mask to the appropriate baked texture structure +void LLAvatarAppearance::addMaskedMorph(EBakedTextureIndex index, LLVisualParam* morph_target, BOOL invert, std::string layer) +{ + if (index < BAKED_NUM_INDICES) + { + LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer); + mBakedTextureDatas[index].mMaskedMorphs.push_front(morph); + } +} + + //static BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) { diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 0e746b3b9d..9bff6b111e 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -30,6 +30,7 @@ #include "llcharacter.h" //#include "llframetimer.h" #include "llavatarappearancedefines.h" +#include "lljoint.h" class LLTexLayerSet; class LLTexGlobalColor; @@ -79,6 +80,7 @@ public: // Morph masks //-------------------------------------------------------------------- public: + void addMaskedMorph(LLAvatarAppearanceDefines::EBakedTextureIndex index, LLVisualParam* morph_target, BOOL invert, std::string layer); virtual void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0; /** Rendering @@ -153,6 +155,43 @@ public: virtual LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) = 0; virtual const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const = 0; +/******************************************************************************** + ** ** + ** BAKED TEXTURES + **/ +protected: + struct LLMaskedMorph; + typedef std::deque morph_list_t; + struct BakedTextureData + { + LLUUID mLastTextureIndex; + LLTexLayerSet* mTexLayerSet; // Only exists for self + bool mIsLoaded; + bool mIsUsed; + LLAvatarAppearanceDefines::ETextureIndex mTextureIndex; + U32 mMaskTexName; + // Stores pointers to the joint meshes that this baked texture deals with + std::vector< LLJoint* > mMeshes; // std::vector mJoints[i]->mMeshParts + morph_list_t mMaskedMorphs; + }; + typedef std::vector bakedtexturedata_vec_t; + bakedtexturedata_vec_t mBakedTextureDatas; + + +/******************************************************************************** + ** ** + ** SUPPORT CLASSES + **/ + + class LLMaskedMorph + { + public: + LLMaskedMorph(LLVisualParam *morph_target, BOOL invert, std::string layer); + + LLVisualParam *mMorphTarget; + BOOL mInvert; + std::string mLayer; + }; }; -- cgit v1.2.3 From 85d0bcc0630bfbf8b50be3a47a113c4f8d6ec9df Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 6 Sep 2012 02:53:55 +0000 Subject: Extracted mWearableDatas from LLAgentWearables into llappearance/LLWearableData. Moved LLDriverParam into llappearance --- indra/llappearance/CMakeLists.txt | 4 + indra/llappearance/llavatarappearance.cpp | 60 ++- indra/llappearance/llavatarappearance.h | 21 +- indra/llappearance/lldriverparam.cpp | 614 ++++++++++++++++++++++++++++++ indra/llappearance/lldriverparam.h | 133 +++++++ indra/llappearance/lltexlayer.cpp | 5 +- indra/llappearance/llwearable.h | 7 + indra/llappearance/llwearabledata.cpp | 353 +++++++++++++++++ indra/llappearance/llwearabledata.h | 108 ++++++ 9 files changed, 1292 insertions(+), 13 deletions(-) create mode 100644 indra/llappearance/lldriverparam.cpp create mode 100644 indra/llappearance/lldriverparam.h create mode 100644 indra/llappearance/llwearabledata.cpp create mode 100644 indra/llappearance/llwearabledata.h (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index 0206f76546..41da898457 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -42,6 +42,7 @@ include_directories( set(llappearance_SOURCE_FILES llavatarappearance.cpp + lldriverparam.cpp llinventoryicon.cpp lllocaltextureobject.cpp lltexglobalcolor.cpp @@ -49,6 +50,7 @@ set(llappearance_SOURCE_FILES lltexlayerparams.cpp lltexturemanagerbridge.cpp llwearable.cpp + llwearabledata.cpp llwearabletype.cpp llviewervisualparam.cpp llavatarappearancedefines.cpp @@ -58,6 +60,7 @@ set(llappearance_HEADER_FILES CMakeLists.txt llavatarappearance.h + lldriverparam.h llinventoryicon.h lljointpickname.h lllocaltextureobject.h @@ -66,6 +69,7 @@ set(llappearance_HEADER_FILES lltexlayerparams.h lltexturemanagerbridge.h llwearable.h + llwearabledata.h llwearabletype.h llviewervisualparam.h llavatarappearancedefines.h diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 75b9c1ffa5..0f0942d8dc 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -29,16 +29,19 @@ #include "llavatarappearance.h" #include "lldeleteutils.h" #include "lltexglobalcolor.h" +#include "llwearabledata.h" const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); -LLAvatarAppearance::LLAvatarAppearance() : +LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : LLCharacter(), + mIsDummy(FALSE), mTexSkinColor( NULL ), mTexHairColor( NULL ), mTexEyeColor( NULL ), - mIsDummy(FALSE) + mWearableData(wearable_data) { + llassert(mWearableData); } // virtual @@ -51,6 +54,17 @@ LLAvatarAppearance::~LLAvatarAppearance() using namespace LLAvatarAppearanceDefines; +// virtual +BOOL LLAvatarAppearance::isValid() const +{ + // This should only be called on ourself. + if (!isSelf()) + { + llerrs << "Called LLAvatarAppearance::isValid() on when isSelf() == false" << llendl; + } + return TRUE; +} + //static BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) { @@ -178,5 +192,47 @@ LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) con } } +// Unlike most wearable functions, this works for both self and other. +// virtual +BOOL LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const +{ + if (mIsDummy) return TRUE; + + switch(type) + { + case LLWearableType::WT_SHAPE: + case LLWearableType::WT_SKIN: + case LLWearableType::WT_HAIR: + case LLWearableType::WT_EYES: + return TRUE; // everyone has all bodyparts + default: + break; // Do nothing + } + + /* switch(type) + case LLWearableType::WT_SHIRT: + indicator_te = TEX_UPPER_SHIRT; */ + for (LLAvatarAppearanceDictionary::Textures::const_iterator tex_iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); + tex_iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + ++tex_iter) + { + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_iter->second; + if (texture_dict->mWearableType == type) + { + // If you're checking another avatar's clothing, you don't have component textures. + // Thus, you must check to see if the corresponding baked texture is defined. + // NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing + // this works for detecting a skirt (most important), but is ineffective at any piece of clothing that + // gets baked into a texture that always exists (upper or lower). + if (texture_dict->mIsUsedByBakedTexture) + { + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + return isTextureDefined(LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex); + } + return FALSE; + } + } + return FALSE; +} diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 0e746b3b9d..2209ede927 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -33,6 +33,7 @@ class LLTexLayerSet; class LLTexGlobalColor; +class LLWearableData; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLAvatarAppearance @@ -47,9 +48,12 @@ class LLAvatarAppearance : public LLCharacter ** ** ** INITIALIZATION **/ +private: + // Hide default constructor. + LLAvatarAppearance() {} public: - LLAvatarAppearance(); + LLAvatarAppearance(LLWearableData* wearable_data); virtual ~LLAvatarAppearance(); /** Initialization @@ -62,6 +66,7 @@ public: **/ public: virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent + virtual BOOL isValid() const; virtual BOOL isUsingBakedTextures() const = 0; /** State @@ -145,15 +150,13 @@ public: **/ public: - virtual BOOL isWearingWearableType(LLWearableType::EType type ) const = 0; - - virtual U32 getWearableCount(const LLWearableType::EType type) const = 0; - virtual U32 getWearableCount(const U32 tex_index) const = 0; - - virtual LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) = 0; - virtual const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const = 0; - + LLWearableData* getWearableData() { return mWearableData; } + const LLWearableData* getWearableData() const { return mWearableData; } + virtual BOOL isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex te, U32 index = 0 ) const = 0; + virtual BOOL isWearingWearableType(LLWearableType::EType type ) const; +private: + LLWearableData* mWearableData; }; #endif // LL_AVATAR_APPEARANCE_H diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp new file mode 100644 index 0000000000..1092b525d0 --- /dev/null +++ b/indra/llappearance/lldriverparam.cpp @@ -0,0 +1,614 @@ +/** + * @file lldriverparam.cpp + * @brief A visual parameter that drives (controls) other visual parameters. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lldriverparam.h" + +#include "llavatarappearance.h" +#include "llwearable.h" +#include "llwearabledata.h" + +//----------------------------------------------------------------------------- +// LLDriverParamInfo +//----------------------------------------------------------------------------- + +LLDriverParamInfo::LLDriverParamInfo() : + mDriverParam(NULL) +{ +} + +BOOL LLDriverParamInfo::parseXml(LLXmlTreeNode* node) +{ + llassert( node->hasName( "param" ) && node->getChildByName( "param_driver" ) ); + + if( !LLViewerVisualParamInfo::parseXml( node )) + return FALSE; + + LLXmlTreeNode* param_driver_node = node->getChildByName( "param_driver" ); + if( !param_driver_node ) + return FALSE; + + for (LLXmlTreeNode* child = param_driver_node->getChildByName( "driven" ); + child; + child = param_driver_node->getNextNamedChild()) + { + S32 driven_id; + static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id"); + if( child->getFastAttributeS32( id_string, driven_id ) ) + { + F32 min1 = mMinWeight; + F32 max1 = mMaxWeight; + F32 max2 = max1; + F32 min2 = max1; + + // driven ________ // + // ^ /| |\ // + // | / | | \ // + // | / | | \ // + // | / | | \ // + // | / | | \ // + //-------|----|-------|----|-------> driver // + // | min1 max1 max2 min2 + + static LLStdStringHandle min1_string = LLXmlTree::addAttributeString("min1"); + child->getFastAttributeF32( min1_string, min1 ); // optional + static LLStdStringHandle max1_string = LLXmlTree::addAttributeString("max1"); + child->getFastAttributeF32( max1_string, max1 ); // optional + static LLStdStringHandle max2_string = LLXmlTree::addAttributeString("max2"); + child->getFastAttributeF32( max2_string, max2 ); // optional + static LLStdStringHandle min2_string = LLXmlTree::addAttributeString("min2"); + child->getFastAttributeF32( min2_string, min2 ); // optional + + // Push these on the front of the deque, so that we can construct + // them in order later (faster) + mDrivenInfoList.push_front( LLDrivenEntryInfo( driven_id, min1, max1, max2, min2 ) ); + } + else + { + llerrs << " Unable to resolve driven parameter: " << driven_id << llendl; + return FALSE; + } + } + return TRUE; +} + +//virtual +void LLDriverParamInfo::toStream(std::ostream &out) +{ + LLViewerVisualParamInfo::toStream(out); + out << "driver" << "\t"; + out << mDrivenInfoList.size() << "\t"; + for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++) + { + LLDrivenEntryInfo driven = *iter; + out << driven.mDrivenID << "\t"; + } + + out << std::endl; + + if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() && + mDriverParam->getAvatarAppearance()->isValid()) + { + for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++) + { + LLDrivenEntryInfo driven = *iter; + LLViewerVisualParam *param = + (LLViewerVisualParam*)mDriverParam->getAvatarAppearance()->getVisualParam(driven.mDrivenID); + if (param) + { + param->getInfo()->toStream(out); + if (param->getWearableType() != mWearableType) + { + if(param->getCrossWearable()) + { + out << "cross-wearable" << "\t"; + } + else + { + out << "ERROR!" << "\t"; + } + } + else + { + out << "valid" << "\t"; + } + } + else + { + llwarns << "could not get parameter " << driven.mDrivenID << " from avatar " + << mDriverParam->getAvatarAppearance() + << " for driver parameter " << getID() << llendl; + } + out << std::endl; + } + } +} + +//----------------------------------------------------------------------------- +// LLDriverParam +//----------------------------------------------------------------------------- + +LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */) : + mCurrentDistortionParam( NULL ), + mAvatarAppearance(appearance), + mWearablep(wearable) +{ + llassert(mAvatarAppearance); + if (mWearablep) + { + llassert(mAvatarAppearance->isSelf()); + } + mDefaultVec.clear(); +} + +LLDriverParam::~LLDriverParam() +{ +} + +BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) +{ + llassert(mInfo == NULL); + if (info->mID < 0) + return FALSE; + mInfo = info; + mID = info->mID; + info->mDriverParam = this; + + setWeight(getDefaultWeight(), FALSE ); + + return TRUE; +} + +/*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const +{ + llassert(wearable); + LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable); + *new_param = *this; + return new_param; +} + +void LLDriverParam::setWeight(F32 weight, BOOL upload_bake) +{ + F32 min_weight = getMinWeight(); + F32 max_weight = getMaxWeight(); + if (mIsAnimating) + { + // allow overshoot when animating + mCurWeight = weight; + } + else + { + mCurWeight = llclamp(weight, min_weight, max_weight); + } + + // driven ________ + // ^ /| |\ ^ + // | / | | \ | + // | / | | \ | + // | / | | \ | + // | / | | \ | + //-------|----|-------|----|-------> driver + // | min1 max1 max2 min2 + + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + LLDrivenEntryInfo* info = driven->mInfo; + + F32 driven_weight = 0.f; + F32 driven_min = driven->mParam->getMinWeight(); + F32 driven_max = driven->mParam->getMaxWeight(); + + if (mIsAnimating) + { + // driven param doesn't interpolate (textures, for example) + if (!driven->mParam->getAnimating()) + { + continue; + } + if( mCurWeight < info->mMin1 ) + { + if (info->mMin1 == min_weight) + { + if (info->mMin1 == info->mMax1) + { + driven_weight = driven_max; + } + else + { + //up slope extrapolation + F32 t = (mCurWeight - info->mMin1) / (info->mMax1 - info->mMin1 ); + driven_weight = driven_min + t * (driven_max - driven_min); + } + } + else + { + driven_weight = driven_min; + } + + setDrivenWeight(driven,driven_weight,upload_bake); + continue; + } + else + if ( mCurWeight > info->mMin2 ) + { + if (info->mMin2 == max_weight) + { + if (info->mMin2 == info->mMax2) + { + driven_weight = driven_max; + } + else + { + //down slope extrapolation + F32 t = (mCurWeight - info->mMax2) / (info->mMin2 - info->mMax2 ); + driven_weight = driven_max + t * (driven_min - driven_max); + } + } + else + { + driven_weight = driven_min; + } + + setDrivenWeight(driven,driven_weight,upload_bake); + continue; + } + } + + driven_weight = getDrivenWeight(driven, mCurWeight); + setDrivenWeight(driven,driven_weight,upload_bake); + } +} + +F32 LLDriverParam::getTotalDistortion() +{ + F32 sum = 0.f; + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + sum += driven->mParam->getTotalDistortion(); + } + + return sum; +} + +const LLVector4a &LLDriverParam::getAvgDistortion() +{ + // It's not actually correct to take the average of averages, but it good enough here. + LLVector4a sum; + sum.clear(); + S32 count = 0; + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + sum.add(driven->mParam->getAvgDistortion()); + count++; + } + sum.mul( 1.f/(F32)count); + + mDefaultVec = sum; + return mDefaultVec; +} + +F32 LLDriverParam::getMaxDistortion() +{ + F32 max = 0.f; + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + F32 param_max = driven->mParam->getMaxDistortion(); + if( param_max > max ) + { + max = param_max; + } + } + + return max; +} + + +LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) +{ + LLVector4a sum; + sum.clear(); + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + sum.add(driven->mParam->getVertexDistortion( index, poly_mesh )); + } + return sum; +} + +const LLVector4a* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) +{ + mCurrentDistortionParam = NULL; + const LLVector4a* v = NULL; + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + v = driven->mParam->getFirstDistortion( index, poly_mesh ); + if( v ) + { + mCurrentDistortionParam = driven->mParam; + break; + } + } + + return v; +}; + +const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) +{ + llassert( mCurrentDistortionParam ); + if( !mCurrentDistortionParam ) + { + return NULL; + } + + LLDrivenEntry* driven = NULL; + entry_list_t::iterator iter; + + // Set mDriven iteration to the right point + for( iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + driven = &(*iter); + if( driven->mParam == mCurrentDistortionParam ) + { + break; + } + } + + llassert(driven); + if (!driven) + { + return NULL; // shouldn't happen, but... + } + + // We're already in the middle of a param's distortions, so get the next one. + const LLVector4a* v = driven->mParam->getNextDistortion( index, poly_mesh ); + if( (!v) && (iter != mDriven.end()) ) + { + // This param is finished, so start the next param. It might not have any + // distortions, though, so we have to loop to find the next param that does. + for( iter++; iter != mDriven.end(); iter++ ) + { + driven = &(*iter); + v = driven->mParam->getFirstDistortion( index, poly_mesh ); + if( v ) + { + mCurrentDistortionParam = driven->mParam; + break; + } + } + } + + return v; +}; + +S32 LLDriverParam::getDrivenParamsCount() const +{ + return mDriven.size(); +} + +const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const +{ + if (0 > index || index >= mDriven.size()) + { + return NULL; + } + return mDriven[index].mParam; +} + +//----------------------------------------------------------------------------- +// setAnimationTarget() +//----------------------------------------------------------------------------- +void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake ) +{ + LLVisualParam::setAnimationTarget(target_value, upload_bake); + + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + F32 driven_weight = getDrivenWeight(driven, mTargetWeight); + + // this isn't normally necessary, as driver params handle interpolation of their driven params + // but texture params need to know to assume their final value at beginning of interpolation + driven->mParam->setAnimationTarget(driven_weight, upload_bake); + } +} + +//----------------------------------------------------------------------------- +// stopAnimating() +//----------------------------------------------------------------------------- +void LLDriverParam::stopAnimating(BOOL upload_bake) +{ + LLVisualParam::stopAnimating(upload_bake); + + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + driven->mParam->setAnimating(FALSE); + } +} + +/*virtual*/ +BOOL LLDriverParam::linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params) +{ + BOOL success = TRUE; + LLDriverParamInfo::entry_info_list_t::iterator iter; + for (iter = getInfo()->mDrivenInfoList.begin(); iter != getInfo()->mDrivenInfoList.end(); ++iter) + { + LLDrivenEntryInfo *driven_info = &(*iter); + S32 driven_id = driven_info->mDrivenID; + + // check for already existing links. Do not overwrite. + BOOL found = FALSE; + for (entry_list_t::iterator driven_iter = mDriven.begin(); driven_iter != mDriven.end() && !found; ++driven_iter) + { + if (driven_iter->mInfo->mDrivenID == driven_id) + { + found = TRUE; + } + } + + if (!found) + { + LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id); + bool push = param && (!only_cross_params || param->getCrossWearable()); + if (push) + { + mDriven.push_back(LLDrivenEntry( param, driven_info )); + } + else + { + success = FALSE; + } + } + } + + return success; +} + +void LLDriverParam::resetDrivenParams() +{ + mDriven.clear(); + mDriven.reserve(getInfo()->mDrivenInfoList.size()); +} + +void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type) +{ + bool needs_update = (getWearableType()==driven_type); + + // if the driver has a driven entry for the passed-in wearable type, we need to refresh the value + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + { + LLDrivenEntry* driven = &(*iter); + if (driven && driven->mParam && driven->mParam->getCrossWearable() && driven->mParam->getWearableType() == driven_type) + { + needs_update = true; + } + } + + + if (needs_update) + { + LLWearableType::EType driver_type = (LLWearableType::EType)getWearableType(); + + // If we've gotten here, we've added a new wearable of type "type" + // Thus this wearable needs to get updates from the driver wearable. + // The call to setVisualParamWeight seems redundant, but is necessary + // as the number of driven wearables has changed since the last update. -Nyx + LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type); + if (wearable) + { + wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false); + } + } +} + + +//----------------------------------------------------------------------------- +// getDrivenWeight() +//----------------------------------------------------------------------------- +F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight) +{ + F32 min_weight = getMinWeight(); + F32 max_weight = getMaxWeight(); + const LLDrivenEntryInfo* info = driven->mInfo; + + F32 driven_weight = 0.f; + F32 driven_min = driven->mParam->getMinWeight(); + F32 driven_max = driven->mParam->getMaxWeight(); + + if( input_weight <= info->mMin1 ) + { + if( info->mMin1 == info->mMax1 && + info->mMin1 <= min_weight) + { + driven_weight = driven_max; + } + else + { + driven_weight = driven_min; + } + } + else + if( input_weight <= info->mMax1 ) + { + F32 t = (input_weight - info->mMin1) / (info->mMax1 - info->mMin1 ); + driven_weight = driven_min + t * (driven_max - driven_min); + } + else + if( input_weight <= info->mMax2 ) + { + driven_weight = driven_max; + } + else + if( input_weight <= info->mMin2 ) + { + F32 t = (input_weight - info->mMax2) / (info->mMin2 - info->mMax2 ); + driven_weight = driven_max + t * (driven_min - driven_max); + } + else + { + if (info->mMax2 >= max_weight) + { + driven_weight = driven_max; + } + else + { + driven_weight = driven_min; + } + } + + return driven_weight; +} + +void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake) +{ + bool use_self = false; + if(mWearablep && + mAvatarAppearance->isValid() && + driven->mParam->getCrossWearable()) + { + LLWearable* wearable = dynamic_cast (mWearablep); + if (mAvatarAppearance->getWearableData()->isOnTop(wearable)) + { + use_self = true; + } + } + + if (use_self) + { + // call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values + mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake ); + } + else + { + driven->mParam->setWeight( driven_weight, upload_bake ); + } +} diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h new file mode 100644 index 0000000000..30e71daad9 --- /dev/null +++ b/indra/llappearance/lldriverparam.h @@ -0,0 +1,133 @@ +/** + * @file lldriverparam.h + * @brief A visual parameter that drives (controls) other visual parameters. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDRIVERPARAM_H +#define LL_LLDRIVERPARAM_H + +#include "llviewervisualparam.h" +#include "llwearabletype.h" + +class LLAvatarAppearance; +class LLDriverParam; +class LLWearable; + +//----------------------------------------------------------------------------- + +struct LLDrivenEntryInfo +{ + LLDrivenEntryInfo( S32 id, F32 min1, F32 max1, F32 max2, F32 min2 ) + : mDrivenID( id ), mMin1( min1 ), mMax1( max1 ), mMax2( max2 ), mMin2( min2 ) {} + S32 mDrivenID; + F32 mMin1; + F32 mMax1; + F32 mMax2; + F32 mMin2; +}; + +struct LLDrivenEntry +{ + LLDrivenEntry( LLViewerVisualParam* param, LLDrivenEntryInfo *info ) + : mParam( param ), mInfo( info ) {} + LLViewerVisualParam* mParam; + LLDrivenEntryInfo* mInfo; +}; + +//----------------------------------------------------------------------------- + +class LLDriverParamInfo : public LLViewerVisualParamInfo +{ + friend class LLDriverParam; +public: + LLDriverParamInfo(); + /*virtual*/ ~LLDriverParamInfo() {}; + + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + + /*virtual*/ void toStream(std::ostream &out); + +protected: + typedef std::deque entry_info_list_t; + entry_info_list_t mDrivenInfoList; + LLDriverParam* mDriverParam; // backpointer +}; + +//----------------------------------------------------------------------------- + +class LLDriverParam : public LLViewerVisualParam +{ +private: + // Hide the default constructor. Force construction with LLAvatarAppearance. + LLDriverParam() {} +public: + LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable = NULL); + ~LLDriverParam(); + + // Special: These functions are overridden by child classes + LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; } + // This sets mInfo and calls initialization functions + BOOL setInfo(LLDriverParamInfo *info); + + LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; } + const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } + + void updateCrossDrivenParams(LLWearableType::EType driven_type); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + + // LLVisualParam Virtual functions + /*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param. + /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); + /*virtual*/ void setAnimationTarget( F32 target_value, BOOL upload_bake ); + /*virtual*/ void stopAnimating(BOOL upload_bake); + /*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); + /*virtual*/ void resetDrivenParams(); + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion(); + /*virtual*/ const LLVector4a& getAvgDistortion(); + /*virtual*/ F32 getMaxDistortion(); + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); + + S32 getDrivenParamsCount() const; + const LLViewerVisualParam* getDrivenParam(S32 index) const; + +protected: + F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); + void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake); + + + LLVector4a mDefaultVec; // temp holder + typedef std::vector entry_list_t; + entry_list_t mDriven; + LLViewerVisualParam* mCurrentDistortionParam; + // Backlink only; don't make this an LLPointer. + LLAvatarAppearance* mAvatarAppearance; + LLWearable* mWearablep; +}; + +#endif // LL_LLDRIVERPARAM_H diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index a741a83af7..9b70f737a0 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -40,6 +40,7 @@ #include "lltexturemanagerbridge.h" #include "llui.h" #include "llwearable.h" +#include "llwearabledata.h" #include "llvertexbuffer.h" #include "llviewervisualparam.h" @@ -1560,11 +1561,11 @@ U32 LLTexLayerTemplate::updateWearableCache() const return 0; } LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te); - U32 num_wearables = getAvatarAppearance()->getWearableCount(wearable_type); + U32 num_wearables = getAvatarAppearance()->getWearableData()->getWearableCount(wearable_type); U32 added = 0; for (U32 i = 0; i < num_wearables; i++) { - LLWearable* wearable = getAvatarAppearance()->getWearable(wearable_type, i); + LLWearable* wearable = getAvatarAppearance()->getWearableData()->getWearable(wearable_type, i); if (!wearable) { continue; diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index 8a99debac8..e1cd26bdef 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -33,6 +33,7 @@ #include "llwearabletype.h" #include "lllocaltextureobject.h" +class LLMD5; class LLVisualParam; class LLTexGlobalColorInfo; class LLTexGlobalColor; @@ -98,6 +99,12 @@ public: typedef std::map texture_id_map_t; const texture_id_map_t& getTextureIDMap() const { return mTextureIDMap; } + // Something happened that requires the wearable to be updated (e.g. worn/unworn). + virtual void setUpdated() const = 0; + + // Update the baked texture hash. + virtual void addToBakedTextureHash(LLMD5& hash) const = 0; + protected: virtual void createVisualParams() = 0; diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp new file mode 100644 index 0000000000..d70bbf286a --- /dev/null +++ b/indra/llappearance/llwearabledata.cpp @@ -0,0 +1,353 @@ +/** + * @file llwearabledata.cpp + * @brief LLWearableData class implementation + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llwearabledata.h" + +#include "llavatarappearance.h" +#include "llavatarappearancedefines.h" +#include "lldriverparam.h" +#include "llmd5.h" + +LLWearableData::LLWearableData() : + mAvatarAppearance(NULL) +{ +} + +// virtual +LLWearableData::~LLWearableData() +{ +} + +using namespace LLAvatarAppearanceDefines; + +LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index) +{ + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return NULL; + } + wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + return NULL; + } + else + { + return wearable_vec[index]; + } +} + +void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable) +{ + LLWearable *old_wearable = getWearable(type,index); + if (!old_wearable) + { + pushWearable(type,wearable); + return; + } + + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + llwarns << "invalid type, type " << type << " index " << index << llendl; + return; + } + wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + llwarns << "invalid index, type " << type << " index " << index << llendl; + } + else + { + wearable_vec[index] = wearable; + old_wearable->setUpdated(); + const BOOL removed = FALSE; + wearableUpdated(wearable, removed); + } +} + +U32 LLWearableData::pushWearable(const LLWearableType::EType type, + LLWearable *wearable, + bool trigger_updated /* = true */) +{ + if (wearable == NULL) + { + // no null wearables please! + llwarns << "Null wearable sent for type " << type << llendl; + return MAX_CLOTHING_PER_TYPE; + } + if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) + { + mWearableDatas[type].push_back(wearable); + if (trigger_updated) + { + const BOOL removed = FALSE; + wearableUpdated(wearable, removed); + } + return mWearableDatas[type].size()-1; + } + return MAX_CLOTHING_PER_TYPE; +} + +// virtual +void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed) +{ + wearable->setUpdated(); + if (!removed) + { + pullCrossWearableValues(wearable->getType()); + } +} + +void LLWearableData::popWearable(LLWearable *wearable) +{ + if (wearable == NULL) + { + // nothing to do here. move along. + return; + } + + U32 index = getWearableIndex(wearable); + const LLWearableType::EType type = wearable->getType(); + + if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type)) + { + popWearable(type, index); + } +} + +void LLWearableData::popWearable(const LLWearableType::EType type, U32 index) +{ + LLWearable *wearable = getWearable(type, index); + if (wearable) + { + mWearableDatas[type].erase(mWearableDatas[type].begin() + index); + const BOOL removed = TRUE; + wearableUpdated(wearable, removed); + } +} + +void LLWearableData::clearWearableType(const LLWearableType::EType type) +{ + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return; + } + wearableentry_vec_t& wearable_vec = wearable_iter->second; + wearable_vec.clear(); +} + +bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b) +{ + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return false; + } + + wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (0 > index_a || index_a >= wearable_vec.size()) return false; + if (0 > index_b || index_b >= wearable_vec.size()) return false; + + LLWearable* wearable = wearable_vec[index_a]; + wearable_vec[index_a] = wearable_vec[index_b]; + wearable_vec[index_b] = wearable; + return true; +} + +void LLWearableData::pullCrossWearableValues(const LLWearableType::EType type) +{ + llassert(mAvatarAppearance); + // scan through all of the avatar's visual parameters + for (LLViewerVisualParam* param = (LLViewerVisualParam*) mAvatarAppearance->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) mAvatarAppearance->getNextVisualParam()) + { + if( param ) + { + LLDriverParam *driver_param = dynamic_cast(param); + if(driver_param) + { + // parameter is a driver parameter, have it update its cross-driven params + driver_param->updateCrossDrivenParams(type); + } + } + } +} + + +U32 LLWearableData::getWearableIndex(const LLWearable *wearable) const +{ + if (wearable == NULL) + { + return MAX_CLOTHING_PER_TYPE; + } + + const LLWearableType::EType type = wearable->getType(); + wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + llwarns << "tried to get wearable index with an invalid type!" << llendl; + return MAX_CLOTHING_PER_TYPE; + } + const wearableentry_vec_t& wearable_vec = wearable_iter->second; + for(U32 index = 0; index < wearable_vec.size(); index++) + { + if (wearable_vec[index] == wearable) + { + return index; + } + } + + return MAX_CLOTHING_PER_TYPE; +} + +BOOL LLWearableData::isOnTop(LLWearable* wearable) const +{ + if (!wearable) return FALSE; + const LLWearableType::EType type = wearable->getType(); + return ( getTopWearable(type) == wearable ); +} + +const LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index) const +{ + wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return NULL; + } + const wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + return NULL; + } + else + { + return wearable_vec[index]; + } +} + +LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type) +{ + U32 count = getWearableCount(type); + if ( count == 0) + { + return NULL; + } + + return getWearable(type, count-1); +} + +const LLWearable* LLWearableData::getTopWearable(const LLWearableType::EType type) const +{ + U32 count = getWearableCount(type); + if ( count == 0) + { + return NULL; + } + + return getWearable(type, count-1); +} + +LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type) +{ + if (getWearableCount(type) == 0) + { + return NULL; + } + + return getWearable(type, 0); +} + +const LLWearable* LLWearableData::getBottomWearable(const LLWearableType::EType type) const +{ + if (getWearableCount(type) == 0) + { + return NULL; + } + + return getWearable(type, 0); +} + +U32 LLWearableData::getWearableCount(const LLWearableType::EType type) const +{ + wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return 0; + } + const wearableentry_vec_t& wearable_vec = wearable_iter->second; + return wearable_vec.size(); +} + +U32 LLWearableData::getWearableCount(const U32 tex_index) const +{ + const LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index); + return getWearableCount(wearable_type); +} + +LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index, + BOOL generate_valid_hash) // Set to false if you want to upload the baked texture w/o putting it in the cache +{ + LLUUID hash_id; + bool hash_computed = false; + LLMD5 hash; + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index); + + for (U8 i=0; i < baked_dict->mWearables.size(); i++) + { + const LLWearableType::EType baked_type = baked_dict->mWearables[i]; + const U32 num_wearables = getWearableCount(baked_type); + for (U32 index = 0; index < num_wearables; ++index) + { + const LLWearable* wearable = getWearable(baked_type,index); + if (wearable) + { + wearable->addToBakedTextureHash(hash); + hash_computed = true; + } + } + } + if (hash_computed) + { + hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES); + + if (!generate_valid_hash) + { + invalidateBakedTextureHash(hash); + } + hash.finalize(); + hash.raw_digest(hash_id.mData); + } + + return hash_id; +} + + diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h new file mode 100644 index 0000000000..2931424131 --- /dev/null +++ b/indra/llappearance/llwearabledata.h @@ -0,0 +1,108 @@ +/** + * @file llwearabledata.h + * @brief LLWearableData class header file + * + * $LicenseInfo:firstyear=20012license=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_WEARABLEDATA_H +#define LL_WEARABLEDATA_H + +#include "llavatarappearancedefines.h" +#include "llerror.h" + +class LLAvatarAppearance; + +class LLWearableData +{ + // *TODO: Figure out why this is causing compile error. + //LOG_CLASS(LLWearableData); + + //-------------------------------------------------------------------- + // Constructors / destructors / Initializers + //-------------------------------------------------------------------- +public: + LLWearableData(); + virtual ~LLWearableData(); + + void setAvatarAppearance(LLAvatarAppearance* appearance) { mAvatarAppearance = appearance; } + +protected: + //-------------------------------------------------------------------- + // Accessors + //-------------------------------------------------------------------- +public: + LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/); + const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const; + LLWearable* getTopWearable(const LLWearableType::EType type); + const LLWearable* getTopWearable(const LLWearableType::EType type) const; + LLWearable* getBottomWearable(const LLWearableType::EType type); + const LLWearable* getBottomWearable(const LLWearableType::EType type) const; + U32 getWearableCount(const LLWearableType::EType type) const; + U32 getWearableCount(const U32 tex_index) const; + U32 getWearableIndex(const LLWearable *wearable) const; + + BOOL isOnTop(LLWearable* wearable) const; + + static const U32 MAX_CLOTHING_PER_TYPE = 5; + + //-------------------------------------------------------------------- + // Setters + //-------------------------------------------------------------------- +protected: + // Low-level data structure setter - public access is via setWearableItem, etc. + void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable); + U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable, + bool trigger_updated = true); + virtual void wearableUpdated(LLWearable *wearable, BOOL removed); + void popWearable(LLWearable *wearable); + void popWearable(const LLWearableType::EType type, U32 index); + void clearWearableType(const LLWearableType::EType type); + bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b); + +private: + void pullCrossWearableValues(const LLWearableType::EType type); + + //-------------------------------------------------------------------- + // Server Communication + //-------------------------------------------------------------------- +public: + LLUUID computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index, + BOOL generate_valid_hash = TRUE); +protected: + virtual void invalidateBakedTextureHash(LLMD5& hash) const {} + + //-------------------------------------------------------------------- + // Member variables + //-------------------------------------------------------------------- +private: + LLAvatarAppearance* mAvatarAppearance; + typedef std::vector wearableentry_vec_t; // all wearables of a certain type (EG all shirts) + typedef std::map wearableentry_map_t; // wearable "categories" arranged by wearable type + wearableentry_map_t mWearableDatas; + +}; + + + +#endif // LL_WEARABLEDATA_H + -- cgit v1.2.3 From 77b33d9623c08152932282048fe847d79fcf43cd Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Fri, 7 Sep 2012 23:17:34 -0400 Subject: SH-3264 Porting over the XML loading of the avatar structure to llappearance Moved over the necessary classes to llappearance to support the loading of the avatar's structure & params from file. --- indra/llappearance/CMakeLists.txt | 10 + indra/llappearance/llavatarappearance.cpp | 1421 ++++++++++++++++++++++- indra/llappearance/llavatarappearance.h | 207 +++- indra/llappearance/llavatarjoint.cpp | 261 +++++ indra/llappearance/llavatarjoint.h | 127 ++ indra/llappearance/llavatarjointmesh.cpp | 359 ++++++ indra/llappearance/llavatarjointmesh.h | 140 +++ indra/llappearance/llpolymesh.cpp | 1050 +++++++++++++++++ indra/llappearance/llpolymesh.h | 369 ++++++ indra/llappearance/llpolymorph.cpp | 748 ++++++++++++ indra/llappearance/llpolymorph.h | 182 +++ indra/llappearance/llpolyskeletaldistortion.cpp | 293 +++++ indra/llappearance/llpolyskeletaldistortion.h | 119 ++ 13 files changed, 5270 insertions(+), 16 deletions(-) create mode 100644 indra/llappearance/llavatarjoint.cpp create mode 100644 indra/llappearance/llavatarjoint.h create mode 100755 indra/llappearance/llavatarjointmesh.cpp create mode 100755 indra/llappearance/llavatarjointmesh.h create mode 100644 indra/llappearance/llpolymesh.cpp create mode 100644 indra/llappearance/llpolymesh.h create mode 100644 indra/llappearance/llpolymorph.cpp create mode 100644 indra/llappearance/llpolymorph.h create mode 100644 indra/llappearance/llpolyskeletaldistortion.cpp create mode 100644 indra/llappearance/llpolyskeletaldistortion.h (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index 41da898457..c5a855a505 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -42,9 +42,14 @@ include_directories( set(llappearance_SOURCE_FILES llavatarappearance.cpp + llavatarjoint.cpp + llavatarjointmesh.cpp lldriverparam.cpp llinventoryicon.cpp lllocaltextureobject.cpp + llpolyskeletaldistortion.cpp + llpolymesh.cpp + llpolymorph.cpp lltexglobalcolor.cpp lltexlayer.cpp lltexlayerparams.cpp @@ -60,10 +65,15 @@ set(llappearance_HEADER_FILES CMakeLists.txt llavatarappearance.h + llavatarjoint.h + llavatarjointmesh.h lldriverparam.h llinventoryicon.h lljointpickname.h lllocaltextureobject.h + llpolyskeletaldistortion.h + llpolymesh.h + llpolymorph.h lltexglobalcolor.h lltexlayer.h lltexlayerparams.h diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 2c03f8ba02..406e6153e0 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -29,19 +29,128 @@ #include "llavatarappearance.h" #include "llavatarappearancedefines.h" +#include "llavatarjointmesh.h" #include "imageids.h" +#include "lldir.h" #include "lldeleteutils.h" +#include "llpolymorph.h" +#include "llpolymesh.h" +#include "llpolyskeletaldistortion.h" #include "lltexglobalcolor.h" #include "llwearabledata.h" +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +const std::string AVATAR_DEFAULT_CHAR = "avatar"; const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); +/********************************************************************************* + ** ** + ** Begin private LLAvatarAppearance Support classes + ** + **/ + +//------------------------------------------------------------------------ +// LLAvatarBoneInfo +// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton. +//------------------------------------------------------------------------ +class LLAvatarBoneInfo +{ + friend class LLAvatarAppearance; + friend class LLAvatarSkeletonInfo; +public: + LLAvatarBoneInfo() : mIsJoint(FALSE) {} + ~LLAvatarBoneInfo() + { + std::for_each(mChildList.begin(), mChildList.end(), DeletePointer()); + } + BOOL parseXml(LLXmlTreeNode* node); + +private: + std::string mName; + BOOL mIsJoint; + LLVector3 mPos; + LLVector3 mRot; + LLVector3 mScale; + LLVector3 mPivot; + typedef std::vector child_list_t; + child_list_t mChildList; +}; + +//------------------------------------------------------------------------ +// LLAvatarSkeletonInfo +// Overall avatar skeleton +//------------------------------------------------------------------------ +class LLAvatarSkeletonInfo +{ + friend class LLAvatarAppearance; +public: + LLAvatarSkeletonInfo() : + mNumBones(0), mNumCollisionVolumes(0) {} + ~LLAvatarSkeletonInfo() + { + std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer()); + } + BOOL parseXml(LLXmlTreeNode* node); + S32 getNumBones() const { return mNumBones; } + S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; } + +private: + S32 mNumBones; + S32 mNumCollisionVolumes; + typedef std::vector bone_info_list_t; + bone_info_list_t mBoneInfoList; +}; + +//----------------------------------------------------------------------------- +// LLAvatarXmlInfo +//----------------------------------------------------------------------------- + +LLAvatarAppearance::LLAvatarXmlInfo::LLAvatarXmlInfo() + : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0) +{ +} + +LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo() +{ + std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer()); + std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer()); + std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer()); + deleteAndClear(mTexSkinColorInfo); + deleteAndClear(mTexHairColorInfo); + deleteAndClear(mTexEyeColorInfo); + std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer()); + std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer()); + std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer()); +} + + +/** + ** + ** End LLAvatarAppearance Support classes + ** ** + *********************************************************************************/ + +//----------------------------------------------------------------------------- +// Static Data +//----------------------------------------------------------------------------- +LLXmlTree LLAvatarAppearance::sXMLTree; +LLXmlTree LLAvatarAppearance::sSkeletonXMLTree; +LLAvatarSkeletonInfo* LLAvatarAppearance::sAvatarSkeletonInfo = NULL; +LLAvatarAppearance::LLAvatarXmlInfo* LLAvatarAppearance::sAvatarXmlInfo = NULL; + + LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : LLCharacter(), mIsDummy(FALSE), mTexSkinColor( NULL ), mTexHairColor( NULL ), mTexEyeColor( NULL ), + mPelvisToFoot(0.f), + mHeadOffset(), + mWearableData(wearable_data) { llassert(mWearableData); @@ -55,30 +164,824 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mBakedTextureDatas[i].mMaskTexName = 0; mBakedTextureDatas[i].mTextureIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i); } + + mIsBuilt = FALSE; + + mNumJoints = 0; + mSkeleton = NULL; + + mNumCollisionVolumes = 0; + mCollisionVolumes = NULL; + + mRoot = new LLAvatarJoint(); + +} + +// virtual +LLAvatarAppearance::~LLAvatarAppearance() +{ + deleteAndClear(mTexSkinColor); + deleteAndClear(mTexHairColor); + deleteAndClear(mTexEyeColor); + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + deleteAndClear(mBakedTextureDatas[i].mTexLayerSet); + mBakedTextureDatas[i].mMeshes.clear(); + + for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin(); + iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++) + { + LLMaskedMorph* masked_morph = (*iter2); + delete masked_morph; + } + } + + mRoot->removeAllChildren(); + mJointMap.clear(); + + deleteAndClearArray(mSkeleton); + deleteAndClearArray(mCollisionVolumes); + + mNumJoints = 0; + + deleteAndClear(mTexSkinColor); + deleteAndClear(mTexHairColor); + deleteAndClear(mTexEyeColor); + + std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer()); + mMeshes.clear(); + + for (std::vector::iterator jointIter = mMeshLOD.begin(); + jointIter != mMeshLOD.end(); + ++jointIter) + { + LLAvatarJoint* joint = (LLAvatarJoint *) *jointIter; + std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer()); + joint->mMeshParts.clear(); + } + std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer()); + mMeshLOD.clear(); +} + +//static +void LLAvatarAppearance::initClass() +{ + std::string xmlFile; + + xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml"; + BOOL success = sXMLTree.parseFile( xmlFile, FALSE ); + if (!success) + { + llerrs << "Problem reading avatar configuration file:" << xmlFile << llendl; + } + + // now sanity check xml file + LLXmlTreeNode* root = sXMLTree.getRoot(); + if (!root) + { + llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl; + return; + } + + //------------------------------------------------------------------------- + // (root) + //------------------------------------------------------------------------- + if( !root->hasName( "linden_avatar" ) ) + { + llerrs << "Invalid avatar file header: " << xmlFile << llendl; + } + + std::string version; + static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); + if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) + { + llerrs << "Invalid avatar file version: " << version << " in file: " << xmlFile << llendl; + } + + S32 wearable_def_version = 1; + static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version"); + root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version ); + LLWearable::setCurrentDefinitionVersion( wearable_def_version ); + + std::string mesh_file_name; + + LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" ); + if (!skeleton_node) + { + llerrs << "No skeleton in avatar configuration file: " << xmlFile << llendl; + return; + } + + std::string skeleton_file_name; + static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); + if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name)) + { + llerrs << "No file name in skeleton node in avatar config file: " << xmlFile << llendl; + } + + std::string skeleton_path; + skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name); + if (!parseSkeletonFile(skeleton_path)) + { + llerrs << "Error parsing skeleton file: " << skeleton_path << llendl; + } + + // Process XML data + + // avatar_skeleton.xml + if (sAvatarSkeletonInfo) + { //this can happen if a login attempt failed + delete sAvatarSkeletonInfo; + } + sAvatarSkeletonInfo = new LLAvatarSkeletonInfo; + if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot())) + { + llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl; + } + // parse avatar_lad.xml + if (sAvatarXmlInfo) + { //this can happen if a login attempt failed + deleteAndClear(sAvatarXmlInfo); + } + sAvatarXmlInfo = new LLAvatarXmlInfo; + if (!sAvatarXmlInfo->parseXmlSkeletonNode(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlMeshNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlColorNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlLayerNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlDriverNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } + if (!sAvatarXmlInfo->parseXmlMorphNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } +} + +using namespace LLAvatarAppearanceDefines; + +//------------------------------------------------------------------------ +// The viewer can only suggest a good size for the agent, +// the simulator will keep it inside a reasonable range. +void LLAvatarAppearance::computeBodySize() +{ + LLVector3 pelvis_scale = mPelvisp->getScale(); + + // some of the joints have not been cached + LLVector3 skull = mSkullp->getPosition(); + LLVector3 skull_scale = mSkullp->getScale(); + + LLVector3 neck = mNeckp->getPosition(); + LLVector3 neck_scale = mNeckp->getScale(); + + LLVector3 chest = mChestp->getPosition(); + LLVector3 chest_scale = mChestp->getScale(); + + // the rest of the joints have been cached + LLVector3 head = mHeadp->getPosition(); + LLVector3 head_scale = mHeadp->getScale(); + + LLVector3 torso = mTorsop->getPosition(); + LLVector3 torso_scale = mTorsop->getScale(); + + LLVector3 hip = mHipLeftp->getPosition(); + LLVector3 hip_scale = mHipLeftp->getScale(); + + LLVector3 knee = mKneeLeftp->getPosition(); + LLVector3 knee_scale = mKneeLeftp->getScale(); + + LLVector3 ankle = mAnkleLeftp->getPosition(); + LLVector3 ankle_scale = mAnkleLeftp->getScale(); + + LLVector3 foot = mFootLeftp->getPosition(); + + mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] - + knee.mV[VZ] * hip_scale.mV[VZ] - + ankle.mV[VZ] * knee_scale.mV[VZ] - + foot.mV[VZ] * ankle_scale.mV[VZ]; + + LLVector3 new_body_size; + new_body_size.mV[VZ] = mPelvisToFoot + + // the sqrt(2) correction below is an approximate + // correction to get to the top of the head + F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + + head.mV[VZ] * neck_scale.mV[VZ] + + neck.mV[VZ] * chest_scale.mV[VZ] + + chest.mV[VZ] * torso_scale.mV[VZ] + + torso.mV[VZ] * pelvis_scale.mV[VZ]; + + // TODO -- measure the real depth and width + new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; + new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; + + if (new_body_size != mBodySize) + { + mBodySize = new_body_size; + bodySizeChanged(); + } +} + +//----------------------------------------------------------------------------- +// parseSkeletonFile() +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + //------------------------------------------------------------------------- + // parse the file + //------------------------------------------------------------------------- + BOOL parsesuccess = sSkeletonXMLTree.parseFile( filename, FALSE ); + + if (!parsesuccess) + { + llerrs << "Can't parse skeleton file: " << filename << llendl; + return FALSE; + } + + // now sanity check xml file + LLXmlTreeNode* root = sSkeletonXMLTree.getRoot(); + if (!root) + { + llerrs << "No root node found in avatar skeleton file: " << filename << llendl; + return FALSE; + } + + if( !root->hasName( "linden_skeleton" ) ) + { + llerrs << "Invalid avatar skeleton file header: " << filename << llendl; + return FALSE; + } + + std::string version; + static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); + if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) + { + llerrs << "Invalid avatar skeleton file version: " << version << " in file: " << filename << llendl; + return FALSE; + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// setupBone() +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &volume_num, S32 &joint_num) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + LLJoint* joint = NULL; + + if (info->mIsJoint) + { + joint = getCharacterJoint(joint_num); + if (!joint) + { + llwarns << "Too many bones" << llendl; + return FALSE; + } + joint->setName( info->mName ); + } + else // collision volume + { + if (volume_num >= (S32)mNumCollisionVolumes) + { + llwarns << "Too many bones" << llendl; + return FALSE; + } + joint = (&mCollisionVolumes[volume_num]); + joint->setName( info->mName ); + } + + // add to parent + if (parent) + { + parent->addChild( joint ); + } + + joint->setPosition(info->mPos); + joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY], + info->mRot.mV[VZ], LLQuaternion::XYZ)); + joint->setScale(info->mScale); + + joint->setDefaultFromCurrentXform(); + + if (info->mIsJoint) + { + joint->setSkinOffset( info->mPivot ); + joint_num++; + } + else // collision volume + { + volume_num++; + } + + // setup children + LLAvatarBoneInfo::child_list_t::const_iterator iter; + for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter) + { + LLAvatarBoneInfo *child_info = *iter; + if (!setupBone(child_info, joint, volume_num, joint_num)) + { + return FALSE; + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// buildSkeleton() +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + //------------------------------------------------------------------------- + // allocate joints + //------------------------------------------------------------------------- + if (!allocateCharacterJoints(info->mNumBones)) + { + llerrs << "Can't allocate " << info->mNumBones << " joints" << llendl; + return FALSE; + } + + //------------------------------------------------------------------------- + // allocate volumes + //------------------------------------------------------------------------- + if (info->mNumCollisionVolumes) + { + if (!allocateCollisionVolumes(info->mNumCollisionVolumes)) + { + llerrs << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << llendl; + return FALSE; + } + } + + S32 current_joint_num = 0; + S32 current_volume_num = 0; + LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; + for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter) + { + LLAvatarBoneInfo *info = *iter; + if (!setupBone(info, NULL, current_volume_num, current_joint_num)) + { + llerrs << "Error parsing bone in skeleton file" << llendl; + return FALSE; + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLAvatarAppearance::buildCharacter() +// Deferred initialization and rebuild of the avatar. +//----------------------------------------------------------------------------- +void LLAvatarAppearance::buildCharacter() +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + //------------------------------------------------------------------------- + // remove all references to our existing skeleton + // so we can rebuild it + //------------------------------------------------------------------------- + flushAllMotions(); + + //------------------------------------------------------------------------- + // remove all of mRoot's children + //------------------------------------------------------------------------- + mRoot->removeAllChildren(); + mJointMap.clear(); + mIsBuilt = FALSE; + + //------------------------------------------------------------------------- + // (re)load our skeleton and meshes + //------------------------------------------------------------------------- + LLTimer timer; + + BOOL status = loadAvatar(); + stop_glerror(); + +// gPrintMessagesThisFrame = TRUE; + lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl; + + if (!status) + { + if (isSelf()) + { + llerrs << "Unable to load user's avatar" << llendl; + } + else + { + llwarns << "Unable to load other's avatar" << llendl; + } + return; + } + + //------------------------------------------------------------------------- + // initialize "well known" joint pointers + //------------------------------------------------------------------------- + mPelvisp = mRoot->findJoint("mPelvis"); + mTorsop = mRoot->findJoint("mTorso"); + mChestp = mRoot->findJoint("mChest"); + mNeckp = mRoot->findJoint("mNeck"); + mHeadp = mRoot->findJoint("mHead"); + mSkullp = mRoot->findJoint("mSkull"); + mHipLeftp = mRoot->findJoint("mHipLeft"); + mHipRightp = mRoot->findJoint("mHipRight"); + mKneeLeftp = mRoot->findJoint("mKneeLeft"); + mKneeRightp = mRoot->findJoint("mKneeRight"); + mAnkleLeftp = mRoot->findJoint("mAnkleLeft"); + mAnkleRightp = mRoot->findJoint("mAnkleRight"); + mFootLeftp = mRoot->findJoint("mFootLeft"); + mFootRightp = mRoot->findJoint("mFootRight"); + mWristLeftp = mRoot->findJoint("mWristLeft"); + mWristRightp = mRoot->findJoint("mWristRight"); + mEyeLeftp = mRoot->findJoint("mEyeLeft"); + mEyeRightp = mRoot->findJoint("mEyeRight"); + + //------------------------------------------------------------------------- + // Make sure "well known" pointers exist + //------------------------------------------------------------------------- + if (!(mPelvisp && + mTorsop && + mChestp && + mNeckp && + mHeadp && + mSkullp && + mHipLeftp && + mHipRightp && + mKneeLeftp && + mKneeRightp && + mAnkleLeftp && + mAnkleRightp && + mFootLeftp && + mFootRightp && + mWristLeftp && + mWristRightp && + mEyeLeftp && + mEyeRightp)) + { + llerrs << "Failed to create avatar." << llendl; + return; + } + + //------------------------------------------------------------------------- + // initialize the pelvis + //------------------------------------------------------------------------- + mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) ); + + mIsBuilt = TRUE; + stop_glerror(); + +} + +BOOL LLAvatarAppearance::loadAvatar() +{ +// LLFastTimer t(FTM_LOAD_AVATAR); + + // avatar_skeleton.xml + if( !buildSkeleton(sAvatarSkeletonInfo) ) + { + llwarns << "avatar file: buildSkeleton() failed" << llendl; + return FALSE; + } + + // avatar_lad.xml : + if( !loadSkeletonNode() ) + { + llwarns << "avatar file: loadNodeSkeleton() failed" << llendl; + return FALSE; + } + + // avatar_lad.xml : + if( !loadMeshNodes() ) + { + llwarns << "avatar file: loadNodeMesh() failed" << llendl; + return FALSE; + } + + // avatar_lad.xml : + if( sAvatarXmlInfo->mTexSkinColorInfo ) + { + mTexSkinColor = new LLTexGlobalColor( this ); + if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) ) + { + llwarns << "avatar file: mTexSkinColor->setInfo() failed" << llendl; + return FALSE; + } + } + else + { + llwarns << " name=\"skin_color\" not found" << llendl; + return FALSE; + } + if( sAvatarXmlInfo->mTexHairColorInfo ) + { + mTexHairColor = new LLTexGlobalColor( this ); + if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) ) + { + llwarns << "avatar file: mTexHairColor->setInfo() failed" << llendl; + return FALSE; + } + } + else + { + llwarns << " name=\"hair_color\" not found" << llendl; + return FALSE; + } + if( sAvatarXmlInfo->mTexEyeColorInfo ) + { + mTexEyeColor = new LLTexGlobalColor( this ); + if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) ) + { + llwarns << "avatar file: mTexEyeColor->setInfo() failed" << llendl; + return FALSE; + } + } + else + { + llwarns << " name=\"eye_color\" not found" << llendl; + return FALSE; + } + + // avatar_lad.xml : + if (sAvatarXmlInfo->mLayerInfoList.empty()) + { + llwarns << "avatar file: missing node" << llendl; + return FALSE; + } + + if (sAvatarXmlInfo->mMorphMaskInfoList.empty()) + { + llwarns << "avatar file: missing node" << llendl; + return FALSE; + } + + // avatar_lad.xml : + for (LLAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin(); + iter != sAvatarXmlInfo->mMorphMaskInfoList.end(); + ++iter) + { + LLAvatarXmlInfo::LLAvatarMorphInfo *info = *iter; + + EBakedTextureIndex baked = LLAvatarAppearanceDictionary::findBakedByRegionName(info->mRegion); + if (baked != BAKED_NUM_INDICES) + { + LLVisualParam* morph_param; + const std::string *name = &info->mName; + morph_param = getVisualParam(name->c_str()); + if (morph_param) + { + BOOL invert = info->mInvert; + addMaskedMorph(baked, morph_param, invert, info->mLayer); + } + } + + } + + loadLayersets(); + + // avatar_lad.xml : + for (LLAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); + iter != sAvatarXmlInfo->mDriverInfoList.end(); + ++iter) + { + LLDriverParamInfo *info = *iter; + LLDriverParam* driver_param = new LLDriverParam( this ); + if (driver_param->setInfo(info)) + { + addVisualParam( driver_param ); + LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam; + if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false)) + { + llwarns << "could not link driven params for avatar " << getID().asString() << " param id: " << driver_param->getID() << llendl; + continue; + } + } + else + { + delete driver_param; + llwarns << "avatar file: driver_param->parseData() failed" << llendl; + return FALSE; + } + } + + + return TRUE; +} + +//----------------------------------------------------------------------------- +// loadSkeletonNode(): loads node from XML tree +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::loadSkeletonNode () +{ + mRoot->addChild( &mSkeleton[0] ); + + mRoot->addChild(mMeshLOD[MESH_ID_HEAD]); + mRoot->addChild(mMeshLOD[MESH_ID_EYELASH]); + mRoot->addChild(mMeshLOD[MESH_ID_UPPER_BODY]); + mRoot->addChild(mMeshLOD[MESH_ID_LOWER_BODY]); + mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]); + mRoot->addChild(mMeshLOD[MESH_ID_HEAD]); + + LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull"); + if (skull) + { + skull->addChild(mMeshLOD[MESH_ID_HAIR] ); + } + + LLAvatarJoint *eyeL = (LLAvatarJoint*)mRoot->findJoint("mEyeLeft"); + if (eyeL) + { + eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] ); + } + + LLAvatarJoint *eyeR = (LLAvatarJoint*)mRoot->findJoint("mEyeRight"); + if (eyeR) + { + eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] ); + } + + // SKELETAL DISTORTIONS + { + LLAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin(); + iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end(); + ++iter) + { + LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)*iter; + LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this); + if (!param->setInfo(info)) + { + delete param; + return FALSE; + } + else + { + addVisualParam(param); + } + } + } + + + return TRUE; } -// virtual -LLAvatarAppearance::~LLAvatarAppearance() +//----------------------------------------------------------------------------- +// loadMeshNodes(): loads nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::loadMeshNodes() { - deleteAndClear(mTexSkinColor); - deleteAndClear(mTexHairColor); - deleteAndClear(mTexEyeColor); - - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + for (LLAvatarXmlInfo::mesh_info_list_t::const_iterator meshinfo_iter = sAvatarXmlInfo->mMeshInfoList.begin(); + meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end(); + ++meshinfo_iter) { - deleteAndClear(mBakedTextureDatas[i].mTexLayerSet); - mBakedTextureDatas[i].mMeshes.clear(); + const LLAvatarXmlInfo::LLAvatarMeshInfo *info = *meshinfo_iter; + const std::string &type = info->mType; + S32 lod = info->mLOD; - for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin(); - iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++) + LLAvatarJointMesh* mesh = NULL; + U8 mesh_id = 0; + BOOL found_mesh_id = FALSE; + + /* if (type == "hairMesh") + switch(lod) + case 0: + mesh = &mHairMesh0; */ + for (LLAvatarAppearanceDictionary::Meshes::const_iterator mesh_iter = LLAvatarAppearanceDictionary::getInstance()->getMeshes().begin(); + mesh_iter != LLAvatarAppearanceDictionary::getInstance()->getMeshes().end(); + ++mesh_iter) { - LLMaskedMorph* masked_morph = (*iter2); - delete masked_morph; + const EMeshIndex mesh_index = mesh_iter->first; + const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_iter->second; + if (type.compare(mesh_dict->mName) == 0) + { + mesh_id = mesh_index; + found_mesh_id = TRUE; + break; + } + } + + if (found_mesh_id) + { + if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size()) + { + mesh = mMeshLOD[mesh_id]->mMeshParts[lod]; + } + else + { + llwarns << "Avatar file: has invalid lod setting " << lod << llendl; + return FALSE; + } + } + else + { + llwarns << "Ignoring unrecognized mesh type: " << type << llendl; + return FALSE; + } + + // llinfos << "Parsing mesh data for " << type << "..." << llendl; + + // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings. + // Do not touch!!! + mesh->setColor( 1.0f, 1.0f, 1.0f, 1.0f ); + + LLPolyMesh *poly_mesh = NULL; + + if (!info->mReferenceMeshName.empty()) + { + polymesh_map_t::const_iterator polymesh_iter = mMeshes.find(info->mReferenceMeshName); + if (polymesh_iter != mMeshes.end()) + { + poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second); + poly_mesh->setAvatar(this); + } + else + { + // This should never happen + LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL; + } + } + else + { + poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName); + poly_mesh->setAvatar(this); + } + + if( !poly_mesh ) + { + llwarns << "Failed to load mesh of type " << type << llendl; + return FALSE; + } + + // Multimap insert + mMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh)); + + mesh->setMesh( poly_mesh ); + mesh->setLOD( info->mMinPixelArea ); + + for (LLAvatarXmlInfo::LLAvatarMeshInfo::morph_info_list_t::const_iterator xmlinfo_iter = info->mPolyMorphTargetInfoList.begin(); + xmlinfo_iter != info->mPolyMorphTargetInfoList.end(); + ++xmlinfo_iter) + { + const LLAvatarXmlInfo::LLAvatarMeshInfo::morph_info_pair_t *info_pair = &(*xmlinfo_iter); + LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh()); + if (!param->setInfo((LLPolyMorphTargetInfo*)info_pair->first)) + { + delete param; + return FALSE; + } + else + { + if (info_pair->second) + { + addSharedVisualParam(param); + } + else + { + addVisualParam(param); + } + } } } + + return TRUE; } -using namespace LLAvatarAppearanceDefines; +//----------------------------------------------------------------------------- +// loadLayerSets() +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::loadLayersets() +{ + BOOL success = TRUE; + for (LLAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin(); + layerset_iter != sAvatarXmlInfo->mLayerInfoList.end(); + ++layerset_iter) + { + // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. + LLTexLayerSetInfo *layerset_info = *layerset_iter; + layerset_info->createVisualParams(this); + } + return success; +} + + // virtual BOOL LLAvatarAppearance::isValid() const @@ -273,4 +1176,494 @@ BOOL LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const return FALSE; } +//----------------------------------------------------------------------------- +// allocateCollisionVolumes() +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num ) +{ + deleteAndClearArray(mCollisionVolumes); + mNumCollisionVolumes = 0; + + mCollisionVolumes = new LLAvatarJointCollisionVolume[num]; + if (!mCollisionVolumes) + { + return FALSE; + } + + mNumCollisionVolumes = num; + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLAvatarBoneInfo::parseXml() +//----------------------------------------------------------------------------- +BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node) +{ + if (node->hasName("bone")) + { + mIsJoint = TRUE; + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!node->getFastAttributeString(name_string, mName)) + { + llwarns << "Bone without name" << llendl; + return FALSE; + } + } + else if (node->hasName("collision_volume")) + { + mIsJoint = FALSE; + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!node->getFastAttributeString(name_string, mName)) + { + mName = "Collision Volume"; + } + } + else + { + llwarns << "Invalid node " << node->getName() << llendl; + return FALSE; + } + + static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos"); + if (!node->getFastAttributeVector3(pos_string, mPos)) + { + llwarns << "Bone without position" << llendl; + return FALSE; + } + + static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot"); + if (!node->getFastAttributeVector3(rot_string, mRot)) + { + llwarns << "Bone without rotation" << llendl; + return FALSE; + } + + static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); + if (!node->getFastAttributeVector3(scale_string, mScale)) + { + llwarns << "Bone without scale" << llendl; + return FALSE; + } + + if (mIsJoint) + { + static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot"); + if (!node->getFastAttributeVector3(pivot_string, mPivot)) + { + llwarns << "Bone without pivot" << llendl; + return FALSE; + } + } + + // parse children + LLXmlTreeNode* child; + for( child = node->getFirstChild(); child; child = node->getNextChild() ) + { + LLAvatarBoneInfo *child_info = new LLAvatarBoneInfo; + if (!child_info->parseXml(child)) + { + delete child_info; + return FALSE; + } + mChildList.push_back(child_info); + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLAvatarSkeletonInfo::parseXml() +//----------------------------------------------------------------------------- +BOOL LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) +{ + static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones"); + if (!node->getFastAttributeS32(num_bones_string, mNumBones)) + { + llwarns << "Couldn't find number of bones." << llendl; + return FALSE; + } + + static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes"); + node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes); + + LLXmlTreeNode* child; + for( child = node->getFirstChild(); child; child = node->getNextChild() ) + { + LLAvatarBoneInfo *info = new LLAvatarBoneInfo; + if (!info->parseXml(child)) + { + delete info; + llwarns << "Error parsing bone in skeleton file" << llendl; + return FALSE; + } + mBoneInfoList.push_back(info); + } + return TRUE; +} + + +//----------------------------------------------------------------------------- +// parseXmlSkeletonNode(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root) +{ + LLXmlTreeNode* node = root->getChildByName( "skeleton" ); + if( !node ) + { + llwarns << "avatar file: missing " << llendl; + return FALSE; + } + + LLXmlTreeNode* child; + + // SKELETON DISTORTIONS + for (child = node->getChildByName( "param" ); + child; + child = node->getNextNamedChild()) + { + if (!child->getChildByName("param_skeleton")) + { + if (child->getChildByName("param_morph")) + { + llwarns << "Can't specify morph param in skeleton definition." << llendl; + } + else + { + llwarns << "Unknown param type." << llendl; + } + continue; + } + + LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo; + if (!info->parseXml(child)) + { + delete info; + return FALSE; + } + + mSkeletalDistortionInfoList.push_back(info); + } + + // ATTACHMENT POINTS + for (child = node->getChildByName( "attachment_point" ); + child; + child = node->getNextNamedChild()) + { + LLAvatarAttachmentInfo* info = new LLAvatarAttachmentInfo(); + + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!child->getFastAttributeString(name_string, info->mName)) + { + llwarns << "No name supplied for attachment point." << llendl; + delete info; + continue; + } + + static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint"); + if (!child->getFastAttributeString(joint_string, info->mJointName)) + { + llwarns << "No bone declared in attachment point " << info->mName << llendl; + delete info; + continue; + } + + static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position"); + if (child->getFastAttributeVector3(position_string, info->mPosition)) + { + info->mHasPosition = TRUE; + } + + static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation"); + if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler)) + { + info->mHasRotation = TRUE; + } + static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group"); + if (child->getFastAttributeS32(group_string, info->mGroup)) + { + if (info->mGroup == -1) + info->mGroup = -1111; // -1 = none parsed, < -1 = bad value + } + + static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id"); + if (!child->getFastAttributeS32(id_string, info->mAttachmentID)) + { + llwarns << "No id supplied for attachment point " << info->mName << llendl; + delete info; + continue; + } + + static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice"); + child->getFastAttributeS32(slot_string, info->mPieMenuSlice); + + static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person"); + child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson); + + static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud"); + child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment); + + mAttachmentInfoList.push_back(info); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlMeshNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) +{ + for (LLXmlTreeNode* node = root->getChildByName( "mesh" ); + node; + node = root->getNextNamedChild()) + { + LLAvatarMeshInfo *info = new LLAvatarMeshInfo; + + // attribute: type + static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type"); + if( !node->getFastAttributeString( type_string, info->mType ) ) + { + llwarns << "Avatar file: is missing type attribute. Ignoring element. " << llendl; + delete info; + return FALSE; // Ignore this element + } + + static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod"); + if (!node->getFastAttributeS32( lod_string, info->mLOD )) + { + llwarns << "Avatar file: is missing lod attribute. Ignoring element. " << llendl; + delete info; + return FALSE; // Ignore this element + } + + static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); + if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) ) + { + llwarns << "Avatar file: is missing file_name attribute. Ignoring: " << info->mType << llendl; + delete info; + return FALSE; // Ignore this element + } + + static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference"); + node->getFastAttributeString( reference_string, info->mReferenceMeshName ); + + // attribute: min_pixel_area + static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area"); + static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width"); + if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea )) + { + F32 min_pixel_area = 0.1f; + if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area )) + { + // this is square root of pixel area (sensible to use linear space in defining lods) + min_pixel_area = min_pixel_area * min_pixel_area; + } + info->mMinPixelArea = min_pixel_area; + } + + // Parse visual params for this node only if we haven't already + for (LLXmlTreeNode* child = node->getChildByName( "param" ); + child; + child = node->getNextNamedChild()) + { + if (!child->getChildByName("param_morph")) + { + if (child->getChildByName("param_skeleton")) + { + llwarns << "Can't specify skeleton param in a mesh definition." << llendl; + } + else + { + llwarns << "Unknown param type." << llendl; + } + continue; + } + + LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo(); + if (!morphinfo->parseXml(child)) + { + delete morphinfo; + delete info; + return -1; + } + BOOL shared = FALSE; + static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared"); + child->getFastAttributeBOOL(shared_string, shared); + + info->mPolyMorphTargetInfoList.push_back(LLAvatarMeshInfo::morph_info_pair_t(morphinfo, shared)); + } + + mMeshInfoList.push_back(info); + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlColorNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) +{ + for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" ); + color_node; + color_node = root->getNextNamedChild()) + { + std::string global_color_name; + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (color_node->getFastAttributeString( name_string, global_color_name ) ) + { + if( global_color_name == "skin_color" ) + { + if (mTexSkinColorInfo) + { + llwarns << "avatar file: multiple instances of skin_color" << llendl; + return FALSE; + } + mTexSkinColorInfo = new LLTexGlobalColorInfo; + if( !mTexSkinColorInfo->parseXml( color_node ) ) + { + deleteAndClear(mTexSkinColorInfo); + llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl; + return FALSE; + } + } + else if( global_color_name == "hair_color" ) + { + if (mTexHairColorInfo) + { + llwarns << "avatar file: multiple instances of hair_color" << llendl; + return FALSE; + } + mTexHairColorInfo = new LLTexGlobalColorInfo; + if( !mTexHairColorInfo->parseXml( color_node ) ) + { + deleteAndClear(mTexHairColorInfo); + llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl; + return FALSE; + } + } + else if( global_color_name == "eye_color" ) + { + if (mTexEyeColorInfo) + { + llwarns << "avatar file: multiple instances of eye_color" << llendl; + return FALSE; + } + mTexEyeColorInfo = new LLTexGlobalColorInfo; + if( !mTexEyeColorInfo->parseXml( color_node ) ) + { + llwarns << "avatar file: mTexEyeColor->parseXml() failed" << llendl; + return FALSE; + } + } + } + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlLayerNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root) +{ + for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" ); + layer_node; + layer_node = root->getNextNamedChild()) + { + LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo(); + if( layer_info->parseXml( layer_node ) ) + { + mLayerInfoList.push_back(layer_info); + } + else + { + delete layer_info; + llwarns << "avatar file: layer_set->parseXml() failed" << llendl; + return FALSE; + } + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlDriverNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root) +{ + LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" ); + if( driver ) + { + for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" ); + grand_child; + grand_child = driver->getNextNamedChild()) + { + if( grand_child->getChildByName( "param_driver" ) ) + { + LLDriverParamInfo* driver_info = new LLDriverParamInfo(); + if( driver_info->parseXml( grand_child ) ) + { + mDriverInfoList.push_back(driver_info); + } + else + { + delete driver_info; + llwarns << "avatar file: driver_param->parseXml() failed" << llendl; + return FALSE; + } + } + } + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// parseXmlDriverNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root) +{ + LLXmlTreeNode* masks = root->getChildByName( "morph_masks" ); + if( !masks ) + { + return FALSE; + } + + for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" ); + grand_child; + grand_child = masks->getNextNamedChild()) + { + LLAvatarMorphInfo* info = new LLAvatarMorphInfo(); + + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name"); + if (!grand_child->getFastAttributeString(name_string, info->mName)) + { + llwarns << "No name supplied for morph mask." << llendl; + delete info; + continue; + } + + static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region"); + if (!grand_child->getFastAttributeString(region_string, info->mRegion)) + { + llwarns << "No region supplied for morph mask." << llendl; + delete info; + continue; + } + + static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer"); + if (!grand_child->getFastAttributeString(layer_string, info->mLayer)) + { + llwarns << "No layer supplied for morph mask." << llendl; + delete info; + continue; + } + + // optional parameter. don't throw a warning if not present. + static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert"); + grand_child->getFastAttributeBOOL(invert_string, info->mInvert); + + mMorphMaskInfoList.push_back(info); + } + + return TRUE; +} + + diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index b2ab6b069f..38a54d904d 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -30,11 +30,17 @@ #include "llcharacter.h" //#include "llframetimer.h" #include "llavatarappearancedefines.h" -#include "lljoint.h" +#include "llavatarjoint.h" +#include "lldriverparam.h" +#include "lltexlayer.h" +#include "llviewervisualparam.h" +#include "llxmltree.h" class LLTexLayerSet; class LLTexGlobalColor; class LLWearableData; +class LLAvatarBoneInfo; +class LLAvatarSkeletonInfo; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLAvatarAppearance @@ -45,6 +51,9 @@ class LLAvatarAppearance : public LLCharacter { LOG_CLASS(LLAvatarAppearance); +protected: + struct LLAvatarXmlInfo; + /******************************************************************************** ** ** ** INITIALIZATION @@ -57,6 +66,12 @@ public: LLAvatarAppearance(LLWearableData* wearable_data); virtual ~LLAvatarAppearance(); + static void initClass(); // initializes static members + virtual BOOL loadSkeletonNode(); + virtual BOOL loadMeshNodes(); + virtual BOOL loadLayersets(); + + /** Initialization ** ** *******************************************************************************/ @@ -69,16 +84,94 @@ public: virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent virtual BOOL isValid() const; virtual BOOL isUsingBakedTextures() const = 0; + + bool isBuilt() const { return mIsBuilt; } + /** State ** ** *******************************************************************************/ +/******************************************************************************** + ** ** + ** SKELETON + **/ + +public: + F32 getPelvisToFoot() const { return mPelvisToFoot; } + + LLVector3 mHeadOffset; // current head position + LLAvatarJoint *mRoot; + + typedef std::map joint_map_t; + joint_map_t mJointMap; + +protected: + static BOOL parseSkeletonFile(const std::string& filename); + virtual void buildCharacter(); + virtual BOOL loadAvatar(); + virtual void bodySizeChanged() = 0; + void computeBodySize(); + + BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); + BOOL buildSkeleton(const LLAvatarSkeletonInfo *info); +protected: + BOOL mIsBuilt; // state of deferred character building + S32 mNumJoints; + LLJoint* mSkeleton; + + //-------------------------------------------------------------------- + // Pelvis height adjustment members. + //-------------------------------------------------------------------- +public: + LLVector3 mBodySize; +protected: + F32 mPelvisToFoot; + + //-------------------------------------------------------------------- + // Cached pointers to well known joints + //-------------------------------------------------------------------- +public: + LLJoint* mPelvisp; + LLJoint* mTorsop; + LLJoint* mChestp; + LLJoint* mNeckp; + LLJoint* mHeadp; + LLJoint* mSkullp; + LLJoint* mEyeLeftp; + LLJoint* mEyeRightp; + LLJoint* mHipLeftp; + LLJoint* mHipRightp; + LLJoint* mKneeLeftp; + LLJoint* mKneeRightp; + LLJoint* mAnkleLeftp; + LLJoint* mAnkleRightp; + LLJoint* mFootLeftp; + LLJoint* mFootRightp; + LLJoint* mWristLeftp; + LLJoint* mWristRightp; + + //-------------------------------------------------------------------- + // XML parse tree + //-------------------------------------------------------------------- +protected: + static LLXmlTree sXMLTree; // avatar config file + static LLXmlTree sSkeletonXMLTree; // avatar skeleton file + + static LLAvatarSkeletonInfo* sAvatarSkeletonInfo; + static LLAvatarXmlInfo* sAvatarXmlInfo; + + +/** Skeleton + ** ** + *******************************************************************************/ + /******************************************************************************** ** ** ** RENDERING **/ +public: BOOL mIsDummy; // for special views //-------------------------------------------------------------------- @@ -109,6 +202,11 @@ public: protected: virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority +protected: + typedef std::multimap polymesh_map_t; + polymesh_map_t mMeshes; + std::vector mMeshLOD; + /** Meshes ** ** *******************************************************************************/ @@ -182,12 +280,115 @@ protected: typedef std::vector bakedtexturedata_vec_t; bakedtexturedata_vec_t mBakedTextureDatas; +/******************************************************************************** + ** ** + ** PHYSICS + **/ + + //-------------------------------------------------------------------- + // Collision volumes + //-------------------------------------------------------------------- +public: + S32 mNumCollisionVolumes; + LLAvatarJointCollisionVolume* mCollisionVolumes; +protected: + BOOL allocateCollisionVolumes(U32 num); + +/** Physics + ** ** + *******************************************************************************/ /******************************************************************************** ** ** ** SUPPORT CLASSES **/ + struct LLAvatarXmlInfo + { + LLAvatarXmlInfo(); + ~LLAvatarXmlInfo(); + + BOOL parseXmlSkeletonNode(LLXmlTreeNode* root); + BOOL parseXmlMeshNodes(LLXmlTreeNode* root); + BOOL parseXmlColorNodes(LLXmlTreeNode* root); + BOOL parseXmlLayerNodes(LLXmlTreeNode* root); + BOOL parseXmlDriverNodes(LLXmlTreeNode* root); + BOOL parseXmlMorphNodes(LLXmlTreeNode* root); + + struct LLAvatarMeshInfo + { + typedef std::pair morph_info_pair_t; // LLPolyMorphTargetInfo stored here + typedef std::vector morph_info_list_t; + + LLAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {} + ~LLAvatarMeshInfo() + { + morph_info_list_t::iterator iter; + for (iter = mPolyMorphTargetInfoList.begin(); iter != mPolyMorphTargetInfoList.end(); iter++) + { + delete iter->first; + } + mPolyMorphTargetInfoList.clear(); + } + + std::string mType; + S32 mLOD; + std::string mMeshFileName; + std::string mReferenceMeshName; + F32 mMinPixelArea; + morph_info_list_t mPolyMorphTargetInfoList; + }; + typedef std::vector mesh_info_list_t; + mesh_info_list_t mMeshInfoList; + + typedef std::vector skeletal_distortion_info_list_t; // LLPolySkeletalDistortionInfo stored here + skeletal_distortion_info_list_t mSkeletalDistortionInfoList; + + struct LLAvatarAttachmentInfo + { + LLAvatarAttachmentInfo() + : mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(FALSE), + mIsHUDAttachment(FALSE), mHasPosition(FALSE), mHasRotation(FALSE) {} + std::string mName; + std::string mJointName; + LLVector3 mPosition; + LLVector3 mRotationEuler; + S32 mGroup; + S32 mAttachmentID; + S32 mPieMenuSlice; + BOOL mVisibleFirstPerson; + BOOL mIsHUDAttachment; + BOOL mHasPosition; + BOOL mHasRotation; + }; + typedef std::vector attachment_info_list_t; + attachment_info_list_t mAttachmentInfoList; + + LLTexGlobalColorInfo *mTexSkinColorInfo; + LLTexGlobalColorInfo *mTexHairColorInfo; + LLTexGlobalColorInfo *mTexEyeColorInfo; + + typedef std::vector layer_info_list_t; + layer_info_list_t mLayerInfoList; + + typedef std::vector driver_info_list_t; + driver_info_list_t mDriverInfoList; + + struct LLAvatarMorphInfo + { + LLAvatarMorphInfo() + : mInvert(FALSE) {} + std::string mName; + std::string mRegion; + std::string mLayer; + BOOL mInvert; + }; + + typedef std::vector morph_info_list_t; + morph_info_list_t mMorphMaskInfoList; + }; + + class LLMaskedMorph { public: @@ -197,7 +398,9 @@ protected: BOOL mInvert; std::string mLayer; }; - +/** Support Classes + ** ** + *******************************************************************************/ }; #endif // LL_AVATAR_APPEARANCE_H diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp new file mode 100644 index 0000000000..809a261633 --- /dev/null +++ b/indra/llappearance/llavatarjoint.cpp @@ -0,0 +1,261 @@ +/** + * @file llavatarjoint.cpp + * @brief Implementation of LLAvatarJoint class + * + * $LicenseInfo:firstyear=2001&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$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "llavatarjoint.h" + +#include "llgl.h" +#include "llrender.h" +#include "llmath.h" +#include "llglheaders.h" +#include "llrendersphere.h" +#include "llavatarappearance.h" +//#include "pipeline.h" + +#define DEFAULT_LOD 0.0f + +const S32 MIN_PIXEL_AREA_3PASS_HAIR = 64*64; + +//----------------------------------------------------------------------------- +// Static Data +//----------------------------------------------------------------------------- +BOOL LLAvatarJoint::sDisableLOD = FALSE; + +//----------------------------------------------------------------------------- +// LLAvatarJoint() +// Class Constructor +//----------------------------------------------------------------------------- +LLAvatarJoint::LLAvatarJoint() + : LLJoint() +{ + init(); +} + + +//----------------------------------------------------------------------------- +// LLAvatarJoint() +// Class Constructor +//----------------------------------------------------------------------------- +LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) + : LLJoint(name, parent) +{ + init(); +} + + +void LLAvatarJoint::init() +{ + mValid = FALSE; + mComponents = SC_JOINT | SC_BONE | SC_AXES; + mMinPixelArea = DEFAULT_LOD; + mPickName = PN_DEFAULT; + mVisible = TRUE; + mMeshID = 0; +} + + +//----------------------------------------------------------------------------- +// ~LLAvatarJoint() +// Class Destructor +//----------------------------------------------------------------------------- +LLAvatarJoint::~LLAvatarJoint() +{ +} + + +//-------------------------------------------------------------------- +// setValid() +//-------------------------------------------------------------------- +void LLAvatarJoint::setValid( BOOL valid, BOOL recursive ) +{ + //---------------------------------------------------------------- + // set visibility for this joint + //---------------------------------------------------------------- + mValid = valid; + + //---------------------------------------------------------------- + // set visibility for children + //---------------------------------------------------------------- + if (recursive) + { + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLAvatarJoint* joint = (LLAvatarJoint*)(*iter); + joint->setValid(valid, TRUE); + } + } + +} + +//-------------------------------------------------------------------- +// isTransparent() +//-------------------------------------------------------------------- +BOOL LLAvatarJoint::isTransparent() +{ + return FALSE; +} + +//-------------------------------------------------------------------- +// setSkeletonComponents() +//-------------------------------------------------------------------- +void LLAvatarJoint::setSkeletonComponents( U32 comp, BOOL recursive ) +{ + mComponents = comp; + if (recursive) + { + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLAvatarJoint* joint = (LLAvatarJoint*)(*iter); + joint->setSkeletonComponents(comp, recursive); + } + } +} + +void LLAvatarJoint::setVisible(BOOL visible, BOOL recursive) +{ + mVisible = visible; + + if (recursive) + { + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLAvatarJoint* joint = (LLAvatarJoint*)(*iter); + joint->setVisible(visible, recursive); + } + } +} + + +void LLAvatarJoint::setMeshesToChildren() +{ + removeAllChildren(); + for (std::vector::iterator iter = mMeshParts.begin(); + iter != mMeshParts.end(); iter++) + { + addChild((LLAvatarJoint*) *iter); + } +} +//----------------------------------------------------------------------------- +// LLAvatarJointCollisionVolume() +//----------------------------------------------------------------------------- + +LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume() +{ + mUpdateXform = FALSE; +} + +LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume(const std::string &name, LLJoint *parent) : LLAvatarJoint(name, parent) +{ + +} + +LLVector3 LLAvatarJointCollisionVolume::getVolumePos(LLVector3 &offset) +{ + mUpdateXform = TRUE; + + LLVector3 result = offset; + result.scaleVec(getScale()); + result.rotVec(getWorldRotation()); + result += getWorldPosition(); + + return result; +} + +void LLAvatarJointCollisionVolume::renderCollision() +{ + updateWorldMatrix(); + + gGL.pushMatrix(); + gGL.multMatrix( &mXform.getWorldMatrix().mMatrix[0][0] ); + + gGL.diffuseColor3f( 0.f, 0.f, 1.f ); + + gGL.begin(LLRender::LINES); + + LLVector3 v[] = + { + LLVector3(1,0,0), + LLVector3(-1,0,0), + LLVector3(0,1,0), + LLVector3(0,-1,0), + + LLVector3(0,0,-1), + LLVector3(0,0,1), + }; + + //sides + gGL.vertex3fv(v[0].mV); + gGL.vertex3fv(v[2].mV); + + gGL.vertex3fv(v[0].mV); + gGL.vertex3fv(v[3].mV); + + gGL.vertex3fv(v[1].mV); + gGL.vertex3fv(v[2].mV); + + gGL.vertex3fv(v[1].mV); + gGL.vertex3fv(v[3].mV); + + + //top + gGL.vertex3fv(v[0].mV); + gGL.vertex3fv(v[4].mV); + + gGL.vertex3fv(v[1].mV); + gGL.vertex3fv(v[4].mV); + + gGL.vertex3fv(v[2].mV); + gGL.vertex3fv(v[4].mV); + + gGL.vertex3fv(v[3].mV); + gGL.vertex3fv(v[4].mV); + + + //bottom + gGL.vertex3fv(v[0].mV); + gGL.vertex3fv(v[5].mV); + + gGL.vertex3fv(v[1].mV); + gGL.vertex3fv(v[5].mV); + + gGL.vertex3fv(v[2].mV); + gGL.vertex3fv(v[5].mV); + + gGL.vertex3fv(v[3].mV); + gGL.vertex3fv(v[5].mV); + + gGL.end(); + + gGL.popMatrix(); +} + + +// End diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h new file mode 100644 index 0000000000..cbfc1b73ea --- /dev/null +++ b/indra/llappearance/llavatarjoint.h @@ -0,0 +1,127 @@ +/** + * @file llavatarjoint.h + * @brief Implementation of LLAvatarJoint class + * + * $LicenseInfo:firstyear=2001&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_LLAVATARJOINT_H +#define LL_LLAVATARJOINT_H + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "lljoint.h" +#include "lljointpickname.h" + +class LLFace; +class LLAvatarJointMesh; + +//----------------------------------------------------------------------------- +// class LLViewerJoint +//----------------------------------------------------------------------------- +class LLAvatarJoint : + public LLJoint +{ +public: + LLAvatarJoint(); + LLAvatarJoint(const std::string &name, LLJoint *parent = NULL); + virtual ~LLAvatarJoint(); + + // Gets the validity of this joint + BOOL getValid() { return mValid; } + + // Sets the validity of this joint + virtual void setValid( BOOL valid, BOOL recursive=FALSE ); + + // Returns true if this object is transparent. + // This is used to determine in which order to draw objects. + virtual BOOL isTransparent(); + + // Returns true if this object should inherit scale modifiers from its immediate parent + virtual BOOL inheritScale() { return FALSE; } + + + enum Components + { + SC_BONE = 1, + SC_JOINT = 2, + SC_AXES = 4 + }; + + // Selects which skeleton components to draw + void setSkeletonComponents( U32 comp, BOOL recursive = TRUE ); + + // Returns which skeleton components are enables for drawing + U32 getSkeletonComponents() { return mComponents; } + + // Sets the level of detail for this node as a minimum + // pixel area threshold. If the current pixel area for this + // object is less than the specified threshold, the node is + // not traversed. In addition, if a value is specified (not + // default of 0.0), and the pixel area is larger than the + // specified minimum, the node is rendered, but no other siblings + // of this node under the same parent will be. + F32 getLOD() { return mMinPixelArea; } + void setLOD( F32 pixelArea ) { mMinPixelArea = pixelArea; } + + void setPickName(LLJointPickName name) { mPickName = name; } + LLJointPickName getPickName() { return mPickName; } + + void setVisible( BOOL visible, BOOL recursive ); + + // Takes meshes in mMeshParts and sets each one as a child joint + void setMeshesToChildren(); + +public: + static BOOL sDisableLOD; + std::vector mMeshParts; //LLViewerJointMesh* + void setMeshID( S32 id ) {mMeshID = id;} + +protected: + void init(); + + BOOL mValid; + U32 mComponents; + F32 mMinPixelArea; + LLJointPickName mPickName; + BOOL mVisible; + S32 mMeshID; +}; + +class LLAvatarJointCollisionVolume : public LLAvatarJoint +{ +public: + LLAvatarJointCollisionVolume(); + LLAvatarJointCollisionVolume(const std::string &name, LLJoint *parent = NULL); + virtual ~LLAvatarJointCollisionVolume() {}; + + virtual BOOL inheritScale() { return TRUE; } + + void renderCollision(); + + LLVector3 getVolumePos(LLVector3 &offset); +}; + +#endif // LL_LLAVATARJOINT_H + + diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp new file mode 100755 index 0000000000..92c213126a --- /dev/null +++ b/indra/llappearance/llavatarjointmesh.cpp @@ -0,0 +1,359 @@ +/** + * @file LLAvatarJointMesh.cpp + * @brief Implementation of LLAvatarJointMesh class + * + * $LicenseInfo:firstyear=2001&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$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" +#include "imageids.h" +#include "llfasttimer.h" +#include "llrender.h" + +#include "llavatarjointmesh.h" +#include "llavatarappearance.h" +//#include "llapr.h" +//#include "llbox.h" +//#include "lldrawable.h" +//#include "lldrawpoolavatar.h" +//#include "lldrawpoolbump.h" +//#include "lldynamictexture.h" +//#include "llface.h" +//#include "llgldbg.h" +//#include "llglheaders.h" +#include "lltexlayer.h" +//#include "llviewercamera.h" +//#include "llviewercontrol.h" +//#include "llviewertexturelist.h" +//#include "llsky.h" +//#include "pipeline.h" +//#include "llviewershadermgr.h" +#include "llmath.h" +#include "v4math.h" +#include "m3math.h" +#include "m4math.h" +#include "llmatrix4a.h" + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LLAvatarJointMesh::LLSkinJoint +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// LLSkinJoint +//----------------------------------------------------------------------------- +LLSkinJoint::LLSkinJoint() +{ + mJoint = NULL; +} + +//----------------------------------------------------------------------------- +// ~LLSkinJoint +//----------------------------------------------------------------------------- +LLSkinJoint::~LLSkinJoint() +{ + mJoint = NULL; +} + + +//----------------------------------------------------------------------------- +// LLSkinJoint::setupSkinJoint() +//----------------------------------------------------------------------------- +BOOL LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint) +{ + // find the named joint + mJoint = joint; + if ( !mJoint ) + { + llinfos << "Can't find joint" << llendl; + } + + // compute the inverse root skin matrix + mRootToJointSkinOffset.clearVec(); + + LLVector3 rootSkinOffset; + while (joint) + { + rootSkinOffset += joint->getSkinOffset(); + joint = (LLAvatarJoint*)joint->getParent(); + } + + mRootToJointSkinOffset = -rootSkinOffset; + mRootToParentJointSkinOffset = mRootToJointSkinOffset; + mRootToParentJointSkinOffset += mJoint->getSkinOffset(); + + return TRUE; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// LLAvatarJointMesh +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +BOOL LLAvatarJointMesh::sPipelineRender = FALSE; +EAvatarRenderPass LLAvatarJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE; +U32 LLAvatarJointMesh::sClothingMaskImageName = 0; +LLColor4 LLAvatarJointMesh::sClothingInnerColor; + +//----------------------------------------------------------------------------- +// LLAvatarJointMesh() +//----------------------------------------------------------------------------- +LLAvatarJointMesh::LLAvatarJointMesh() + : + mTexture( NULL ), + mLayerSet( NULL ), + mTestImageName( 0 ), + mFaceIndexCount(0), + mIsTransparent(FALSE) +{ + + mColor[0] = 1.0f; + mColor[1] = 1.0f; + mColor[2] = 1.0f; + mColor[3] = 1.0f; + mShiny = 0.0f; + mCullBackFaces = TRUE; + + mMesh = NULL; + + mNumSkinJoints = 0; + mSkinJoints = NULL; + + mFace = NULL; + + mMeshID = 0; + mUpdateXform = FALSE; + + mValid = FALSE; +} + + +//----------------------------------------------------------------------------- +// ~LLAvatarJointMesh() +// Class Destructor +//----------------------------------------------------------------------------- +LLAvatarJointMesh::~LLAvatarJointMesh() +{ + mMesh = NULL; + mTexture = NULL; + freeSkinData(); +} + + +//----------------------------------------------------------------------------- +// LLAvatarJointMesh::allocateSkinData() +//----------------------------------------------------------------------------- +BOOL LLAvatarJointMesh::allocateSkinData( U32 numSkinJoints ) +{ + mSkinJoints = new LLSkinJoint[ numSkinJoints ]; + mNumSkinJoints = numSkinJoints; + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLAvatarJointMesh::freeSkinData() +//----------------------------------------------------------------------------- +void LLAvatarJointMesh::freeSkinData() +{ + mNumSkinJoints = 0; + delete [] mSkinJoints; + mSkinJoints = NULL; +} + +//-------------------------------------------------------------------- +// LLAvatarJointMesh::getColor() +//-------------------------------------------------------------------- +void LLAvatarJointMesh::getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha ) +{ + *red = mColor[0]; + *green = mColor[1]; + *blue = mColor[2]; + *alpha = mColor[3]; +} + +//-------------------------------------------------------------------- +// LLAvatarJointMesh::setColor() +//-------------------------------------------------------------------- +void LLAvatarJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha ) +{ + mColor[0] = red; + mColor[1] = green; + mColor[2] = blue; + mColor[3] = alpha; +} + + +//-------------------------------------------------------------------- +// LLAvatarJointMesh::getTexture() +//-------------------------------------------------------------------- +//LLViewerTexture *LLAvatarJointMesh::getTexture() +//{ +// return mTexture; +//} + +//-------------------------------------------------------------------- +// LLAvatarJointMesh::setTexture() +//-------------------------------------------------------------------- +void LLAvatarJointMesh::setTexture( LLGLTexture *texture ) +{ + mTexture = texture; + + // texture and dynamic_texture are mutually exclusive + if( texture ) + { + mLayerSet = NULL; + //texture->bindTexture(0); + //texture->setClamp(TRUE, TRUE); + } +} + +//-------------------------------------------------------------------- +// LLAvatarJointMesh::setLayerSet() +// Sets the shape texture (takes precedence over normal texture) +//-------------------------------------------------------------------- +void LLAvatarJointMesh::setLayerSet( LLTexLayerSet* layer_set ) +{ + mLayerSet = layer_set; + + // texture and dynamic_texture are mutually exclusive + if( layer_set ) + { + mTexture = NULL; + } +} + + + +//-------------------------------------------------------------------- +// LLAvatarJointMesh::getMesh() +//-------------------------------------------------------------------- +LLPolyMesh *LLAvatarJointMesh::getMesh() +{ + return mMesh; +} + +//----------------------------------------------------------------------------- +// LLAvatarJointMesh::setMesh() +//----------------------------------------------------------------------------- +void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh ) +{ + // set the mesh pointer + mMesh = mesh; + + // release any existing skin joints + freeSkinData(); + + if ( mMesh == NULL ) + { + return; + } + + // acquire the transform from the mesh object + setPosition( mMesh->getPosition() ); + setRotation( mMesh->getRotation() ); + setScale( mMesh->getScale() ); + + // create skin joints if necessary + if ( mMesh->hasWeights() && !mMesh->isLOD()) + { + U32 numJointNames = mMesh->getNumJointNames(); + + allocateSkinData( numJointNames ); + std::string *jointNames = mMesh->getJointNames(); + + U32 jn; + for (jn = 0; jn < numJointNames; jn++) + { + //llinfos << "Setting up joint " << jointNames[jn] << llendl; + LLAvatarJoint* joint = (LLAvatarJoint*)(getRoot()->findJoint(jointNames[jn]) ); + mSkinJoints[jn].setupSkinJoint( joint ); + } + } + + // setup joint array + if (!mMesh->isLOD()) + { + setupJoint((LLAvatarJoint*)getRoot()); + } + +// llinfos << "joint render entries: " << mMesh->mJointRenderData.count() << llendl; +} + +//----------------------------------------------------------------------------- +// setupJoint() +//----------------------------------------------------------------------------- +void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint) +{ +// llinfos << "Mesh: " << getName() << llendl; + +// S32 joint_count = 0; + U32 sj; + for (sj=0; sjmJointRenderData.count() && mMesh->mJointRenderData[mMesh->mJointRenderData.count() - 1]->mWorldMatrix == ¤t_joint->getParent()->getWorldMatrix()) + { + // ...then just add ourselves + LLAvatarJoint* jointp = js.mJoint; + mMesh->mJointRenderData.put(new LLJointRenderData(&jointp->getWorldMatrix(), &js)); +// llinfos << "joint " << joint_count << js.mJoint->getName() << llendl; +// joint_count++; + } + // otherwise add our parent and ourselves + else + { + mMesh->mJointRenderData.put(new LLJointRenderData(¤t_joint->getParent()->getWorldMatrix(), NULL)); +// llinfos << "joint " << joint_count << current_joint->getParent()->getName() << llendl; +// joint_count++; + mMesh->mJointRenderData.put(new LLJointRenderData(¤t_joint->getWorldMatrix(), &js)); +// llinfos << "joint " << joint_count << current_joint->getName() << llendl; +// joint_count++; + } + } + + // depth-first traversal + for (LLJoint::child_list_t::iterator iter = current_joint->mChildren.begin(); + iter != current_joint->mChildren.end(); ++iter) + { + LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); + setupJoint(child_joint); + } +} + + +// End diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h new file mode 100755 index 0000000000..dcd202bdaf --- /dev/null +++ b/indra/llappearance/llavatarjointmesh.h @@ -0,0 +1,140 @@ +/** + * @file llavatarjointmesh.h + * @brief Implementation of LLAvatarJointMesh class + * + * $LicenseInfo:firstyear=2001&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_LLAVATARJOINTMESH_H +#define LL_LLAVATARJOINTMESH_H + +#include "llavatarjoint.h" +#include "llgltexture.h" +#include "llpolymesh.h" +#include "v4color.h" + +class LLDrawable; +class LLFace; +class LLCharacter; +class LLTexLayerSet; + +typedef enum e_avatar_render_pass +{ + AVATAR_RENDER_PASS_SINGLE, + AVATAR_RENDER_PASS_CLOTHING_INNER, + AVATAR_RENDER_PASS_CLOTHING_OUTER +} EAvatarRenderPass; + +class LLSkinJoint +{ +public: + LLSkinJoint(); + ~LLSkinJoint(); + BOOL setupSkinJoint( LLAvatarJoint *joint); + + LLAvatarJoint *mJoint; + LLVector3 mRootToJointSkinOffset; + LLVector3 mRootToParentJointSkinOffset; +}; + +//----------------------------------------------------------------------------- +// class LLViewerJointMesh +//----------------------------------------------------------------------------- +class LLAvatarJointMesh : public LLAvatarJoint +{ + friend class LLAvatarAppearance; +protected: + LLColor4 mColor; // color value +// LLColor4 mSpecular; // specular color (always white for now) + F32 mShiny; // shiny value + LLPointer mTexture; // ptr to a global texture + LLTexLayerSet* mLayerSet; // ptr to a layer set owned by the avatar + U32 mTestImageName; // handle to a temporary texture for previewing uploads + LLPolyMesh* mMesh; // ptr to a global polymesh + BOOL mCullBackFaces; // true by default + LLFace* mFace; // ptr to a face w/ AGP copy of mesh + + U32 mFaceIndexCount; + BOOL mIsTransparent; + + U32 mNumSkinJoints; + LLSkinJoint* mSkinJoints; + S32 mMeshID; + +public: + static BOOL sPipelineRender; + //RN: this is here for testing purposes + static U32 sClothingMaskImageName; + static EAvatarRenderPass sRenderPass; + static LLColor4 sClothingInnerColor; + +public: + // Constructor + LLAvatarJointMesh(); + + // Destructor + virtual ~LLAvatarJointMesh(); + + // Gets the shape color + void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha ); + + // Sets the shape color + void setColor( F32 red, F32 green, F32 blue, F32 alpha ); + + // Sets the shininess + void setSpecular( const LLColor4& color, F32 shiny ) { /*mSpecular = color;*/ mShiny = shiny; }; + + // Sets the shape texture + void setTexture( LLGLTexture *texture ); + + void setTestTexture( U32 name ) { mTestImageName = name; } + + // Sets layer set responsible for a dynamic shape texture (takes precedence over normal texture) + void setLayerSet( LLTexLayerSet* layer_set ); + + // Gets the poly mesh + LLPolyMesh *getMesh(); + + // Sets the poly mesh + void setMesh( LLPolyMesh *mesh ); + + // Sets up joint matrix data for rendering + void setupJoint(LLAvatarJoint* current_joint); + + // Render time method to upload batches of joint matrices + void uploadJointMatrices(); + + // Sets ID for picking + void setMeshID( S32 id ) {mMeshID = id;} + + // Gets ID for picking + S32 getMeshID() { return mMeshID; } + +private: + // Allocate skin data + BOOL allocateSkinData( U32 numSkinJoints ); + + // Free skin data + void freeSkinData(); +}; + +#endif // LL_LLAVATARJOINTMESH_H diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp new file mode 100644 index 0000000000..b1370ab1e3 --- /dev/null +++ b/indra/llappearance/llpolymesh.cpp @@ -0,0 +1,1050 @@ +/** + * @file llpolymesh.cpp + * @brief Implementation of LLPolyMesh class + * + * $LicenseInfo:firstyear=2001&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$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "linden_common.h" +#include "llpolymesh.h" +#include "llfasttimer.h" +#include "llmemory.h" + +//#include "llviewercontrol.h" +#include "llxmltree.h" +#include "llavatarappearance.h" +#include "llwearable.h" +#include "lldir.h" +#include "llvolume.h" +#include "llendianswizzle.h" + + +#define HEADER_ASCII "Linden Mesh 1.0" +#define HEADER_BINARY "Linden Binary Mesh 1.0" + +//extern LLControlGroup gSavedSettings; // read only + +LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data, + const std::string &name); +LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, + const LLVector3 &direction, + const std::string &name); +LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, + F32 scale, + const std::string &name); + +//----------------------------------------------------------------------------- +// Global table of loaded LLPolyMeshes +//----------------------------------------------------------------------------- +LLPolyMesh::LLPolyMeshSharedDataTable LLPolyMesh::sGlobalSharedMeshList; + +//----------------------------------------------------------------------------- +// LLPolyMeshSharedData() +//----------------------------------------------------------------------------- +LLPolyMeshSharedData::LLPolyMeshSharedData() +{ + mNumVertices = 0; + mBaseCoords = NULL; + mBaseNormals = NULL; + mBaseBinormals = NULL; + mTexCoords = NULL; + mDetailTexCoords = NULL; + mWeights = NULL; + mHasWeights = FALSE; + mHasDetailTexCoords = FALSE; + + mNumFaces = 0; + mFaces = NULL; + + mNumJointNames = 0; + mJointNames = NULL; + + mTriangleIndices = NULL; + mNumTriangleIndices = 0; + + mReferenceData = NULL; + + mLastIndexOffset = -1; +} + +//----------------------------------------------------------------------------- +// ~LLPolyMeshSharedData() +//----------------------------------------------------------------------------- +LLPolyMeshSharedData::~LLPolyMeshSharedData() +{ + freeMeshData(); + for_each(mMorphData.begin(), mMorphData.end(), DeletePointer()); + mMorphData.clear(); +} + +//----------------------------------------------------------------------------- +// setupLOD() +//----------------------------------------------------------------------------- +void LLPolyMeshSharedData::setupLOD(LLPolyMeshSharedData* reference_data) +{ + mReferenceData = reference_data; + + if (reference_data) + { + mBaseCoords = reference_data->mBaseCoords; + mBaseNormals = reference_data->mBaseNormals; + mBaseBinormals = reference_data->mBaseBinormals; + mTexCoords = reference_data->mTexCoords; + mDetailTexCoords = reference_data->mDetailTexCoords; + mWeights = reference_data->mWeights; + mHasWeights = reference_data->mHasWeights; + mHasDetailTexCoords = reference_data->mHasDetailTexCoords; + } +} + +//----------------------------------------------------------------------------- +// LLPolyMeshSharedData::freeMeshData() +//----------------------------------------------------------------------------- +void LLPolyMeshSharedData::freeMeshData() +{ + if (!mReferenceData) + { + mNumVertices = 0; + + ll_aligned_free_16(mBaseCoords); + mBaseCoords = NULL; + + ll_aligned_free_16(mBaseNormals); + mBaseNormals = NULL; + + ll_aligned_free_16(mBaseBinormals); + mBaseBinormals = NULL; + + ll_aligned_free_16(mTexCoords); + mTexCoords = NULL; + + ll_aligned_free_16(mDetailTexCoords); + mDetailTexCoords = NULL; + + ll_aligned_free_16(mWeights); + mWeights = NULL; + } + + mNumFaces = 0; + delete [] mFaces; + mFaces = NULL; + + mNumJointNames = 0; + delete [] mJointNames; + mJointNames = NULL; + + delete [] mTriangleIndices; + mTriangleIndices = NULL; + +// mVertFaceMap.deleteAllData(); +} + +// compate_int is used by the qsort function to sort the index array +int compare_int(const void *a, const void *b); + +//----------------------------------------------------------------------------- +// genIndices() +//----------------------------------------------------------------------------- +void LLPolyMeshSharedData::genIndices(S32 index_offset) +{ + if (index_offset == mLastIndexOffset) + { + return; + } + + delete []mTriangleIndices; + mTriangleIndices = new U32[mNumTriangleIndices]; + + S32 cur_index = 0; + for (S32 i = 0; i < mNumFaces; i++) + { + mTriangleIndices[cur_index] = mFaces[i][0] + index_offset; + cur_index++; + mTriangleIndices[cur_index] = mFaces[i][1] + index_offset; + cur_index++; + mTriangleIndices[cur_index] = mFaces[i][2] + index_offset; + cur_index++; + } + + mLastIndexOffset = index_offset; +} + +//-------------------------------------------------------------------- +// LLPolyMeshSharedData::getNumKB() +//-------------------------------------------------------------------- +U32 LLPolyMeshSharedData::getNumKB() +{ + U32 num_kb = sizeof(LLPolyMesh); + + if (!isLOD()) + { + num_kb += mNumVertices * + ( sizeof(LLVector3) + // coords + sizeof(LLVector3) + // normals + sizeof(LLVector2) ); // texCoords + } + + if (mHasDetailTexCoords && !isLOD()) + { + num_kb += mNumVertices * sizeof(LLVector2); // detailTexCoords + } + + if (mHasWeights && !isLOD()) + { + num_kb += mNumVertices * sizeof(float); // weights + } + + num_kb += mNumFaces * sizeof(LLPolyFace); // faces + + num_kb /= 1024; + return num_kb; +} + +//----------------------------------------------------------------------------- +// LLPolyMeshSharedData::allocateVertexData() +//----------------------------------------------------------------------------- +BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices ) +{ + U32 i; + mBaseCoords = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a)); + mBaseNormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a)); + mBaseBinormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a)); + mTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2)); + mDetailTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2)); + mWeights = (F32*) ll_aligned_malloc_16(numVertices*sizeof(F32)); + for (i = 0; i < numVertices; i++) + { + mBaseCoords[i].clear(); + mBaseNormals[i].clear(); + mBaseBinormals[i].clear(); + mTexCoords[i].clear(); + mWeights[i] = 0.f; + } + mNumVertices = numVertices; + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLPolyMeshSharedData::allocateFaceData() +//----------------------------------------------------------------------------- +BOOL LLPolyMeshSharedData::allocateFaceData( U32 numFaces ) +{ + mFaces = new LLPolyFace[ numFaces ]; + mNumFaces = numFaces; + mNumTriangleIndices = mNumFaces * 3; + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLPolyMeshSharedData::allocateJointNames() +//----------------------------------------------------------------------------- +BOOL LLPolyMeshSharedData::allocateJointNames( U32 numJointNames ) +{ + mJointNames = new std::string[ numJointNames ]; + mNumJointNames = numJointNames; + return TRUE; +} + +//-------------------------------------------------------------------- +// LLPolyMeshSharedData::loadMesh() +//-------------------------------------------------------------------- +BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) +{ + //------------------------------------------------------------------------- + // Open the file + //------------------------------------------------------------------------- + if(fileName.empty()) + { + llerrs << "Filename is Empty!" << llendl; + return FALSE; + } + LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/ + if (!fp) + { + llerrs << "can't open: " << fileName << llendl; + return FALSE; + } + + //------------------------------------------------------------------------- + // Read a chunk + //------------------------------------------------------------------------- + char header[128]; /*Flawfinder: ignore*/ + if (fread(header, sizeof(char), 128, fp) != 128) + { + llwarns << "Short read" << llendl; + } + + //------------------------------------------------------------------------- + // Check for proper binary header + //------------------------------------------------------------------------- + BOOL status = FALSE; + if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/ + { + lldebugs << "Loading " << fileName << llendl; + + //---------------------------------------------------------------- + // File Header (seek past it) + //---------------------------------------------------------------- + fseek(fp, 24, SEEK_SET); + + //---------------------------------------------------------------- + // HasWeights + //---------------------------------------------------------------- + U8 hasWeights; + size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp); + if (numRead != 1) + { + llerrs << "can't read HasWeights flag from " << fileName << llendl; + return FALSE; + } + if (!isLOD()) + { + mHasWeights = (hasWeights==0) ? FALSE : TRUE; + } + + //---------------------------------------------------------------- + // HasDetailTexCoords + //---------------------------------------------------------------- + U8 hasDetailTexCoords; + numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp); + if (numRead != 1) + { + llerrs << "can't read HasDetailTexCoords flag from " << fileName << llendl; + return FALSE; + } + + //---------------------------------------------------------------- + // Position + //---------------------------------------------------------------- + LLVector3 position; + numRead = fread(position.mV, sizeof(float), 3, fp); + llendianswizzle(position.mV, sizeof(float), 3); + if (numRead != 3) + { + llerrs << "can't read Position from " << fileName << llendl; + return FALSE; + } + setPosition( position ); + + //---------------------------------------------------------------- + // Rotation + //---------------------------------------------------------------- + LLVector3 rotationAngles; + numRead = fread(rotationAngles.mV, sizeof(float), 3, fp); + llendianswizzle(rotationAngles.mV, sizeof(float), 3); + if (numRead != 3) + { + llerrs << "can't read RotationAngles from " << fileName << llendl; + return FALSE; + } + + U8 rotationOrder; + numRead = fread(&rotationOrder, sizeof(U8), 1, fp); + + if (numRead != 1) + { + llerrs << "can't read RotationOrder from " << fileName << llendl; + return FALSE; + } + + rotationOrder = 0; + + setRotation( mayaQ( rotationAngles.mV[0], + rotationAngles.mV[1], + rotationAngles.mV[2], + (LLQuaternion::Order)rotationOrder ) ); + + //---------------------------------------------------------------- + // Scale + //---------------------------------------------------------------- + LLVector3 scale; + numRead = fread(scale.mV, sizeof(float), 3, fp); + llendianswizzle(scale.mV, sizeof(float), 3); + if (numRead != 3) + { + llerrs << "can't read Scale from " << fileName << llendl; + return FALSE; + } + setScale( scale ); + + //------------------------------------------------------------------------- + // Release any existing mesh geometry + //------------------------------------------------------------------------- + freeMeshData(); + + U16 numVertices = 0; + + //---------------------------------------------------------------- + // NumVertices + //---------------------------------------------------------------- + if (!isLOD()) + { + numRead = fread(&numVertices, sizeof(U16), 1, fp); + llendianswizzle(&numVertices, sizeof(U16), 1); + if (numRead != 1) + { + llerrs << "can't read NumVertices from " << fileName << llendl; + return FALSE; + } + + allocateVertexData( numVertices ); + + for (U16 i = 0; i < numVertices; ++i) + { + //---------------------------------------------------------------- + // Coords + //---------------------------------------------------------------- + numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp); + llendianswizzle(&mBaseCoords[i], sizeof(float), 3); + if (numRead != 3) + { + llerrs << "can't read Coordinates from " << fileName << llendl; + return FALSE; + } + } + + for (U16 i = 0; i < numVertices; ++i) + { + //---------------------------------------------------------------- + // Normals + //---------------------------------------------------------------- + numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp); + llendianswizzle(&mBaseNormals[i], sizeof(float), 3); + if (numRead != 3) + { + llerrs << " can't read Normals from " << fileName << llendl; + return FALSE; + } + } + + for (U16 i = 0; i < numVertices; ++i) + { + //---------------------------------------------------------------- + // Binormals + //---------------------------------------------------------------- + numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp); + llendianswizzle(&mBaseBinormals[i], sizeof(float), 3); + if (numRead != 3) + { + llerrs << " can't read Binormals from " << fileName << llendl; + return FALSE; + } + } + + //---------------------------------------------------------------- + // TexCoords + //---------------------------------------------------------------- + numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp); + llendianswizzle(mTexCoords, sizeof(float), 2*numVertices); + if (numRead != numVertices) + { + llerrs << "can't read TexCoords from " << fileName << llendl; + return FALSE; + } + + //---------------------------------------------------------------- + // DetailTexCoords + //---------------------------------------------------------------- + if (mHasDetailTexCoords) + { + numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp); + llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices); + if (numRead != numVertices) + { + llerrs << "can't read DetailTexCoords from " << fileName << llendl; + return FALSE; + } + } + + //---------------------------------------------------------------- + // Weights + //---------------------------------------------------------------- + if (mHasWeights) + { + numRead = fread(mWeights, sizeof(float), numVertices, fp); + llendianswizzle(mWeights, sizeof(float), numVertices); + if (numRead != numVertices) + { + llerrs << "can't read Weights from " << fileName << llendl; + return FALSE; + } + } + } + + //---------------------------------------------------------------- + // NumFaces + //---------------------------------------------------------------- + U16 numFaces; + numRead = fread(&numFaces, sizeof(U16), 1, fp); + llendianswizzle(&numFaces, sizeof(U16), 1); + if (numRead != 1) + { + llerrs << "can't read NumFaces from " << fileName << llendl; + return FALSE; + } + allocateFaceData( numFaces ); + + + //---------------------------------------------------------------- + // Faces + //---------------------------------------------------------------- + U32 i; + U32 numTris = 0; + for (i = 0; i < numFaces; i++) + { + S16 face[3]; + numRead = fread(face, sizeof(U16), 3, fp); + llendianswizzle(face, sizeof(U16), 3); + if (numRead != 3) + { + llerrs << "can't read Face[" << i << "] from " << fileName << llendl; + return FALSE; + } + if (mReferenceData) + { + llassert(face[0] < mReferenceData->mNumVertices); + llassert(face[1] < mReferenceData->mNumVertices); + llassert(face[2] < mReferenceData->mNumVertices); + } + + if (isLOD()) + { + // store largest index in case of LODs + for (S32 j = 0; j < 3; j++) + { + if (face[j] > mNumVertices - 1) + { + mNumVertices = face[j] + 1; + } + } + } + mFaces[i][0] = face[0]; + mFaces[i][1] = face[1]; + mFaces[i][2] = face[2]; + +// S32 j; +// for(j = 0; j < 3; j++) +// { +// LLDynamicArray *face_list = mVertFaceMap.getIfThere(face[j]); +// if (!face_list) +// { +// face_list = new LLDynamicArray; +// mVertFaceMap.addData(face[j], face_list); +// } +// face_list->put(i); +// } + + numTris++; + } + + lldebugs << "verts: " << numVertices + << ", faces: " << numFaces + << ", tris: " << numTris + << llendl; + + //---------------------------------------------------------------- + // NumSkinJoints + //---------------------------------------------------------------- + if (!isLOD()) + { + U16 numSkinJoints = 0; + if ( mHasWeights ) + { + numRead = fread(&numSkinJoints, sizeof(U16), 1, fp); + llendianswizzle(&numSkinJoints, sizeof(U16), 1); + if (numRead != 1) + { + llerrs << "can't read NumSkinJoints from " << fileName << llendl; + return FALSE; + } + allocateJointNames( numSkinJoints ); + } + + //---------------------------------------------------------------- + // SkinJoints + //---------------------------------------------------------------- + for (i=0; i < numSkinJoints; i++) + { + char jointName[64+1]; + numRead = fread(jointName, sizeof(jointName)-1, 1, fp); + jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination + if (numRead != 1) + { + llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl; + return FALSE; + } + + std::string *jn = &mJointNames[i]; + *jn = jointName; + } + + //------------------------------------------------------------------------- + // look for morph section + //------------------------------------------------------------------------- + char morphName[64+1]; + morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination + while(fread(&morphName, sizeof(char), 64, fp) == 64) + { + if (!strcmp(morphName, "End Morphs")) + { + // we reached the end of the morphs + break; + } + LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName)); + + BOOL result = morph_data->loadBinary(fp, this); + + if (!result) + { + delete morph_data; + continue; + } + + mMorphData.insert(morph_data); + + if (!strcmp(morphName, "Breast_Female_Cleavage")) + { + mMorphData.insert(clone_morph_param_cleavage(morph_data, + .75f, + "Breast_Physics_LeftRight_Driven")); + } + + if (!strcmp(morphName, "Breast_Female_Cleavage")) + { + mMorphData.insert(clone_morph_param_duplicate(morph_data, + "Breast_Physics_InOut_Driven")); + } + if (!strcmp(morphName, "Breast_Gravity")) + { + mMorphData.insert(clone_morph_param_duplicate(morph_data, + "Breast_Physics_UpDown_Driven")); + } + + if (!strcmp(morphName, "Big_Belly_Torso")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Torso_UpDown_Driven")); + } + + if (!strcmp(morphName, "Big_Belly_Legs")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Legs_UpDown_Driven")); + } + + if (!strcmp(morphName, "skirt_belly")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Skirt_UpDown_Driven")); + } + + if (!strcmp(morphName, "Small_Butt")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Butt_Physics_UpDown_Driven")); + } + if (!strcmp(morphName, "Small_Butt")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0.03f,0), + "Butt_Physics_LeftRight_Driven")); + } + } + + S32 numRemaps; + if (fread(&numRemaps, sizeof(S32), 1, fp) == 1) + { + llendianswizzle(&numRemaps, sizeof(S32), 1); + for (S32 i = 0; i < numRemaps; i++) + { + S32 remapSrc; + S32 remapDst; + if (fread(&remapSrc, sizeof(S32), 1, fp) != 1) + { + llerrs << "can't read source vertex in vertex remap data" << llendl; + break; + } + if (fread(&remapDst, sizeof(S32), 1, fp) != 1) + { + llerrs << "can't read destination vertex in vertex remap data" << llendl; + break; + } + llendianswizzle(&remapSrc, sizeof(S32), 1); + llendianswizzle(&remapDst, sizeof(S32), 1); + + mSharedVerts[remapSrc] = remapDst; + } + } + } + + status = TRUE; + } + else + { + llerrs << "invalid mesh file header: " << fileName << llendl; + status = FALSE; + } + + if (0 == mNumJointNames) + { + allocateJointNames(1); + } + + fclose( fp ); + + return status; +} + +//----------------------------------------------------------------------------- +// getSharedVert() +//----------------------------------------------------------------------------- +const S32 *LLPolyMeshSharedData::getSharedVert(S32 vert) +{ + if (mSharedVerts.count(vert) > 0) + { + return &mSharedVerts[vert]; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// getUV() +//----------------------------------------------------------------------------- +const LLVector2 &LLPolyMeshSharedData::getUVs(U32 index) +{ + // TODO: convert all index variables to S32 + llassert((S32)index < mNumVertices); + + return mTexCoords[index]; +} + +//----------------------------------------------------------------------------- +// LLPolyMesh() +//----------------------------------------------------------------------------- +LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR_MESH); + + llassert(shared_data); + + mSharedData = shared_data; + mReferenceMesh = reference_mesh; + mAvatarp = NULL; + mVertexData = NULL; + + mCurVertexCount = 0; + mFaceIndexCount = 0; + mFaceIndexOffset = 0; + mFaceVertexCount = 0; + mFaceVertexOffset = 0; + + if (shared_data->isLOD() && reference_mesh) + { + mCoords = reference_mesh->mCoords; + mNormals = reference_mesh->mNormals; + mScaledNormals = reference_mesh->mScaledNormals; + mBinormals = reference_mesh->mBinormals; + mScaledBinormals = reference_mesh->mScaledBinormals; + mTexCoords = reference_mesh->mTexCoords; + mClothingWeights = reference_mesh->mClothingWeights; + } + else + { + // Allocate memory without initializing every vector + // NOTE: This makes asusmptions about the size of LLVector[234] + S32 nverts = mSharedData->mNumVertices; + //make sure it's an even number of verts for alignment + nverts += nverts%2; + S32 nfloats = nverts * ( + 4 + //coords + 4 + //normals + 4 + //weights + 2 + //coords + 4 + //scaled normals + 4 + //binormals + 4); //scaled binormals + + //use 16 byte aligned vertex data to make LLPolyMesh SSE friendly + mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4); + S32 offset = 0; + mCoords = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mClothingWeights = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts; + mScaledNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mScaledBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + initializeForMorph(); + } +} + + +//----------------------------------------------------------------------------- +// ~LLPolyMesh() +//----------------------------------------------------------------------------- +LLPolyMesh::~LLPolyMesh() +{ + S32 i; + for (i = 0; i < mJointRenderData.count(); i++) + { + delete mJointRenderData[i]; + mJointRenderData[i] = NULL; + } + + ll_aligned_free_16(mVertexData); + +} + + +//----------------------------------------------------------------------------- +// LLPolyMesh::getMesh() +//----------------------------------------------------------------------------- +LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_mesh) +{ + //------------------------------------------------------------------------- + // search for an existing mesh by this name + //------------------------------------------------------------------------- + LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL); + if (meshSharedData) + { +// llinfos << "Polymesh " << name << " found in global mesh table." << llendl; + LLPolyMesh *poly_mesh = new LLPolyMesh(meshSharedData, reference_mesh); + return poly_mesh; + } + + //------------------------------------------------------------------------- + // if not found, create a new one, add it to the list + //------------------------------------------------------------------------- + std::string full_path; + full_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name); + + LLPolyMeshSharedData *mesh_data = new LLPolyMeshSharedData(); + if (reference_mesh) + { + mesh_data->setupLOD(reference_mesh->getSharedData()); + } + if ( ! mesh_data->loadMesh( full_path ) ) + { + delete mesh_data; + return NULL; + } + + LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh); + +// llinfos << "Polymesh " << name << " added to global mesh table." << llendl; + sGlobalSharedMeshList[name] = poly_mesh->mSharedData; + + return poly_mesh; +} + +//----------------------------------------------------------------------------- +// LLPolyMesh::freeAllMeshes() +//----------------------------------------------------------------------------- +void LLPolyMesh::freeAllMeshes() +{ + // delete each item in the global lists + for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer()); + sGlobalSharedMeshList.clear(); +} + +LLPolyMeshSharedData *LLPolyMesh::getSharedData() const +{ + return mSharedData; +} + + +//-------------------------------------------------------------------- +// LLPolyMesh::dumpDiagInfo() +//-------------------------------------------------------------------- +void LLPolyMesh::dumpDiagInfo() +{ + // keep track of totals + U32 total_verts = 0; + U32 total_faces = 0; + U32 total_kb = 0; + + std::string buf; + + llinfos << "-----------------------------------------------------" << llendl; + llinfos << " Global PolyMesh Table (DEBUG only)" << llendl; + llinfos << " Verts Faces Mem(KB) Name" << llendl; + llinfos << "-----------------------------------------------------" << llendl; + + // print each loaded mesh, and it's memory usage + for(LLPolyMeshSharedDataTable::iterator iter = sGlobalSharedMeshList.begin(); + iter != sGlobalSharedMeshList.end(); ++iter) + { + const std::string& mesh_name = iter->first; + LLPolyMeshSharedData* mesh = iter->second; + + S32 num_verts = mesh->mNumVertices; + S32 num_faces = mesh->mNumFaces; + U32 num_kb = mesh->getNumKB(); + + buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str()); + llinfos << buf << llendl; + + total_verts += num_verts; + total_faces += num_faces; + total_kb += num_kb; + } + + llinfos << "-----------------------------------------------------" << llendl; + buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb ); + llinfos << buf << llendl; + llinfos << "-----------------------------------------------------" << llendl; +} + +//----------------------------------------------------------------------------- +// getWritableCoords() +//----------------------------------------------------------------------------- +LLVector4a *LLPolyMesh::getWritableCoords() +{ + return mCoords; +} + +//----------------------------------------------------------------------------- +// getWritableNormals() +//----------------------------------------------------------------------------- +LLVector4a *LLPolyMesh::getWritableNormals() +{ + return mNormals; +} + +//----------------------------------------------------------------------------- +// getWritableBinormals() +//----------------------------------------------------------------------------- +LLVector4a *LLPolyMesh::getWritableBinormals() +{ + return mBinormals; +} + + +//----------------------------------------------------------------------------- +// getWritableClothingWeights() +//----------------------------------------------------------------------------- +LLVector4a *LLPolyMesh::getWritableClothingWeights() +{ + return mClothingWeights; +} + +//----------------------------------------------------------------------------- +// getWritableTexCoords() +//----------------------------------------------------------------------------- +LLVector2 *LLPolyMesh::getWritableTexCoords() +{ + return mTexCoords; +} + +//----------------------------------------------------------------------------- +// getScaledNormals() +//----------------------------------------------------------------------------- +LLVector4a *LLPolyMesh::getScaledNormals() +{ + return mScaledNormals; +} + +//----------------------------------------------------------------------------- +// getScaledBinormals() +//----------------------------------------------------------------------------- +LLVector4a *LLPolyMesh::getScaledBinormals() +{ + return mScaledBinormals; +} + + +//----------------------------------------------------------------------------- +// initializeForMorph() +//----------------------------------------------------------------------------- +void LLPolyMesh::initializeForMorph() +{ + LLVector4a::memcpyNonAliased16((F32*) mCoords, (F32*) mSharedData->mBaseCoords, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2)); + + for (U32 i = 0; i < mSharedData->mNumVertices; ++i) + { + mClothingWeights[i].clear(); + } +} + +//----------------------------------------------------------------------------- +// getMorphData() +//----------------------------------------------------------------------------- +LLPolyMorphData* LLPolyMesh::getMorphData(const std::string& morph_name) +{ + if (!mSharedData) + return NULL; + for (LLPolyMeshSharedData::morphdata_list_t::iterator iter = mSharedData->mMorphData.begin(); + iter != mSharedData->mMorphData.end(); ++iter) + { + LLPolyMorphData *morph_data = *iter; + if (morph_data->getName() == morph_name) + { + return morph_data; + } + } + return NULL; +} + +//----------------------------------------------------------------------------- +// removeMorphData() +//----------------------------------------------------------------------------- +// // erasing but not deleting seems bad, but fortunately we don't actually use this... +// void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target) +// { +// if (!mSharedData) +// return; +// mSharedData->mMorphData.erase(morph_target); +// } + +//----------------------------------------------------------------------------- +// deleteAllMorphData() +//----------------------------------------------------------------------------- +// void LLPolyMesh::deleteAllMorphData() +// { +// if (!mSharedData) +// return; + +// for_each(mSharedData->mMorphData.begin(), mSharedData->mMorphData.end(), DeletePointer()); +// mSharedData->mMorphData.clear(); +// } + +//----------------------------------------------------------------------------- +// getWritableWeights() +//----------------------------------------------------------------------------- +F32* LLPolyMesh::getWritableWeights() const +{ + return mSharedData->mWeights; +} + +// End diff --git a/indra/llappearance/llpolymesh.h b/indra/llappearance/llpolymesh.h new file mode 100644 index 0000000000..ef1dfb1adb --- /dev/null +++ b/indra/llappearance/llpolymesh.h @@ -0,0 +1,369 @@ +/** + * @file llpolymesh.h + * @brief Implementation of LLPolyMesh class + * + * $LicenseInfo:firstyear=2001&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_LLPOLYMESHINTERFACE_H +#define LL_LLPOLYMESHINTERFACE_H + +#include +#include +#include "llstl.h" + +#include "v3math.h" +#include "v2math.h" +#include "llquaternion.h" +#include "llpolymorph.h" +#include "lljoint.h" +//#include "lldarray.h" + +class LLSkinJoint; +class LLAvatarAppearance; +class LLWearable; + +//#define USE_STRIPS // Use tri-strips for rendering. + +//----------------------------------------------------------------------------- +// LLPolyFace +// A set of 4 vertex indices. +// An LLPolyFace can represent either a triangle or quad. +// If the last index is -1, it's a triangle. +//----------------------------------------------------------------------------- +typedef S32 LLPolyFace[3]; + +//struct PrimitiveGroup; + +//----------------------------------------------------------------------------- +// LLPolyMesh +// A polyhedra consisting of any number of triangles and quads. +// All instances contain a set of faces, and optionally may include +// faces grouped into named face sets. +//----------------------------------------------------------------------------- +class LLPolyMorphTarget; + +class LLPolyMeshSharedData +{ + friend class LLPolyMesh; +private: + // transform data + LLVector3 mPosition; + LLQuaternion mRotation; + LLVector3 mScale; + + // vertex data + S32 mNumVertices; + LLVector4a *mBaseCoords; + LLVector4a *mBaseNormals; + LLVector4a *mBaseBinormals; + LLVector2 *mTexCoords; + LLVector2 *mDetailTexCoords; + F32 *mWeights; + + BOOL mHasWeights; + BOOL mHasDetailTexCoords; + + // face data + S32 mNumFaces; + LLPolyFace *mFaces; + + // face set data + U32 mNumJointNames; + std::string* mJointNames; + + // morph targets + typedef std::set morphdata_list_t; + morphdata_list_t mMorphData; + + std::map mSharedVerts; + + LLPolyMeshSharedData* mReferenceData; + S32 mLastIndexOffset; + +public: + // Temporarily... + // Triangle indices + U32 mNumTriangleIndices; + U32 *mTriangleIndices; + +public: + LLPolyMeshSharedData(); + ~LLPolyMeshSharedData(); + +private: + void setupLOD(LLPolyMeshSharedData* reference_data); + + // Frees all mesh memory resources + void freeMeshData(); + + void setPosition( const LLVector3 &pos ) { mPosition = pos; } + void setRotation( const LLQuaternion &rot ) { mRotation = rot; } + void setScale( const LLVector3 &scale ) { mScale = scale; } + + BOOL allocateVertexData( U32 numVertices ); + + BOOL allocateFaceData( U32 numFaces ); + + BOOL allocateJointNames( U32 numJointNames ); + + // Retrieve the number of KB of memory used by this instance + U32 getNumKB(); + + // Load mesh data from file + BOOL loadMesh( const std::string& fileName ); + +public: + void genIndices(S32 offset); + + const LLVector2 &getUVs(U32 index); + + const S32 *getSharedVert(S32 vert); + + BOOL isLOD() { return (mReferenceData != NULL); } +}; + + +class LLJointRenderData +{ +public: + LLJointRenderData(const LLMatrix4* world_matrix, LLSkinJoint* skin_joint) : mWorldMatrix(world_matrix), mSkinJoint(skin_joint) {} + ~LLJointRenderData(){} + + const LLMatrix4* mWorldMatrix; + LLSkinJoint* mSkinJoint; +}; + + +class LLPolyMesh +{ +public: + + // Constructor + LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh); + + // Destructor + ~LLPolyMesh(); + + // Requests a mesh by name. + // If the mesh already exists in the global mesh table, it is returned, + // otherwise it is loaded from file, added to the table, and returned. + static LLPolyMesh *getMesh( const std::string &name, LLPolyMesh* reference_mesh = NULL); + + // Frees all loaded meshes. + // This should only be called once you know there are no outstanding + // references to these objects. Generally, upon exit of the application. + static void freeAllMeshes(); + + //-------------------------------------------------------------------- + // Transform Data Access + //-------------------------------------------------------------------- + // Get position + const LLVector3 &getPosition() { + llassert (mSharedData); + return mSharedData->mPosition; + } + + // Get rotation + const LLQuaternion &getRotation() { + llassert (mSharedData); + return mSharedData->mRotation; + } + + // Get scale + const LLVector3 &getScale() { + llassert (mSharedData); + return mSharedData->mScale; + } + + //-------------------------------------------------------------------- + // Vertex Data Access + //-------------------------------------------------------------------- + // Get number of vertices + U32 getNumVertices() { + llassert (mSharedData); + return mSharedData->mNumVertices; + } + + // Returns whether or not the mesh has detail texture coords + BOOL hasDetailTexCoords() { + llassert (mSharedData); + return mSharedData->mHasDetailTexCoords; + } + + // Returns whether or not the mesh has vertex weights + BOOL hasWeights() const{ + llassert (mSharedData); + return mSharedData->mHasWeights; + } + + // Get coords + const LLVector4a *getCoords() const{ + return mCoords; + } + + // non const version + LLVector4a *getWritableCoords(); + + // Get normals + const LLVector4a *getNormals() const{ + return mNormals; + } + + // Get normals + const LLVector4a *getBinormals() const{ + return mBinormals; + } + + // Get base mesh normals + const LLVector4a *getBaseNormals() const{ + llassert(mSharedData); + return mSharedData->mBaseNormals; + } + + // Get base mesh normals + const LLVector4a *getBaseBinormals() const{ + llassert(mSharedData); + return mSharedData->mBaseBinormals; + } + + // intermediate morphed normals and output normals + LLVector4a *getWritableNormals(); + LLVector4a *getScaledNormals(); + + LLVector4a *getWritableBinormals(); + LLVector4a *getScaledBinormals(); + + // Get texCoords + const LLVector2 *getTexCoords() const { + return mTexCoords; + } + + // non const version + LLVector2 *getWritableTexCoords(); + + // Get detailTexCoords + const LLVector2 *getDetailTexCoords() const { + llassert (mSharedData); + return mSharedData->mDetailTexCoords; + } + + // Get weights + const F32 *getWeights() const { + llassert (mSharedData); + return mSharedData->mWeights; + } + + F32 *getWritableWeights() const; + + LLVector4a *getWritableClothingWeights(); + + const LLVector4a *getClothingWeights() + { + return mClothingWeights; + } + + //-------------------------------------------------------------------- + // Face Data Access + //-------------------------------------------------------------------- + // Get number of faces + S32 getNumFaces() { + llassert (mSharedData); + return mSharedData->mNumFaces; + } + + // Get faces + LLPolyFace *getFaces() { + llassert (mSharedData); + return mSharedData->mFaces; + } + + U32 getNumJointNames() { + llassert (mSharedData); + return mSharedData->mNumJointNames; + } + + std::string *getJointNames() { + llassert (mSharedData); + return mSharedData->mJointNames; + } + + LLPolyMorphData* getMorphData(const std::string& morph_name); +// void removeMorphData(LLPolyMorphData *morph_target); +// void deleteAllMorphData(); + + LLPolyMeshSharedData *getSharedData() const; + LLPolyMesh *getReferenceMesh() { return mReferenceMesh ? mReferenceMesh : this; } + + // Get indices + U32* getIndices() { return mSharedData ? mSharedData->mTriangleIndices : NULL; } + + BOOL isLOD() { return mSharedData && mSharedData->isLOD(); } + + void setAvatar(LLAvatarAppearance* avatarp) { mAvatarp = avatarp; } + LLAvatarAppearance* getAvatar() { return mAvatarp; } + + LLDynamicArray mJointRenderData; + + U32 mFaceVertexOffset; + U32 mFaceVertexCount; + U32 mFaceIndexOffset; + U32 mFaceIndexCount; + U32 mCurVertexCount; +private: + void initializeForMorph(); + + // Dumps diagnostic information about the global mesh table + static void dumpDiagInfo(); + +protected: + // mesh data shared across all instances of a given mesh + LLPolyMeshSharedData *mSharedData; + // Single array of floats for allocation / deletion + F32 *mVertexData; + // deformed vertices (resulting from application of morph targets) + LLVector4a *mCoords; + // deformed normals (resulting from application of morph targets) + LLVector4a *mScaledNormals; + // output normals (after normalization) + LLVector4a *mNormals; + // deformed binormals (resulting from application of morph targets) + LLVector4a *mScaledBinormals; + // output binormals (after normalization) + LLVector4a *mBinormals; + // weight values that mark verts as clothing/skin + LLVector4a *mClothingWeights; + // output texture coordinates + LLVector2 *mTexCoords; + + LLPolyMesh *mReferenceMesh; + + // global mesh list + typedef std::map LLPolyMeshSharedDataTable; + static LLPolyMeshSharedDataTable sGlobalSharedMeshList; + + // Backlink only; don't make this an LLPointer. + LLAvatarAppearance* mAvatarp; +}; + +#endif // LL_LLPOLYMESHINTERFACE_H + diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp new file mode 100644 index 0000000000..aa680894ff --- /dev/null +++ b/indra/llappearance/llpolymorph.cpp @@ -0,0 +1,748 @@ +/** + * @file llpolymorph.cpp + * @brief Implementation of LLPolyMesh class + * + * $LicenseInfo:firstyear=2001&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$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- + +#include "llpolymorph.h" +#include "llavatarappearance.h" +#include "llavatarjoint.h" +#include "llwearable.h" +#include "llxmltree.h" +#include "llendianswizzle.h" +#include "llpolymesh.h" + +//#include "../tools/imdebug/imdebug.h" + +const F32 NORMAL_SOFTEN_FACTOR = 0.65f; + +//----------------------------------------------------------------------------- +// LLPolyMorphData() +//----------------------------------------------------------------------------- +LLPolyMorphData::LLPolyMorphData(const std::string& morph_name) + : mName(morph_name) +{ + mNumIndices = 0; + mCurrentIndex = 0; + mTotalDistortion = 0.f; + mAvgDistortion.clear(); + mMaxDistortion = 0.f; + mVertexIndices = NULL; + mCoords = NULL; + mNormals = NULL; + mBinormals = NULL; + mTexCoords = NULL; + + mMesh = NULL; +} + +LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) : + mName(rhs.mName), + mNumIndices(rhs.mNumIndices), + mTotalDistortion(rhs.mTotalDistortion), + mAvgDistortion(rhs.mAvgDistortion), + mMaxDistortion(rhs.mMaxDistortion), + mVertexIndices(NULL), + mCoords(NULL), + mNormals(NULL), + mBinormals(NULL), + mTexCoords(NULL) +{ + const S32 numVertices = mNumIndices; + + mCoords = new LLVector4a[numVertices]; + mNormals = new LLVector4a[numVertices]; + mBinormals = new LLVector4a[numVertices]; + mTexCoords = new LLVector2[numVertices]; + mVertexIndices = new U32[numVertices]; + + for (S32 v=0; v < numVertices; v++) + { + mCoords[v] = rhs.mCoords[v]; + mNormals[v] = rhs.mNormals[v]; + mBinormals[v] = rhs.mBinormals[v]; + mTexCoords[v] = rhs.mTexCoords[v]; + mVertexIndices[v] = rhs.mVertexIndices[v]; + } +} + + +//----------------------------------------------------------------------------- +// ~LLPolyMorphData() +//----------------------------------------------------------------------------- +LLPolyMorphData::~LLPolyMorphData() +{ + delete [] mVertexIndices; + delete [] mCoords; + delete [] mNormals; + delete [] mBinormals; + delete [] mTexCoords; +} + +//----------------------------------------------------------------------------- +// loadBinary() +//----------------------------------------------------------------------------- +BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) +{ + S32 numVertices; + S32 numRead; + + numRead = fread(&numVertices, sizeof(S32), 1, fp); + llendianswizzle(&numVertices, sizeof(S32), 1); + if (numRead != 1) + { + llwarns << "Can't read number of morph target vertices" << llendl; + return FALSE; + } + + //------------------------------------------------------------------------- + // allocate vertices + //------------------------------------------------------------------------- + mCoords = new LLVector4a[numVertices]; + mNormals = new LLVector4a[numVertices]; + mBinormals = new LLVector4a[numVertices]; + mTexCoords = new LLVector2[numVertices]; + // Actually, we are allocating more space than we need for the skiplist + mVertexIndices = new U32[numVertices]; + mNumIndices = 0; + mTotalDistortion = 0.f; + mMaxDistortion = 0.f; + mAvgDistortion.clear(); + mMesh = mesh; + + //------------------------------------------------------------------------- + // read vertices + //------------------------------------------------------------------------- + for(S32 v = 0; v < numVertices; v++) + { + numRead = fread(&mVertexIndices[v], sizeof(U32), 1, fp); + llendianswizzle(&mVertexIndices[v], sizeof(U32), 1); + if (numRead != 1) + { + llwarns << "Can't read morph target vertex number" << llendl; + return FALSE; + } + + if (mVertexIndices[v] > 10000) + { + llerrs << "Bad morph index: " << mVertexIndices[v] << llendl; + } + + + numRead = fread(&mCoords[v], sizeof(F32), 3, fp); + llendianswizzle(&mCoords[v], sizeof(F32), 3); + if (numRead != 3) + { + llwarns << "Can't read morph target vertex coordinates" << llendl; + return FALSE; + } + + F32 magnitude = mCoords[v].getLength3().getF32(); + + mTotalDistortion += magnitude; + LLVector4a t; + t.setAbs(mCoords[v]); + mAvgDistortion.add(t); + + if (magnitude > mMaxDistortion) + { + mMaxDistortion = magnitude; + } + + numRead = fread(&mNormals[v], sizeof(F32), 3, fp); + llendianswizzle(&mNormals[v], sizeof(F32), 3); + if (numRead != 3) + { + llwarns << "Can't read morph target normal" << llendl; + return FALSE; + } + + numRead = fread(&mBinormals[v], sizeof(F32), 3, fp); + llendianswizzle(&mBinormals[v], sizeof(F32), 3); + if (numRead != 3) + { + llwarns << "Can't read morph target binormal" << llendl; + return FALSE; + } + + + numRead = fread(&mTexCoords[v].mV, sizeof(F32), 2, fp); + llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2); + if (numRead != 2) + { + llwarns << "Can't read morph target uv" << llendl; + return FALSE; + } + + mNumIndices++; + } + + mAvgDistortion.mul(1.f/(F32)mNumIndices); + mAvgDistortion.normalize3fast(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLPolyMorphTargetInfo() +//----------------------------------------------------------------------------- +LLPolyMorphTargetInfo::LLPolyMorphTargetInfo() + : mIsClothingMorph(FALSE) +{ +} + +BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node) +{ + llassert( node->hasName( "param" ) && node->getChildByName( "param_morph" ) ); + + if (!LLViewerVisualParamInfo::parseXml(node)) + return FALSE; + + // Get mixed-case name + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if( !node->getFastAttributeString( name_string, mMorphName ) ) + { + llwarns << "Avatar file: is missing name attribute" << llendl; + return FALSE; // Continue, ignoring this tag + } + + static LLStdStringHandle clothing_morph_string = LLXmlTree::addAttributeString("clothing_morph"); + node->getFastAttributeBOOL(clothing_morph_string, mIsClothingMorph); + + LLXmlTreeNode *paramNode = node->getChildByName("param_morph"); + + if (NULL == paramNode) + { + llwarns << "Failed to getChildByName(\"param_morph\")" + << llendl; + return FALSE; + } + + for (LLXmlTreeNode* child_node = paramNode->getFirstChild(); + child_node; + child_node = paramNode->getNextChild()) + { + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (child_node->hasName("volume_morph")) + { + std::string volume_name; + if (child_node->getFastAttributeString(name_string, volume_name)) + { + LLVector3 scale; + static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); + child_node->getFastAttributeVector3(scale_string, scale); + + LLVector3 pos; + static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos"); + child_node->getFastAttributeVector3(pos_string, pos); + + mVolumeInfoList.push_back(LLPolyVolumeMorphInfo(volume_name,scale,pos)); + } + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLPolyMorphTarget() +//----------------------------------------------------------------------------- +LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh) + : mMorphData(NULL), mMesh(poly_mesh), + mVertMask(NULL), + mLastSex(SEX_FEMALE), + mNumMorphMasksPending(0) +{ +} + +//----------------------------------------------------------------------------- +// ~LLPolyMorphTarget() +//----------------------------------------------------------------------------- +LLPolyMorphTarget::~LLPolyMorphTarget() +{ + if (mVertMask) + { + delete mVertMask; + } +} + +//----------------------------------------------------------------------------- +// setInfo() +//----------------------------------------------------------------------------- +BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) +{ + llassert(mInfo == NULL); + if (info->mID < 0) + return FALSE; + mInfo = info; + mID = info->mID; + setWeight(getDefaultWeight(), FALSE ); + + LLAvatarAppearance* avatarp = mMesh->getAvatar(); + LLPolyMorphTargetInfo::volume_info_list_t::iterator iter; + for (iter = getInfo()->mVolumeInfoList.begin(); iter != getInfo()->mVolumeInfoList.end(); iter++) + { + LLPolyVolumeMorphInfo *volume_info = &(*iter); + for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++) + { + if (avatarp->mCollisionVolumes[i].getName() == volume_info->mName) + { + mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i], + volume_info->mScale, + volume_info->mPos)); + break; + } + } + } + + std::string morph_param_name = getInfo()->mMorphName; + + mMorphData = mMesh->getMorphData(morph_param_name); + if (!mMorphData) + { + const std::string driven_tag = "_Driven"; + U32 pos = morph_param_name.find(driven_tag); + if (pos > 0) + { + morph_param_name = morph_param_name.substr(0,pos); + mMorphData = mMesh->getMorphData(morph_param_name); + } + } + if (!mMorphData) + { + llwarns << "No morph target named " << morph_param_name << " found in mesh." << llendl; + return FALSE; // Continue, ignoring this tag + } + return TRUE; +} + +/*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const +{ + LLPolyMorphTarget *new_param = new LLPolyMorphTarget(mMesh); + *new_param = *this; + return new_param; +} + +#if 0 // obsolete +//----------------------------------------------------------------------------- +// parseData() +//----------------------------------------------------------------------------- +BOOL LLPolyMorphTarget::parseData(LLXmlTreeNode* node) +{ + LLPolyMorphTargetInfo* info = new LLPolyMorphTargetInfo; + + info->parseXml(node); + if (!setInfo(info)) + { + delete info; + return FALSE; + } + return TRUE; +} +#endif + +//----------------------------------------------------------------------------- +// getVertexDistortion() +//----------------------------------------------------------------------------- +LLVector4a LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh) +{ + if (!mMorphData || mMesh != mesh) return LLVector4a::getZero(); + + for(U32 index = 0; index < mMorphData->mNumIndices; index++) + { + if (mMorphData->mVertexIndices[index] == (U32)requested_index) + { + return mMorphData->mCoords[index]; + } + } + + return LLVector4a::getZero(); +} + +//----------------------------------------------------------------------------- +// getFirstDistortion() +//----------------------------------------------------------------------------- +const LLVector4a *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) +{ + if (!mMorphData) return &LLVector4a::getZero(); + + LLVector4a* resultVec; + mMorphData->mCurrentIndex = 0; + if (mMorphData->mNumIndices) + { + resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex]; + if (index != NULL) + { + *index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex]; + } + if (poly_mesh != NULL) + { + *poly_mesh = mMesh; + } + + return resultVec; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// getNextDistortion() +//----------------------------------------------------------------------------- +const LLVector4a *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) +{ + if (!mMorphData) return &LLVector4a::getZero(); + + LLVector4a* resultVec; + mMorphData->mCurrentIndex++; + if (mMorphData->mCurrentIndex < mMorphData->mNumIndices) + { + resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex]; + if (index != NULL) + { + *index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex]; + } + if (poly_mesh != NULL) + { + *poly_mesh = mMesh; + } + return resultVec; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// getTotalDistortion() +//----------------------------------------------------------------------------- +F32 LLPolyMorphTarget::getTotalDistortion() +{ + if (mMorphData) + { + return mMorphData->mTotalDistortion; + } + else + { + return 0.f; + } +} + +//----------------------------------------------------------------------------- +// getAvgDistortion() +//----------------------------------------------------------------------------- +const LLVector4a& LLPolyMorphTarget::getAvgDistortion() +{ + if (mMorphData) + { + return mMorphData->mAvgDistortion; + } + else + { + return LLVector4a::getZero(); + } +} + +//----------------------------------------------------------------------------- +// getMaxDistortion() +//----------------------------------------------------------------------------- +F32 LLPolyMorphTarget::getMaxDistortion() +{ + if (mMorphData) + { + return mMorphData->mMaxDistortion; + } + else + { + return 0.f; + } +} + +//----------------------------------------------------------------------------- +// apply() +//----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_APPLY_MORPH_TARGET("Apply Morph"); + +void LLPolyMorphTarget::apply( ESex avatar_sex ) +{ + if (!mMorphData || mNumMorphMasksPending > 0) + { + return; + } + + LLFastTimer t(FTM_APPLY_MORPH_TARGET); + + mLastSex = avatar_sex; + + // Check for NaN condition (NaN is detected if a variable doesn't equal itself. + if (mCurWeight != mCurWeight) + { + mCurWeight = 0.0; + } + if (mLastWeight != mLastWeight) + { + mLastWeight = mCurWeight+.001; + } + + // perform differential update of morph + F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight); + // store last weight + mLastWeight += delta_weight; + + if (delta_weight != 0.f) + { + llassert(!mMesh->isLOD()); + LLVector4a *coords = mMesh->getWritableCoords(); + + LLVector4a *scaled_normals = mMesh->getScaledNormals(); + LLVector4a *normals = mMesh->getWritableNormals(); + + LLVector4a *scaled_binormals = mMesh->getScaledBinormals(); + LLVector4a *binormals = mMesh->getWritableBinormals(); + + LLVector4a *clothing_weights = mMesh->getWritableClothingWeights(); + LLVector2 *tex_coords = mMesh->getWritableTexCoords(); + + F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; + + for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++) + { + S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph]; + + F32 maskWeight = 1.f; + if (maskWeightArray) + { + maskWeight = maskWeightArray[vert_index_morph]; + } + + + LLVector4a pos = mMorphData->mCoords[vert_index_morph]; + pos.mul(delta_weight*maskWeight); + coords[vert_index_mesh].add(pos); + + if (getInfo()->mIsClothingMorph && clothing_weights) + { + LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph]; + clothing_offset.mul(delta_weight * maskWeight); + LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh]; + clothing_weight->add(clothing_offset); + clothing_weight->getF32ptr()[VW] = maskWeight; + } + + // calculate new normals based on half angles + LLVector4a norm = mMorphData->mNormals[vert_index_morph]; + norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); + scaled_normals[vert_index_mesh].add(norm); + norm = scaled_normals[vert_index_mesh]; + norm.normalize3fast(); + normals[vert_index_mesh] = norm; + + // calculate new binormals + LLVector4a binorm = mMorphData->mBinormals[vert_index_morph]; + binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); + scaled_binormals[vert_index_mesh].add(binorm); + LLVector4a tangent; + tangent.setCross3(scaled_binormals[vert_index_mesh], norm); + LLVector4a& normalized_binormal = binormals[vert_index_mesh]; + normalized_binormal.setCross3(norm, tangent); + normalized_binormal.normalize3fast(); + + tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight; + } + + // now apply volume changes + for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) + { + LLPolyVolumeMorph* volume_morph = &(*iter); + LLVector3 scale_delta = volume_morph->mScale * delta_weight; + LLVector3 pos_delta = volume_morph->mPos * delta_weight; + + volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); + volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); + } + } + + if (mNext) + { + mNext->apply(avatar_sex); + } +} + +//----------------------------------------------------------------------------- +// applyMask() +//----------------------------------------------------------------------------- +void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert) +{ + LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL; + + if (!mVertMask) + { + mVertMask = new LLPolyVertexMask(mMorphData); + mNumMorphMasksPending--; + } + else + { + // remove effect of previous mask + F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; + + if (maskWeights) + { + LLVector4a *coords = mMesh->getWritableCoords(); + LLVector4a *scaled_normals = mMesh->getScaledNormals(); + LLVector4a *scaled_binormals = mMesh->getScaledBinormals(); + LLVector2 *tex_coords = mMesh->getWritableTexCoords(); + + LLVector4Logical clothing_mask; + clothing_mask.clear(); + clothing_mask.setElement<0>(); + clothing_mask.setElement<1>(); + clothing_mask.setElement<2>(); + + + for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++) + { + F32 lastMaskWeight = mLastWeight * maskWeights[vert]; + S32 out_vert = mMorphData->mVertexIndices[vert]; + + // remove effect of existing masked morph + LLVector4a t; + t = mMorphData->mCoords[vert]; + t.mul(lastMaskWeight); + coords[out_vert].sub(t); + + t = mMorphData->mNormals[vert]; + t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR); + scaled_normals[out_vert].sub(t); + + t = mMorphData->mBinormals[vert]; + t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR); + scaled_binormals[out_vert].sub(t); + + tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight; + + if (clothing_weights) + { + LLVector4a clothing_offset = mMorphData->mCoords[vert]; + clothing_offset.mul(lastMaskWeight); + LLVector4a* clothing_weight = &clothing_weights[out_vert]; + LLVector4a t; + t.setSub(*clothing_weight, clothing_offset); + clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight); + } + } + } + } + + // set last weight to 0, since we've removed the effect of this morph + mLastWeight = 0.f; + + mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights); + + apply(mLastSex); +} + + +//----------------------------------------------------------------------------- +// LLPolyVertexMask() +//----------------------------------------------------------------------------- +LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data) +{ + mWeights = new F32[morph_data->mNumIndices]; + mMorphData = morph_data; + mWeightsGenerated = FALSE; +} + +//----------------------------------------------------------------------------- +// ~LLPolyVertexMask() +//----------------------------------------------------------------------------- +LLPolyVertexMask::~LLPolyVertexMask() +{ + delete[] mWeights; +} + +//----------------------------------------------------------------------------- +// generateMask() +//----------------------------------------------------------------------------- +void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights) +{ +// RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/) +// BOOL debugImg = FALSE; +// if (debugImg) +// { +// if (invert) +// { +// imdebug("lum rbga=rgba b=8 w=%d h=%d *-1 %p", width, height, maskTextureData); +// } +// else +// { +// imdebug("lum rbga=rgba b=8 w=%d h=%d %p", width, height, maskTextureData); +// } +// } + for (U32 index = 0; index < mMorphData->mNumIndices; index++) + { + S32 vertIndex = mMorphData->mVertexIndices[index]; + const S32 *sharedVertIndex = mMorphData->mMesh->getSharedVert(vertIndex); + LLVector2 uvCoords; + + if (sharedVertIndex) + { + uvCoords = mMorphData->mMesh->getUVs(*sharedVertIndex); + } + else + { + uvCoords = mMorphData->mMesh->getUVs(vertIndex); + } + U32 s = llclamp((U32)(uvCoords.mV[VX] * (F32)(width - 1)), (U32)0, (U32)width - 1); + U32 t = llclamp((U32)(uvCoords.mV[VY] * (F32)(height - 1)), (U32)0, (U32)height - 1); + + mWeights[index] = ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f; + + if (invert) + { + mWeights[index] = 1.f - mWeights[index]; + } + + // now apply step function + // mWeights[index] = mWeights[index] > 0.95f ? 1.f : 0.f; + + if (clothing_weights) + { + clothing_weights[vertIndex].getF32ptr()[VW] = mWeights[index]; + } + } + mWeightsGenerated = TRUE; +} + +//----------------------------------------------------------------------------- +// getMaskForMorphIndex() +//----------------------------------------------------------------------------- +F32* LLPolyVertexMask::getMorphMaskWeights() +{ + if (!mWeightsGenerated) + { + return NULL; + } + + return mWeights; +} diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h new file mode 100644 index 0000000000..d6cf9e52ca --- /dev/null +++ b/indra/llappearance/llpolymorph.h @@ -0,0 +1,182 @@ +/** + * @file llpolymorph.h + * @brief Implementation of LLPolyMesh class + * + * $LicenseInfo:firstyear=2001&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_LLPOLYMORPH_H +#define LL_LLPOLYMORPH_H + +#include +#include + +#include "llviewervisualparam.h" + +class LLAvatarJointCollisionVolume; +class LLPolyMeshSharedData; +class LLVector2; +class LLAvatarJointCollisionVolume; +class LLWearable; + +//----------------------------------------------------------------------------- +// LLPolyMorphData() +//----------------------------------------------------------------------------- +class LLPolyMorphData +{ +public: + LLPolyMorphData(const std::string& morph_name); + ~LLPolyMorphData(); + LLPolyMorphData(const LLPolyMorphData &rhs); + + BOOL loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh); + const std::string& getName() { return mName; } + +public: + std::string mName; + + // morphology + U32 mNumIndices; + U32* mVertexIndices; + U32 mCurrentIndex; + LLVector4a* mCoords; + LLVector4a* mNormals; + LLVector4a* mBinormals; + LLVector2* mTexCoords; + + F32 mTotalDistortion; // vertex distortion summed over entire morph + F32 mMaxDistortion; // maximum single vertex distortion in a given morph + LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph + LLPolyMeshSharedData* mMesh; +}; + +//----------------------------------------------------------------------------- +// LLPolyVertexMask() +//----------------------------------------------------------------------------- +class LLPolyVertexMask +{ +public: + LLPolyVertexMask(LLPolyMorphData* morph_data); + ~LLPolyVertexMask(); + + void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights); + F32* getMorphMaskWeights(); + + +protected: + F32* mWeights; + LLPolyMorphData *mMorphData; + BOOL mWeightsGenerated; + +}; + +//----------------------------------------------------------------------------- +// LLPolyMorphTarget Data structs +//----------------------------------------------------------------------------- +struct LLPolyVolumeMorphInfo +{ + LLPolyVolumeMorphInfo(std::string &name, LLVector3 &scale, LLVector3 &pos) + : mName(name), mScale(scale), mPos(pos) {}; + + std::string mName; + LLVector3 mScale; + LLVector3 mPos; +}; + +struct LLPolyVolumeMorph +{ + LLPolyVolumeMorph(LLAvatarJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos) + : mVolume(volume), mScale(scale), mPos(pos) {}; + + LLAvatarJointCollisionVolume* mVolume; + LLVector3 mScale; + LLVector3 mPos; +}; + +//----------------------------------------------------------------------------- +// LLPolyMorphTargetInfo +// Shared information for LLPolyMorphTargets +//----------------------------------------------------------------------------- +class LLPolyMorphTargetInfo : public LLViewerVisualParamInfo +{ + friend class LLPolyMorphTarget; +public: + LLPolyMorphTargetInfo(); + /*virtual*/ ~LLPolyMorphTargetInfo() {}; + + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + +protected: + std::string mMorphName; + BOOL mIsClothingMorph; + typedef std::vector volume_info_list_t; + volume_info_list_t mVolumeInfoList; +}; + +//----------------------------------------------------------------------------- +// LLPolyMorphTarget +// A set of vertex data associated with morph target. +// These morph targets must be topologically consistent with a given Polymesh +// (share face sets) +//----------------------------------------------------------------------------- +class LLPolyMorphTarget : public LLViewerVisualParam +{ +public: + LLPolyMorphTarget(LLPolyMesh *poly_mesh); + ~LLPolyMorphTarget(); + + // Special: These functions are overridden by child classes + LLPolyMorphTargetInfo* getInfo() const { return (LLPolyMorphTargetInfo*)mInfo; } + // This sets mInfo and calls initialization functions + BOOL setInfo(LLPolyMorphTargetInfo *info); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ void apply( ESex sex ); + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion(); + /*virtual*/ const LLVector4a& getAvgDistortion(); + /*virtual*/ F32 getMaxDistortion(); + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); + + void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); + void addPendingMorphMask() { mNumMorphMasksPending++; } + +protected: + LLPolyMorphData* mMorphData; + LLPolyMesh* mMesh; + LLPolyVertexMask * mVertMask; + ESex mLastSex; + // number of morph masks that haven't been generated, must be 0 before this morph is applied + BOOL mNumMorphMasksPending; + + typedef std::vector volume_list_t; + volume_list_t mVolumeMorphs; + +}; + +#endif // LL_LLPOLYMORPH_H diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp new file mode 100644 index 0000000000..4ba16691c2 --- /dev/null +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -0,0 +1,293 @@ +/** + * @file llpolyskeletaldistortion.cpp + * @brief Implementation of LLPolySkeletalDistortion classes + * + * $LicenseInfo:firstyear=2001&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$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "llpreprocessor.h" +#include "llerrorlegacy.h" +//#include "llcommon.h" +//#include "llmemory.h" +#include "llavatarappearance.h" +#include "llavatarjoint.h" +#include "llpolymorph.h" +//#include "llviewercontrol.h" +//#include "llxmltree.h" +//#include "llvoavatar.h" +#include "llwearable.h" +//#include "lldir.h" +//#include "llvolume.h" +//#include "llendianswizzle.h" + +#include "llpolyskeletaldistortion.h" + +//----------------------------------------------------------------------------- +// LLPolySkeletalDistortionInfo() +//----------------------------------------------------------------------------- +LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo() +{ +} + +BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node) +{ + llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) ); + + if (!LLViewerVisualParamInfo::parseXml(node)) + return FALSE; + + LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton"); + + if (NULL == skeletalParam) + { + llwarns << "Failed to getChildByName(\"param_skeleton\")" + << llendl; + return FALSE; + } + + for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() ) + { + if (bone->hasName("bone")) + { + std::string name; + LLVector3 scale; + LLVector3 pos; + BOOL haspos = FALSE; + + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!bone->getFastAttributeString(name_string, name)) + { + llwarns << "No bone name specified for skeletal param." << llendl; + continue; + } + + static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); + if (!bone->getFastAttributeVector3(scale_string, scale)) + { + llwarns << "No scale specified for bone " << name << "." << llendl; + continue; + } + + // optional offset deformation (translation) + static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset"); + if (bone->getFastAttributeVector3(offset_string, pos)) + { + haspos = TRUE; + } + mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos)); + } + else + { + llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl; + continue; + } + } + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLPolySkeletalDistortion() +//----------------------------------------------------------------------------- +LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp) +{ + mAvatar = avatarp; + mDefaultVec.splat(0.001f); +} + +//----------------------------------------------------------------------------- +// ~LLPolySkeletalDistortion() +//----------------------------------------------------------------------------- +LLPolySkeletalDistortion::~LLPolySkeletalDistortion() +{ +} + +BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) +{ + llassert(mInfo == NULL); + if (info->mID < 0) + return FALSE; + mInfo = info; + mID = info->mID; + setWeight(getDefaultWeight(), FALSE ); + + LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; + for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) + { + LLPolySkeletalBoneInfo *bone_info = &(*iter); + LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); + if (!joint) + { + llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl; + continue; + } + + if (mJointScales.find(joint) != mJointScales.end()) + { + llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl; + } + + // store it + mJointScales[joint] = bone_info->mScaleDeformation; + + // apply to children that need to inherit it + for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + iter != joint->mChildren.end(); ++iter) + { + LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); + if (child_joint->inheritScale()) + { + LLVector3 childDeformation = LLVector3(child_joint->getScale()); + childDeformation.scaleVec(bone_info->mScaleDeformation); + mJointScales[child_joint] = childDeformation; + } + } + + if (bone_info->mHasPositionDeformation) + { + if (mJointOffsets.find(joint) != mJointOffsets.end()) + { + llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl; + } + mJointOffsets[joint] = bone_info->mPositionDeformation; + } + } + return TRUE; +} + +/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const +{ + LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar); + *new_param = *this; + return new_param; +} + +//----------------------------------------------------------------------------- +// apply() +//----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion"); + +void LLPolySkeletalDistortion::apply( ESex avatar_sex ) +{ + LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY); + + F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); + + LLJoint* joint; + joint_vec_map_t::iterator iter; + + for (iter = mJointScales.begin(); + iter != mJointScales.end(); + iter++) + { + joint = iter->first; + LLVector3 newScale = joint->getScale(); + LLVector3 scaleDelta = iter->second; + newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); + joint->setScale(newScale); + } + + for (iter = mJointOffsets.begin(); + iter != mJointOffsets.end(); + iter++) + { + joint = iter->first; + LLVector3 newPosition = joint->getPosition(); + LLVector3 positionDelta = iter->second; + newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); + joint->setPosition(newPosition); + } + + if (mLastWeight != mCurWeight && !mIsAnimating) + { + mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); + } + mLastWeight = mCurWeight; +} + + +LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = src_data->mCoords[v]; + cloned_morph_data->mNormals[v] = src_data->mNormals[v]; + cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]; + } + return cloned_morph_data; +} + +LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, + const LLVector3 &direction, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + LLVector4a dir; + dir.load3(direction.mV); + + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = dir; + cloned_morph_data->mNormals[v].clear(); + cloned_morph_data->mBinormals[v].clear(); + } + return cloned_morph_data; +} + +LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, + F32 scale, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + + LLVector4a sc; + sc.splat(scale); + + LLVector4a nsc; + nsc.set(scale, -scale, scale, scale); + + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + if (cloned_morph_data->mCoords[v][1] < 0) + { + cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc); + cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc); + cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc); + } + else + { + cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc); + cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc); + cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc); + } + } + return cloned_morph_data; +} + +// End diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h new file mode 100644 index 0000000000..040cf841ea --- /dev/null +++ b/indra/llappearance/llpolyskeletaldistortion.h @@ -0,0 +1,119 @@ +/** + * @file llpolyskeletaldistortion.h + * @brief Implementation of LLPolyMesh class + * + * $LicenseInfo:firstyear=2001&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_LLPOLYSKELETALDISTORTION_H +#define LL_LLPOLYSKELETALDISTORTION_H + +#include "llcommon.h" + +#include +#include +#include "llstl.h" + +#include "v3math.h" +#include "v2math.h" +#include "llquaternion.h" +//#include "llpolymorph.h" +#include "lljoint.h" +#include "llviewervisualparam.h" +//#include "lldarray.h" + +//class LLSkinJoint; +class LLAvatarAppearance; + +//#define USE_STRIPS // Use tri-strips for rendering. + +//----------------------------------------------------------------------------- +// LLPolySkeletalDeformationInfo +// Shared information for LLPolySkeletalDeformations +//----------------------------------------------------------------------------- +struct LLPolySkeletalBoneInfo +{ + LLPolySkeletalBoneInfo(std::string &name, LLVector3 &scale, LLVector3 &pos, BOOL haspos) + : mBoneName(name), + mScaleDeformation(scale), + mPositionDeformation(pos), + mHasPositionDeformation(haspos) {} + std::string mBoneName; + LLVector3 mScaleDeformation; + LLVector3 mPositionDeformation; + BOOL mHasPositionDeformation; +}; + +class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo +{ + friend class LLPolySkeletalDistortion; +public: + LLPolySkeletalDistortionInfo(); + /*virtual*/ ~LLPolySkeletalDistortionInfo() {}; + + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + +protected: + typedef std::vector bone_info_list_t; + bone_info_list_t mBoneInfoList; +}; + +//----------------------------------------------------------------------------- +// LLPolySkeletalDeformation +// A set of joint scale data for deforming the avatar mesh +//----------------------------------------------------------------------------- +class LLPolySkeletalDistortion : public LLViewerVisualParam +{ +public: + LLPolySkeletalDistortion(LLAvatarAppearance *avatarp); + ~LLPolySkeletalDistortion(); + + // Special: These functions are overridden by child classes + LLPolySkeletalDistortionInfo* getInfo() const { return (LLPolySkeletalDistortionInfo*)mInfo; } + // This sets mInfo and calls initialization functions + BOOL setInfo(LLPolySkeletalDistortionInfo *info); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ void apply( ESex sex ); + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion() { return 0.1f; } + /*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; } + /*virtual*/ F32 getMaxDistortion() { return 0.1f; } + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);} + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;}; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;}; + +protected: + typedef std::map joint_vec_map_t; + joint_vec_map_t mJointScales; + joint_vec_map_t mJointOffsets; + LLVector4a mDefaultVec; + // Backlink only; don't make this an LLPointer. + LLAvatarAppearance *mAvatar; +}; + +#endif // LL_LLPOLYSKELETALDISTORTION_H + -- cgit v1.2.3 From cf7eb79fa7eadd6d76890d2a3f9da905de8f4691 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Sat, 8 Sep 2012 04:39:11 +0000 Subject: Removed most llappearance -> llui dependencies (LLTrans remains). Moved LLInventoryIcon::EIconName into LLInventoryType. Moved LLInventoryIcon back to newview. Moved LLUI gl_* functions into llrender. --- indra/llappearance/CMakeLists.txt | 2 - indra/llappearance/llinventoryicon.cpp | 183 ----------------------------- indra/llappearance/llinventoryicon.h | 102 ---------------- indra/llappearance/lltexlayer.cpp | 2 +- indra/llappearance/lltexlayer.h | 2 +- indra/llappearance/lltexlayerparams.cpp | 2 +- indra/llappearance/llviewervisualparam.cpp | 1 - indra/llappearance/llwearabletype.cpp | 46 ++++---- indra/llappearance/llwearabletype.h | 4 +- 9 files changed, 28 insertions(+), 316 deletions(-) delete mode 100644 indra/llappearance/llinventoryicon.cpp delete mode 100644 indra/llappearance/llinventoryicon.h (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index 41da898457..717efb2f8b 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -43,7 +43,6 @@ include_directories( set(llappearance_SOURCE_FILES llavatarappearance.cpp lldriverparam.cpp - llinventoryicon.cpp lllocaltextureobject.cpp lltexglobalcolor.cpp lltexlayer.cpp @@ -61,7 +60,6 @@ set(llappearance_HEADER_FILES llavatarappearance.h lldriverparam.h - llinventoryicon.h lljointpickname.h lllocaltextureobject.h lltexglobalcolor.h diff --git a/indra/llappearance/llinventoryicon.cpp b/indra/llappearance/llinventoryicon.cpp deleted file mode 100644 index 371f60353b..0000000000 --- a/indra/llappearance/llinventoryicon.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/** - * @file llinventoryicon.cpp - * @brief Implementation of the inventory icon. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llinventoryicon.h" - -#include "lldictionary.h" -#include "llinventorydefines.h" -#include "llui.h" -#include "llwearabletype.h" - -struct IconEntry : public LLDictionaryEntry -{ - IconEntry(const std::string &item_name) - : - LLDictionaryEntry(item_name) - {} -}; - -class LLIconDictionary : public LLSingleton, - public LLDictionary -{ -public: - LLIconDictionary(); -}; - -LLIconDictionary::LLIconDictionary() -{ - addEntry(LLInventoryIcon::ICONNAME_TEXTURE, new IconEntry("Inv_Texture")); - addEntry(LLInventoryIcon::ICONNAME_SOUND, new IconEntry("Inv_Sound")); - addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_ONLINE, new IconEntry("Inv_CallingCard")); - addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_OFFLINE, new IconEntry("Inv_CallingCard")); - addEntry(LLInventoryIcon::ICONNAME_LANDMARK, new IconEntry("Inv_Landmark")); - addEntry(LLInventoryIcon::ICONNAME_LANDMARK_VISITED, new IconEntry("Inv_Landmark")); - addEntry(LLInventoryIcon::ICONNAME_SCRIPT, new IconEntry("Inv_Script")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING, new IconEntry("Inv_Clothing")); - addEntry(LLInventoryIcon::ICONNAME_OBJECT, new IconEntry("Inv_Object")); - addEntry(LLInventoryIcon::ICONNAME_OBJECT_MULTI, new IconEntry("Inv_Object_Multi")); - addEntry(LLInventoryIcon::ICONNAME_NOTECARD, new IconEntry("Inv_Notecard")); - addEntry(LLInventoryIcon::ICONNAME_BODYPART, new IconEntry("Inv_Skin")); - addEntry(LLInventoryIcon::ICONNAME_SNAPSHOT, new IconEntry("Inv_Snapshot")); - - addEntry(LLInventoryIcon::ICONNAME_BODYPART_SHAPE, new IconEntry("Inv_BodyShape")); - addEntry(LLInventoryIcon::ICONNAME_BODYPART_SKIN, new IconEntry("Inv_Skin")); - addEntry(LLInventoryIcon::ICONNAME_BODYPART_HAIR, new IconEntry("Inv_Hair")); - addEntry(LLInventoryIcon::ICONNAME_BODYPART_EYES, new IconEntry("Inv_Eye")); - - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SHIRT, new IconEntry("Inv_Shirt")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_PANTS, new IconEntry("Inv_Pants")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SHOES, new IconEntry("Inv_Shoe")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SOCKS, new IconEntry("Inv_Socks")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_JACKET, new IconEntry("Inv_Jacket")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_GLOVES, new IconEntry("Inv_Gloves")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT, new IconEntry("Inv_Undershirt")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS, new IconEntry("Inv_Underpants")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_SKIRT, new IconEntry("Inv_Skirt")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_ALPHA, new IconEntry("Inv_Alpha")); - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_TATTOO, new IconEntry("Inv_Tattoo")); - addEntry(LLInventoryIcon::ICONNAME_ANIMATION, new IconEntry("Inv_Animation")); - addEntry(LLInventoryIcon::ICONNAME_GESTURE, new IconEntry("Inv_Gesture")); - - addEntry(LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, new IconEntry("Inv_Physics")); - - addEntry(LLInventoryIcon::ICONNAME_LINKITEM, new IconEntry("Inv_LinkItem")); - addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, new IconEntry("Inv_LinkFolder")); - addEntry(LLInventoryIcon::ICONNAME_MESH, new IconEntry("Inv_Mesh")); - - addEntry(LLInventoryIcon::ICONNAME_INVALID, new IconEntry("Inv_Invalid")); - - addEntry(LLInventoryIcon::ICONNAME_NONE, new IconEntry("NONE")); -} - -LLUIImagePtr LLInventoryIcon::getIcon(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - U32 misc_flag, - BOOL item_is_multi) -{ - const std::string& icon_name = getIconName(asset_type, inventory_type, misc_flag, item_is_multi); - return LLUI::getUIImage(icon_name); -} - -LLUIImagePtr LLInventoryIcon::getIcon(EIconName idx) -{ - return LLUI::getUIImage(getIconName(idx)); -} - -const std::string& LLInventoryIcon::getIconName(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - U32 misc_flag, - BOOL item_is_multi) -{ - EIconName idx = ICONNAME_OBJECT; - if (item_is_multi) - { - idx = ICONNAME_OBJECT_MULTI; - return getIconName(idx); - } - - switch(asset_type) - { - case LLAssetType::AT_TEXTURE: - idx = (inventory_type == LLInventoryType::IT_SNAPSHOT) ? ICONNAME_SNAPSHOT : ICONNAME_TEXTURE; - break; - case LLAssetType::AT_SOUND: - idx = ICONNAME_SOUND; - break; - case LLAssetType::AT_CALLINGCARD: - idx = (misc_flag != 0) ? ICONNAME_CALLINGCARD_ONLINE : ICONNAME_CALLINGCARD_OFFLINE; - break; - case LLAssetType::AT_LANDMARK: - idx = (misc_flag != 0) ? ICONNAME_LANDMARK_VISITED : ICONNAME_LANDMARK; - break; - case LLAssetType::AT_SCRIPT: - case LLAssetType::AT_LSL_TEXT: - case LLAssetType::AT_LSL_BYTECODE: - idx = ICONNAME_SCRIPT; - break; - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - idx = assignWearableIcon(misc_flag); - break; - case LLAssetType::AT_NOTECARD: - idx = ICONNAME_NOTECARD; - break; - case LLAssetType::AT_ANIMATION: - idx = ICONNAME_ANIMATION; - break; - case LLAssetType::AT_GESTURE: - idx = ICONNAME_GESTURE; - break; - case LLAssetType::AT_LINK: - idx = ICONNAME_LINKITEM; - break; - case LLAssetType::AT_LINK_FOLDER: - idx = ICONNAME_LINKFOLDER; - break; - case LLAssetType::AT_OBJECT: - idx = ICONNAME_OBJECT; - break; - case LLAssetType::AT_MESH: - idx = ICONNAME_MESH; - default: - break; - } - - return getIconName(idx); -} - - -const std::string& LLInventoryIcon::getIconName(EIconName idx) -{ - const IconEntry *entry = LLIconDictionary::instance().lookup(idx); - return entry->mName; -} - -LLInventoryIcon::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag) -{ - const LLWearableType::EType wearable_type = LLWearableType::EType(LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK & misc_flag); - return LLWearableType::getIconName(wearable_type); -} diff --git a/indra/llappearance/llinventoryicon.h b/indra/llappearance/llinventoryicon.h deleted file mode 100644 index c7e2998a20..0000000000 --- a/indra/llappearance/llinventoryicon.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @file llinventoryfunctions.h - * @brief Miscellaneous inventory-related functions and classes - * class definition - * - * $LicenseInfo:firstyear=2001&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_LLINVENTORYICON_H -#define LL_LLINVENTORYICON_H - -#include "llassettype.h" -#include "llinventorytype.h" -#include "lluiimage.h" - -class LLInventoryIcon -{ -public: - enum EIconName - { - ICONNAME_TEXTURE, - ICONNAME_SOUND, - ICONNAME_CALLINGCARD_ONLINE, - ICONNAME_CALLINGCARD_OFFLINE, - ICONNAME_LANDMARK, - ICONNAME_LANDMARK_VISITED, - ICONNAME_SCRIPT, - ICONNAME_CLOTHING, - ICONNAME_OBJECT, - ICONNAME_OBJECT_MULTI, - ICONNAME_NOTECARD, - ICONNAME_BODYPART, - ICONNAME_SNAPSHOT, - - ICONNAME_BODYPART_SHAPE, - ICONNAME_BODYPART_SKIN, - ICONNAME_BODYPART_HAIR, - ICONNAME_BODYPART_EYES, - ICONNAME_CLOTHING_SHIRT, - ICONNAME_CLOTHING_PANTS, - ICONNAME_CLOTHING_SHOES, - ICONNAME_CLOTHING_SOCKS, - ICONNAME_CLOTHING_JACKET, - ICONNAME_CLOTHING_GLOVES, - ICONNAME_CLOTHING_UNDERSHIRT, - ICONNAME_CLOTHING_UNDERPANTS, - ICONNAME_CLOTHING_SKIRT, - ICONNAME_CLOTHING_ALPHA, - ICONNAME_CLOTHING_TATTOO, - - ICONNAME_ANIMATION, - ICONNAME_GESTURE, - - ICONNAME_CLOTHING_PHYSICS, - - ICONNAME_LINKITEM, - ICONNAME_LINKFOLDER, - ICONNAME_MESH, - - ICONNAME_INVALID, - ICONNAME_COUNT, - ICONNAME_NONE = -1 - }; - - static const std::string& getIconName(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type = LLInventoryType::IT_NONE, - U32 misc_flag = 0, // different meanings depending on item type - BOOL item_is_multi = FALSE); - static const std::string& getIconName(EIconName idx); - - static LLUIImagePtr getIcon(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type = LLInventoryType::IT_NONE, - U32 misc_flag = 0, // different meanings depending on item type - BOOL item_is_multi = FALSE); - static LLUIImagePtr getIcon(EIconName idx); - -protected: - static EIconName assignWearableIcon(U32 misc_flag); -}; -#endif // LL_LLINVENTORYICON_H - - - diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 9b70f737a0..1325267dc2 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -38,7 +38,7 @@ #include "llvfs.h" #include "lltexlayerparams.h" #include "lltexturemanagerbridge.h" -#include "llui.h" +#include "llrender2dutils.h" #include "llwearable.h" #include "llwearabledata.h" #include "llvertexbuffer.h" diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index e6c2ece64a..0d7fad349c 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -28,8 +28,8 @@ #define LL_LLTEXLAYER_H #include +#include "llglslshader.h" #include "llgltexture.h" -//#include "llframetimer.h" #include "llavatarappearancedefines.h" #include "lltexlayerparams.h" diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 06001c6b15..82c92b5a5e 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -33,8 +33,8 @@ #include "llquantize.h" #include "lltexlayer.h" #include "lltexturemanagerbridge.h" +#include "llrender2dutils.h" #include "llwearable.h" -#include "llui.h" //----------------------------------------------------------------------------- // LLTexLayerParam diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index a6792d0974..cc81bcf118 100644 --- a/indra/llappearance/llviewervisualparam.cpp +++ b/indra/llappearance/llviewervisualparam.cpp @@ -31,7 +31,6 @@ #include "llviewervisualparam.h" #include "llxmltree.h" -#include "llui.h" #include "llwearable.h" //----------------------------------------------------------------------------- diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index c72a0965fe..3a8e1b8be3 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -26,15 +26,15 @@ #include "linden_common.h" #include "llwearabletype.h" -#include "llinventoryicon.h" -#include "lltrans.h" +#include "llinventorytype.h" +#include "llui/lltrans.h" struct WearableEntry : public LLDictionaryEntry { WearableEntry(const std::string &name, const std::string& default_new_name, LLAssetType::EType assetType, - LLInventoryIcon::EIconName iconName, + LLInventoryType::EIconName iconName, BOOL disable_camera_switch = FALSE, BOOL allow_multiwear = TRUE) : LLDictionaryEntry(name), @@ -50,7 +50,7 @@ struct WearableEntry : public LLDictionaryEntry const LLAssetType::EType mAssetType; const std::string mLabel; const std::string mDefaultNewName; //keep mLabel for backward compatibility - LLInventoryIcon::EIconName mIconName; + LLInventoryType::EIconName mIconName; BOOL mDisableCameraSwitch; BOOL mAllowMultiwear; }; @@ -64,26 +64,26 @@ public: LLWearableDictionary::LLWearableDictionary() { - addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); - addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); - addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); - addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_EYES, FALSE, FALSE)); - addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE)); - addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PANTS, FALSE, TRUE)); - addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHOES, FALSE, TRUE)); - addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE)); - addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_JACKET, FALSE, TRUE)); - addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE)); - addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE)); - addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE)); - addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE)); - addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE)); - addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); + addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); + addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); - addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); - addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE)); - addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE)); + addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE)); + addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE)); } // static @@ -131,7 +131,7 @@ LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type) } // static -LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType type) +LLInventoryType::EIconName LLWearableType::getIconName(LLWearableType::EType type) { const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); const WearableEntry *entry = dict->lookup(type); diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index d633b4807e..78008c27ea 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -29,7 +29,7 @@ #include "llassettype.h" #include "lldictionary.h" -#include "llinventoryicon.h" +#include "llinventorytype.h" #include "llsingleton.h" class LLWearableType @@ -64,7 +64,7 @@ public: static const std::string& getTypeLabel(EType type); static LLAssetType::EType getAssetType(EType type); static EType typeNameToType(const std::string& type_name); - static LLInventoryIcon::EIconName getIconName(EType type); + static LLInventoryType::EIconName getIconName(EType type); static BOOL getDisableCameraSwitch(EType type); static BOOL getAllowMultiwear(EType type); -- cgit v1.2.3 From b77e2eff481512667c35bc99946fb62eca1be169 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Sat, 8 Sep 2012 06:20:19 +0000 Subject: Fixed #include typo --- indra/llappearance/llwearabletype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index 3a8e1b8be3..aa0afe348a 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -27,7 +27,7 @@ #include "linden_common.h" #include "llwearabletype.h" #include "llinventorytype.h" -#include "llui/lltrans.h" +#include "lltrans.h" struct WearableEntry : public LLDictionaryEntry { -- cgit v1.2.3 From e1580128ab2a42ecd4019ef35069f9e939dc4ff2 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Sun, 9 Sep 2012 12:12:19 +0000 Subject: Fixed crashes on login. Moved most of the remaining character/skeleton generation code into llappearance. Moved non-rendering related LLViewerJoint functionality into LLAvatarJoint. --- indra/llappearance/llavatarappearance.cpp | 245 ++++++++++++++++++++--- indra/llappearance/llavatarappearance.h | 27 ++- indra/llappearance/llavatarappearancedefines.cpp | 4 +- indra/llappearance/llavatarappearancedefines.h | 10 +- indra/llappearance/llavatarjoint.cpp | 120 ++++++++--- indra/llappearance/llavatarjoint.h | 24 ++- indra/llappearance/llavatarjointmesh.cpp | 10 + indra/llappearance/llavatarjointmesh.h | 12 +- indra/llappearance/lljointpickname.h | 3 + 9 files changed, 378 insertions(+), 77 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 406e6153e0..e2dfa2fb74 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -24,8 +24,13 @@ * $/LicenseInfo$ */ -#include "linden_common.h" +#if LL_MSVC +// disable warning about boost::lexical_cast returning uninitialized data +// when it fails to parse the string +#pragma warning (disable:4701) +#endif +#include "linden_common.h" #include "llavatarappearance.h" #include "llavatarappearancedefines.h" @@ -36,9 +41,20 @@ #include "llpolymorph.h" #include "llpolymesh.h" #include "llpolyskeletaldistortion.h" +#include "llstl.h" #include "lltexglobalcolor.h" #include "llwearabledata.h" + +#if LL_MSVC +// disable boost::lexical_cast warning +#pragma warning (disable:4702) +#endif + +#include + +using namespace LLAvatarAppearanceDefines; + //----------------------------------------------------------------------------- // Constants //----------------------------------------------------------------------------- @@ -153,7 +169,9 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mWearableData(wearable_data) { - llassert(mWearableData); + LLMemType mt(LLMemType::MTYPE_AVATAR); + + llassert_always(mWearableData); mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) { @@ -167,13 +185,85 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mIsBuilt = FALSE; - mNumJoints = 0; - mSkeleton = NULL; - mNumCollisionVolumes = 0; mCollisionVolumes = NULL; +} + +// virtual +void LLAvatarAppearance::initInstance() +{ + //------------------------------------------------------------------------- + // initialize joint, mesh and shape members + //------------------------------------------------------------------------- + mRoot = createAvatarJoint(); + mRoot->setName( "mRoot" ); + + for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin(); + iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end(); + ++iter) + { + const EMeshIndex mesh_index = iter->first; + const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = iter->second; + LLAvatarJoint* joint = createAvatarJoint(); + joint->setName(mesh_dict->mName); + joint->setMeshID(mesh_index); + mMeshLOD.push_back(joint); + + /* mHairLOD.setName("mHairLOD"); + mHairMesh0.setName("mHairMesh0"); + mHairMesh0.setMeshID(MESH_ID_HAIR); + mHairMesh1.setName("mHairMesh1"); */ + for (U32 lod = 0; lod < mesh_dict->mLOD; lod++) + { + LLAvatarJointMesh* mesh = createAvatarJointMesh(); + std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast(lod); + // We pre-pended an m - need to capitalize first character for camelCase + mesh_name[1] = toupper(mesh_name[1]); + mesh->setName(mesh_name); + mesh->setMeshID(mesh_index); + mesh->setPickName(mesh_dict->mPickName); + mesh->setIsTransparent(FALSE); + switch((int)mesh_index) + { + case MESH_ID_HAIR: + mesh->setIsTransparent(TRUE); + break; + case MESH_ID_SKIRT: + mesh->setIsTransparent(TRUE); + break; + case MESH_ID_EYEBALL_LEFT: + case MESH_ID_EYEBALL_RIGHT: + mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f ); + break; + } + + joint->mMeshParts.push_back(mesh); + } + } - mRoot = new LLAvatarJoint(); + //------------------------------------------------------------------------- + // associate baked textures with meshes + //------------------------------------------------------------------------- + for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin(); + iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end(); + ++iter) + { + const EMeshIndex mesh_index = iter->first; + const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = iter->second; + const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID; + // Skip it if there's no associated baked texture. + if (baked_texture_index == BAKED_NUM_INDICES) continue; + + for (avatar_joint_mesh_list_t::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin(); + iter != mMeshLOD[mesh_index]->mMeshParts.end(); + ++iter) + { + LLAvatarJointMesh* mesh = (*iter); + mBakedTextureDatas[(int)baked_texture_index].mJointMeshes.push_back(mesh); + } + } + + buildCharacter(); } @@ -187,7 +277,7 @@ LLAvatarAppearance::~LLAvatarAppearance() for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { deleteAndClear(mBakedTextureDatas[i].mTexLayerSet); - mBakedTextureDatas[i].mMeshes.clear(); + mBakedTextureDatas[i].mJointMeshes.clear(); for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin(); iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++) @@ -200,23 +290,21 @@ LLAvatarAppearance::~LLAvatarAppearance() mRoot->removeAllChildren(); mJointMap.clear(); - deleteAndClearArray(mSkeleton); + clearSkeleton(); deleteAndClearArray(mCollisionVolumes); - mNumJoints = 0; - deleteAndClear(mTexSkinColor); deleteAndClear(mTexHairColor); deleteAndClear(mTexEyeColor); - std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer()); - mMeshes.clear(); + std::for_each(mPolyMeshes.begin(), mPolyMeshes.end(), DeletePairedPointer()); + mPolyMeshes.clear(); - for (std::vector::iterator jointIter = mMeshLOD.begin(); + for (avatar_joint_list_t::iterator jointIter = mMeshLOD.begin(); jointIter != mMeshLOD.end(); ++jointIter) { - LLAvatarJoint* joint = (LLAvatarJoint *) *jointIter; + LLAvatarJoint* joint = *jointIter; std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer()); joint->mMeshParts.clear(); } @@ -504,6 +592,22 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent return TRUE; } +//----------------------------------------------------------------------------- +// allocateCharacterJoints() +//----------------------------------------------------------------------------- +BOOL LLAvatarAppearance::allocateCharacterJoints( U32 num ) +{ + clearSkeleton(); + + for(S32 joint_num = 0; joint_num < (S32)num; joint_num++) + { + mSkeleton.push_back(createAvatarJoint(joint_num)); + } + + return TRUE; +} + + //----------------------------------------------------------------------------- // buildSkeleton() //----------------------------------------------------------------------------- @@ -548,6 +652,15 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) return TRUE; } +//----------------------------------------------------------------------------- +// clearSkeleton() +//----------------------------------------------------------------------------- +void LLAvatarAppearance::clearSkeleton() +{ + std::for_each(mSkeleton.begin(), mSkeleton.end(), DeletePointer()); + mSkeleton.clear(); +} + //----------------------------------------------------------------------------- // LLAvatarAppearance::buildCharacter() // Deferred initialization and rebuild of the avatar. @@ -569,6 +682,21 @@ void LLAvatarAppearance::buildCharacter() mJointMap.clear(); mIsBuilt = FALSE; + //------------------------------------------------------------------------- + // clear mesh data + //------------------------------------------------------------------------- + for (avatar_joint_list_t::iterator jointIter = mMeshLOD.begin(); + jointIter != mMeshLOD.end(); ++jointIter) + { + LLAvatarJoint* joint = *jointIter; + for (avatar_joint_mesh_list_t::iterator meshIter = joint->mMeshParts.begin(); + meshIter != joint->mMeshParts.end(); ++meshIter) + { + LLAvatarJointMesh * mesh = *meshIter; + mesh->setMesh(NULL); + } + } + //------------------------------------------------------------------------- // (re)load our skeleton and meshes //------------------------------------------------------------------------- @@ -755,7 +883,7 @@ BOOL LLAvatarAppearance::loadAvatar() } - loadLayersets(); + loadLayersets(); // avatar_lad.xml : for (LLAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); @@ -791,7 +919,17 @@ BOOL LLAvatarAppearance::loadAvatar() //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::loadSkeletonNode () { - mRoot->addChild( &mSkeleton[0] ); + mRoot->addChild( mSkeleton[0] ); + + // make meshes children before calling parent version of the function + for (avatar_joint_list_t::iterator iter = mMeshLOD.begin(); + iter != mMeshLOD.end(); + ++iter) + { + LLAvatarJoint *joint = *iter; + joint->mUpdateXform = FALSE; + joint->setMeshesToChildren(); + } mRoot->addChild(mMeshLOD[MESH_ID_HEAD]); mRoot->addChild(mMeshLOD[MESH_ID_EYELASH]); @@ -864,8 +1002,8 @@ BOOL LLAvatarAppearance::loadMeshNodes() switch(lod) case 0: mesh = &mHairMesh0; */ - for (LLAvatarAppearanceDictionary::Meshes::const_iterator mesh_iter = LLAvatarAppearanceDictionary::getInstance()->getMeshes().begin(); - mesh_iter != LLAvatarAppearanceDictionary::getInstance()->getMeshes().end(); + for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator mesh_iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin(); + mesh_iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end(); ++mesh_iter) { const EMeshIndex mesh_index = mesh_iter->first; @@ -906,8 +1044,8 @@ BOOL LLAvatarAppearance::loadMeshNodes() if (!info->mReferenceMeshName.empty()) { - polymesh_map_t::const_iterator polymesh_iter = mMeshes.find(info->mReferenceMeshName); - if (polymesh_iter != mMeshes.end()) + polymesh_map_t::const_iterator polymesh_iter = mPolyMeshes.find(info->mReferenceMeshName); + if (polymesh_iter != mPolyMeshes.end()) { poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second); poly_mesh->setAvatar(this); @@ -931,7 +1069,7 @@ BOOL LLAvatarAppearance::loadMeshNodes() } // Multimap insert - mMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh)); + mPolyMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh)); mesh->setMesh( poly_mesh ); mesh->setLOD( info->mMinPixelArea ); @@ -974,15 +1112,72 @@ BOOL LLAvatarAppearance::loadLayersets() layerset_iter != sAvatarXmlInfo->mLayerInfoList.end(); ++layerset_iter) { - // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. LLTexLayerSetInfo *layerset_info = *layerset_iter; - layerset_info->createVisualParams(this); + if (isSelf()) + { + // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. + LLTexLayerSet* layer_set = createTexLayerSet(); + + if (!layer_set->setInfo(layerset_info)) + { + stop_glerror(); + delete layer_set; + llwarns << "avatar file: layer_set->setInfo() failed" << llendl; + return FALSE; + } + + // scan baked textures and associate the layerset with the appropriate one + EBakedTextureIndex baked_index = BAKED_NUM_INDICES; + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); + ++baked_iter) + { + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second; + if (layer_set->isBodyRegion(baked_dict->mName)) + { + baked_index = baked_iter->first; + // ensure both structures are aware of each other + mBakedTextureDatas[baked_index].mTexLayerSet = layer_set; + layer_set->setBakedTexIndex(baked_index); + break; + } + } + // if no baked texture was found, warn and cleanup + if (baked_index == BAKED_NUM_INDICES) + { + llwarns << " has invalid body_region attribute" << llendl; + delete layer_set; + return FALSE; + } + + // scan morph masks and let any affected layers know they have an associated morph + for (LLAvatarAppearance::morph_list_t::const_iterator morph_iter = mBakedTextureDatas[baked_index].mMaskedMorphs.begin(); + morph_iter != mBakedTextureDatas[baked_index].mMaskedMorphs.end(); + ++morph_iter) + { + LLMaskedMorph *morph = *morph_iter; + LLTexLayerInterface* layer = layer_set->findLayerByName(morph->mLayer); + if (layer) + { + layer->setHasMorph(TRUE); + } + else + { + llwarns << "Could not find layer named " << morph->mLayer << " to set morph flag" << llendl; + success = FALSE; + } + } + } + else // !isSelf() + { + // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. + LLTexLayerSetInfo *layerset_info = *layerset_iter; + layerset_info->createVisualParams(this); + } } return success; } - - // virtual BOOL LLAvatarAppearance::isValid() const { diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 38a54d904d..96dd81be77 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -28,9 +28,8 @@ #define LL_AVATAR_APPEARANCE_H #include "llcharacter.h" -//#include "llframetimer.h" #include "llavatarappearancedefines.h" -#include "llavatarjoint.h" +#include "llavatarjointmesh.h" #include "lldriverparam.h" #include "lltexlayer.h" #include "llviewervisualparam.h" @@ -67,9 +66,10 @@ public: virtual ~LLAvatarAppearance(); static void initClass(); // initializes static members + virtual void initInstance(); // Called after construction to initialize the instance. virtual BOOL loadSkeletonNode(); - virtual BOOL loadMeshNodes(); - virtual BOOL loadLayersets(); + BOOL loadMeshNodes(); + BOOL loadLayersets(); /** Initialization @@ -97,8 +97,13 @@ public: ** SKELETON **/ +protected: + virtual LLAvatarJoint* createAvatarJoint() = 0; + virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0; + virtual LLAvatarJointMesh* createAvatarJointMesh() = 0; public: F32 getPelvisToFoot() const { return mPelvisToFoot; } + /*virtual*/ LLJoint* getRootJoint() { return mRoot; } LLVector3 mHeadOffset; // current head position LLAvatarJoint *mRoot; @@ -114,11 +119,13 @@ protected: void computeBodySize(); BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); + BOOL allocateCharacterJoints(U32 num); BOOL buildSkeleton(const LLAvatarSkeletonInfo *info); protected: + void clearSkeleton(); BOOL mIsBuilt; // state of deferred character building - S32 mNumJoints; - LLJoint* mSkeleton; + typedef std::vector avatar_joint_list_t; + avatar_joint_list_t mSkeleton; //-------------------------------------------------------------------- // Pelvis height adjustment members. @@ -204,8 +211,8 @@ protected: protected: typedef std::multimap polymesh_map_t; - polymesh_map_t mMeshes; - std::vector mMeshLOD; + polymesh_map_t mPolyMeshes; + avatar_joint_list_t mMeshLOD; /** Meshes ** ** @@ -262,6 +269,8 @@ private: ** ** ** BAKED TEXTURES **/ +protected: + virtual LLTexLayerSet* createTexLayerSet() = 0; protected: struct LLMaskedMorph; typedef std::deque morph_list_t; @@ -274,7 +283,7 @@ protected: LLAvatarAppearanceDefines::ETextureIndex mTextureIndex; U32 mMaskTexName; // Stores pointers to the joint meshes that this baked texture deals with - std::vector< LLJoint* > mMeshes; // std::vector mJoints[i]->mMeshParts + avatar_joint_mesh_list_t mJointMeshes; morph_list_t mMaskedMorphs; }; typedef std::vector bakedtexturedata_vec_t; diff --git a/indra/llappearance/llavatarappearancedefines.cpp b/indra/llappearance/llavatarappearancedefines.cpp index 2c3cf781c1..0416309fc7 100644 --- a/indra/llappearance/llavatarappearancedefines.cpp +++ b/indra/llappearance/llavatarappearancedefines.cpp @@ -109,9 +109,9 @@ LLAvatarAppearanceDictionary::BakedTextures::BakedTextures() 2, LLWearableType::WT_HAIR, LLWearableType::WT_ALPHA)); } -LLAvatarAppearanceDictionary::Meshes::Meshes() +LLAvatarAppearanceDictionary::MeshEntries::MeshEntries() { - // Meshes + // MeshEntries addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, PN_4)); addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, PN_5)); addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, PN_0)); // no baked mesh associated currently diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h index c5285ddc02..e7c94104cc 100644 --- a/indra/llappearance/llavatarappearancedefines.h +++ b/indra/llappearance/llavatarappearancedefines.h @@ -174,12 +174,12 @@ public: const LLJointPickName mPickName; }; - struct Meshes : public LLDictionary + struct MeshEntries : public LLDictionary { - Meshes(); - } mMeshes; - const MeshEntry* getMesh(EMeshIndex index) const { return mMeshes.lookup(index); } - const Meshes& getMeshes() const { return mMeshes; } + MeshEntries(); + } mMeshEntries; + const MeshEntry* getMeshEntry(EMeshIndex index) const { return mMeshEntries.lookup(index); } + const MeshEntries& getMeshEntries() const { return mMeshEntries; } //-------------------------------------------------------------------- // Baked Textures diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp index 809a261633..eb450485c7 100644 --- a/indra/llappearance/llavatarjoint.cpp +++ b/indra/llappearance/llavatarjoint.cpp @@ -33,13 +33,9 @@ #include "llrender.h" #include "llmath.h" #include "llglheaders.h" -#include "llrendersphere.h" #include "llavatarappearance.h" -//#include "pipeline.h" -#define DEFAULT_LOD 0.0f - -const S32 MIN_PIXEL_AREA_3PASS_HAIR = 64*64; +const F32 DEFAULT_AVATAR_JOINT_LOD = 0.0f; //----------------------------------------------------------------------------- // Static Data @@ -48,21 +44,22 @@ BOOL LLAvatarJoint::sDisableLOD = FALSE; //----------------------------------------------------------------------------- // LLAvatarJoint() -// Class Constructor +// Class Constructors //----------------------------------------------------------------------------- -LLAvatarJoint::LLAvatarJoint() - : LLJoint() +LLAvatarJoint::LLAvatarJoint() : + LLJoint() { init(); } +LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) : + LLJoint(name, parent) +{ + init(); +} -//----------------------------------------------------------------------------- -// LLAvatarJoint() -// Class Constructor -//----------------------------------------------------------------------------- -LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent) - : LLJoint(name, parent) +LLAvatarJoint::LLAvatarJoint(S32 joint_num) : + LLJoint(joint_num) { init(); } @@ -72,7 +69,7 @@ void LLAvatarJoint::init() { mValid = FALSE; mComponents = SC_JOINT | SC_BONE | SC_AXES; - mMinPixelArea = DEFAULT_LOD; + mMinPixelArea = DEFAULT_AVATAR_JOINT_LOD; mPickName = PN_DEFAULT; mVisible = TRUE; mMeshID = 0; @@ -113,14 +110,6 @@ void LLAvatarJoint::setValid( BOOL valid, BOOL recursive ) } -//-------------------------------------------------------------------- -// isTransparent() -//-------------------------------------------------------------------- -BOOL LLAvatarJoint::isTransparent() -{ - return FALSE; -} - //-------------------------------------------------------------------- // setSkeletonComponents() //-------------------------------------------------------------------- @@ -132,7 +121,7 @@ void LLAvatarJoint::setSkeletonComponents( U32 comp, BOOL recursive ) for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = (LLAvatarJoint*)(*iter); + LLAvatarJoint* joint = dynamic_cast(*iter); joint->setSkeletonComponents(comp, recursive); } } @@ -153,14 +142,87 @@ void LLAvatarJoint::setVisible(BOOL visible, BOOL recursive) } } +void LLAvatarJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area) +{ + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLAvatarJoint* joint = dynamic_cast(*iter); + joint->updateFaceSizes(num_vertices, num_indices, pixel_area); + } +} + +void LLAvatarJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update) +{ + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLAvatarJoint* joint = dynamic_cast(*iter); + joint->updateFaceData(face, pixel_area, damp_wind, terse_update); + } +} + +void LLAvatarJoint::updateJointGeometry() +{ + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLAvatarJoint* joint = dynamic_cast(*iter); + joint->updateJointGeometry(); + } +} + + +BOOL LLAvatarJoint::updateLOD(F32 pixel_area, BOOL activate) +{ + BOOL lod_changed = FALSE; + BOOL found_lod = FALSE; + + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLAvatarJoint* joint = dynamic_cast(*iter); + F32 jointLOD = joint->getLOD(); + + if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD) + { + // we've already found a joint to enable, so enable the rest as alternatives + lod_changed |= joint->updateLOD(pixel_area, TRUE); + } + else + { + if (pixel_area >= jointLOD || sDisableLOD) + { + lod_changed |= joint->updateLOD(pixel_area, TRUE); + found_lod = TRUE; + } + else + { + lod_changed |= joint->updateLOD(pixel_area, FALSE); + } + } + } + return lod_changed; +} + +void LLAvatarJoint::dump() +{ + for (child_list_t::iterator iter = mChildren.begin(); + iter != mChildren.end(); ++iter) + { + LLAvatarJoint* joint = dynamic_cast(*iter); + joint->dump(); + } +} + void LLAvatarJoint::setMeshesToChildren() { removeAllChildren(); - for (std::vector::iterator iter = mMeshParts.begin(); + for (avatar_joint_mesh_list_t::iterator iter = mMeshParts.begin(); iter != mMeshParts.end(); iter++) { - addChild((LLAvatarJoint*) *iter); + addChild((*iter)); } } //----------------------------------------------------------------------------- @@ -172,9 +234,11 @@ LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume() mUpdateXform = FALSE; } -LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume(const std::string &name, LLJoint *parent) : LLAvatarJoint(name, parent) +/*virtual*/ +U32 LLAvatarJointCollisionVolume::render( F32 pixelArea, BOOL first_pass, BOOL is_dummy ) { - + llerrs << "Cannot call render() on LLAvatarJointCollisionVolume" << llendl; + return 0; } LLVector3 LLAvatarJointCollisionVolume::getVolumePos(LLVector3 &offset) diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h index cbfc1b73ea..1dfbd37456 100644 --- a/indra/llappearance/llavatarjoint.h +++ b/indra/llappearance/llavatarjoint.h @@ -36,6 +36,8 @@ class LLFace; class LLAvatarJointMesh; +extern const F32 DEFAULT_AVATAR_JOINT_LOD; + //----------------------------------------------------------------------------- // class LLViewerJoint //----------------------------------------------------------------------------- @@ -44,6 +46,8 @@ class LLAvatarJoint : { public: LLAvatarJoint(); + LLAvatarJoint(S32 joint_num); + // *TODO: Only used for LLVOAvatarSelf::mScreenp. *DOES NOT INITIALIZE mResetAfterRestoreOldXform* LLAvatarJoint(const std::string &name, LLJoint *parent = NULL); virtual ~LLAvatarJoint(); @@ -55,12 +59,11 @@ public: // Returns true if this object is transparent. // This is used to determine in which order to draw objects. - virtual BOOL isTransparent(); + virtual BOOL isTransparent() { return FALSE; } // Returns true if this object should inherit scale modifiers from its immediate parent virtual BOOL inheritScale() { return FALSE; } - enum Components { SC_BONE = 1, @@ -83,7 +86,7 @@ public: // of this node under the same parent will be. F32 getLOD() { return mMinPixelArea; } void setLOD( F32 pixelArea ) { mMinPixelArea = pixelArea; } - + void setPickName(LLJointPickName name) { mPickName = name; } LLJointPickName getPickName() { return mPickName; } @@ -92,9 +95,18 @@ public: // Takes meshes in mMeshParts and sets each one as a child joint void setMeshesToChildren(); + // LLViewerJoint interface + virtual U32 render( F32 pixelArea, BOOL first_pass = TRUE, BOOL is_dummy = FALSE ) = 0; + virtual void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area); + virtual void updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind = FALSE, bool terse_update = false); + virtual BOOL updateLOD(F32 pixel_area, BOOL activate); + virtual void updateJointGeometry(); + virtual void dump(); + + public: static BOOL sDisableLOD; - std::vector mMeshParts; //LLViewerJointMesh* + avatar_joint_mesh_list_t mMeshParts; //LLViewerJointMesh* void setMeshID( S32 id ) {mMeshID = id;} protected: @@ -112,10 +124,10 @@ class LLAvatarJointCollisionVolume : public LLAvatarJoint { public: LLAvatarJointCollisionVolume(); - LLAvatarJointCollisionVolume(const std::string &name, LLJoint *parent = NULL); virtual ~LLAvatarJointCollisionVolume() {}; - virtual BOOL inheritScale() { return TRUE; } + /*virtual*/ BOOL inheritScale() { return TRUE; } + /*virtual*/ U32 render( F32 pixelArea, BOOL first_pass = TRUE, BOOL is_dummy = FALSE ); void renderCollision(); diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp index 92c213126a..d39587defe 100755 --- a/indra/llappearance/llavatarjointmesh.cpp +++ b/indra/llappearance/llavatarjointmesh.cpp @@ -233,6 +233,12 @@ void LLAvatarJointMesh::setTexture( LLGLTexture *texture ) } } + +BOOL LLAvatarJointMesh::hasGLTexture() const +{ + return mTexture.notNull() && mTexture->hasGLTexture(); +} + //-------------------------------------------------------------------- // LLAvatarJointMesh::setLayerSet() // Sets the shape texture (takes precedence over normal texture) @@ -248,6 +254,10 @@ void LLAvatarJointMesh::setLayerSet( LLTexLayerSet* layer_set ) } } +BOOL LLAvatarJointMesh::hasComposite() const +{ + return (mLayerSet && mLayerSet->hasComposite()); +} //-------------------------------------------------------------------- diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h index dcd202bdaf..4b56a168ac 100755 --- a/indra/llappearance/llavatarjointmesh.h +++ b/indra/llappearance/llavatarjointmesh.h @@ -59,9 +59,8 @@ public: //----------------------------------------------------------------------------- // class LLViewerJointMesh //----------------------------------------------------------------------------- -class LLAvatarJointMesh : public LLAvatarJoint +class LLAvatarJointMesh : public virtual LLAvatarJoint { - friend class LLAvatarAppearance; protected: LLColor4 mColor; // color value // LLColor4 mSpecular; // specular color (always white for now) @@ -94,6 +93,9 @@ public: // Destructor virtual ~LLAvatarJointMesh(); + // overloaded from base class + /*virtual*/ BOOL isTransparent() { return mIsTransparent; } + // Gets the shape color void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha ); @@ -106,11 +108,15 @@ public: // Sets the shape texture void setTexture( LLGLTexture *texture ); + BOOL hasGLTexture() const; + void setTestTexture( U32 name ) { mTestImageName = name; } // Sets layer set responsible for a dynamic shape texture (takes precedence over normal texture) void setLayerSet( LLTexLayerSet* layer_set ); + BOOL hasComposite() const; + // Gets the poly mesh LLPolyMesh *getMesh(); @@ -129,6 +135,8 @@ public: // Gets ID for picking S32 getMeshID() { return mMeshID; } + void setIsTransparent(BOOL is_transparent) { mIsTransparent = is_transparent; } + private: // Allocate skin data BOOL allocateSkinData( U32 numSkinJoints ); diff --git a/indra/llappearance/lljointpickname.h b/indra/llappearance/lljointpickname.h index 17181520e3..1d41a761fc 100644 --- a/indra/llappearance/lljointpickname.h +++ b/indra/llappearance/lljointpickname.h @@ -28,6 +28,7 @@ #ifndef LL_LLJOINTPICKNAME_H #define LL_LLJOINTPICKNAME_H +class LLAvatarJointMesh; // Sets the OpenGL selection stack name that is pushed and popped // with this joint state. The default value indicates that no name @@ -43,4 +44,6 @@ enum LLJointPickName PN_5 = 5 }; +typedef std::vector avatar_joint_mesh_list_t; + #endif // LL_LLJOINTPICKNAME_H -- cgit v1.2.3 From d3cdc92039349ba44cc62c616a8a040236ea696d Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Mon, 10 Sep 2012 11:34:17 -0400 Subject: BUILDFIX WIN fixing windows build error converted a struct to a class, cleaning up a forward declaration that caused windows build issues. --- indra/llappearance/llavatarappearance.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 96dd81be77..6eab9b9d1f 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -272,7 +272,7 @@ private: protected: virtual LLTexLayerSet* createTexLayerSet() = 0; protected: - struct LLMaskedMorph; + class LLMaskedMorph; typedef std::deque morph_list_t; struct BakedTextureData { -- cgit v1.2.3 From f1d6052e36ed6d817faedf9b32cb9d889395cd88 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Tue, 11 Sep 2012 11:59:45 -0400 Subject: SH-3264 Moved over a few more items to llappearance moved over: isWearingWearableType wearable::writeToAvatar wearable::mTEMap (stores LocalTextureObject*) more from wearable::import/export wearable::createVisualParams, etc --- indra/llappearance/llavatarappearance.cpp | 45 ++-------- indra/llappearance/llavatarappearance.h | 4 + indra/llappearance/lltexlayer.cpp | 2 +- indra/llappearance/llwearable.cpp | 138 ++++++++++++++++++++++++------ indra/llappearance/llwearable.h | 18 ++-- 5 files changed, 137 insertions(+), 70 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index e2dfa2fb74..7d37f5f509 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -1332,43 +1332,16 @@ LLColor4 LLAvatarAppearance::getGlobalColor( const std::string& color_name ) con // virtual BOOL LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const { - if (mIsDummy) return TRUE; - - switch(type) - { - case LLWearableType::WT_SHAPE: - case LLWearableType::WT_SKIN: - case LLWearableType::WT_HAIR: - case LLWearableType::WT_EYES: - return TRUE; // everyone has all bodyparts - default: - break; // Do nothing - } + return mWearableData->getWearableCount(type) > 0; +} - /* switch(type) - case LLWearableType::WT_SHIRT: - indicator_te = TEX_UPPER_SHIRT; */ - for (LLAvatarAppearanceDictionary::Textures::const_iterator tex_iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); - tex_iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); - ++tex_iter) - { - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_iter->second; - if (texture_dict->mWearableType == type) - { - // If you're checking another avatar's clothing, you don't have component textures. - // Thus, you must check to see if the corresponding baked texture is defined. - // NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing - // this works for detecting a skirt (most important), but is ineffective at any piece of clothing that - // gets baked into a texture that always exists (upper or lower). - if (texture_dict->mIsUsedByBakedTexture) - { - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - return isTextureDefined(LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex); - } - return FALSE; - } - } - return FALSE; +LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_index) const +{ + /* switch(index) + case TEX_HEAD_BAKED: + case TEX_HEAD_BODYPAINT: + return mHeadLayerSet; */ + return mBakedTextureDatas[baked_index].mTexLayerSet; } //----------------------------------------------------------------------------- diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 6eab9b9d1f..b512fd4eda 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -269,8 +269,12 @@ private: ** ** ** BAKED TEXTURES **/ +public: + LLTexLayerSet* getAvatarLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const; + protected: virtual LLTexLayerSet* createTexLayerSet() = 0; + protected: class LLMaskedMorph; typedef std::deque morph_list_t; diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 1325267dc2..e90efac36b 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -1620,7 +1620,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const } if (layer) { - wearable->writeToAvatar(); + wearable->writeToAvatar(mAvatarAppearance); layer->setLTO(lto); success &= layer->render(x,y,width,height); } diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index ea14c6320f..9e73a6669a 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -123,27 +123,80 @@ BOOL LLWearable::exportFile(LLFILE* file) const } // texture entries - S32 num_textures = mTextureIDMap.size(); + S32 num_textures = mTEMap.size(); if( fprintf( file, "textures %d\n", num_textures ) < 0 ) { - return FALSE; + return FALSE; } - - for (texture_id_map_t::const_iterator iter = mTextureIDMap.begin(); iter != mTextureIDMap.end(); ++iter) + + for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter) { - S32 te = iter->first; - const LLUUID& image_id = iter->second; - if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 ) + S32 te = iter->first; + const LLUUID& image_id = iter->second->getID(); + if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 ) + { + return FALSE; + } + } + return TRUE; +} + +void LLWearable::createVisualParams(LLAvatarAppearance *avatarp) +{ + for (LLViewerVisualParam* param = (LLViewerVisualParam*) avatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) avatarp->getNextVisualParam()) + { + if (param->getWearableType() == mType) { - return FALSE; + addVisualParam(param->cloneParam(this)); + } + } + + // resync driver parameters to point to the newly cloned driven parameters + for (visual_param_index_map_t::iterator param_iter = mVisualParamIndexMap.begin(); + param_iter != mVisualParamIndexMap.end(); + ++param_iter) + { + LLVisualParam* param = param_iter->second; + LLVisualParam*(LLWearable::*wearable_function)(S32)const = &LLWearable::getVisualParam; + // need this line to disambiguate between versions of LLCharacter::getVisualParam() + LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam; + param->resetDrivenParams(); + if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false)) + { + if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true)) + { + llwarns << "could not link driven params for wearable " << getName() << " id: " << param->getID() << llendl; + continue; + } } } - return TRUE; } +void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp) +{ + LLTexLayerSet *layer_set = NULL; + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); + if (texture_dict->mIsUsedByBakedTexture) + { + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + + layer_set = avatarp->getAvatarLayerSet(baked_index); + } + + if (layer_set) + { + layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this); + } + else + { + llerrs << "could not find layerset for LTO in wearable!" << llendl; + } +} // virtual -LLWearable::EImportResult LLWearable::importFile( LLFILE* file ) +LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearance* avatarp ) { // *NOTE: changing the type or size of this buffer will require // changes in the fscanf() code below. You would be better off @@ -158,6 +211,11 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file ) return LLWearable::BAD_HEADER; } + if(!avatarp) + { + return LLWearable::FAILURE; + } + // Temporary hack to allow wearables with definition version 24 to still load. // This should only affect lindens and NDA'd testers who have saved wearables in 2.0 @@ -265,7 +323,7 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file ) } if( 0 <= type && type < LLWearableType::WT_COUNT ) { - setType((LLWearableType::EType)type); + setType((LLWearableType::EType)type, avatarp); } else { @@ -313,37 +371,49 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file ) } // textures - mTextureIDMap.clear(); for( i = 0; i < num_textures; i++ ) { S32 te = 0; - fields_read = fscanf( /* Flawfinder: ignore */ - file, - "%d %2047s\n", - &te, text_buffer); + fields_read = fscanf( /* Flawfinder: ignore */ + file, + "%d %2047s\n", + &te, text_buffer); if( fields_read != 2 ) { - llwarns << "Bad Wearable asset: bad texture, #" << i << llendl; - return LLWearable::FAILURE; + llwarns << "Bad Wearable asset: bad texture, #" << i << llendl; + return LLWearable::FAILURE; } - + if( !LLUUID::validate( text_buffer ) ) { - llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl; - return LLWearable::FAILURE; + llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl; + return LLWearable::FAILURE; } LLUUID id = LLUUID(text_buffer); - mTextureIDMap[te] = id; + LLGLTexture* image = gTextureManagerBridgep->getFetchedTexture( id ); + if( mTEMap.find(te) != mTEMap.end() ) + { + delete mTEMap[te]; + } + if( mSavedTEMap.find(te) != mSavedTEMap.end() ) + { + delete mSavedTEMap[te]; + } + + LLUUID textureid(text_buffer); + mTEMap[te] = new LLLocalTextureObject(image, textureid); + mSavedTEMap[te] = new LLLocalTextureObject(image, textureid); + createLayers(te, avatarp); } return LLWearable::SUCCESS; } -void LLWearable::setType(LLWearableType::EType type) +void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp) { mType = type; - createVisualParams(); + createVisualParams(avatarp); } @@ -442,6 +512,26 @@ void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload } } +void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp) +{ + if (!avatarp) return; + + // Pull params + for( LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() ) + { + // cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the + // avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way. + if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (!((LLViewerVisualParam*)param)->getCrossWearable()) ) + { + S32 param_id = param->getID(); + F32 weight = getVisualParamWeight(param_id); + + avatarp->setVisualParamWeight( param_id, weight, FALSE ); + } + } +} + + std::string terse_F32_to_string(F32 f) { std::string r = llformat("%.2f", f); diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index e1cd26bdef..b8bbf82a6e 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -37,6 +37,7 @@ class LLMD5; class LLVisualParam; class LLTexGlobalColorInfo; class LLTexGlobalColor; +class LLAvatarAppearance; // Abstract class. class LLWearable @@ -52,7 +53,7 @@ public: //-------------------------------------------------------------------- public: LLWearableType::EType getType() const { return mType; } - void setType(LLWearableType::EType type); + void setType(LLWearableType::EType type, LLAvatarAppearance *avatarp); const std::string& getName() const { return mName; } void setName(const std::string& name) { mName = name; } const std::string& getDescription() const { return mDescription; } @@ -70,7 +71,7 @@ public: public: typedef std::vector visual_param_vec_t; - virtual void writeToAvatar() = 0; + virtual void writeToAvatar(LLAvatarAppearance* avatarp); enum EImportResult { @@ -79,7 +80,7 @@ public: BAD_HEADER }; virtual BOOL exportFile(LLFILE* file) const; - virtual EImportResult importFile(LLFILE* file); + virtual EImportResult importFile(LLFILE* file, LLAvatarAppearance* avatarp); @@ -96,9 +97,6 @@ public: LLColor4 getClothesColor(S32 te) const; void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ); - typedef std::map texture_id_map_t; - const texture_id_map_t& getTextureIDMap() const { return mTextureIDMap; } - // Something happened that requires the wearable to be updated (e.g. worn/unworn). virtual void setUpdated() const = 0; @@ -106,7 +104,8 @@ public: virtual void addToBakedTextureHash(LLMD5& hash) const = 0; protected: - virtual void createVisualParams() = 0; + void createVisualParams(LLAvatarAppearance *avatarp); + void createLayers(S32 te, LLAvatarAppearance *avatarp); static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml. S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created. @@ -122,8 +121,9 @@ protected: typedef std::map visual_param_index_map_t; visual_param_index_map_t mVisualParamIndexMap; - // *TODO: Lazy mutable. Find a better way? - mutable texture_id_map_t mTextureIDMap; + typedef std::map te_map_t; + te_map_t mTEMap; // maps TE to LocalTextureObject + te_map_t mSavedTEMap; // last saved version of TEMap }; #endif // LL_LLWEARABLE_H -- cgit v1.2.3 From c34329fa4c8cc5adbad15d8e8f00296c71016a02 Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Wed, 12 Sep 2012 21:35:25 +0000 Subject: SH-3347 create demo of back end texture baking service First link of the back-end service with some LLAppearance code. --- indra/llappearance/llavatarappearance.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 7d37f5f509..ed8ff1e69e 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -1833,5 +1833,18 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root return TRUE; } +//virtual +LLAvatarAppearance::LLMaskedMorph::LLMaskedMorph(LLVisualParam *morph_target, BOOL invert, std::string layer) : + mMorphTarget(morph_target), + mInvert(invert), + mLayer(layer) +{ + LLPolyMorphTarget *target = dynamic_cast(morph_target); + if (target) + { + target->addPendingMorphMask(); + } +} + -- cgit v1.2.3 From da1a303fc33b098f133cb72a8bac9d8e886d65df Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 13 Sep 2012 02:09:21 +0000 Subject: Moved most of the appearance utility application level logic into LLAppAppearanceUtility. Added LLBakingProcess class for adding new process modes. Create a couple concrete classes for llappearance base classes. --- indra/llappearance/llavatarjointmesh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h index 4b56a168ac..427375e733 100755 --- a/indra/llappearance/llavatarjointmesh.h +++ b/indra/llappearance/llavatarjointmesh.h @@ -1,6 +1,6 @@ /** * @file llavatarjointmesh.h - * @brief Implementation of LLAvatarJointMesh class + * @brief Declaration of LLAvatarJointMesh class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code -- cgit v1.2.3 From 929b7e029513ecbb08c415e945c83ea09dc1b3eb Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 13 Sep 2012 03:30:17 +0000 Subject: Instantiated bare-bones LLBakingAvatar concrete class (derived from LLAvatarAppearance). Moved some LLCharacter funcionality from LLVOAvatar to LLAvatarAppearance. --- indra/llappearance/llavatarappearance.cpp | 79 ++++++++++++++++++++++++++++++- indra/llappearance/llavatarappearance.h | 22 +++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index ed8ff1e69e..19c656044c 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -166,7 +166,7 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mTexEyeColor( NULL ), mPelvisToFoot(0.f), mHeadOffset(), - + mRoot(NULL), mWearableData(wearable_data) { LLMemType mt(LLMemType::MTYPE_AVATAR); @@ -287,7 +287,7 @@ LLAvatarAppearance::~LLAvatarAppearance() } } - mRoot->removeAllChildren(); + if (mRoot) mRoot->removeAllChildren(); mJointMap.clear(); clearSkeleton(); @@ -1178,6 +1178,81 @@ BOOL LLAvatarAppearance::loadLayersets() return success; } +//----------------------------------------------------------------------------- +// getCharacterJoint() +//----------------------------------------------------------------------------- +LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num ) +{ + if ((S32)num >= mSkeleton.size() + || (S32)num < 0) + { + return NULL; + } + return mSkeleton[num]; +} + + +//----------------------------------------------------------------------------- +// getVolumePos() +//----------------------------------------------------------------------------- +LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_offset) +{ + if (joint_index > mNumCollisionVolumes) + { + return LLVector3::zero; + } + + return mCollisionVolumes[joint_index].getVolumePos(volume_offset); +} + +//----------------------------------------------------------------------------- +// findCollisionVolume() +//----------------------------------------------------------------------------- +LLJoint* LLAvatarAppearance::findCollisionVolume(U32 volume_id) +{ + if ((S32)volume_id > mNumCollisionVolumes) + { + return NULL; + } + + return &mCollisionVolumes[volume_id]; +} + +//----------------------------------------------------------------------------- +// findCollisionVolume() +//----------------------------------------------------------------------------- +S32 LLAvatarAppearance::getCollisionVolumeID(std::string &name) +{ + for (S32 i = 0; i < mNumCollisionVolumes; i++) + { + if (mCollisionVolumes[i].getName() == name) + { + return i; + } + } + + return -1; +} + +//----------------------------------------------------------------------------- +// LLAvatarAppearance::getHeadMesh() +//----------------------------------------------------------------------------- +LLPolyMesh* LLAvatarAppearance::getHeadMesh() +{ + return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh(); +} + + +//----------------------------------------------------------------------------- +// LLAvatarAppearance::getUpperBodyMesh() +//----------------------------------------------------------------------------- +LLPolyMesh* LLAvatarAppearance::getUpperBodyMesh() +{ + return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh(); +} + + + // virtual BOOL LLAvatarAppearance::isValid() const { diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index b512fd4eda..06607ef899 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -76,6 +76,28 @@ public: ** ** *******************************************************************************/ +/******************************************************************************** + ** ** + ** INHERITED + **/ + + //-------------------------------------------------------------------- + // LLCharacter interface and related + //-------------------------------------------------------------------- +public: + /*virtual*/ LLJoint* getCharacterJoint(U32 num); + + /*virtual*/ const char* getAnimationPrefix() { return "avatar"; } + /*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset); + /*virtual*/ LLJoint* findCollisionVolume(U32 volume_id); + /*virtual*/ S32 getCollisionVolumeID(std::string &name); + /*virtual*/ LLPolyMesh* getHeadMesh(); + /*virtual*/ LLPolyMesh* getUpperBodyMesh(); + +/** Inherited + ** ** + *******************************************************************************/ + /******************************************************************************** ** ** ** STATE -- cgit v1.2.3 From 8ba2b388769e245ec1b49b7d6d4b0372d684ff86 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 13 Sep 2012 10:25:48 +0000 Subject: Fleshed out target_link_libraries dependencies between libraries. Appearance utility now reads avatar_lad.xml during stubbed out params processing. --- indra/llappearance/CMakeLists.txt | 25 ++++++++++++------------- indra/llappearance/llavatarappearance.cpp | 8 ++++++++ indra/llappearance/llavatarappearance.h | 3 ++- indra/llappearance/llwearabletype.cpp | 16 ++++++++++++++-- indra/llappearance/llwearabletype.h | 10 ++++++++++ 5 files changed, 46 insertions(+), 16 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index adce620372..c570f0c93b 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -4,37 +4,24 @@ project(llappearance) include(00-Common) include(LLCommon) -include(LLAudio) include(LLCharacter) -include(LLCommon) include(LLImage) -include(LLImageJ2COJ) include(LLInventory) include(LLMath) include(LLMessage) -include(LLPhysicsExtensions) -include(LLPlugin) -include(LLPrimitive) include(LLRender) -include(LLUI) include(LLVFS) include(LLWindow) include(LLXML) include(Linking) -include(LLKDU) -include(ViewerMiscLibs) -include(LLLogin) include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} - ${LLPHYSICS_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} - ${LLKDU_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} - ${LLUI_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} @@ -90,6 +77,18 @@ list(APPEND llappearance_SOURCE_FILES ${llappearance_HEADER_FILES}) add_library (llappearance ${llappearance_SOURCE_FILES}) +target_link_libraries(llappearance + ${LLCHARACTER_LIBRARIES} + ${LLINVENTORY_LIBRARIES} + ${LLIMAGE_LIBRARIES} + ${LLRENDER_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLXML_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ) + #add unit tests #if (LL_TESTS) # INCLUDE(LLAddBuildTest) diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 19c656044c..824f0a1e32 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -419,6 +419,14 @@ void LLAvatarAppearance::initClass() } } +void LLAvatarAppearance::cleanupClass() +{ + deleteAndClear(sAvatarXmlInfo); + // *TODO: What about sAvatarSkeletonInfo ??? + sSkeletonXMLTree.cleanup(); + sXMLTree.cleanup(); +} + using namespace LLAvatarAppearanceDefines; //------------------------------------------------------------------------ diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 06607ef899..5726ff62d1 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -65,7 +65,8 @@ public: LLAvatarAppearance(LLWearableData* wearable_data); virtual ~LLAvatarAppearance(); - static void initClass(); // initializes static members + static void initClass(); // initializes static members + static void cleanupClass(); // Cleanup data that's only init'd once per class. virtual void initInstance(); // Called after construction to initialize the instance. virtual BOOL loadSkeletonNode(); BOOL loadMeshNodes(); diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index aa0afe348a..618e2a1941 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -27,7 +27,19 @@ #include "linden_common.h" #include "llwearabletype.h" #include "llinventorytype.h" -#include "lltrans.h" + +static LLTranslationBridge* sTrans = NULL; + +// static +void LLWearableType::initClass(LLTranslationBridge* trans) +{ + sTrans = trans; +} + +void LLWearableType::cleanupClass() +{ + delete sTrans; +} struct WearableEntry : public LLDictionaryEntry { @@ -40,7 +52,7 @@ struct WearableEntry : public LLDictionaryEntry LLDictionaryEntry(name), mAssetType(assetType), mDefaultNewName(default_new_name), - mLabel(LLTrans::getString(name)), + mLabel(sTrans->getString(name)), mIconName(iconName), mDisableCameraSwitch(disable_camera_switch), mAllowMultiwear(allow_multiwear) diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index 78008c27ea..e51e6731d3 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -32,6 +32,13 @@ #include "llinventorytype.h" #include "llsingleton.h" +class LLTranslationBridge +{ +public: + virtual std::string getString(const std::string &xml_desc) = 0; +}; + + class LLWearableType { public: @@ -59,6 +66,9 @@ public: WT_NONE = -1, }; + static void initClass(LLTranslationBridge* trans); // initializes static members + static void cleanupClass(); // initializes static members + static const std::string& getTypeName(EType type); static const std::string& getTypeDefaultNewName(EType type); static const std::string& getTypeLabel(EType type); -- cgit v1.2.3 From 8b2cb3766e3ed546994f81518983283e68263b09 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Fri, 14 Sep 2012 11:29:17 -0400 Subject: BUILDFIX: WIN fixing up windows building issues Cleaned up a couple of things that the windows compiler was warning about, with our inheritance structure --- indra/llappearance/llavatarjoint.cpp | 1 + indra/llappearance/llavatarjoint.h | 3 ++- indra/llappearance/llavatarjointmesh.cpp | 5 +++-- indra/llappearance/llavatarjointmesh.h | 4 ---- 4 files changed, 6 insertions(+), 7 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp index eb450485c7..6ab341af64 100644 --- a/indra/llappearance/llavatarjoint.cpp +++ b/indra/llappearance/llavatarjoint.cpp @@ -73,6 +73,7 @@ void LLAvatarJoint::init() mPickName = PN_DEFAULT; mVisible = TRUE; mMeshID = 0; + mIsTransparent = FALSE; } diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h index 1dfbd37456..fec91503c7 100644 --- a/indra/llappearance/llavatarjoint.h +++ b/indra/llappearance/llavatarjoint.h @@ -59,7 +59,7 @@ public: // Returns true if this object is transparent. // This is used to determine in which order to draw objects. - virtual BOOL isTransparent() { return FALSE; } + virtual BOOL isTransparent() { return mIsTransparent; } // Returns true if this object should inherit scale modifiers from its immediate parent virtual BOOL inheritScale() { return FALSE; } @@ -113,6 +113,7 @@ protected: void init(); BOOL mValid; + BOOL mIsTransparent; U32 mComponents; F32 mMinPixelArea; LLJointPickName mPickName; diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp index c611ab7cec..4a5cff1dc3 100755 --- a/indra/llappearance/llavatarjointmesh.cpp +++ b/indra/llappearance/llavatarjointmesh.cpp @@ -129,8 +129,7 @@ LLAvatarJointMesh::LLAvatarJointMesh() mTexture( NULL ), mLayerSet( NULL ), mTestImageName( 0 ), - mFaceIndexCount(0), - mIsTransparent(FALSE) + mFaceIndexCount(0) { mColor[0] = 1.0f; @@ -151,6 +150,8 @@ LLAvatarJointMesh::LLAvatarJointMesh() mUpdateXform = FALSE; mValid = FALSE; + + mIsTransparent = FALSE; } diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h index 2aade4d62b..6486932cdf 100755 --- a/indra/llappearance/llavatarjointmesh.h +++ b/indra/llappearance/llavatarjointmesh.h @@ -73,7 +73,6 @@ protected: LLFace* mFace; // ptr to a face w/ AGP copy of mesh U32 mFaceIndexCount; - BOOL mIsTransparent; U32 mNumSkinJoints; LLSkinJoint* mSkinJoints; @@ -93,9 +92,6 @@ public: // Destructor virtual ~LLAvatarJointMesh(); - // overloaded from base class - /*virtual*/ BOOL isTransparent() { return mIsTransparent; } - // Gets the shape color void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha ); -- cgit v1.2.3 From f3d52b8d54c3be67262d4d8ae9a00253e9d55249 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 19 Sep 2012 17:59:27 -0400 Subject: small tweaks to param debugging, restricting LLWearable::writeToAvatar --- indra/llappearance/lldriverparam.cpp | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 indra/llappearance/lldriverparam.cpp (limited to 'indra/llappearance') diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp old mode 100644 new mode 100755 index 1092b525d0..ec282c50eb --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -187,7 +187,9 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) { llassert(wearable); LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable); + // FIXME this clobbers mWearablep, which means any code currently using mWearablep is wrong. *new_param = *this; +// new_param->mDriven.clear(); // clear driven list to avoid overwriting avatar driven params from wearables. return new_param; } -- cgit v1.2.3 From 7153d1db11c00245a379fa9601f092020152ea73 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 20 Sep 2012 04:29:17 +0000 Subject: Partial rewrite of llifstream and llofstream (Windows implementation pending). Moved more functionality from llviewerwearable to llwearable --- indra/llappearance/llavatarappearance.h | 1 + indra/llappearance/llavatarappearancedefines.h | 3 +- indra/llappearance/lllocaltextureobject.h | 1 - indra/llappearance/lltexlayer.h | 1 + indra/llappearance/lltexturemanagerbridge.h | 1 + indra/llappearance/llwearable.cpp | 443 ++++++++++++++++++------- indra/llappearance/llwearable.h | 23 +- indra/llappearance/llwearabledata.h | 1 + 8 files changed, 346 insertions(+), 128 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 5726ff62d1..4f57335688 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -37,6 +37,7 @@ class LLTexLayerSet; class LLTexGlobalColor; +class LLTexGlobalColorInfo; class LLWearableData; class LLAvatarBoneInfo; class LLAvatarSkeletonInfo; diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h index e7c94104cc..0351f28429 100644 --- a/indra/llappearance/llavatarappearancedefines.h +++ b/indra/llappearance/llavatarappearancedefines.h @@ -29,9 +29,10 @@ #define LL_AVATARAPPEARANCE_DEFINES_H #include -#include "llwearable.h" #include "lljointpickname.h" #include "lldictionary.h" +#include "llwearabletype.h" +#include "lluuid.h" namespace LLAvatarAppearanceDefines { diff --git a/indra/llappearance/lllocaltextureobject.h b/indra/llappearance/lllocaltextureobject.h index 6f14448cca..9b9f41fd19 100644 --- a/indra/llappearance/lllocaltextureobject.h +++ b/indra/llappearance/lllocaltextureobject.h @@ -32,7 +32,6 @@ #include "llpointer.h" #include "llgltexture.h" -class LLUUID; class LLTexLayer; class LLTexLayerTemplate; class LLWearable; diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 0d7fad349c..692cfa1a38 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -36,6 +36,7 @@ class LLAvatarAppearance; class LLImageTGA; class LLImageRaw; +class LLLocalTextureObject; class LLXmlTreeNode; class LLTexLayerSet; class LLTexLayerSetInfo; diff --git a/indra/llappearance/lltexturemanagerbridge.h b/indra/llappearance/lltexturemanagerbridge.h index 99c01755d4..4b814b522d 100644 --- a/indra/llappearance/lltexturemanagerbridge.h +++ b/indra/llappearance/lltexturemanagerbridge.h @@ -27,6 +27,7 @@ #ifndef LL_TEXTUREMANAGERBRIDGE_H #define LL_TEXTUREMANAGERBRIDGE_H +#include "llavatarappearancedefines.h" #include "llpointer.h" #include "llgltexture.h" diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 9e73a6669a..78ff510909 100755 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -62,52 +62,41 @@ LLAssetType::EType LLWearable::getAssetType() const return LLWearableType::getAssetType(mType); } +BOOL LLWearable::exportFile(LLFILE* fp) const +{ + llofstream ofs(fp); + return exportStream(ofs); +} + // virtual -BOOL LLWearable::exportFile(LLFILE* file) const +BOOL LLWearable::exportStream( std::ostream& output_stream ) const { - // header and version - if( fprintf( file, "LLWearable version %d\n", mDefinitionVersion ) < 0 ) - { - return FALSE; - } + if (!output_stream.good()) return FALSE; + // header and version + output_stream << "LLWearable version " << mDefinitionVersion << "\n"; // name - if( fprintf( file, "%s\n", mName.c_str() ) < 0 ) - { - return FALSE; - } - + output_stream << mName << "\n"; // description - if( fprintf( file, "%s\n", mDescription.c_str() ) < 0 ) - { - return FALSE; - } - + output_stream << mDescription << "\n"; + // permissions - if( !mPermissions.exportFile( file ) ) + if( !mPermissions.exportStream( output_stream ) ) { return FALSE; } // sale info - if( !mSaleInfo.exportFile( file ) ) + if( !mSaleInfo.exportStream( output_stream ) ) { return FALSE; } // wearable type - S32 type = (S32)mType; - if( fprintf( file, "type %d\n", type ) < 0 ) - { - return FALSE; - } + output_stream << "type " << (S32) getType() << "\n"; // parameters - S32 num_parameters = mVisualParamIndexMap.size(); - if( fprintf( file, "parameters %d\n", num_parameters ) < 0 ) - { - return FALSE; - } + output_stream << "parameters " << mVisualParamIndexMap.size() << "\n"; for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); @@ -116,27 +105,17 @@ BOOL LLWearable::exportFile(LLFILE* file) const S32 param_id = iter->first; const LLVisualParam* param = iter->second; F32 param_weight = param->getWeight(); - if( fprintf( file, "%d %s\n", param_id, terse_F32_to_string( param_weight ).c_str() ) < 0 ) - { - return FALSE; - } + output_stream << param_id << " " << terse_F32_to_string( param_weight ) << "\n"; } // texture entries - S32 num_textures = mTEMap.size(); - if( fprintf( file, "textures %d\n", num_textures ) < 0 ) - { - return FALSE; - } + output_stream << "textures " << mTEMap.size() << "\n"; for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter) { S32 te = iter->first; const LLUUID& image_id = iter->second->getID(); - if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 ) - { - return FALSE; - } + output_stream << te << " " << image_id << "\n"; } return TRUE; } @@ -195,29 +174,49 @@ void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp) } } +LLWearable::EImportResult LLWearable::importFile(LLFILE* fp, LLAvatarAppearance* avatarp ) +{ + llifstream ifs(fp); + return importStream(ifs, avatarp); +} + // virtual -LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearance* avatarp ) +LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, LLAvatarAppearance* avatarp ) { // *NOTE: changing the type or size of this buffer will require - // changes in the fscanf() code below. You would be better off - // rewriting this to use streams and not require an open FILE. - char text_buffer[2048]; /* Flawfinder: ignore */ - S32 fields_read = 0; + // changes in the fscanf() code below. + // We are using a local max buffer size here to avoid issues + // if MAX_STRING size changes. + const U32 PARSE_BUFFER_SIZE = 2048; + char buffer[2048]; /* Flawfinder: ignore */ + char uuid_buffer[37]; /* Flawfinder: ignore */ + + // This data is being generated on the viewer. + // Impose some sane limits on parameter and texture counts. + const S32 MAX_WEARABLE_ASSET_TEXTURES = 100; + const S32 MAX_WEARABLE_ASSET_PARAMETERS = 1000; - // read header and version - fields_read = fscanf( file, "LLWearable version %d\n", &mDefinitionVersion ); - if( fields_read != 1 ) + if(!avatarp) { - return LLWearable::BAD_HEADER; + return LLWearable::FAILURE; } - if(!avatarp) + // read header and version + if (!input_stream.good()) { + llwarns << "Failed to read wearable asset input stream." << llendl; return LLWearable::FAILURE; } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + if ( 1 != sscanf( /* Flawfinder: ignore */ + buffer, + "LLWearable version %d\n", + &mDefinitionVersion ) ) + { + return LLWearable::BAD_HEADER; + } - - // Temporary hack to allow wearables with definition version 24 to still load. + // Hack to allow wearables with definition version 24 to still load. // This should only affect lindens and NDA'd testers who have saved wearables in 2.0 // the extra check for version == 24 can be removed before release, once internal testers // have loaded these wearables again. See hack pt 2 at bottom of function to ensure that @@ -229,68 +228,58 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearan } // name - int next_char = fgetc( file ); /* Flawfinder: ignore */ - if( '\n' == next_char ) - { - // no name - mName = ""; - } - else + if (!input_stream.good()) { - ungetc( next_char, file ); - fields_read = fscanf( /* Flawfinder: ignore */ - file, - "%2047[^\n]", - text_buffer); - if( (1 != fields_read) || (fgetc( file ) != '\n') ) /* Flawfinder: ignore */ - { - llwarns << "Bad Wearable asset: early end of file" << llendl; - return LLWearable::FAILURE; - } - mName = text_buffer; + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading name" << llendl; + return LLWearable::FAILURE; } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + mName = buffer; // description - next_char = fgetc( file ); /* Flawfinder: ignore */ - if( '\n' == next_char ) + if (!input_stream.good()) { - // no description - mDescription = ""; - } - else - { - ungetc( next_char, file ); - fields_read = fscanf( /* Flawfinder: ignore */ - file, - "%2047[^\n]", - text_buffer ); - if( (1 != fields_read) || (fgetc( file ) != '\n') ) /* Flawfinder: ignore */ - { - llwarns << "Bad Wearable asset: early end of file" << llendl; - return LLWearable::FAILURE; - } - mDescription = text_buffer; + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading description" << llendl; + return LLWearable::FAILURE; } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + mDescription = buffer; // permissions - S32 perm_version; - fields_read = fscanf( file, " permissions %d\n", &perm_version ); - if( (fields_read != 1) || (perm_version != 0) ) + if (!input_stream.good()) + { + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading permissions" << llendl; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + S32 perm_version = -1; + if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) || + perm_version != 0 ) { - llwarns << "Bad Wearable asset: missing permissions" << llendl; + llwarns << "Bad Wearable asset: missing valid permissions" << llendl; return LLWearable::FAILURE; } - if( !mPermissions.importFile( file ) ) + if( !mPermissions.importStream( input_stream ) ) { return LLWearable::FAILURE; } // sale info - S32 sale_info_version; - fields_read = fscanf( file, " sale_info %d\n", &sale_info_version ); - if( (fields_read != 1) || (sale_info_version != 0) ) + if (!input_stream.good()) { - llwarns << "Bad Wearable asset: missing sale_info" << llendl; + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading sale info" << llendl; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + S32 sale_info_version = -1; + if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) || + sale_info_version != 0 ) + { + llwarns << "Bad Wearable asset: missing valid sale_info" << llendl; return LLWearable::FAILURE; } // Sale info used to contain next owner perm. It is now in the @@ -299,7 +288,7 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearan // up the vast majority of the tasks. BOOL has_perm_mask = FALSE; U32 perm_mask = 0; - if( !mSaleInfo.importFile(file, has_perm_mask, perm_mask) ) + if( !mSaleInfo.importStream(input_stream, has_perm_mask, perm_mask) ) { return LLWearable::FAILURE; } @@ -314,9 +303,15 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearan } // wearable type + if (!input_stream.good()) + { + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading type" << llendl; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 type = -1; - fields_read = fscanf( file, "type %d\n", &type ); - if( fields_read != 1 ) + if ( 1 != sscanf( buffer, "type %d\n", &type ) ) { llwarns << "Bad Wearable asset: bad type" << llendl; return LLWearable::FAILURE; @@ -333,27 +328,48 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearan } // parameters header - S32 num_parameters = 0; - fields_read = fscanf( file, "parameters %d\n", &num_parameters ); - if( fields_read != 1 ) + if (!input_stream.good()) + { + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading parameters header" << llendl; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + S32 num_parameters = -1; + if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) ) { llwarns << "Bad Wearable asset: missing parameters block" << llendl; return LLWearable::FAILURE; } - + if ( num_parameters > MAX_WEARABLE_ASSET_PARAMETERS ) + { + llwarns << "Bad Wearable asset: too many parameters, " + << num_parameters << llendl; + return LLWearable::FAILURE; + } if( num_parameters != mVisualParamIndexMap.size() ) { - llwarns << "Wearable parameter mismatch. Reading in " << num_parameters << " from file, but created " << mVisualParamIndexMap.size() << " from avatar parameters. type: " << mType << llendl; + llwarns << "Wearable parameter mismatch. Reading in " + << num_parameters << " from file, but created " + << mVisualParamIndexMap.size() + << " from avatar parameters. type: " + << getType() << llendl; } // parameters S32 i; for( i = 0; i < num_parameters; i++ ) { + if (!input_stream.good()) + { + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading parameter #" << i << llendl; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 param_id = 0; F32 param_weight = 0.f; - fields_read = fscanf( file, "%d %f\n", ¶m_id, ¶m_weight ); - if( fields_read != 2 ) + if ( 2 != sscanf( buffer, "%d %f\n", ¶m_id, ¶m_weight ) ) { llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl; return LLWearable::FAILURE; @@ -362,34 +378,53 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearan } // textures header - S32 num_textures = 0; - fields_read = fscanf( file, "textures %d\n", &num_textures); - if( fields_read != 1 ) + if (!input_stream.good()) + { + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading textures header" << i << llendl; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); + S32 num_textures = -1; + if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) ) { llwarns << "Bad Wearable asset: missing textures block" << llendl; return LLWearable::FAILURE; } + if ( num_textures > MAX_WEARABLE_ASSET_TEXTURES ) + { + llwarns << "Bad Wearable asset: too many textures, " + << num_textures << llendl; + return LLWearable::FAILURE; + } // textures for( i = 0; i < num_textures; i++ ) { + if (!input_stream.good()) + { + llwarns << "Bad Wearable asset: early end of input stream " + << "while reading textures #" << i << llendl; + return LLWearable::FAILURE; + } + input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 te = 0; - fields_read = fscanf( /* Flawfinder: ignore */ - file, - "%d %2047s\n", - &te, text_buffer); - if( fields_read != 2 ) + if ( 2 != sscanf( /* Flawfinder: ignore */ + buffer, + "%d %36s\n", + &te, uuid_buffer) ) { llwarns << "Bad Wearable asset: bad texture, #" << i << llendl; return LLWearable::FAILURE; } - if( !LLUUID::validate( text_buffer ) ) + if( !LLUUID::validate( uuid_buffer ) ) { - llwarns << "Bad Wearable asset: bad texture uuid: " << text_buffer << llendl; + llwarns << "Bad Wearable asset: bad texture uuid: " + << uuid_buffer << llendl; return LLWearable::FAILURE; } - LLUUID id = LLUUID(text_buffer); + LLUUID id = LLUUID(uuid_buffer); LLGLTexture* image = gTextureManagerBridgep->getFetchedTexture( id ); if( mTEMap.find(te) != mTEMap.end() ) { @@ -400,12 +435,15 @@ LLWearable::EImportResult LLWearable::importFile( LLFILE* file, LLAvatarAppearan delete mSavedTEMap[te]; } - LLUUID textureid(text_buffer); + LLUUID textureid(uuid_buffer); mTEMap[te] = new LLLocalTextureObject(image, textureid); mSavedTEMap[te] = new LLLocalTextureObject(image, textureid); createLayers(te, avatarp); } + // copy all saved param values to working params + revertValues(); + return LLWearable::SUCCESS; } @@ -417,6 +455,171 @@ void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp } +LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) +{ + te_map_t::iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + LLLocalTextureObject* lto = iter->second; + return lto; + } + return NULL; +} + +const LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const +{ + te_map_t::const_iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + const LLLocalTextureObject* lto = iter->second; + return lto; + } + return NULL; +} + +std::vector LLWearable::getLocalTextureListSeq() +{ + std::vector result; + + for(te_map_t::const_iterator iter = mTEMap.begin(); + iter != mTEMap.end(); iter++) + { + LLLocalTextureObject* lto = iter->second; + result.push_back(lto); + } + + return result; +} + +void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject <o) +{ + if( mTEMap.find(index) != mTEMap.end() ) + { + mTEMap.erase(index); + } + mTEMap[index] = new LLLocalTextureObject(lto); +} + +void LLWearable::revertValues() +{ + //update saved settings so wearable is no longer dirty + // non-driver params first + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + F32 value = iter->second; + LLVisualParam *param = getVisualParam(id); + if(param && !dynamic_cast(param) ) + { + setVisualParamWeight(id, value, TRUE); + } + } + + //then driver params + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + F32 value = iter->second; + LLVisualParam *param = getVisualParam(id); + if(param && dynamic_cast(param) ) + { + setVisualParamWeight(id, value, TRUE); + } + } + + // make sure that saved values are sane + for (param_map_t::const_iterator iter = mSavedVisualParamMap.begin(); iter != mSavedVisualParamMap.end(); iter++) + { + S32 id = iter->first; + LLVisualParam *param = getVisualParam(id); + if( param ) + { + mSavedVisualParamMap[id] = param->getWeight(); + } + } + + syncImages(mSavedTEMap, mTEMap); +} + +void LLWearable::saveValues() +{ + //update saved settings so wearable is no longer dirty + mSavedVisualParamMap.clear(); + for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter) + { + S32 id = iter->first; + LLVisualParam *wearable_param = iter->second; + F32 value = wearable_param->getWeight(); + mSavedVisualParamMap[id] = value; + } + + // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) + syncImages(mTEMap, mSavedTEMap); +} + +void LLWearable::syncImages(te_map_t &src, te_map_t &dst) +{ + // Deep copy of src (copies only those tes that are current, filling in defaults where needed) + for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) + { + if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex) te) == mType) + { + te_map_t::const_iterator iter = src.find(te); + LLUUID image_id; + LLGLTexture *image = NULL; + LLLocalTextureObject *lto = NULL; + if(iter != src.end()) + { + // there's a Local Texture Object in the source image map. Use this to populate the values to store in the destination image map. + lto = iter->second; + image = lto->getImage(); + image_id = lto->getID(); + } + else + { + // there is no Local Texture Object in the source image map. Get defaults values for populating the destination image map. + image_id = getDefaultTextureImageID((ETextureIndex) te); + image = gTextureManagerBridgep->getFetchedTexture( image_id ); + } + + if( dst.find(te) != dst.end() ) + { + // there's already an entry in the destination map for the texture. Just update its values. + dst[te]->setImage(image); + dst[te]->setID(image_id); + } + else + { + // no entry found in the destination map, we need to create a new Local Texture Object + dst[te] = new LLLocalTextureObject(image, image_id); + } + + if( lto ) + { + // If we pulled values from a Local Texture Object in the source map, make sure the proper flags are set in the new (or updated) entry in the destination map. + dst[te]->setBakedReady(lto->getBakedReady()); + dst[te]->setDiscard(lto->getDiscard()); + } + } + } +} + +void LLWearable::destroyTextures() +{ + for( te_map_t::iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter ) + { + LLLocalTextureObject *lto = iter->second; + delete lto; + } + mTEMap.clear(); + for( te_map_t::iterator iter = mSavedTEMap.begin(); iter != mSavedTEMap.end(); ++iter ) + { + LLLocalTextureObject *lto = iter->second; + delete lto; + } + mSavedTEMap.clear(); +} + void LLWearable::addVisualParam(LLVisualParam *param) { if( mVisualParamIndexMap[param->getID()] ) diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index b8bbf82a6e..bc73ed4d8c 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -27,6 +27,7 @@ #ifndef LL_LLWEARABLE_H #define LL_LLWEARABLE_H +#include "llavatarappearancedefines.h" #include "llextendedstatus.h" #include "llpermissions.h" #include "llsaleinfo.h" @@ -79,14 +80,19 @@ public: SUCCESS, BAD_HEADER }; - virtual BOOL exportFile(LLFILE* file) const; - virtual EImportResult importFile(LLFILE* file, LLAvatarAppearance* avatarp); - - + BOOL exportFile(LLFILE* file) const; + EImportResult importFile(LLFILE* file, LLAvatarAppearance* avatarp ); + virtual BOOL exportStream( std::ostream& output_stream ) const; + virtual EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp ); static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; } + virtual LLUUID getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const = 0; + + LLLocalTextureObject* getLocalTextureObject(S32 index); + const LLLocalTextureObject* getLocalTextureObject(S32 index) const; + std::vector getLocalTextureListSeq(); - virtual LLLocalTextureObject* getLocalTextureObject(S32 index) = 0; + void setLocalTextureObject(S32 index, LLLocalTextureObject <o); void addVisualParam(LLVisualParam *param); void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); F32 getVisualParamWeight(S32 index) const; @@ -97,6 +103,9 @@ public: LLColor4 getClothesColor(S32 te) const; void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ); + virtual void revertValues(); + virtual void saveValues(); + // Something happened that requires the wearable to be updated (e.g. worn/unworn). virtual void setUpdated() const = 0; @@ -104,6 +113,9 @@ public: virtual void addToBakedTextureHash(LLMD5& hash) const = 0; protected: + typedef std::map te_map_t; + void syncImages(te_map_t &src, te_map_t &dst); + void destroyTextures(); void createVisualParams(LLAvatarAppearance *avatarp); void createLayers(S32 te, LLAvatarAppearance *avatarp); @@ -121,7 +133,6 @@ protected: typedef std::map visual_param_index_map_t; visual_param_index_map_t mVisualParamIndexMap; - typedef std::map te_map_t; te_map_t mTEMap; // maps TE to LocalTextureObject te_map_t mSavedTEMap; // last saved version of TEMap }; diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h index 2931424131..379384a989 100644 --- a/indra/llappearance/llwearabledata.h +++ b/indra/llappearance/llwearabledata.h @@ -28,6 +28,7 @@ #define LL_WEARABLEDATA_H #include "llavatarappearancedefines.h" +#include "llwearable.h" #include "llerror.h" class LLAvatarAppearance; -- cgit v1.2.3 From 3171c2414fd622f72c23e796d5cf54fb84f8eff0 Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Fri, 21 Sep 2012 18:22:36 +0000 Subject: Making computeBodySize public --- indra/llappearance/llavatarappearance.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 4f57335688..a27779e295 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -134,13 +134,15 @@ public: typedef std::map joint_map_t; joint_map_t mJointMap; + + void computeBodySize(); + protected: static BOOL parseSkeletonFile(const std::string& filename); virtual void buildCharacter(); virtual BOOL loadAvatar(); virtual void bodySizeChanged() = 0; - void computeBodySize(); BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); BOOL allocateCharacterJoints(U32 num); -- cgit v1.2.3 From ae0bb922909af95d96c140c1d74a4f39a264d4ec Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 26 Sep 2012 06:36:24 -0400 Subject: renamed isUsingBakedTextures to more accurate isUsingServerBakes. Commented some areas we are probably using the function incorrectly --- indra/llappearance/llavatarappearance.h | 4 +++- indra/llappearance/lltexlayerparams.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) mode change 100644 => 100755 indra/llappearance/llavatarappearance.h (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h old mode 100644 new mode 100755 index 5726ff62d1..2aa43d25d2 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -106,7 +106,9 @@ public: public: virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent virtual BOOL isValid() const; - virtual BOOL isUsingBakedTextures() const = 0; + virtual BOOL isUsingServerBakes() const = 0; + virtual BOOL isUsingLocalAppearance() const = 0; + virtual BOOL isEditingAppearance() const = 0; bool isBuilt() const { return mIsBuilt; } diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 82c92b5a5e..651468b1a5 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -176,7 +176,7 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. { - if (!mAvatarAppearance->isUsingBakedTextures()) + if (!mAvatarAppearance->isUsingServerBakes()) { upload_bake = FALSE; } -- cgit v1.2.3 From ab83fab72c66e753917001a9030aa55e69a3c496 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 26 Sep 2012 11:52:19 -0400 Subject: error checking, comments for areas needing fix/check in appearance --- indra/llappearance/lldriverparam.cpp | 2 +- indra/llappearance/lltexlayerparams.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 indra/llappearance/lltexlayerparams.cpp (limited to 'indra/llappearance') diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index ec282c50eb..a43878899c 100755 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -187,7 +187,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) { llassert(wearable); LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable); - // FIXME this clobbers mWearablep, which means any code currently using mWearablep is wrong. + // FIXME DRANO this clobbers mWearablep, which means any code currently using mWearablep is wrong. *new_param = *this; // new_param->mDriven.clear(); // clear driven list to avoid overwriting avatar driven params from wearables. return new_param; diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp old mode 100644 new mode 100755 index 651468b1a5..18e70af23c --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -176,6 +176,7 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. { + // FIXME DRANO - is this check right? if (!mAvatarAppearance->isUsingServerBakes()) { upload_bake = FALSE; -- cgit v1.2.3 From 93e210d91f521b01deb10aa6aa25160364e6ae28 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 26 Sep 2012 15:45:58 -0400 Subject: more state management stuff, DRANO flags for problematic areas --- indra/llappearance/lldriverparam.cpp | 3 ++- indra/llappearance/lltexlayerparams.cpp | 8 ++------ 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index a43878899c..2d91ebdee9 100755 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -187,7 +187,8 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) { llassert(wearable); LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable); - // FIXME DRANO this clobbers mWearablep, which means any code currently using mWearablep is wrong. + // FIXME DRANO this clobbers mWearablep, which means any code + // currently using mWearablep is wrong, or at least untested. *new_param = *this; // new_param->mDriven.clear(); // clear driven list to avoid overwriting avatar driven params from wearables. return new_param; diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 18e70af23c..32bdba4e1c 100755 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -174,13 +174,9 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) { mCurWeight = new_weight; - if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. + if ((mAvatarAppearance->getSex() & getSex()) && + (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. { - // FIXME DRANO - is this check right? - if (!mAvatarAppearance->isUsingServerBakes()) - { - upload_bake = FALSE; - } mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake); mTexLayer->invalidateMorphMasks(); } -- cgit v1.2.3 From f9a5cdba507096d16d834fe58c850b9f55ad9462 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Fri, 28 Sep 2012 01:06:17 +0000 Subject: Started stubbing out llsd support for tex layer information. --- indra/llappearance/lltexlayer.cpp | 31 +++++++++++++++++++++++++++++++ indra/llappearance/lltexlayer.h | 7 ++++++- indra/llappearance/llwearable.h | 1 + indra/llappearance/llwearabledata.h | 2 +- 4 files changed, 39 insertions(+), 2 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index e90efac36b..79d870c61d 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -469,6 +469,31 @@ const std::string LLTexLayerSet::getBodyRegionName() const } +// virtual +void LLTexLayerSet::asLLSD(LLSD& sd) const +{ + sd["visible"] = LLSD::Boolean(isVisible()); + LLSD layer_list_sd; + layer_list_t::const_iterator layer_iter = mLayerList.begin(); + layer_list_t::const_iterator layer_end = mLayerList.end(); + for(; layer_iter != layer_end; ++layer_iter); + { + LLSD layer_sd; + //LLTexLayerInterface* layer = (*layer_iter); + //if (layer) + //{ + // layer->asLLSD(layer_sd); + //} + layer_list_sd.append(layer_sd); + } + LLSD mask_list_sd; + LLSD info_sd; + sd["layers"] = layer_list_sd; + sd["masks"] = mask_list_sd; + sd["info"] = info_sd; +} + + void LLTexLayerSet::destroyComposite() { if( mComposite ) @@ -966,6 +991,12 @@ LLTexLayer::~LLTexLayer() } +void LLTexLayer::asLLSD(LLSD& sd) const +{ + // *TODO: Finish + sd["id"] = getUUID(); +} + //----------------------------------------------------------------------------- // setInfo //----------------------------------------------------------------------------- diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 692cfa1a38..a288d7fc50 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -89,6 +89,8 @@ public: ERenderPass getRenderPass() const; BOOL isVisibilityMask() const; + virtual void asLLSD(LLSD& sd) const {} + protected: const std::string& getGlobalColor() const; LLViewerVisualParam* getVisualParamPtr(S32 index) const; @@ -163,10 +165,11 @@ public: void setLTO(LLLocalTextureObject *lto) { mLocalTextureObject = lto; } LLLocalTextureObject* getLTO() { return mLocalTextureObject; } + /*virtual*/ void asLLSD(LLSD& sd) const; + static void calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color); protected: LLUUID getUUID() const; -private: typedef std::map alpha_cache_t; alpha_cache_t mAlphaCache; LLLocalTextureObject* mLocalTextureObject; @@ -214,6 +217,8 @@ public: static BOOL sHasCaches; + virtual void asLLSD(LLSD& sd) const; + protected: typedef std::vector layer_list_t; layer_list_t mLayerList; diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index bc73ed4d8c..4a59811795 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -68,6 +68,7 @@ public: LLAssetType::EType getAssetType() const; S32 getDefinitionVersion() const { return mDefinitionVersion; } void setDefinitionVersion( S32 new_version ) { mDefinitionVersion = new_version; } + static S32 getCurrentDefinitionVersion() { return LLWearable::sCurrentDefinitionVersion; } public: typedef std::vector visual_param_vec_t; diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h index 379384a989..3e92f2ead8 100644 --- a/indra/llappearance/llwearabledata.h +++ b/indra/llappearance/llwearabledata.h @@ -95,7 +95,7 @@ protected: //-------------------------------------------------------------------- // Member variables //-------------------------------------------------------------------- -private: +protected: LLAvatarAppearance* mAvatarAppearance; typedef std::vector wearableentry_vec_t; // all wearables of a certain type (EG all shirts) typedef std::map wearableentry_map_t; // wearable "categories" arranged by wearable type -- cgit v1.2.3 From 0a94b5bb390675bb1746f24c8352e73240a8d670 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Fri, 28 Sep 2012 23:56:55 +0000 Subject: Exposing more tex layer information for hash id generation --- indra/llappearance/llavatarappearancedefines.h | 1 + indra/llappearance/lltexlayer.cpp | 20 +++++++++++++++++--- indra/llappearance/lltexlayer.h | 4 +++- 3 files changed, 21 insertions(+), 4 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h index 0351f28429..2e073bf5d2 100644 --- a/indra/llappearance/llavatarappearancedefines.h +++ b/indra/llappearance/llavatarappearancedefines.h @@ -46,6 +46,7 @@ extern const S32 IMPOSTOR_PERIOD; //-------------------------------------------------------------------- enum ETextureIndex { + TEX_INVALID = -1, TEX_HEAD_BODYPAINT = 0, TEX_UPPER_SHIRT, TEX_LOWER_PANTS, diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 79d870c61d..6f079b4abb 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -903,6 +903,21 @@ const std::string& LLTexLayerInterface::getName() const return mInfo->mName; } +ETextureIndex LLTexLayerInterface::getLocalTextureIndex() const +{ + return (ETextureIndex) mInfo->mLocalTexture; +} + +LLWearableType::EType LLTexLayerInterface::getWearableType() const +{ + ETextureIndex te = getLocalTextureIndex(); + if (TEX_INVALID == te) + { + return LLWearableType::WT_INVALID; + } + return LLAvatarAppearanceDictionary::getTEWearableType(te); +} + LLTexLayerInterface::ERenderPass LLTexLayerInterface::getRenderPass() const { return mInfo->mRenderPass; @@ -1585,13 +1600,12 @@ U32 LLTexLayerTemplate::updateWearableCache() const { mWearableCache.clear(); - S32 te = mInfo->mLocalTexture; - if (te == -1) + LLWearableType::EType wearable_type = getWearableType(); + if (LLWearableType::WT_INVALID == wearable_type) { //this isn't a cloneable layer return 0; } - LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te); U32 num_wearables = getAvatarAppearance()->getWearableData()->getWearableCount(wearable_type); U32 added = 0; for (U32 i = 0; i < num_wearables; i++) diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index a288d7fc50..f9f8bdd817 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -72,6 +72,8 @@ public: const LLTexLayerInfo* getInfo() const { return mInfo; } virtual BOOL setInfo(const LLTexLayerInfo *info, LLWearable* wearable); // sets mInfo, calls initialization functions + LLWearableType::EType getWearableType() const; + LLAvatarAppearanceDefines::ETextureIndex getLocalTextureIndex() const; const std::string& getName() const; const LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; } @@ -211,7 +213,7 @@ public: LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } const std::string getBodyRegionName() const; BOOL hasComposite() const { return (mComposite.notNull()); } - LLAvatarAppearanceDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; } + LLAvatarAppearanceDefines::EBakedTextureIndex getBakedTexIndex() const { return mBakedTexIndex; } void setBakedTexIndex(LLAvatarAppearanceDefines::EBakedTextureIndex index) { mBakedTexIndex = index; } BOOL isVisible() const { return mIsVisible; } -- cgit v1.2.3 From 5483bc28ae6b33bf5b2371d46648ad20975daf8c Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 2 Oct 2012 01:02:34 +0000 Subject: Moved gatherMorphMaskAlpha into llappearance. --- indra/llappearance/llavatarappearancedefines.cpp | 24 +++++++++++++++++++++++- indra/llappearance/llavatarappearancedefines.h | 1 + indra/llappearance/lltexlayer.cpp | 15 +++++++++++++++ indra/llappearance/lltexlayer.h | 1 + 4 files changed, 40 insertions(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearancedefines.cpp b/indra/llappearance/llavatarappearancedefines.cpp index 0416309fc7..f1c78946a1 100644 --- a/indra/llappearance/llavatarappearancedefines.cpp +++ b/indra/llappearance/llavatarappearancedefines.cpp @@ -220,7 +220,7 @@ ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextu return LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(index)->mTextureIndex; } -//static +// static EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name) { U8 index = 0; @@ -238,6 +238,28 @@ EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::stri return BAKED_NUM_INDICES; } +// static +EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name) +{ + U8 index = 0; + while (index < BAKED_NUM_INDICES) + { + const BakedEntry *be = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index); + if (be) + { + const TextureEntry *te = LLAvatarAppearanceDictionary::getInstance()->getTexture(be->mTextureIndex); + if (te && te->mDefaultImageName.compare(name) == 0) + { + // baked texture found + return (EBakedTextureIndex) index; + } + } + index++; + } + // baked texture could not be found + return BAKED_NUM_INDICES; +} + // static LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIndex index ) { diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h index 2e073bf5d2..496f85c107 100644 --- a/indra/llappearance/llavatarappearancedefines.h +++ b/indra/llappearance/llavatarappearancedefines.h @@ -217,6 +217,7 @@ public: // find a baked texture index based on its name static EBakedTextureIndex findBakedByRegionName(std::string name); + static EBakedTextureIndex findBakedByImageName(std::string name); // Given a texture entry, determine which wearable type owns it. static LLWearableType::EType getTEWearableType(ETextureIndex index); diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 6f079b4abb..16f94c48dd 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -516,6 +516,21 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const return mComposite; } +void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height) +{ + memset(data, 255, width * height); + + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + { + LLTexLayerInterface* layer = *iter; + layer->gatherAlphaMasks(data, origin_x, origin_y, width, height); + } + + // Set alpha back to that of our alpha masks. + renderAlphaMaskTextures(origin_x, origin_y, width, height, true); +} + + void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear) { const LLTexLayerSetInfo *info = getInfo(); diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index f9f8bdd817..405d2c7df4 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -194,6 +194,7 @@ public: const LLTexLayerSetBuffer* getComposite() const; // Do not create one if it doesn't exist. virtual void createComposite() = 0; void destroyComposite(); + void gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height); const LLTexLayerSetInfo* getInfo() const { return mInfo; } BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions -- cgit v1.2.3 From e29b66ed6ce29528f7b733c51db22a31a05d3a5f Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 3 Oct 2012 17:13:18 -0400 Subject: additional fixes for avoiding avatar param manipulation via wearables, setting correct state from avatar appearance --- indra/llappearance/llwearabledata.cpp | 5 +++++ 1 file changed, 5 insertions(+) mode change 100644 => 100755 indra/llappearance/llwearabledata.cpp (limited to 'indra/llappearance') diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp old mode 100644 new mode 100755 index d70bbf286a..401b1dc192 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -119,6 +119,11 @@ U32 LLWearableData::pushWearable(const LLWearableType::EType type, void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed) { wearable->setUpdated(); + // FIXME DRANO avoid updating params via wearables when rendering server-baked appearance. + if (mAvatarAppearance->isUsingServerBakes() && !mAvatarAppearance->isUsingLocalAppearance()) + { + return; + } if (!removed) { pullCrossWearableValues(wearable->getType()); -- cgit v1.2.3 From 8c0aa31536c447edb6ef4fbee43f99debf593a20 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 4 Oct 2012 00:42:31 +0000 Subject: Adding optimization to skip alpha image analysis when it isn't needed. --- indra/llappearance/lltexlayerparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 32bdba4e1c..8f1551353f 100755 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -288,7 +288,6 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) (mCachedProcessedTexture->getHeight() != image_tga_height) || (weight_changed)) { -// llinfos << "Building Cached Alpha: " << mName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << effective_weight << llendl; mCachedEffectiveWeight = effective_weight; if (!mCachedProcessedTexture) @@ -307,6 +306,7 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) mStaticImageRaw = new LLImageRaw; mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight); mNeedsCreateTexture = TRUE; + lldebugs << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << llendl; } if (mCachedProcessedTexture) -- cgit v1.2.3 From 21df924a10c1c32f7fc28bb29b20dc2179863b24 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 4 Oct 2012 06:29:07 +0000 Subject: Building headless and non-headless libraries side-by-side, removing the need for the BAKING cmake setting. --- indra/llappearance/CMakeLists.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'indra/llappearance') diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index c570f0c93b..0dbd58b7cd 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -89,6 +89,22 @@ target_link_libraries(llappearance ${LLCOMMON_LIBRARIES} ) +if (BUILD_HEADLESS) + add_library (llappearanceheadless ${llappearance_SOURCE_FILES}) + + target_link_libraries(llappearanceheadless + ${LLCHARACTER_LIBRARIES} + ${LLINVENTORY_LIBRARIES} + ${LLIMAGE_LIBRARIES} + ${LLRENDERHEADLESS_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLXML_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ) +endif (BUILD_HEADLESS) + #add unit tests #if (LL_TESTS) # INCLUDE(LLAddBuildTest) -- cgit v1.2.3 From 19e43e4b588d4aec8f23498993a3a22c0e08a329 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Sat, 6 Oct 2012 08:08:52 +0000 Subject: Added fast timers for baked texture rendering. Updated appearance utility --- indra/llappearance/lltexlayer.cpp | 15 ++++++++++++++- indra/llappearance/lltexlayerparams.cpp | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 16f94c48dd..6e2623b860 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -516,8 +516,10 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const return mComposite; } +static LLFastTimer::DeclareTimer FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha"); void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height) { + LLFastTimer t(FTM_GATHER_MORPH_MASK_ALPHA); memset(data, 255, width * height); for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) @@ -530,9 +532,10 @@ void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S renderAlphaMaskTextures(origin_x, origin_y, width, height, true); } - +static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures"); void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear) { + LLFastTimer t(FTM_RENDER_ALPHA_MASK_TEXTURES); const LLTexLayerSetInfo *info = getInfo(); bool use_shaders = LLGLSLShader::sNoFixedFunction; @@ -1374,8 +1377,10 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) addAlphaMask(data, originX, originY, width, height); } +static LLFastTimer::DeclareTimer FTM_RENDER_MORPH_MASKS("renderMorphMasks"); BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color) { + LLFastTimer t(FTM_RENDER_MORPH_MASKS); BOOL success = TRUE; llassert( !mParamAlphaList.empty() ); @@ -1511,8 +1516,10 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC return success; } +static LLFastTimer::DeclareTimer FTM_ADD_ALPHA_MASK("addAlphaMask"); void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height) { + LLFastTimer t(FTM_ADD_ALPHA_MASK); S32 size = width * height; const U8* alphaData = getAlphaData(); if (!alphaData && hasAlphaParams()) @@ -1854,8 +1861,10 @@ void LLTexLayerStaticImageList::deleteCachedImages() // Returns an LLImageTGA that contains the encoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. +static LLFastTimer::DeclareTimer FTM_LOAD_STATIC_TGA("getImageTGA"); LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) { + LLFastTimer t(FTM_LOAD_STATIC_TGA); const char *namekey = mImageNames.addString(file_name); image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey); if( iter != mStaticImageListTGA.end() ) @@ -1882,8 +1891,10 @@ LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) // Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. +static LLFastTimer::DeclareTimer FTM_LOAD_STATIC_TEXTURE("getTexture"); LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) { + LLFastTimer t(FTM_LOAD_STATIC_TEXTURE); LLPointer tex; const char *namekey = mImageNames.addString(file_name); @@ -1924,8 +1935,10 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, // Reads a .tga file, decodes it, and puts the decoded data in image_raw. // Returns TRUE if successful. +static LLFastTimer::DeclareTimer FTM_LOAD_IMAGE_RAW("loadImageRaw"); BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw) { + LLFastTimer t(FTM_LOAD_IMAGE_RAW); BOOL success = FALSE; std::string path; path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name); diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 8f1551353f..58737f7ff4 100755 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -237,8 +237,10 @@ BOOL LLTexLayerParamAlpha::getSkip() const } +static LLFastTimer::DeclareTimer FTM_TEX_LAYER_PARAM_ALPHA("alpha render"); BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) { + LLFastTimer t(FTM_TEX_LAYER_PARAM_ALPHA); BOOL success = TRUE; if (!mTexLayer) -- cgit v1.2.3 From c06c35609c6683731eaea283468f6b32af18fea2 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 11 Oct 2012 00:09:04 +0000 Subject: Updating linux build to gcc4.6 --- indra/llappearance/llavatarappearance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 8677a1daff..bdd2d75822 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -438,7 +438,7 @@ void LLAvatarAppearance::computeBodySize() // some of the joints have not been cached LLVector3 skull = mSkullp->getPosition(); - LLVector3 skull_scale = mSkullp->getScale(); + //LLVector3 skull_scale = mSkullp->getScale(); LLVector3 neck = mNeckp->getPosition(); LLVector3 neck_scale = mNeckp->getScale(); -- cgit v1.2.3 From 22f53c85588912582f33d840d106b10f54f2c62d Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 15 Oct 2012 18:41:55 -0400 Subject: additional debugging info, including tracking where visual params live --- indra/llappearance/llavatarappearance.cpp | 4 ++++ indra/llappearance/lldriverparam.cpp | 1 + indra/llappearance/lltexlayerparams.cpp | 1 + indra/llappearance/llwearable.cpp | 1 + 4 files changed, 7 insertions(+) mode change 100644 => 100755 indra/llappearance/llavatarappearance.cpp (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp old mode 100644 new mode 100755 index bdd2d75822..3c01a00e61 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -903,6 +903,7 @@ BOOL LLAvatarAppearance::loadAvatar() if (driver_param->setInfo(info)) { addVisualParam( driver_param ); + driver_param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam; if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false)) { @@ -981,6 +982,7 @@ BOOL LLAvatarAppearance::loadSkeletonNode () else { addVisualParam(param); + param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); } } } @@ -1098,10 +1100,12 @@ BOOL LLAvatarAppearance::loadMeshNodes() if (info_pair->second) { addSharedVisualParam(param); + param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); } else { addVisualParam(param); + param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); } } } diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index 2d91ebdee9..01184a9e23 100755 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -481,6 +481,7 @@ BOOL LLDriverParam::linkDrivenParams(visual_param_mapper mapper, BOOL only_cross if (!found) { LLViewerVisualParam* param = (LLViewerVisualParam*)mapper(driven_id); + if (param) param->setParamLocation(this->getParamLocation()); bool push = param && (!only_cross_params || param->getCrossWearable()); if (push) { diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 58737f7ff4..64b3b62185 100755 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -67,6 +67,7 @@ BOOL LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, BOOL add_to_appeara if (add_to_appearance) { mAvatarAppearance->addVisualParam( this); + this->setParamLocation(mAvatarAppearance->isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); } return TRUE; diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 5d53d1ae39..f4891c61bd 100755 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -629,6 +629,7 @@ void LLWearable::addVisualParam(LLVisualParam *param) delete mVisualParamIndexMap[param->getID()]; } param->setIsDummy(FALSE); + param->setParamLocation(LOC_WEARABLE); mVisualParamIndexMap[param->getID()] = param; mSavedVisualParamMap[param->getID()] = param->getDefaultWeight(); } -- cgit v1.2.3 From 7d6da2ebe8db7aa73113659c709d03e16eca5094 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 17 Oct 2012 13:43:19 -0400 Subject: more param location logging, added wearable type info to dumpArchetypeXML --- indra/llappearance/llwearable.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index f4891c61bd..b33adb254d 100755 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -128,7 +128,10 @@ void LLWearable::createVisualParams(LLAvatarAppearance *avatarp) { if (param->getWearableType() == mType) { - addVisualParam(param->cloneParam(this)); + LLVisualParam *clone_param = param->cloneParam(this); + clone_param->setParamLocation(LOC_UNKNOWN); + clone_param->setParamLocation(LOC_WEARABLE); + addVisualParam(clone_param); } } -- cgit v1.2.3 From 2390e21a9d2fc6f5cabe132a2bbd807aec186cfa Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 17 Oct 2012 18:32:26 -0400 Subject: additional diagnostics, improved shape stability at cost of increasing entanglement between baked and local appearance --- indra/llappearance/llwearabledata.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp index 401b1dc192..68fdcca782 100755 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -120,10 +120,12 @@ void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed) { wearable->setUpdated(); // FIXME DRANO avoid updating params via wearables when rendering server-baked appearance. +#if 0 if (mAvatarAppearance->isUsingServerBakes() && !mAvatarAppearance->isUsingLocalAppearance()) { return; } +#endif if (!removed) { pullCrossWearableValues(wearable->getType()); -- cgit v1.2.3 From b9714ba85ebabdc39191565a26d732a82fd9a4a0 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Thu, 18 Oct 2012 15:00:05 -0400 Subject: Setting alpha rejection settings properly for texture bakes without basic shaders enabled --- indra/llappearance/lltexlayer.cpp | 90 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 6e2623b860..b8c8228f85 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -153,6 +153,10 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet() gAlphaMaskProgram.bind(); gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } LLVertexBuffer::unbind(); @@ -400,6 +404,11 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) { gAlphaMaskProgram.setMinimumAlpha(0.0f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.0f); + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 1.f ); @@ -410,6 +419,10 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } } if (mIsVisible) @@ -440,6 +453,10 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) { gAlphaMaskProgram.setMinimumAlpha(0.f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.0f); + } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 0.f ); @@ -452,6 +469,11 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } + } return success; @@ -568,6 +590,11 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, { gAlphaMaskProgram.setMinimumAlpha(0.f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.0f); + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 1.f ); @@ -578,6 +605,11 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, { gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } + } // (Optional) Mask out part of the baked texture with alpha masks @@ -1171,9 +1203,16 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) { bool no_alpha_test = getInfo()->mWriteAllChannels; LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0); - if (use_shaders && no_alpha_test) + if (no_alpha_test) { - gAlphaMaskProgram.setMinimumAlpha(0.f); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.f); + } + else + { + glAlphaFunc(GL_GEQUAL, 0.0f); + } } LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); @@ -1185,9 +1224,16 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) gGL.getTexUnit(0)->setTextureAddressMode(old_mode); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (use_shaders && no_alpha_test) + if (no_alpha_test) { - gAlphaMaskProgram.setMinimumAlpha(0.004f); + if (use_shaders) + { + gAlphaMaskProgram.setMinimumAlpha(0.004f); + } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } } } @@ -1226,6 +1272,11 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.0f); + } + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4fv( net_color.mV ); gl_rect_2d_simple( width, height ); @@ -1233,6 +1284,10 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } } if( alpha_mask_specified || getInfo()->mWriteAllChannels ) @@ -1332,6 +1387,11 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.0f); + } + gGL.getTexUnit(0)->bind(tex, TRUE); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1339,6 +1399,10 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } } else { @@ -1357,6 +1421,11 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.0f); + } + gGL.getTexUnit(0)->bind(tex); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1365,6 +1434,10 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } } } } @@ -1391,6 +1464,11 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC { gAlphaMaskProgram.setMinimumAlpha(0.f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.0f); + } + gGL.setColorMask(false, true); @@ -1471,6 +1549,10 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC { gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + glAlphaFunc(GL_GEQUAL, 0.004f); + } LLGLSUIDefault gls_ui; -- cgit v1.2.3 From 3ac3f76fc36332e02551ed68c361c9808a8459e1 Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Fri, 19 Oct 2012 21:49:26 +0000 Subject: FIX: fixed broken baked texture rendering in lltexlayer, by enforcing correct gl state in lltexlayer.cpp FIX: updated appearance utility source package --- indra/llappearance/lltexlayer.cpp | 41 +++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index b8c8228f85..c44799f40d 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -148,6 +148,8 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet() bool use_shaders = LLGLSLShader::sNoFixedFunction; + LLGLEnable(GL_ALPHA_TEST); + if (use_shaders) { gAlphaMaskProgram.bind(); @@ -155,7 +157,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet() } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); } LLVertexBuffer::unbind(); @@ -395,6 +397,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) LLGLSUIDefault gls_ui; LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE); gGL.setColorMask(true, true); + LLGLEnable(GL_ALPHA_TEST); // clear buffer area to ensure we don't pick up UI elements { @@ -406,7 +409,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) } else { - glAlphaFunc(GL_GEQUAL, 0.0f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -421,7 +424,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); } } @@ -455,7 +458,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) } else { - glAlphaFunc(GL_GEQUAL, 0.0f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -471,7 +474,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); } } @@ -564,6 +567,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, gGL.setColorMask(false, true); gGL.setSceneBlendType(LLRender::BT_REPLACE); + LLGLEnable(GL_ALPHA_TEST); // (Optionally) replace alpha with a single component image from a tga file. if (!info->mStaticAlphaFileName.empty()) @@ -592,7 +596,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, } else { - glAlphaFunc(GL_GEQUAL, 0.0f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -607,7 +611,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); } } @@ -1117,6 +1121,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) //gPipeline.disableLights(); stop_glerror(); glDisable(GL_LIGHTING); + glEnable(GL_ALPHA_TEST); stop_glerror(); bool use_shaders = LLGLSLShader::sNoFixedFunction; @@ -1211,7 +1216,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) } else { - glAlphaFunc(GL_GEQUAL, 0.0f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } } @@ -1232,7 +1237,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); } } @@ -1274,7 +1279,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) } else { - glAlphaFunc(GL_GEQUAL, 0.0f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1286,7 +1291,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); } } @@ -1376,6 +1381,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) gGL.flush(); bool use_shaders = LLGLSLShader::sNoFixedFunction; + LLGLEnable(GL_ALPHA_TEST); if( !getInfo()->mStaticImageFileName.empty() ) { @@ -1389,7 +1395,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) } else { - glAlphaFunc(GL_GEQUAL, 0.0f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } gGL.getTexUnit(0)->bind(tex, TRUE); @@ -1401,7 +1407,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); } } else @@ -1423,7 +1429,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) } else { - glAlphaFunc(GL_GEQUAL, 0.0f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } gGL.getTexUnit(0)->bind(tex); @@ -1436,7 +1442,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } } } @@ -1459,6 +1465,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC llassert( !mParamAlphaList.empty() ); bool use_shaders = LLGLSLShader::sNoFixedFunction; + LLGLEnable(GL_ALPHA_TEST); if (use_shaders) { @@ -1466,7 +1473,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC } else { - glAlphaFunc(GL_GEQUAL, 0.0f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); } @@ -1551,7 +1558,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC } else { - glAlphaFunc(GL_GEQUAL, 0.004f); + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); } LLGLSUIDefault gls_ui; -- cgit v1.2.3 From c961b5f6571cc6147410f9e7620e5aa44c009f3f Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 22 Oct 2012 11:09:32 -0400 Subject: handling for crossing from non-server-bake to server-bake regions --- indra/llappearance/lldriverparam.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index 01184a9e23..1f7e8b8652 100755 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -190,6 +190,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) // FIXME DRANO this clobbers mWearablep, which means any code // currently using mWearablep is wrong, or at least untested. *new_param = *this; + //new_param->mWearablep = wearable; // new_param->mDriven.clear(); // clear driven list to avoid overwriting avatar driven params from wearables. return new_param; } -- cgit v1.2.3 From 866ea1dc44fb15a13e8297a1cd079297e7ddbfb9 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 29 Oct 2012 18:05:50 -0400 Subject: Fix for general graphical glitching on some cards --- indra/llappearance/lltexlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 indra/llappearance/lltexlayer.cpp (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp old mode 100644 new mode 100755 index c44799f40d..a65b9e83c6 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -1121,7 +1121,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) //gPipeline.disableLights(); stop_glerror(); glDisable(GL_LIGHTING); - glEnable(GL_ALPHA_TEST); + LLGLEnable(GL_ALPHA_TEST); stop_glerror(); bool use_shaders = LLGLSLShader::sNoFixedFunction; -- cgit v1.2.3 From ee2bc008ea8f04ffd1271787382a2b756e6293aa Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 5 Nov 2012 18:02:03 -0500 Subject: renamed a confusingly-named field --- indra/llappearance/llavatarappearance.cpp | 2 +- indra/llappearance/llavatarappearance.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 3c01a00e61..c4ff667fa1 100755 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -175,7 +175,7 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) { - mBakedTextureDatas[i].mLastTextureIndex = IMG_DEFAULT_AVATAR; + mBakedTextureDatas[i].mLastTextureID = IMG_DEFAULT_AVATAR; mBakedTextureDatas[i].mTexLayerSet = NULL; mBakedTextureDatas[i].mIsLoaded = false; mBakedTextureDatas[i].mIsUsed = false; diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index abe3599685..11ea5e5a46 100755 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -308,7 +308,7 @@ protected: typedef std::deque morph_list_t; struct BakedTextureData { - LLUUID mLastTextureIndex; + LLUUID mLastTextureID; LLTexLayerSet* mTexLayerSet; // Only exists for self bool mIsLoaded; bool mIsUsed; -- cgit v1.2.3 From 2234ed87e4da21a9da257d99d410355306c99171 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 9 Nov 2012 17:44:50 -0500 Subject: SH-3484 WIP - added additional logging under DebugAvatarCompositeBaked to try to track down baked texture issues --- indra/llappearance/lltexlayer.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index a65b9e83c6..a8bbbdbc06 100755 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -48,9 +48,6 @@ using namespace LLAvatarAppearanceDefines; -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(); -- cgit v1.2.3 From 07d05c2967fb1013a3f21c1c055ad068b2be9995 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 6 Dec 2012 22:54:50 +0000 Subject: Alpha rendering fixes for appearance utility. --- indra/llappearance/lltexlayer.cpp | 85 +-------------------------------------- 1 file changed, 1 insertion(+), 84 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index a8bbbdbc06..d1edd4f095 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -145,17 +145,11 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet() bool use_shaders = LLGLSLShader::sNoFixedFunction; - LLGLEnable(GL_ALPHA_TEST); - if (use_shaders) { gAlphaMaskProgram.bind(); gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); - } LLVertexBuffer::unbind(); @@ -394,7 +388,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) LLGLSUIDefault gls_ui; LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE); gGL.setColorMask(true, true); - LLGLEnable(GL_ALPHA_TEST); // clear buffer area to ensure we don't pick up UI elements { @@ -404,11 +397,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) { gAlphaMaskProgram.setMinimumAlpha(0.0f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 1.f ); @@ -419,10 +407,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); - } } if (mIsVisible) @@ -453,10 +437,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) { gAlphaMaskProgram.setMinimumAlpha(0.f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); - } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 0.f ); @@ -469,11 +449,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); - } - } return success; @@ -564,7 +539,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, gGL.setColorMask(false, true); gGL.setSceneBlendType(LLRender::BT_REPLACE); - LLGLEnable(GL_ALPHA_TEST); // (Optionally) replace alpha with a single component image from a tga file. if (!info->mStaticAlphaFileName.empty()) @@ -591,11 +565,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, { gAlphaMaskProgram.setMinimumAlpha(0.f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 1.f ); @@ -606,11 +575,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, { gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); - } - } // (Optional) Mask out part of the baked texture with alpha masks @@ -1118,7 +1082,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) //gPipeline.disableLights(); stop_glerror(); glDisable(GL_LIGHTING); - LLGLEnable(GL_ALPHA_TEST); stop_glerror(); bool use_shaders = LLGLSLShader::sNoFixedFunction; @@ -1211,10 +1174,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); - } } LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); @@ -1232,12 +1191,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); - } } - } } // else @@ -1272,11 +1226,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) LLGLDisable no_alpha(GL_ALPHA_TEST); if (use_shaders) { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); + gAlphaMaskProgram.setMinimumAlpha(0.000f); } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1286,10 +1236,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); - } } if( alpha_mask_specified || getInfo()->mWriteAllChannels ) @@ -1378,7 +1324,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) gGL.flush(); bool use_shaders = LLGLSLShader::sNoFixedFunction; - LLGLEnable(GL_ALPHA_TEST); if( !getInfo()->mStaticImageFileName.empty() ) { @@ -1390,11 +1335,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); - } - gGL.getTexUnit(0)->bind(tex, TRUE); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1402,10 +1342,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); - } } else { @@ -1424,11 +1360,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); - } - gGL.getTexUnit(0)->bind(tex); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1437,10 +1368,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) { gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); - } } } } @@ -1462,17 +1389,11 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC llassert( !mParamAlphaList.empty() ); bool use_shaders = LLGLSLShader::sNoFixedFunction; - LLGLEnable(GL_ALPHA_TEST); if (use_shaders) { gAlphaMaskProgram.setMinimumAlpha(0.f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.0f); - } - gGL.setColorMask(false, true); @@ -1553,10 +1474,6 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC { gAlphaMaskProgram.setMinimumAlpha(0.004f); } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.004f); - } LLGLSUIDefault gls_ui; -- cgit v1.2.3 From 802e738b77f09a67c893825dc8699f8273cebbee Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Tue, 18 Dec 2012 23:40:31 +0000 Subject: Fix for alpha blending using gl fixed-functions not matching shader implementation --- indra/llappearance/lltexlayer.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index d1edd4f095..6e184beac8 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -150,6 +150,10 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet() gAlphaMaskProgram.bind(); gAlphaMaskProgram.setMinimumAlpha(0.004f); } + else + { + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.00f); + } LLVertexBuffer::unbind(); @@ -1915,9 +1919,15 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, { if( (image_raw->getComponents() == 1) && is_mask ) { - // Note: these are static, unchanging images so it's ok to assume - // that once an image is a mask it's always a mask. - tex->setExplicitFormat( GL_ALPHA8, GL_ALPHA ); + // Convert grayscale alpha masks from single channel into RGBA. + // Fill RGB with black to allow fixed function gl calls + // to match shader implementation. + LLPointer alpha_image_raw = image_raw; + image_raw = new LLImageRaw(image_raw->getWidth(), + image_raw->getHeight(), + 4); + + image_raw->copyUnscaledAlphaMask(alpha_image_raw, LLColor4U::black); } tex->createGLTexture(0, image_raw, 0, TRUE, LLGLTexture::LOCAL); -- cgit v1.2.3 From 2f7901ab929e90748e38734555cb861a2645f256 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 20 Dec 2012 21:33:30 +0000 Subject: Skipping rendering of unneeded morph masks --- indra/llappearance/lltexlayer.cpp | 34 ++++++++++++++++++++++++---------- indra/llappearance/lltexlayer.h | 2 +- 2 files changed, 25 insertions(+), 11 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 6e184beac8..15d531259f 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -1136,7 +1136,8 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) } }//*/ - renderMorphMasks(x, y, width, height, net_color); + const bool force_render = true; + renderMorphMasks(x, y, width, height, net_color, force_render); alpha_mask_specified = TRUE; gGL.flush(); gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ONE_MINUS_DEST_ALPHA); @@ -1385,8 +1386,13 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) } static LLFastTimer::DeclareTimer FTM_RENDER_MORPH_MASKS("renderMorphMasks"); -BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color) +void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, bool force_render) { + if (!force_render && !hasMorph()) + { + lldebugs << "skipping renderMorphMasks for " << getUUID() << llendl; + return; + } LLFastTimer t(FTM_RENDER_MORPH_MASKS); BOOL success = TRUE; @@ -1423,6 +1429,11 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC { LLTexLayerParamAlpha* param = *iter; success &= param->render( x, y, width, height ); + if (!success && !force_render) + { + lldebugs << "Failed to render param " << param->getID() << " ; skipping morph mask." << llendl; + return; + } } // Approximates a min() function @@ -1448,25 +1459,29 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC } } - if( !getInfo()->mStaticImageFileName.empty() ) + if( !getInfo()->mStaticImageFileName.empty() && getInfo()->mStaticImageIsMask ) { LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); if( tex ) { - if( (tex->getComponents() == 4) || - ( (tex->getComponents() == 1) && getInfo()->mStaticImageIsMask ) ) + if( (tex->getComponents() == 4) || (tex->getComponents() == 1) ) { LLGLSNoAlphaTest gls_no_alpha_test; gGL.getTexUnit(0)->bind(tex, TRUE); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } + else + { + llwarns << "Skipping rendering of " << getInfo()->mStaticImageFileName + << "; expected 1 or 4 components." << llendl; + } } } // Draw a rectangle with the layer color to multiply the alpha by that color's alpha. // Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO ); - if (layer_color.mV[VW] != 1.f) + if ( !is_approx_equal(layer_color.mV[VW], 1.f) ) { LLGLDisable no_alpha(GL_ALPHA_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1519,8 +1534,6 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC mMorphMasksValid = TRUE; getTexLayerSet()->applyMorphMask(alpha_data, width, height, 1); } - - return success; } static LLFastTimer::DeclareTimer FTM_ADD_ALPHA_MASK("addAlphaMask"); @@ -1535,7 +1548,8 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 findNetColor( &net_color ); // TODO: eliminate need for layer morph mask valid flag invalidateMorphMasks(); - renderMorphMasks(originX, originY, width, height, net_color); + const bool force_render = false; + renderMorphMasks(originX, originY, width, height, net_color, force_render); alphaData = getAlphaData(); } if (alphaData) @@ -1544,7 +1558,7 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 { U8 curAlpha = data[i]; U16 resultAlpha = curAlpha; - resultAlpha *= (alphaData[i] + 1); + resultAlpha *= ( ((U16)alphaData[i]) + 1); resultAlpha = resultAlpha >> 8; data[i] = (U8)resultAlpha; } diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 405d2c7df4..959d6e499a 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -160,7 +160,7 @@ public: BOOL findNetColor(LLColor4* color) const; /*virtual*/ BOOL blendAlphaTexture(S32 x, S32 y, S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer /*virtual*/ void gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height); - BOOL renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color); + void renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, bool force_render); void addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height); /*virtual*/ BOOL isInvisibleAlphaMask() const; -- cgit v1.2.3 From 438ceeb008b7c4eec0fc48894935289ca352fc65 Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Fri, 25 Jan 2013 17:58:11 -0500 Subject: BUILDFIX: merge cleanup A couple of merge issues that caused the resulting code to not build. --- indra/llappearance/llavatarappearance.cpp | 10 ---------- indra/llappearance/llpolyskeletaldistortion.h | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index c4ff667fa1..89e64822f8 100755 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -169,8 +169,6 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mRoot(NULL), mWearableData(wearable_data) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - llassert_always(mWearableData); mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) @@ -495,8 +493,6 @@ void LLAvatarAppearance::computeBodySize() //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - //------------------------------------------------------------------------- // parse the file //------------------------------------------------------------------------- @@ -538,8 +534,6 @@ BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename) //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &volume_num, S32 &joint_num) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - LLJoint* joint = NULL; if (info->mIsJoint) @@ -621,8 +615,6 @@ BOOL LLAvatarAppearance::allocateCharacterJoints( U32 num ) //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) { - LLMemType mt(LLMemType::MTYPE_AVATAR); - //------------------------------------------------------------------------- // allocate joints //------------------------------------------------------------------------- @@ -675,8 +667,6 @@ void LLAvatarAppearance::clearSkeleton() //----------------------------------------------------------------------------- void LLAvatarAppearance::buildCharacter() { - LLMemType mt(LLMemType::MTYPE_AVATAR); - //------------------------------------------------------------------------- // remove all references to our existing skeleton // so we can rebuild it diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h index 170f8e8771..774bc7dfa2 100644 --- a/indra/llappearance/llpolyskeletaldistortion.h +++ b/indra/llappearance/llpolyskeletaldistortion.h @@ -119,7 +119,7 @@ public: /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;}; protected: - LL_ALIGN_16(LLVector4a>-mDefaultVec); + LL_ALIGN_16(LLVector4a mDefaultVec); typedef std::map joint_vec_map_t; joint_vec_map_t mJointScales; joint_vec_map_t mJointOffsets; -- cgit v1.2.3 From 1cf611b0592b1f91979bfbac7870b64f3623eef9 Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Wed, 6 Feb 2013 18:38:17 -0500 Subject: SH-3651 FIX Beard edits not applying on server bakes Despite incrementing the COF version, beard edits were not updating the head hash. We were not applying layers/parameters to the baked texture hashes for layers that did not contain a user-defined image. However, many layers have standard morph masks, etc that are affected by wearable parameters. Edited the LLTexLayerInterface::getWearable() method to return the proper wearable type if there is no associated local texture index, and all parameters in the wearable refer to a particular wearable type. Should be safe even if some (but not all) params have no wearable type defined. --- indra/llappearance/lltexlayer.cpp | 40 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 15d531259f..3c23f5f293 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -932,7 +932,45 @@ LLWearableType::EType LLTexLayerInterface::getWearableType() const ETextureIndex te = getLocalTextureIndex(); if (TEX_INVALID == te) { - return LLWearableType::WT_INVALID; + LLWearableType::EType type = LLWearableType::WT_INVALID; + param_color_list_t::const_iterator color_iter = mParamColorList.begin(); + param_alpha_list_t::const_iterator alpha_iter = mParamAlphaList.begin(); + + for (; color_iter != mParamColorList.end(); color_iter++) + { + LLTexLayerParamColor* param = *color_iter; + if (param) + { + LLWearableType::EType new_type = (LLWearableType::EType)param->getWearableType(); + if (new_type != LLWearableType::WT_INVALID && new_type != type) + { + if (type != LLWearableType::WT_INVALID) + { + return LLWearableType::WT_INVALID; + } + type = new_type; + } + } + } + + for (; alpha_iter != mParamAlphaList.end(); alpha_iter++) + { + LLTexLayerParamAlpha* param = *alpha_iter; + if (param) + { + LLWearableType::EType new_type = (LLWearableType::EType)param->getWearableType(); + if (new_type != LLWearableType::WT_INVALID && new_type != type) + { + if (type != LLWearableType::WT_INVALID) + { + return LLWearableType::WT_INVALID; + } + type = new_type; + } + } + } + + return type; } return LLAvatarAppearanceDictionary::getTEWearableType(te); } -- cgit v1.2.3 From 705a23ac0d80da44e61b0b78515dca0768909b32 Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Thu, 14 Feb 2013 13:41:36 -0500 Subject: SH-3803 FIX Missing Wearable reported in sunshine viewer Newly refactored wearable parsing did not account for extra whitespace cleanly. Updated the code to handle extra blank lines in the wearable assets. --- indra/llappearance/llwearable.cpp | 50 +++++++++++++++++++++++---------------- indra/llappearance/llwearable.h | 1 + 2 files changed, 30 insertions(+), 21 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index b33adb254d..9fb8b7749f 100755 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -191,7 +191,7 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // We are using a local max buffer size here to avoid issues // if MAX_STRING size changes. const U32 PARSE_BUFFER_SIZE = 2048; - char buffer[2048]; /* Flawfinder: ignore */ + char buffer[PARSE_BUFFER_SIZE]; /* Flawfinder: ignore */ char uuid_buffer[37]; /* Flawfinder: ignore */ // This data is being generated on the viewer. @@ -205,12 +205,11 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, } // read header and version - if (!input_stream.good()) + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { llwarns << "Failed to read wearable asset input stream." << llendl; return LLWearable::FAILURE; } - input_stream.getline(buffer, PARSE_BUFFER_SIZE); if ( 1 != sscanf( /* Flawfinder: ignore */ buffer, "LLWearable version %d\n", @@ -230,8 +229,8 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, return LLWearable::FAILURE; } - // name - if (!input_stream.good()) + // name may be empty + if (!input_stream.good()) { llwarns << "Bad Wearable asset: early end of input stream " << "while reading name" << llendl; @@ -240,7 +239,7 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, input_stream.getline(buffer, PARSE_BUFFER_SIZE); mName = buffer; - // description + // description may be empty if (!input_stream.good()) { llwarns << "Bad Wearable asset: early end of input stream " @@ -250,14 +249,13 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, input_stream.getline(buffer, PARSE_BUFFER_SIZE); mDescription = buffer; - // permissions - if (!input_stream.good()) + // permissions may have extra empty lines before the correct line + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { llwarns << "Bad Wearable asset: early end of input stream " << "while reading permissions" << llendl; return LLWearable::FAILURE; } - input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 perm_version = -1; if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) || perm_version != 0 ) @@ -271,13 +269,12 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, } // sale info - if (!input_stream.good()) + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { llwarns << "Bad Wearable asset: early end of input stream " << "while reading sale info" << llendl; return LLWearable::FAILURE; } - input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 sale_info_version = -1; if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) || sale_info_version != 0 ) @@ -306,13 +303,12 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, } // wearable type - if (!input_stream.good()) + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { llwarns << "Bad Wearable asset: early end of input stream " << "while reading type" << llendl; return LLWearable::FAILURE; } - input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 type = -1; if ( 1 != sscanf( buffer, "type %d\n", &type ) ) { @@ -331,13 +327,12 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, } // parameters header - if (!input_stream.good()) + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { llwarns << "Bad Wearable asset: early end of input stream " << "while reading parameters header" << llendl; return LLWearable::FAILURE; } - input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 num_parameters = -1; if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) ) { @@ -363,13 +358,12 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, S32 i; for( i = 0; i < num_parameters; i++ ) { - if (!input_stream.good()) + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { llwarns << "Bad Wearable asset: early end of input stream " << "while reading parameter #" << i << llendl; return LLWearable::FAILURE; } - input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 param_id = 0; F32 param_weight = 0.f; if ( 2 != sscanf( buffer, "%d %f\n", ¶m_id, ¶m_weight ) ) @@ -381,13 +375,12 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, } // textures header - if (!input_stream.good()) + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { llwarns << "Bad Wearable asset: early end of input stream " << "while reading textures header" << i << llendl; return LLWearable::FAILURE; } - input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 num_textures = -1; if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) ) { @@ -404,13 +397,12 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // textures for( i = 0; i < num_textures; i++ ) { - if (!input_stream.good()) + if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { llwarns << "Bad Wearable asset: early end of input stream " << "while reading textures #" << i << llendl; return LLWearable::FAILURE; } - input_stream.getline(buffer, PARSE_BUFFER_SIZE); S32 te = 0; if ( 2 != sscanf( /* Flawfinder: ignore */ buffer, @@ -450,6 +442,22 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, return LLWearable::SUCCESS; } +BOOL LLWearable::getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size) +{ + if (!input_stream.good()) + { + return FALSE; + } + + do + { + input_stream.getline(buffer, buffer_size); + } + while (input_stream.good() && buffer[0]=='\0'); + + return input_stream.good(); +} + void LLWearable::setType(LLWearableType::EType type, LLAvatarAppearance *avatarp) { diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index 4a59811795..6f5a1e14e8 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -119,6 +119,7 @@ protected: void destroyTextures(); void createVisualParams(LLAvatarAppearance *avatarp); void createLayers(S32 te, LLAvatarAppearance *avatarp); + BOOL getNextPopulatedLine(std::istream& input_stream, char* buffer, U32 buffer_size); static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml. S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created. -- cgit v1.2.3 From d1c144519306cae7eff7f781417482c85068988c Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Thu, 28 Feb 2013 17:25:37 -0500 Subject: SH-3909 Support avatar height offset Adding a new visual param that allows users to manually adjust an offset for how far off the ground (+ or -) their avatar's root bone is. Supports the +-2m range people are used to adjusting in their viewers, but new implementation should support server-generated appearances. --- indra/llappearance/llavatarappearance.cpp | 9 ++++++++- indra/llappearance/llavatarappearance.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 89e64822f8..2d5744bb5e 100755 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -462,6 +462,10 @@ void LLAvatarAppearance::computeBodySize() LLVector3 foot = mFootLeftp->getPosition(); + F32 old_offset = mAvatarOffset.mV[VZ]; + + mAvatarOffset.mV[VZ] = getVisualParamWeight(11001); + mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] - knee.mV[VZ] * hip_scale.mV[VZ] - ankle.mV[VZ] * knee_scale.mV[VZ] - @@ -481,7 +485,10 @@ void LLAvatarAppearance::computeBodySize() new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH; new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH; - if (new_body_size != mBodySize) + mAvatarOffset.mV[VX] = 0.0f; + mAvatarOffset.mV[VY] = 0.0f; + + if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ]) { mBodySize = new_body_size; bodySizeChanged(); diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 11ea5e5a46..bce2540258 100755 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -160,6 +160,7 @@ protected: //-------------------------------------------------------------------- public: LLVector3 mBodySize; + LLVector3 mAvatarOffset; protected: F32 mPelvisToFoot; -- cgit v1.2.3 From fa3f91e454ac82beffe4aca3789445e8ddf2b27f Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Thu, 28 Feb 2013 23:32:00 +0000 Subject: SH-3798 FIX avatar skins look dull Wearable parsing error caused last texture in some assets to fail to parse. Parser now does not throw an error if the wearable does not end in a newline --- indra/llappearance/llwearable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 9fb8b7749f..4028c1dfad 100755 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -455,7 +455,7 @@ BOOL LLWearable::getNextPopulatedLine(std::istream& input_stream, char* buffer, } while (input_stream.good() && buffer[0]=='\0'); - return input_stream.good(); + return (buffer[0] != '\0'); } -- cgit v1.2.3 From 5a436e46f6893719fc91a1cb70813671cb2a6d44 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 8 Mar 2013 17:07:17 -0500 Subject: SH-3959 WIP - pass information about type of fetched image - server bake, host bake, map tile, etc - down the chain so LLTextureFetchWorker can adjust behavior as needed --- indra/llappearance/lltexturemanagerbridge.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 indra/llappearance/lltexturemanagerbridge.h (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexturemanagerbridge.h b/indra/llappearance/lltexturemanagerbridge.h old mode 100644 new mode 100755 -- cgit v1.2.3 From 46ab23c94be164cb174a97bde11cc38067f9edd0 Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 11 Mar 2013 18:02:16 -0400 Subject: llinventory merge fixes --- indra/llappearance/llwearable.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 4028c1dfad..d86a460511 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -81,13 +81,13 @@ BOOL LLWearable::exportStream( std::ostream& output_stream ) const output_stream << mDescription << "\n"; // permissions - if( !mPermissions.exportStream( output_stream ) ) + if( !mPermissions.exportLegacyStream( output_stream ) ) { return FALSE; } // sale info - if( !mSaleInfo.exportStream( output_stream ) ) + if( !mSaleInfo.exportLegacyStream( output_stream ) ) { return FALSE; } @@ -263,7 +263,7 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, llwarns << "Bad Wearable asset: missing valid permissions" << llendl; return LLWearable::FAILURE; } - if( !mPermissions.importStream( input_stream ) ) + if( !mPermissions.importLegacyStream( input_stream ) ) { return LLWearable::FAILURE; } @@ -288,7 +288,7 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // up the vast majority of the tasks. BOOL has_perm_mask = FALSE; U32 perm_mask = 0; - if( !mSaleInfo.importStream(input_stream, has_perm_mask, perm_mask) ) + if( !mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask) ) { return LLWearable::FAILURE; } -- cgit v1.2.3 From 0cda978db922f7ddbe94809e6ea6bd5256cea027 Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 11 Mar 2013 18:15:40 -0400 Subject: #include fix --- indra/llappearance/lltexlayer.cpp | 3 +-- indra/llappearance/lltexlayerparams.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index c075035226..f951a982e5 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -38,8 +38,7 @@ #include "llvfs.h" #include "lltexlayerparams.h" #include "lltexturemanagerbridge.h" -//#include "llrender2dutils.h" -#include "..\llui\llui.h" +#include "../llui/llui.h" #include "llwearable.h" #include "llwearabledata.h" #include "llvertexbuffer.h" diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 1adc294705..6aae9a8cc1 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -33,8 +33,7 @@ #include "llquantize.h" #include "lltexlayer.h" #include "lltexturemanagerbridge.h" -//#include "llrender2dutils.h" -#include "..\llui\llui.h" +#include "../llui/llui.h" #include "llwearable.h" //----------------------------------------------------------------------------- -- cgit v1.2.3 From 7ea7b236d88ec599c5bae561689b9d079256e551 Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Tue, 2 Apr 2013 18:32:57 -0400 Subject: BUILDFIX commit policy fixes --- indra/llappearance/llwearabledata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h index 3e92f2ead8..03bd179f25 100644 --- a/indra/llappearance/llwearabledata.h +++ b/indra/llappearance/llwearabledata.h @@ -2,7 +2,7 @@ * @file llwearabledata.h * @brief LLWearableData class header file * - * $LicenseInfo:firstyear=20012license=viewerlgpl$ + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * -- cgit v1.2.3 From b724791c2adb3e63c00547c40de2ae1b6ce45b9b Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Wed, 3 Apr 2013 18:59:50 -0400 Subject: SH-4050 FIX camera goes below ground when avatar offset set to 0 Added a constraint to ensure that the avatar's height (with offset) does not go below 0.1 meters. Camera was getting confused since the avatar's effective height was negative. Note the avatar is mostly underground/contorted even at 0.1 meters, but most users setting values this low will be making ultra-tinies and would be hiding the avatar mesh. Camera stays above ground when height is at 0.1. --- indra/llappearance/llavatarappearance.cpp | 21 ++++++++++++++++++++- indra/llappearance/llavatarappearancedefines.h | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 2d5744bb5e..37b7f7b14e 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -464,7 +464,7 @@ void LLAvatarAppearance::computeBodySize() F32 old_offset = mAvatarOffset.mV[VZ]; - mAvatarOffset.mV[VZ] = getVisualParamWeight(11001); + mAvatarOffset.mV[VZ] = getVisualParamWeight(AVATAR_HOVER); mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] - knee.mV[VZ] * hip_scale.mV[VZ] - @@ -488,6 +488,25 @@ void LLAvatarAppearance::computeBodySize() mAvatarOffset.mV[VX] = 0.0f; mAvatarOffset.mV[VY] = 0.0f; + // Certain configurations of avatars can force the overall height (with offset) to go negative. + // Enforce a constraint to make sure we don't go below 0.1 meters. + // Camera positioning and other things start to break down when your avatar is "walking" while being fully underground + if (new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] < 0.1f) + { + mAvatarOffset.mV[VZ] = -(new_body_size.mV[VZ] - 0.11f); // avoid floating point rounding making the above check continue to fail. + + llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f); + + if (mWearableData) + { + LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0); + if (shape) + { + shape->setVisualParamWeight(AVATAR_HOVER, mAvatarOffset.mV[VZ], false); + } + } + } + if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ]) { mBodySize = new_body_size; diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h index 496f85c107..8a1d2c4707 100644 --- a/indra/llappearance/llavatarappearancedefines.h +++ b/indra/llappearance/llavatarappearancedefines.h @@ -41,6 +41,8 @@ extern const S32 SCRATCH_TEX_WIDTH; extern const S32 SCRATCH_TEX_HEIGHT; extern const S32 IMPOSTOR_PERIOD; +static const U32 AVATAR_HOVER = 11001; + //-------------------------------------------------------------------- // Enums //-------------------------------------------------------------------- -- cgit v1.2.3 From 08bd67c0dda8d013ad490e89543297ebc3a15e77 Mon Sep 17 00:00:00 2001 From: Nyx Linden Date: Thu, 4 Apr 2013 11:38:23 -0400 Subject: SH-4059 FIX other's hover parameters affects your avatar's setting Added an additional sanity check to make sure that other avatars don't affect your wearables. --- indra/llappearance/llavatarappearance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llappearance') diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 37b7f7b14e..3bb759d458 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -497,7 +497,7 @@ void LLAvatarAppearance::computeBodySize() llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f); - if (mWearableData) + if (mWearableData && isSelf()) { LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0); if (shape) -- cgit v1.2.3