diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index aa1e4371a..0e70a0d6e 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -312,11 +312,11 @@ LLGLenum LLGLTexture::getPrimaryFormat() const return mGLTexturep->getPrimaryFormat() ; } -BOOL LLGLTexture::getIsAlphaMask(const F32 max_rmse) const +BOOL LLGLTexture::getIsAlphaMask(const F32 max_rmse, const F32 max_mid) const { llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getIsAlphaMask(max_rmse) ; + return mGLTexturep->getIsAlphaMask(max_rmse, max_mid) ; } BOOL LLGLTexture::getMask(const LLVector2 &tc) diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index a27fcb630..569a28af4 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -140,7 +140,7 @@ public: BOOL getBoundRecently() const; S32Bytes getTextureMemory() const ; LLGLenum getPrimaryFormat() const; - BOOL getIsAlphaMask(const F32 max_rmse) const ; + BOOL getIsAlphaMask(const F32 max_rmse, const F32 max_mid) const ; LLTexUnit::eTextureType getTarget(void) const ; BOOL getMask(const LLVector2 &tc); F32 getTimePassedSinceLastBound(); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 90676d7f5..9d5c14e47 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -492,6 +492,7 @@ void LLImageGL::init(BOOL usemipmaps) mIsMask = FALSE; mMaskRMSE = 1.f ; + mMaskMidPercentile = 1.f; mNeedsAlphaAndPickMask = FALSE ; mAlphaStride = 0 ; @@ -2083,6 +2084,9 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) U32 sample[16]; memset(sample, 0, sizeof(U32)*16); + U32 min = 0, max = 0; + U32 mids = 0; + // generate histogram of quantized alpha. // also add-in the histogram of a 2x2 box-sampled version. The idea is // this will mid-skew the data (and thus increase the chances of not @@ -2114,6 +2118,10 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) ++sample[s3/16]; ++sample[s4/16]; + min = std::min(std::min(std::min(std::min(min, s1), s2), s3), s4); + max = std::max(std::max(std::max(std::max(max, s1), s2), s3), s4); + mids += (s1 > 2 && s1 < 253) + (s2 > 2 && s2 < 253) + (s3 > 2 && s3 < 253) + (s4 > 2 && s4 < 253); + const U32 asum = (s1+s2+s3+s4); alphatotal += asum; sample[asum/(16*4)] += 4; @@ -2142,9 +2150,18 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) ++sample[s1/16]; current += mAlphaStride; + min = std::min(min, s1); + max = std::max(max, s1); + mids += (s1 > 2 && s1 < 253); + if(i%2==0) { - S32 avg = (s1+current[mAlphaStride])/2; + const U32 s2 = *current; + min = std::min(min, s2); + max = std::max(max, s2); + mids += (s2 > 2 && s2 < 253); + + S32 avg = (s1+s2)/2; if(avg >=128) avg-=255; sum+=F64(avg*avg*2)/F64(length); @@ -2186,7 +2203,8 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) mIsMask = TRUE; } - mMaskRMSE = sqrt(sum)/255.0; + mMaskMidPercentile = (F32)mids / (F32)length; + mMaskRMSE = ((max-min)%255)==0 ? sqrt(sum)/255.0 : FLT_MAX; /*std::list > &data = sTextureMaskMap[getTexName()]; data.clear(); diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 623013678..8508646c3 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -136,7 +136,7 @@ public: BOOL getHasGLTexture() const { return mTexName != 0; } LLGLuint getTexName() const { return mTexName; } - BOOL getIsAlphaMask(const F32 max_rmse) const { return mNeedsAlphaAndPickMask && (max_rmse < 0.f ? (bool)mIsMask : (mMaskRMSE <= max_rmse)); } + BOOL getIsAlphaMask(const F32 max_rmse, const F32 max_mid) const { return mNeedsAlphaAndPickMask && (max_rmse < 0.f ? (bool)mIsMask : (mMaskRMSE <= max_rmse && mMaskMidPercentile <= max_mid)); } BOOL getIsResident(BOOL test_now = FALSE); // not const @@ -191,6 +191,7 @@ private: BOOL mIsMask; F32 mMaskRMSE; + F32 mMaskMidPercentile; BOOL mNeedsAlphaAndPickMask; S8 mAlphaStride ; S8 mAlphaOffset ; diff --git a/indra/newview/app_settings/settings_sh.xml b/indra/newview/app_settings/settings_sh.xml index c06a6f710..73e7d1cc3 100644 --- a/indra/newview/app_settings/settings_sh.xml +++ b/indra/newview/app_settings/settings_sh.xml @@ -216,7 +216,18 @@ Type F32 Value - 0.09 + 0.2 + + SHAutoMaskMaxMid + + Comment + Sets the maximum percent of mid-range alpha pixels textures for alphamasking. (SHUseRMSEAutoMask must be TRUE for this to have any effect) + Persist + 1 + Type + F32 + Value + 0.25 SHAlwaysSoftenShadows diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 1b334e3ed..e1c909a5d 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1126,9 +1126,10 @@ bool LLFace::canRenderAsMask() static const LLCachedControl use_rmse_auto_mask("SHUseRMSEAutoMask",false); static const LLCachedControl auto_mask_max_rmse("SHAutoMaskMaxRMSE",.09f); + static const LLCachedControl auto_mask_max_mid("SHAutoMaskMaxMid", .25f); if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha (te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask - (getTexture()->getIsAlphaMask((!getViewerObject()->isAttachment() && use_rmse_auto_mask) ? auto_mask_max_rmse : -1.f))) // texture actually qualifies for masking (lazily recalculated but expensive) + (getTexture()->getIsAlphaMask((!getViewerObject()->isAttachment() && use_rmse_auto_mask) ? auto_mask_max_rmse : -1.f, auto_mask_max_mid))) // texture actually qualifies for masking (lazily recalculated but expensive) { if (LLPipeline::sRenderDeferred) { diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index bdd363757..75b00857d 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -282,7 +282,8 @@ void LLPreviewTexture::draw() static const LLCachedControl use_rmse_auto_mask("SHUseRMSEAutoMask",false); static const LLCachedControl auto_mask_max_rmse("SHAutoMaskMaxRMSE",.09f); - if (mAlphaMaskResult != mImage->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f)) + static const LLCachedControl auto_mask_max_mid("SHAutoMaskMaxMid", .25f); + if (mAlphaMaskResult != mImage->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f, auto_mask_max_mid)) { mAlphaMaskResult = !mAlphaMaskResult; if (!mAlphaMaskResult) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 98ec63947..ffbd42531 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2044,6 +2044,27 @@ void handle_attachment_edit(const LLUUID& idItem) } // [/SL:KB] +bool add_object_to_blacklist( const LLUUID& id, const std::string& entry_name ) +{ + // ...don't kill the avatar + if (id != gAgentID) + { + LLSD indata; + indata["entry_type"] = LLAssetType::AT_OBJECT; + indata["entry_name"] = entry_name; + indata["entry_agent"] = gAgentID; + + LLFloaterBlacklist::addEntry(id, indata); + LLViewerObject *objectp = gObjectList.findObject(id); + if (objectp) + { + gObjectList.killObject(objectp); + } + return true; + } + return false; +} + // Derenderizer. Originally by Phox. class LLObjectDerender : public view_listener_t { @@ -2053,76 +2074,64 @@ class LLObjectDerender : public view_listener_t if(!slct)return true; LLUUID id = slct->getID(); - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLUUID root_key; - //delivers null in linked parts if used as getFirstRootNode() - LLSelectNode* node = selection->getFirstRootNode(NULL,TRUE); - /*this works for derendering entire object if child is selected - - LLSelectNode* node = selection->getFirstNode(); - //Delivers node even when linked parts, but only first node - - LLViewerObject* obj = node->getObject(); - LLViewerObject* parent = (LLViewerObject*)obj->getParent();*/ - - if(node) - { - root_key = node->getObject()->getID(); - LL_INFOS() << "Derender node has key " << root_key << LL_ENDL; - } - else - { - LL_INFOS() << "Derender node is null " << LL_ENDL; - } - - LLViewerRegion* cur_region = gAgent.getRegion(); + bool added = false; std::string entry_name; if (slct->isAvatar()) { LLNameValue* firstname = slct->getNVPair("FirstName"); LLNameValue* lastname = slct->getNVPair("LastName"); entry_name = llformat("Derendered: (AV) %s %s",firstname->getString(),lastname->getString()); + added |= add_object_to_blacklist(id, entry_name); } else { - if (root_key.isNull()) - { - return true; - } - id = root_key; - if (!node->mName.empty()) - { - if(cur_region) - entry_name = llformat("Derendered: %s in region %s",node->mName.c_str(),cur_region->getName().c_str()); - else - entry_name = llformat("Derendered: %s",node->mName.c_str()); - } - else - { - if(cur_region) - entry_name = llformat("Derendered: (unknown object) in region %s",cur_region->getName().c_str()); - else - entry_name = "Derendered: (unknown object)"; + LLViewerRegion* cur_region = gAgent.getRegion(); + std::list nodes; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + nodes.push_back(*iter); + } + if (nodes.empty()) + { + nodes.push_back(LLSelectMgr::getInstance()->getSelection()->getFirstNode()); + } + + for( auto node : nodes ) + { + if (node) + { + id = node->getObject()->getID(); + } + if (id.isNull()) + { + continue; + } + LL_INFOS() << "Derender node has key " << id << LL_ENDL; + if (!node->mName.empty()) + { + if (cur_region) + entry_name = llformat("Derendered: %s in region %s", node->mName.c_str(), cur_region->getName().c_str()); + else + entry_name = llformat("Derendered: %s", node->mName.c_str()); + } + else + { + if (cur_region) + entry_name = llformat("Derendered: (unknown object) in region %s", cur_region->getName().c_str()); + else + entry_name = "Derendered: (unknown object)"; + + } + added |= add_object_to_blacklist(id, entry_name); } } - // ...don't kill the avatar - if (id != gAgentID) + if (added) { - LLSD indata; - indata["entry_type"] = 6; //AT_TEXTURE - indata["entry_name"] = entry_name; - indata["entry_agent"] = gAgentID; - - LLFloaterBlacklist::addEntry(id,indata); LLSelectMgr::getInstance()->deselectAll(); - LLViewerObject *objectp = gObjectList.findObject(id); - if (objectp) - { - gObjectList.killObject(objectp); - } } return true; } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 6c6980d29..54f249770 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -368,7 +368,8 @@ public: }*/ static const LLCachedControl use_rmse_auto_mask("SHUseRMSEAutoMask",false); static const LLCachedControl auto_mask_max_rmse("SHAutoMaskMaxRMSE",.09f); - addText(xpos, ypos, llformat("Mask: %s", imagep->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f) ? "TRUE":"FALSE")); ypos += y_inc; + static const LLCachedControl auto_mask_max_mid("SHAutoMaskMaxMid", .25f); + addText(xpos, ypos, llformat("Mask: %s", imagep->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f, auto_mask_max_mid) ? "TRUE":"FALSE")); ypos += y_inc; addText(xpos, ypos, llformat("ID: %s", imagep->getID().asString().c_str())); ypos += y_inc; } }