diff options
Diffstat (limited to 'indra/llappearance/lltexlayerparams.cpp')
-rw-r--r-- | indra/llappearance/lltexlayerparams.cpp | 1188 |
1 files changed, 594 insertions, 594 deletions
diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 19eb0c784d..b55df16185 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -1,594 +1,594 @@ -/** - * @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 "llimagetga.h" -#include "llquantize.h" -#include "lltexlayer.h" -#include "lltexturemanagerbridge.h" -#include "../llui/llui.h" -#include "llwearable.h" -#include "llfasttimer.h" - -//----------------------------------------------------------------------------- -// LLTexLayerParam -//----------------------------------------------------------------------------- -LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) - : LLViewerVisualParam(), - mTexLayer(layer), - mAvatarAppearance(NULL) -{ - if (mTexLayer != NULL) - { - mAvatarAppearance = mTexLayer->getTexLayerSet()->getAvatarAppearance(); - } - else - { - LL_ERRS() << "LLTexLayerParam constructor passed with NULL reference for layer!" << LL_ENDL; - } -} - -LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance) - : LLViewerVisualParam(), - mTexLayer(NULL), - mAvatarAppearance(appearance) -{ -} - -LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& pOther) - : LLViewerVisualParam(pOther), - mTexLayer(pOther.mTexLayer), - mAvatarAppearance(pOther.mAvatarAppearance) -{ -} - -bool LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, bool add_to_appearance) -{ - LLViewerVisualParam::setInfo(info); - - if (add_to_appearance) - { - mAvatarAppearance->addVisualParam( this); - this->setParamLocation(mAvatarAppearance->isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); - } - - return true; -} - - -//----------------------------------------------------------------------------- -// LLTexLayerParamAlpha -//----------------------------------------------------------------------------- - -// static -LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances; - -// static -void LLTexLayerParamAlpha::dumpCacheByteCount() -{ - S32 gl_bytes = 0; - getCacheByteCount( &gl_bytes); - LL_INFOS() << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << LL_ENDL; -} - -// static -void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes) -{ - *gl_bytes = 0; - - for (LLTexLayerParamAlpha* instance : sInstances) - { - LLGLTexture* 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), - mStaticImageTGA(), - mStaticImageRaw(), - 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), - mStaticImageTGA(), - mStaticImageRaw(), - mNeedsCreateTexture(false), - mStaticImageInvalid(false), - mAvgDistortionVec(1.f, 1.f, 1.f), - mCachedEffectiveWeight(0.f) -{ - sInstances.push_front(this); -} - -LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther) - : LLTexLayerParam(pOther), - mCachedProcessedTexture(pOther.mCachedProcessedTexture), - mStaticImageTGA(pOther.mStaticImageTGA), - mStaticImageRaw(pOther.mStaticImageRaw), - mNeedsCreateTexture(pOther.mNeedsCreateTexture.load()), - mStaticImageInvalid(pOther.mStaticImageInvalid), - mAvgDistortionVec(pOther.mAvgDistortionVec), - mCachedEffectiveWeight(pOther.mCachedEffectiveWeight) -{ - sInstances.push_front(this); -} - -LLTexLayerParamAlpha::~LLTexLayerParamAlpha() -{ - deleteCaches(); - sInstances.remove(this); -} - -/*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const -{ - return new LLTexLayerParamAlpha(*this); -} - -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) -{ - 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. - { - mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet()); - mTexLayer->invalidateMorphMasks(); - } - } -} - -void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value) -{ - // do not animate dummy parameters - if (mIsDummy) - { - setWeight(target_value); - return; - } - - mTargetWeight = target_value; - setWeight(target_value); - mIsAnimating = true; - if (mNext) - { - mNext->setAnimationTarget(target_value); - } -} - -void LLTexLayerParamAlpha::animate(F32 delta) -{ - if (mNext) - { - mNext->animate(delta); - } -} - -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) -{ - LL_PROFILE_ZONE_SCOPED; - 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(); - - if (mStaticImageTGA.isNull()) - { - LL_WARNS() << "Unable to load static file: " << info->mStaticImageFileName << LL_ENDL; - 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)) - { - 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.notNull(); - - 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; - LL_DEBUGS() << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << LL_ENDL; - } - - 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); - } - - 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 - { - 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 -// { -// LL_WARNS() << "<param_alpha> element is missing tga_file attribute." << LL_ENDL; -// } - - 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(const LLTexLayerParamColor& pOther) - : LLTexLayerParam(pOther), - mAvgDistortionVec(pOther.mAvgDistortionVec) -{ -} - -LLTexLayerParamColor::~LLTexLayerParamColor() -{ -} - -/*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const -{ - return new LLTexLayerParamColor(*this); -} - -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) -{ - if (mIsAnimating) - { - 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; - - const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); - - 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(); - if (mTexLayer) - { - mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet()); - } - } - -// LL_INFOS() << "param " << mName << " = " << new_weight << LL_ENDL; - } -} - -void LLTexLayerParamColor::setAnimationTarget(F32 target_value) -{ - // set value first then set interpolating flag to ignore further updates - mTargetWeight = target_value; - setWeight(target_value); - mIsAnimating = true; - if (mNext) - { - mNext->setAnimationTarget(target_value); - } -} - -void LLTexLayerParamColor::animate(F32 delta) -{ - if (mNext) - { - mNext->animate(delta); - } -} - -//----------------------------------------------------------------------------- -// 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) - { - LL_WARNS() << "<param_color> is missing <value> sub-elements" << LL_ENDL; - return false; - } - - if ((mOperation == LLTexLayerParamColor::OP_BLEND) && (mNumColors != 1)) - { - LL_WARNS() << "<param_color> with operation\"blend\" must have exactly one <value>" << LL_ENDL; - return false; - } - - return true; -} +/**
+ * @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 "llimagetga.h"
+#include "llquantize.h"
+#include "lltexlayer.h"
+#include "lltexturemanagerbridge.h"
+#include "../llui/llui.h"
+#include "llwearable.h"
+#include "llfasttimer.h"
+
+//-----------------------------------------------------------------------------
+// LLTexLayerParam
+//-----------------------------------------------------------------------------
+LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer)
+ : LLViewerVisualParam(),
+ mTexLayer(layer),
+ mAvatarAppearance(NULL)
+{
+ if (mTexLayer != NULL)
+ {
+ mAvatarAppearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
+ }
+ else
+ {
+ LL_ERRS() << "LLTexLayerParam constructor passed with NULL reference for layer!" << LL_ENDL;
+ }
+}
+
+LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance)
+ : LLViewerVisualParam(),
+ mTexLayer(NULL),
+ mAvatarAppearance(appearance)
+{
+}
+
+LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& pOther)
+ : LLViewerVisualParam(pOther),
+ mTexLayer(pOther.mTexLayer),
+ mAvatarAppearance(pOther.mAvatarAppearance)
+{
+}
+
+bool LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, bool add_to_appearance)
+{
+ LLViewerVisualParam::setInfo(info);
+
+ if (add_to_appearance)
+ {
+ mAvatarAppearance->addVisualParam( this);
+ this->setParamLocation(mAvatarAppearance->isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// LLTexLayerParamAlpha
+//-----------------------------------------------------------------------------
+
+// static
+LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances;
+
+// static
+void LLTexLayerParamAlpha::dumpCacheByteCount()
+{
+ S32 gl_bytes = 0;
+ getCacheByteCount( &gl_bytes);
+ LL_INFOS() << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << LL_ENDL;
+}
+
+// static
+void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
+{
+ *gl_bytes = 0;
+
+ for (LLTexLayerParamAlpha* instance : sInstances)
+ {
+ LLGLTexture* 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),
+ mStaticImageTGA(),
+ mStaticImageRaw(),
+ 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),
+ mStaticImageTGA(),
+ mStaticImageRaw(),
+ mNeedsCreateTexture(false),
+ mStaticImageInvalid(false),
+ mAvgDistortionVec(1.f, 1.f, 1.f),
+ mCachedEffectiveWeight(0.f)
+{
+ sInstances.push_front(this);
+}
+
+LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther)
+ : LLTexLayerParam(pOther),
+ mCachedProcessedTexture(pOther.mCachedProcessedTexture),
+ mStaticImageTGA(pOther.mStaticImageTGA),
+ mStaticImageRaw(pOther.mStaticImageRaw),
+ mNeedsCreateTexture(pOther.mNeedsCreateTexture.load()),
+ mStaticImageInvalid(pOther.mStaticImageInvalid),
+ mAvgDistortionVec(pOther.mAvgDistortionVec),
+ mCachedEffectiveWeight(pOther.mCachedEffectiveWeight)
+{
+ sInstances.push_front(this);
+}
+
+LLTexLayerParamAlpha::~LLTexLayerParamAlpha()
+{
+ deleteCaches();
+ sInstances.remove(this);
+}
+
+/*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const
+{
+ return new LLTexLayerParamAlpha(*this);
+}
+
+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)
+{
+ 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.
+ {
+ mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
+ mTexLayer->invalidateMorphMasks();
+ }
+ }
+}
+
+void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)
+{
+ // do not animate dummy parameters
+ if (mIsDummy)
+ {
+ setWeight(target_value);
+ return;
+ }
+
+ mTargetWeight = target_value;
+ setWeight(target_value);
+ mIsAnimating = true;
+ if (mNext)
+ {
+ mNext->setAnimationTarget(target_value);
+ }
+}
+
+void LLTexLayerParamAlpha::animate(F32 delta)
+{
+ if (mNext)
+ {
+ mNext->animate(delta);
+ }
+}
+
+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)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ 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();
+
+ if (mStaticImageTGA.isNull())
+ {
+ LL_WARNS() << "Unable to load static file: " << info->mStaticImageFileName << LL_ENDL;
+ 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))
+ {
+ 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.notNull();
+
+ 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;
+ LL_DEBUGS() << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << LL_ENDL;
+ }
+
+ 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);
+ }
+
+ 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
+ {
+ 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
+// {
+// LL_WARNS() << "<param_alpha> element is missing tga_file attribute." << LL_ENDL;
+// }
+
+ 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(const LLTexLayerParamColor& pOther)
+ : LLTexLayerParam(pOther),
+ mAvgDistortionVec(pOther.mAvgDistortionVec)
+{
+}
+
+LLTexLayerParamColor::~LLTexLayerParamColor()
+{
+}
+
+/*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const
+{
+ return new LLTexLayerParamColor(*this);
+}
+
+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)
+{
+ if (mIsAnimating)
+ {
+ 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;
+
+ const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
+
+ 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();
+ if (mTexLayer)
+ {
+ mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
+ }
+ }
+
+// LL_INFOS() << "param " << mName << " = " << new_weight << LL_ENDL;
+ }
+}
+
+void LLTexLayerParamColor::setAnimationTarget(F32 target_value)
+{
+ // set value first then set interpolating flag to ignore further updates
+ mTargetWeight = target_value;
+ setWeight(target_value);
+ mIsAnimating = true;
+ if (mNext)
+ {
+ mNext->setAnimationTarget(target_value);
+ }
+}
+
+void LLTexLayerParamColor::animate(F32 delta)
+{
+ if (mNext)
+ {
+ mNext->animate(delta);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// 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)
+ {
+ LL_WARNS() << "<param_color> is missing <value> sub-elements" << LL_ENDL;
+ return false;
+ }
+
+ if ((mOperation == LLTexLayerParamColor::OP_BLEND) && (mNumColors != 1))
+ {
+ LL_WARNS() << "<param_color> with operation\"blend\" must have exactly one <value>" << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
|