From d7468ce79ee27ec7577d430694ce64e5649cb925 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Fri, 16 Aug 2024 14:07:54 -0700 Subject: [PATCH 01/15] Add TE support for texture gamma on legacy content. This is a work around for legacy content to ensure that users can get alpha blending for their stuff closer to what it used to be. This is mainly focused on the messaging end and plumbing. --- indra/llprimitive/llprimitive.cpp | 23 +++++++++++-- indra/llprimitive/llprimitive.h | 2 ++ indra/llprimitive/llprimtexturelist.cpp | 9 +++++ indra/llprimitive/llprimtexturelist.h | 1 + indra/llprimitive/lltextureentry.cpp | 27 +++++++++++++-- indra/llprimitive/lltextureentry.h | 7 +++- indra/newview/llpanelface.cpp | 16 +++++++++ indra/newview/llpanelface.h | 4 +++ indra/newview/llselectmgr.cpp | 22 +++++++++++++ indra/newview/llselectmgr.h | 1 + .../default/xui/en/panel_tools_texture.xml | 33 +++++++++++++++++++ 11 files changed, 138 insertions(+), 7 deletions(-) diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 644476460c..b5335b7e51 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -385,6 +385,11 @@ S32 LLPrimitive::setTEBumpmap(const U8 index, const U8 bump) return mTextureList.setBumpMap(index, bump); } +S32 LLPrimitive::setTEAlphaGamma(const U8 index, const U8 gamma) +{ + return mTextureList.setAlphaGamma(index, gamma); +} + S32 LLPrimitive::setTEBumpShiny(const U8 index, const U8 bump_shiny) { updateNumBumpmap(index, bump_shiny); @@ -1213,6 +1218,7 @@ bool LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const S16 offset_t[MAX_TES]; S16 image_rot[MAX_TES]; U8 bump[MAX_TES]; + U8 alpha_gamma[MAX_TES]; U8 media_flags[MAX_TES]; U8 glow[MAX_TES]; U8 material_data[MAX_TES*16]; @@ -1251,6 +1257,7 @@ bool LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const offset_t[face_index] = (S16) ll_round((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; image_rot[face_index] = (S16) ll_round(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); bump[face_index] = te->getBumpShinyFullbright(); + alpha_gamma[face_index] = te->getAlphaGamma(); media_flags[face_index] = te->getMediaTexGen(); glow[face_index] = (U8) ll_round((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); @@ -1278,7 +1285,10 @@ bool LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const *cur_ptr++ = 0; cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8); *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)material_data, 16, last_face_index, MVT_LLUUID); + cur_ptr += packTEField(cur_ptr, (U8 *) material_data, 16, last_face_index, MVT_LLUUID); + *cur_ptr++ = 0; + *cur_ptr++ = 0x01; + cur_ptr += packTEField(cur_ptr, (U8 *) alpha_gamma, 1, last_face_index, MVT_U8); } mesgsys->addBinaryDataFast(_PREHASH_TextureEntry, packed_buffer, (S32)(cur_ptr - packed_buffer)); @@ -1298,6 +1308,7 @@ bool LLPrimitive::packTEMessage(LLDataPacker &dp) const S16 offset_t[MAX_TES]; S16 image_rot[MAX_TES]; U8 bump[MAX_TES]; + U8 alpha_gamma[MAX_TES]; U8 media_flags[MAX_TES]; U8 glow[MAX_TES]; U8 material_data[MAX_TES*16]; @@ -1336,6 +1347,7 @@ bool LLPrimitive::packTEMessage(LLDataPacker &dp) const offset_t[face_index] = (S16) ll_round((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; image_rot[face_index] = (S16) ll_round(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); bump[face_index] = te->getBumpShinyFullbright(); + alpha_gamma[face_index] = te->getAlphaGamma(); media_flags[face_index] = te->getMediaTexGen(); glow[face_index] = (U8) ll_round((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); @@ -1363,7 +1375,10 @@ bool LLPrimitive::packTEMessage(LLDataPacker &dp) const *cur_ptr++ = 0; cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8); *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)material_data, 16, last_face_index, MVT_LLUUID); + cur_ptr += packTEField(cur_ptr, (U8 *) material_data, 16, last_face_index, MVT_LLUUID); + *cur_ptr++ = 0; + *cur_ptr++ = 0x01; + cur_ptr += packTEField(cur_ptr, (U8 *) alpha_gamma, 1, last_face_index, MVT_U8); } dp.packBinaryData(packed_buffer, (S32)(cur_ptr - packed_buffer), "TextureEntry"); @@ -1420,7 +1435,8 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name unpack_TEField(tec.image_rot, tec.face_count, cur_ptr, buffer_end, MVT_S16) && unpack_TEField(tec.bump, tec.face_count, cur_ptr, buffer_end, MVT_U8) && unpack_TEField(tec.media_flags, tec.face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8))) + unpack_TEField(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(tec.alpha_gamma, tec.face_count, cur_ptr, buffer_end, MVT_U8))) { LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL; return 0; @@ -1456,6 +1472,7 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec) retval |= setTEMediaTexGen(i, tec.media_flags[i]); retval |= setTEGlow(i, (F32)tec.glow[i] / (F32)0xFF); retval |= setTEMaterialID(i, tec.material_ids[i]); + retval |= setTEAlphaGamma(i, tec.alpha_gamma[i]); // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f) // as all zeros. However, the subtraction and addition must be done in unsigned diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 31bc76344c..f7a8a9916c 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -411,6 +411,7 @@ struct LLTEContents S16 offset_t[MAX_TES]; S16 image_rot[MAX_TES]; U8 bump[MAX_TES]; + U8 alpha_gamma[MAX_TES]; U8 media_flags[MAX_TES]; U8 glow[MAX_TES]; LLMaterialID material_ids[MAX_TES]; @@ -482,6 +483,7 @@ class LLPrimitive : public LLXform virtual S32 setTEBumpShiny(const U8 te, const U8 bump); virtual S32 setTEMediaTexGen(const U8 te, const U8 media); virtual S32 setTEBumpmap(const U8 te, const U8 bump); + virtual S32 setTEAlphaGamma(const U8 te, const U8 alphagamma); virtual S32 setTETexGen(const U8 te, const U8 texgen); virtual S32 setTEShiny(const U8 te, const U8 shiny); virtual S32 setTEFullbright(const U8 te, const U8 fullbright); diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index 68f3f5ffac..939957e650 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -305,6 +305,15 @@ S32 LLPrimTextureList::setBumpMap(const U8 index, const U8 bump) return TEM_CHANGE_NONE; } +S32 LLPrimTextureList::setAlphaGamma(const U8 index, const U8 gamma) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setAlphaGamma(gamma); + } + return TEM_CHANGE_NONE; +} + S32 LLPrimTextureList::setBumpShiny(const U8 index, const U8 bump_shiny) { if (index < mEntryList.size()) diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h index 79744e9f08..a9e6b7b38a 100644 --- a/indra/llprimitive/llprimtexturelist.h +++ b/indra/llprimitive/llprimtexturelist.h @@ -99,6 +99,7 @@ class LLPrimTextureList S32 setMediaTexGen(const U8 index, const U8 media); S32 setBumpMap(const U8 index, const U8 bump); S32 setBumpShiny(const U8 index, const U8 bump_shiny); + S32 setAlphaGamma(const U8 index, const U8 gamma); S32 setTexGen(const U8 index, const U8 texgen); S32 setShiny(const U8 index, const U8 shiny); S32 setFullbright(const U8 index, const U8 t); diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index ac482ffbf9..ae351d9337 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -34,6 +34,7 @@ #include "v4color.h" const U8 DEFAULT_BUMP_CODE = 0; // no bump or shininess +const U8 DEFAULT_ALPHA_GAMMA = 100; // Gamma 1 (linear) for alpha blending const LLTextureEntry LLTextureEntry::null; @@ -64,7 +65,7 @@ LLTextureEntry::LLTextureEntry() , mSelected(false) , mMaterialUpdatePending(false) { - init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); + init(LLUUID::null, 1.f, 1.f, 0.f, 0.f, 0.f, DEFAULT_BUMP_CODE, DEFAULT_ALPHA_GAMMA); } LLTextureEntry::LLTextureEntry(const LLUUID& tex_id) @@ -72,7 +73,7 @@ LLTextureEntry::LLTextureEntry(const LLUUID& tex_id) , mSelected(false) , mMaterialUpdatePending(false) { - init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE); + init(tex_id, 1.f, 1.f, 0.f, 0.f, 0.f, DEFAULT_BUMP_CODE, DEFAULT_ALPHA_GAMMA); } LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) @@ -95,6 +96,7 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) mRotation = rhs.mRotation; mColor = rhs.mColor; mBump = rhs.mBump; + mAlphaGamma = rhs.mAlphaGamma; mMediaFlags = rhs.mMediaFlags; mGlow = rhs.mGlow; mMaterialID = rhs.mMaterialID; @@ -135,7 +137,7 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) return *this; } -void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump) +void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump, U8 alphagamma) { setID(tex_id); @@ -145,6 +147,7 @@ void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 of mOffsetT = offset_t; mRotation = rotation; mBump = bump; + mAlphaGamma = alphagamma; mMediaFlags = 0x0; mGlow = 0; mMaterialID.clear(); @@ -181,6 +184,7 @@ bool LLTextureEntry::operator!=(const LLTextureEntry &rhs) const if (mRotation != rhs.mRotation) return(true); if (mColor != rhs.mColor) return (true); if (mBump != rhs.mBump) return (true); + if (mAlphaGamma != rhs.mAlphaGamma) return (true); if (mMediaFlags != rhs.mMediaFlags) return (true); if (mGlow != rhs.mGlow) return (true); if (mMaterialID != rhs.mMaterialID) return (true); @@ -197,6 +201,7 @@ bool LLTextureEntry::operator==(const LLTextureEntry &rhs) const if (mRotation != rhs.mRotation) return(false); if (mColor != rhs.mColor) return (false); if (mBump != rhs.mBump) return (false); + if (mAlphaGamma != rhs.mAlphaGamma) return (false); if (mMediaFlags != rhs.mMediaFlags) return false; if (mGlow != rhs.mGlow) return false; if (mMaterialID != rhs.mMaterialID) return (false); @@ -221,6 +226,7 @@ void LLTextureEntry::asLLSD(LLSD& sd) const sd["offsett"] = mOffsetT; sd["imagerot"] = mRotation; sd["bump"] = getBumpShiny(); + sd["alphagamma"] = getAlphaGamma(); sd["fullbright"] = getFullbright(); sd["media_flags"] = mMediaFlags; if (hasMedia()) { @@ -274,6 +280,11 @@ bool LLTextureEntry::fromLLSD(const LLSD& sd) { setBumpShiny( sd[w].asInteger() ); } else goto fail; + w = "alphagamma"; + if (sd.has(w)) + { + setAlphaGamma(sd[w].asInteger()); + } // else goto fail; w = "fullbright"; if (sd.has(w)) { @@ -472,6 +483,16 @@ S32 LLTextureEntry::setBumpShinyFullbright(U8 bump) return TEM_CHANGE_NONE; } +S32 LLTextureEntry::setAlphaGamma(U8 alpha_gamma) +{ + if (mAlphaGamma != alpha_gamma) + { + mAlphaGamma = alpha_gamma; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + S32 LLTextureEntry::setMediaTexGen(U8 media) { S32 result = TEM_CHANGE_NONE; diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h index 78c61b4d65..717c3bd0d9 100644 --- a/indra/llprimitive/lltextureentry.h +++ b/indra/llprimitive/lltextureentry.h @@ -103,7 +103,7 @@ class LLTextureEntry virtual LLTextureEntry* newBlank() const; virtual LLTextureEntry* newCopy() const; - void init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump); + void init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump, U8 alphagamma); bool hasPendingMaterialUpdate() const { return mMaterialUpdatePending; } bool isSelected() const { return mSelected; } @@ -128,6 +128,8 @@ class LLTextureEntry S32 setBumpShiny(U8 bump); S32 setBumpShinyFullbright(U8 bump); + S32 setAlphaGamma(U8 alpha_gamma); + S32 setMediaFlags(U8 media_flags); S32 setTexGen(U8 texGen); S32 setMediaTexGen(U8 media); @@ -156,6 +158,8 @@ class LLTextureEntry U8 getBumpShiny() const { return mBump & TEM_BUMP_SHINY_MASK; } U8 getBumpShinyFullbright() const { return mBump; } + U8 getAlphaGamma() const { return mAlphaGamma; } + U8 getMediaFlags() const { return mMediaFlags & TEM_MEDIA_MASK; } LLTextureEntry::e_texgen getTexGen() const { return LLTextureEntry::e_texgen(mMediaFlags & TEM_TEX_GEN_MASK); } U8 getMediaTexGen() const { return mMediaFlags; } @@ -233,6 +237,7 @@ class LLTextureEntry LLColor4 mColor; U8 mBump; // Bump map, shiny, and fullbright U8 mMediaFlags; // replace with web page, movie, etc. + U8 mAlphaGamma; // Fixed point gamma correction for alpha blending. F32 mGlow; bool mMaterialUpdatePending; LLMaterialID mMaterialID; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 544b6fbc9c..ee17ee50d7 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -421,6 +421,11 @@ bool LLPanelFace::postBuild() getChildSetCommitCallback(mCheckFullbright, "checkbox fullbright", [&](LLUICtrl*, const LLSD&) { onCommitFullbright(); }); + + mLabelTexGen = getChild("alpha gamma"); + getChildSetCommitCallback(mComboAlphaGamma, "combobox alpha gamma", [&](LLUICtrl *, const LLSD &) { onCommitAlphaGamma(); }); + mComboAlphaGamma->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); + mLabelTexGen = getChild("tex gen"); getChildSetCommitCallback(mComboTexGen, "combobox texgen", [&](LLUICtrl*, const LLSD&) { onCommitTexGen(); }); mComboTexGen->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); @@ -553,6 +558,12 @@ void LLPanelFace::sendBump(U32 bumpiness) LLSelectMgr::getInstance()->selectionSetBumpmap( bump, mBumpyTextureCtrl->getImageItemID() ); } +void LLPanelFace::sendAlphaGamma() +{ + U8 alpha_gamma = (U8) mComboAlphaGamma->getCurrentIndex() << TEM_TEX_GEN_SHIFT; + LLSelectMgr::getInstance()->selectionSetAlphaGamma(alpha_gamma); +} + void LLPanelFace::sendTexGen() { U8 tex_gen = (U8)mComboTexGen->getCurrentIndex() << TEM_TEX_GEN_SHIFT; @@ -2914,6 +2925,11 @@ void LLPanelFace::onCommitBump() sendBump(mComboBumpiness->getCurrentIndex()); } +void LLPanelFace::onCommitAlphaGamma() +{ + sendAlphaGamma(); +} + void LLPanelFace::onCommitTexGen() { sendTexGen(); diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index dfd3201533..9e248ba579 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -146,6 +146,7 @@ class LLPanelFace : public LLPanel void sendColor(); // applies and sends color void sendAlpha(); // applies and sends transparency void sendBump(U32 bumpiness); // applies and sends bump map + void sendAlphaGamma(); // applies and sends bump map void sendTexGen(); // applies and sends bump map void sendShiny(U32 shininess); // applies and sends shininess void sendFullbright(); // applies and sends full bright @@ -234,6 +235,7 @@ class LLPanelFace : public LLPanel void onClickBtnDeleteMedia(); void onClickBtnAddMedia(); void onCommitBump(); + void onCommitAlphaGamma(); void onCommitTexGen(); void onCommitShiny(); void onCommitAlphaMode(); @@ -304,6 +306,8 @@ class LLPanelFace : public LLPanel LLTextBox* mLabelTexGen { nullptr }; LLComboBox* mComboTexGen { nullptr }; + LLComboBox *mComboAlphaGamma {nullptr}; + LLRadioGroup* mRadioMaterialType { nullptr }; LLRadioGroup* mRadioPbrType { nullptr }; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 342048252f..b54fca4e15 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2330,6 +2330,28 @@ void LLSelectMgr::selectionSetBumpmap(U8 bumpmap, const LLUUID &image_id) getSelection()->applyToObjects(&sendfunc); } +void LLSelectMgr::selectionSetAlphaGamma(U8 gamma) +{ + struct f : public LLSelectedTEFunctor + { + U8 mAlphaGamma; + f(const U8 &t) : mAlphaGamma(t) {} + bool apply(LLViewerObject *object, S32 te) + { + if (object->permModify()) + { + // update viewer side color in anticipation of update from simulator + object->setTEAlphaGamma(te, mAlphaGamma); + } + return true; + } + } setfunc(gamma); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + void LLSelectMgr::selectionSetTexGen(U8 texgen) { struct f : public LLSelectedTEFunctor diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index f8242675dc..717d559b2c 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -660,6 +660,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton bool selectionRevertTextures(); void selectionRevertGLTFMaterials(); void selectionSetBumpmap( U8 bumpmap, const LLUUID &image_id ); + void selectionSetAlphaGamma( U8 gamma ); void selectionSetTexGen( U8 texgen ); void selectionSetShiny( U8 shiny, const LLUUID &image_id ); void selectionSetFullbright( U8 fullbright ); diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index e80f315259..b706b06620 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -641,6 +641,39 @@ tool_tip="Click to open color picker" top_delta="-4" width="64" /> + + Alpha Gamma + + + + + + Date: Fri, 16 Aug 2024 14:31:50 -0700 Subject: [PATCH 02/15] Double check we got the thing. --- indra/llprimitive/llprimitive.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index b5335b7e51..8f0fc5a8a2 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1435,8 +1435,7 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name unpack_TEField(tec.image_rot, tec.face_count, cur_ptr, buffer_end, MVT_S16) && unpack_TEField(tec.bump, tec.face_count, cur_ptr, buffer_end, MVT_U8) && unpack_TEField(tec.media_flags, tec.face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(tec.alpha_gamma, tec.face_count, cur_ptr, buffer_end, MVT_U8))) + unpack_TEField(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8))) { LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL; return 0; @@ -1452,6 +1451,14 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name tec.material_ids[i].set(&(material_data[i])); } + if ((cur_ptr < buffer_end) && (*cur_ptr == 0x01)) + { + if (!unpack_TEField(tec.alpha_gamma, tec.face_count, cur_ptr, buffer_end, MVT_U8)) + { + LL_WARNS("TEXTUREENTRY") << "Baddly formed alphagamma unpacking texture entry." << LL_ENDL; + } + } + retval = 1; return retval; } From 7f485338197d1a64f8c40247023b973722c28a22 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Fri, 23 Aug 2024 20:34:00 -0700 Subject: [PATCH 03/15] Add the message for overriding very specific parameters regardless of mod permission. --- indra/llmessage/message_prehash.cpp | 2 + indra/llmessage/message_prehash.h | 2 + indra/llprimitive/llprimitive.cpp | 64 ++++++++++------------ indra/newview/llselectmgr.cpp | 38 +++++++++++++ indra/newview/llselectmgr.h | 1 + scripts/messages/message_template.msg | 20 ++++++- scripts/messages/message_template.msg.sha1 | 2 +- 7 files changed, 92 insertions(+), 37 deletions(-) diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index c264a9f086..0f7c832f99 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -1402,3 +1402,5 @@ char const* const _PREHASH_HoverHeight = LLMessageStringTable::getInstance()->ge char const* const _PREHASH_Experience = LLMessageStringTable::getInstance()->getString("Experience"); char const* const _PREHASH_ExperienceID = LLMessageStringTable::getInstance()->getString("ExperienceID"); char const* const _PREHASH_LargeGenericMessage = LLMessageStringTable::getInstance()->getString("LargeGenericMessage"); +char const* const _PRHASH_ObjectBypassModUpdate = LLMessageStringTable::getInstance()->getString("ObjectBypassModUpdate"); +char const* const _PREHASH_PropertyID = LLMessageStringTable::getInstance()->getString("PropertyID"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 1d30b69b67..dc4afec4f7 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -1403,5 +1403,7 @@ extern char const* const _PREHASH_HoverHeight; extern char const* const _PREHASH_Experience; extern char const* const _PREHASH_ExperienceID; extern char const* const _PREHASH_LargeGenericMessage; +extern char const* const _PRHASH_ObjectBypassModUpdate; +extern char const* const _PREHASH_PropertyID; #endif diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 8f0fc5a8a2..cc9fbc7a6b 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1208,26 +1208,23 @@ namespace // Includes information about image ID, color, scale S,T, offset S,T and rotation bool LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const { - const U32 MAX_TES = 45; - - U8 image_ids[MAX_TES*16]; - U8 colors[MAX_TES*4]; - F32 scale_s[MAX_TES]; - F32 scale_t[MAX_TES]; - S16 offset_s[MAX_TES]; - S16 offset_t[MAX_TES]; - S16 image_rot[MAX_TES]; - U8 bump[MAX_TES]; - U8 alpha_gamma[MAX_TES]; - U8 media_flags[MAX_TES]; - U8 glow[MAX_TES]; - U8 material_data[MAX_TES*16]; - - const U32 MAX_TE_BUFFER = 4096; - U8 packed_buffer[MAX_TE_BUFFER]; + U8 image_ids[LLTEContents::MAX_TES * 16]; + U8 colors[LLTEContents::MAX_TES * 4]; + F32 scale_s[LLTEContents::MAX_TES]; + F32 scale_t[LLTEContents::MAX_TES]; + S16 offset_s[LLTEContents::MAX_TES]; + S16 offset_t[LLTEContents::MAX_TES]; + S16 image_rot[LLTEContents::MAX_TES]; + U8 bump[LLTEContents::MAX_TES]; + U8 alpha_gamma[LLTEContents::MAX_TES]; + U8 media_flags[LLTEContents::MAX_TES]; + U8 glow[LLTEContents::MAX_TES]; + U8 material_data[LLTEContents::MAX_TES * 16]; + + U8 packed_buffer[LLTEContents::MAX_TE_BUFFER]; U8 *cur_ptr = packed_buffer; - S32 last_face_index = llmin((U32) getNumTEs(), MAX_TES) - 1; + S32 last_face_index = llmin((U32) getNumTEs(), LLTEContents::MAX_TES) - 1; if (last_face_index > -1) { @@ -1298,23 +1295,20 @@ bool LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const bool LLPrimitive::packTEMessage(LLDataPacker &dp) const { - const U32 MAX_TES = 45; - - U8 image_ids[MAX_TES*16]; - U8 colors[MAX_TES*4]; - F32 scale_s[MAX_TES]; - F32 scale_t[MAX_TES]; - S16 offset_s[MAX_TES]; - S16 offset_t[MAX_TES]; - S16 image_rot[MAX_TES]; - U8 bump[MAX_TES]; - U8 alpha_gamma[MAX_TES]; - U8 media_flags[MAX_TES]; - U8 glow[MAX_TES]; - U8 material_data[MAX_TES*16]; - - const U32 MAX_TE_BUFFER = 4096; - U8 packed_buffer[MAX_TE_BUFFER]; + U8 image_ids[LLTEContents::MAX_TES * 16]; + U8 colors[LLTEContents::MAX_TES * 4]; + F32 scale_s[LLTEContents::MAX_TES]; + F32 scale_t[LLTEContents::MAX_TES]; + S16 offset_s[LLTEContents::MAX_TES]; + S16 offset_t[LLTEContents::MAX_TES]; + S16 image_rot[LLTEContents::MAX_TES]; + U8 bump[LLTEContents::MAX_TES]; + U8 alpha_gamma[LLTEContents::MAX_TES]; + U8 media_flags[LLTEContents::MAX_TES]; + U8 glow[LLTEContents::MAX_TES]; + U8 material_data[LLTEContents::MAX_TES * 16]; + + U8 packed_buffer[LLTEContents::MAX_TE_BUFFER]; U8 *cur_ptr = packed_buffer; S32 last_face_index = getNumTEs() - 1; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index b54fca4e15..c10c42a4c7 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2343,6 +2343,10 @@ void LLSelectMgr::selectionSetAlphaGamma(U8 gamma) // update viewer side color in anticipation of update from simulator object->setTEAlphaGamma(te, mAlphaGamma); } + else + { + packAlphaGammaOverride(object); + } return true; } } setfunc(gamma); @@ -5802,6 +5806,40 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, // LL_INFOS() << "sendListToRegions " << message_name << " obj " << objects_sent << " pkt " << packets_sent << LL_ENDL; } +void LLSelectMgr::packAlphaGammaOverride(LLViewerObject* object) +{ + gMessageSystem->newMessageFast(_PRHASH_ObjectBypassModUpdate); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); + gMessageSystem->addU8Fast(_PREHASH_PropertyID, 0x01); + + U8 alpha_gamma[LLTEContents::MAX_TES]; + + U8 packed_buffer[LLTEContents::MAX_TE_BUFFER]; + U8* cur_ptr = packed_buffer; + + S32 last_face_index = llmin((U32) object->getNumTEs(), LLTEContents::MAX_TES) - 1; + + if (last_face_index > -1) + { + // ...if we hit the front, send one image id + S8 face_index; + for (face_index = 0; face_index <= last_face_index; face_index++) + { + const LLTextureEntry* te = object->getTE(face_index); + alpha_gamma[face_index] = te->getAlphaGamma(); + } + + cur_ptr += object->packTEField(cur_ptr, (U8*) alpha_gamma, 1, last_face_index, MVT_U8); + } + + gMessageSystem->addBinaryDataFast(_PREHASH_Value, packed_buffer, cur_ptr - packed_buffer); + + gMessageSystem->sendMessage(gAgent.getRegion()->getHost()); +} // // Network communications diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 717d559b2c..2c8b36e704 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -901,6 +901,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton static void logAttachmentRequest(LLSelectNode* node, void *user_data); static void logDetachRequest(LLSelectNode* node, void *user_data); static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle); + static void packAlphaGammaOverride(LLViewerObject* object); // Get the first ID that matches test and whether or not all ids are identical in selected objects. void getFirst(LLSelectGetFirstTest* test); diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg index 1450c111c2..d23e3d3a79 100755 --- a/scripts/messages/message_template.msg +++ b/scripts/messages/message_template.msg @@ -6,7 +6,7 @@ version 2.0 // numbers. Each message must be numbered relative to the // other messages of that type. The current highest number // for each type is listed below: -// Low: 430 +// Low: 431 // Medium: 18 // High: 30 // PLEASE UPDATE THIS WHEN YOU ADD A NEW MESSAGE! @@ -9133,3 +9133,21 @@ version 2.0 } } +// ObjectBypassedUpdate +// Viewer -> Simulator +// Allows the owner of an object to bypass mod protections for +// Predefined fields. +{ + ObjectBypassModUpdate Low 431 NotTrusted Zerocoded + { + AgentData Single + { AgentID LLUUID } + { SessionID LLUUID } + } + { + ObjectData Variable + { ObjectLocalID U32 } + { PropertyID U8 } + { Value Variable 2 } + } +} diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index efa5f3cf48..8320aac32a 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1 +1 @@ -d7915d67467e59287857630bd89bf9529d065199 \ No newline at end of file +0fbf17bcc8a9023e0719ba60e10cd9fa163b80d3 \ No newline at end of file From ad5a207b43c26c1cdb77eb1799ed842bc11a66d4 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Mon, 26 Aug 2024 22:02:21 -0700 Subject: [PATCH 04/15] Hacked together UI for the new message. --- indra/newview/llpanelface.cpp | 11 +++++++++++ indra/newview/llpanelface.h | 3 ++- indra/newview/llselectmgr.cpp | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index ee17ee50d7..0bda6a8950 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1324,6 +1324,15 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } + // Alpha gamma. This should always be enabled, no matter if the object is mod or not. + { + U8 alpha_gamma = 100; + bool identical_alpha_gamma = false; + LLSelectedTE::getAlphaGamma(alpha_gamma, identical_alpha_gamma); + mComboAlphaGamma->getSelectionInterface()->selectByValue(alpha_gamma); + mComboAlphaGamma->setEnabled(true); + } + // planar align bool align_planar = mPlanarAlign->get(); bool identical_planar_aligned = false; @@ -2834,6 +2843,8 @@ void LLPanelFace::updateVisibility(LLViewerObject* objectp /* = nullptr */) mRadioMaterialType->setVisible(show_material); // Shared material controls + mComboAlphaGamma->setVisible(true); + mComboAlphaGamma->setEnabled(true); mCheckSyncSettings->setVisible(show_material || show_media); mLabelTexGen->setVisible(show_material || show_media || show_pbr_asset); mComboTexGen->setVisible(show_material || show_media || show_pbr_asset); diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 9e248ba579..399456e269 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -704,7 +704,8 @@ class LLPanelFace : public LLPanel DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f) DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f) DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT) - DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black); + DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black) + DEF_GET_TE_STATE(U8, U8, getAlphaGamma, 100, false, 0); }; friend struct LLPanelFaceSetTEFunctor; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index c10c42a4c7..ee76df428d 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5836,7 +5836,7 @@ void LLSelectMgr::packAlphaGammaOverride(LLViewerObject* object) cur_ptr += object->packTEField(cur_ptr, (U8*) alpha_gamma, 1, last_face_index, MVT_U8); } - gMessageSystem->addBinaryDataFast(_PREHASH_Value, packed_buffer, cur_ptr - packed_buffer); + gMessageSystem->addBinaryDataFast(_PREHASH_Value, packed_buffer, (S32)(cur_ptr - packed_buffer)); gMessageSystem->sendMessage(gAgent.getRegion()->getHost()); } From 2ed476fdc814b96e14c5309424f9a75e73e9d637 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Fri, 30 Aug 2024 12:02:10 -0700 Subject: [PATCH 05/15] Make sure we're getting the value before we send it anywhere. --- indra/newview/llpanelface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 0bda6a8950..9e212dc9c5 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -560,7 +560,8 @@ void LLPanelFace::sendBump(U32 bumpiness) void LLPanelFace::sendAlphaGamma() { - U8 alpha_gamma = (U8) mComboAlphaGamma->getCurrentIndex() << TEM_TEX_GEN_SHIFT; + U8 alpha_gamma = (U8) mComboAlphaGamma->getValue().asInteger(); + LLSelectMgr::getInstance()->selectionSetAlphaGamma(alpha_gamma); } From 624e8da288fbb5380360d00d5e789fd7d8333cd4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 17 Sep 2024 21:56:08 -0700 Subject: [PATCH 06/15] fix for alpha-gamma-bypass prototype (#2538) * fix the alpha-gamma-bypass prototype --- indra/llprimitive/llprimitive.cpp | 537 ++++++++---------- indra/llprimitive/llprimitive.h | 63 +- indra/llprimitive/llprimtexturelist.cpp | 2 +- indra/llprimitive/lltextureentry.cpp | 2 +- indra/llprimitive/tests/llprimitive_test.cpp | 207 +++++-- .../tests/llprimtexturelist_stub.cpp | 292 ++++++++++ .../llprimitive/tests/lltextureentry_stub.cpp | 316 +++++++++++ indra/newview/llpanelface.cpp | 18 +- indra/newview/llselectmgr.cpp | 26 +- indra/newview/llselectmgr.h | 3 +- indra/newview/llviewerobject.cpp | 4 +- indra/newview/llvoavatar.cpp | 10 +- 12 files changed, 1082 insertions(+), 398 deletions(-) create mode 100644 indra/llprimitive/tests/llprimtexturelist_stub.cpp create mode 100644 indra/llprimitive/tests/lltextureentry_stub.cpp diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index fec3302ff7..598e8d229f 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -125,6 +125,9 @@ const LLUUID SCULPT_DEFAULT_TEXTURE("be293869-d0d9-0a69-5989-ad27f1946fd4"); // // can't be divided by 2. See DEV-19108 const F32 TEXTURE_ROTATION_PACK_FACTOR = ((F32) 0x08000); +constexpr U32 MAX_TE_BUFFER = 4096; +constexpr U8 EXTRA_PROPERTY_ALPHA_GAMMA = 0x01; + struct material_id_type // originally from llrendermaterialtable { material_id_type() @@ -159,6 +162,71 @@ const U8 material_id_type::s_null_id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; // TODO -- eliminate this global from the codebase! LLVolumeMgr* LLPrimitive::sVolumeManager = NULL; +LLTEContents::LLTEContents(size_t N) +{ + llassert(N > 0); + N = std::min(N, size_t(LLTEContents::MAX_TES)); + num_textures = N; + + // allocate one big buffer for all the data and fill it with zeros + size_t bytes_per_texture = sizeof(LLUUID) + + sizeof(LLMaterialID) + + sizeof(LLColor4U) + + 2 * sizeof(F32) + + 3 * sizeof(S16) + + 4 * sizeof(U8); + size_t num_bytes = num_textures * bytes_per_texture; + data = new U8[num_bytes]; + memset(data, 0, num_bytes); + + // compute offset pointers into data for the various fields + size_t offset = 0; + image_ids = reinterpret_cast(data); + offset += num_textures * sizeof(LLUUID); + + material_ids = reinterpret_cast(data + offset); + offset += num_textures * sizeof(LLMaterialID); + + colors = reinterpret_cast(data + offset); + offset += num_textures * sizeof(LLColor4U); + + scale_s = reinterpret_cast(data + offset); + offset += num_textures * sizeof(F32); + + scale_t = reinterpret_cast(data + offset); + offset += num_textures * sizeof(F32); + + offset_s = reinterpret_cast(data + offset); + offset += num_textures * sizeof(S16); + + offset_t = reinterpret_cast(data + offset); + offset += num_textures * sizeof(S16); + + rot = reinterpret_cast(data + offset); + offset += num_textures * sizeof(S16); + + bump = reinterpret_cast(data + offset); + offset += num_textures * sizeof(U8); + + media_flags = reinterpret_cast(data + offset); + offset += num_textures * sizeof(U8); + + glow = reinterpret_cast(data + offset); + offset += num_textures * sizeof(U8); + + alpha_gamma = reinterpret_cast(data + offset); + offset += num_textures * sizeof(U8); + + // verify we correctly computed data size + llassert(offset == num_bytes); +} + +LLTEContents::~LLTEContents() +{ + delete data; + data = nullptr; +} + // static void LLPrimitive::setVolumeManager( LLVolumeMgr* volume_manager ) { @@ -1199,297 +1267,222 @@ namespace } } +S32 LLPrimitive::packTEMessageBuffer(U8* packed_buffer) const +{ + S32 bytes_packed = 0; + U32 num_tes = llmin((U32) getNumTEs(), (U32) LLTEContents::MAX_TES); + if (num_tes == 0) + { + return bytes_packed; + } + LLTEContents contents(num_tes); -// Pack information about all texture entries into container: -// { TextureEntry Variable 2 } -// Includes information about image ID, color, scale S,T, offset S,T and rotation -bool LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const -{ - U8 image_ids[LLTEContents::MAX_TES * 16]; - U8 colors[LLTEContents::MAX_TES * 4]; - F32 scale_s[LLTEContents::MAX_TES]; - F32 scale_t[LLTEContents::MAX_TES]; - S16 offset_s[LLTEContents::MAX_TES]; - S16 offset_t[LLTEContents::MAX_TES]; - S16 image_rot[LLTEContents::MAX_TES]; - U8 bump[LLTEContents::MAX_TES]; - U8 alpha_gamma[LLTEContents::MAX_TES]; - U8 media_flags[LLTEContents::MAX_TES]; - U8 glow[LLTEContents::MAX_TES]; - U8 material_data[LLTEContents::MAX_TES * 16]; - - U8 packed_buffer[LLTEContents::MAX_TE_BUFFER]; + // note: packed_buffer is expected to be at least MAX_TE_BUFFER wide. U8 *cur_ptr = packed_buffer; - S32 last_face_index = llmin((U32) getNumTEs(), LLTEContents::MAX_TES) - 1; - - if (last_face_index > -1) + // ...if we hit the front, send one image id + S8 face_index; + const LLColor4U white(255, 255, 255, 255); + LLColor4U coloru; + S32 last_face_index = num_tes- 1; + for (face_index = 0; face_index <= last_face_index; ++face_index) { - // ...if we hit the front, send one image id - S8 face_index; - LLColor4U coloru; - for (face_index = 0; face_index <= last_face_index; face_index++) - { - // Directly sending image_ids is not safe! - memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16); /* Flawfinder: ignore */ - - // Cast LLColor4 to LLColor4U - coloru.setVec( getTE(face_index)->getColor() ); - - // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f) - // as all zeros. However, the subtraction and addition must be done in unsigned - // byte space, not in float space, otherwise off-by-one errors occur. JC - colors[4*face_index] = 255 - coloru.mV[0]; - colors[4*face_index + 1] = 255 - coloru.mV[1]; - colors[4*face_index + 2] = 255 - coloru.mV[2]; - colors[4*face_index + 3] = 255 - coloru.mV[3]; - - const LLTextureEntry* te = getTE(face_index); - scale_s[face_index] = (F32) te->mScaleS; - scale_t[face_index] = (F32) te->mScaleT; - offset_s[face_index] = (S16) ll_round((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ; - offset_t[face_index] = (S16) ll_round((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; - image_rot[face_index] = (S16) ll_round(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); - bump[face_index] = te->getBumpShinyFullbright(); - alpha_gamma[face_index] = te->getAlphaGamma(); - media_flags[face_index] = te->getMediaTexGen(); - glow[face_index] = (U8) ll_round((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); - - // Directly sending material_ids is not safe! - memcpy(&material_data[face_index*16],getTE(face_index)->getMaterialID().get(),16); /* Flawfinder: ignore */ - } + // Directly sending image_ids is not safe! + const LLTextureEntry* te = getTE(face_index); + contents.image_ids[face_index] = te->getID(); - cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)colors, 4 ,last_face_index, MVT_U8); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)scale_s, 4 ,last_face_index, MVT_F32); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)scale_t, 4 ,last_face_index, MVT_F32); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)offset_s, 2 ,last_face_index, MVT_S16Array); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)offset_t, 2 ,last_face_index, MVT_S16Array); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)image_rot, 2 ,last_face_index, MVT_S16Array); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *) material_data, 16, last_face_index, MVT_LLUUID); - *cur_ptr++ = 0; - *cur_ptr++ = 0x01; - cur_ptr += packTEField(cur_ptr, (U8 *) alpha_gamma, 1, last_face_index, MVT_U8); - } - mesgsys->addBinaryDataFast(_PREHASH_TextureEntry, packed_buffer, (S32)(cur_ptr - packed_buffer)); + // Directly sending material_ids is not safe! + contents.material_ids[face_index] = te->getMaterialID(); - return true; -} + // Cast LLColor4 to LLColor4U + coloru.setVec( te->getColor() ); + // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f) + // as all zeros. However, the subtraction and addition must be done in unsigned + // byte space, not in float space, otherwise off-by-one errors occur. JC + contents.colors[face_index] = white - coloru; + + contents.scale_s[face_index] = te->mScaleS; + contents.scale_t[face_index] = te->mScaleT; + contents.offset_s[face_index] = (S16) ll_round((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ; + contents.offset_t[face_index] = (S16) ll_round((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; + contents.rot[face_index] = (S16) ll_round(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); + contents.bump[face_index] = te->getBumpShinyFullbright(); + contents.media_flags[face_index] = te->getMediaTexGen(); + contents.glow[face_index] = (U8) ll_round((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); + contents.alpha_gamma[face_index] = te->getAlphaGamma(); + } + + // pack required properties + cur_ptr += packTEField(cur_ptr, reinterpret_cast(contents.image_ids), sizeof(LLUUID), last_face_index, MVT_LLUUID); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, reinterpret_cast(contents.colors), 4, last_face_index, MVT_U8); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, reinterpret_cast(contents.scale_s), 4, last_face_index, MVT_F32); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, reinterpret_cast(contents.scale_t), 4, last_face_index, MVT_F32); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, reinterpret_cast(contents.offset_s), 2, last_face_index, MVT_S16Array); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, reinterpret_cast(contents.offset_t), 2, last_face_index, MVT_S16Array); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, reinterpret_cast(contents.rot), 2, last_face_index, MVT_S16Array); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, contents.bump, 1, last_face_index, MVT_U8); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, contents.media_flags, 1, last_face_index, MVT_U8); + *cur_ptr++ = 0; + cur_ptr += packTEField(cur_ptr, contents.glow, 1, last_face_index, MVT_U8); + *cur_ptr++ = 0; + // end of required properties + + // we always pack material_ids however the receiving side can handle the case when it is not included + cur_ptr += packTEField(cur_ptr, reinterpret_cast(contents.material_ids), 16, last_face_index, MVT_LLUUID); + *cur_ptr++ = 0; + + // pack extra properties + *cur_ptr++ = EXTRA_PROPERTY_ALPHA_GAMMA; // indicator alpha_gamma is present + cur_ptr += packTEField(cur_ptr, contents.alpha_gamma, 1, last_face_index, MVT_U8); + // Note: last message is NOT null terminated when on the wire! + + bytes_packed = (S32)(cur_ptr - packed_buffer); + return bytes_packed; +} -bool LLPrimitive::packTEMessage(LLDataPacker &dp) const +// Pack information about all texture entries into container: +// { TextureEntry Variable 2 } +// Includes information about image ID, color, scale S,T, offset S,T and rotation +bool LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const { - U8 image_ids[LLTEContents::MAX_TES * 16]; - U8 colors[LLTEContents::MAX_TES * 4]; - F32 scale_s[LLTEContents::MAX_TES]; - F32 scale_t[LLTEContents::MAX_TES]; - S16 offset_s[LLTEContents::MAX_TES]; - S16 offset_t[LLTEContents::MAX_TES]; - S16 image_rot[LLTEContents::MAX_TES]; - U8 bump[LLTEContents::MAX_TES]; - U8 alpha_gamma[LLTEContents::MAX_TES]; - U8 media_flags[LLTEContents::MAX_TES]; - U8 glow[LLTEContents::MAX_TES]; - U8 material_data[LLTEContents::MAX_TES * 16]; - - U8 packed_buffer[LLTEContents::MAX_TE_BUFFER]; - U8 *cur_ptr = packed_buffer; - - S32 last_face_index = getNumTEs() - 1; - - if (last_face_index > -1) - { - // ...if we hit the front, send one image id - S8 face_index; - LLColor4U coloru; - for (face_index = 0; face_index <= last_face_index; face_index++) - { - // Directly sending image_ids is not safe! - memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16); /* Flawfinder: ignore */ - - // Cast LLColor4 to LLColor4U - coloru.setVec( getTE(face_index)->getColor() ); - - // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f) - // as all zeros. However, the subtraction and addition must be done in unsigned - // byte space, not in float space, otherwise off-by-one errors occur. JC - colors[4*face_index] = 255 - coloru.mV[0]; - colors[4*face_index + 1] = 255 - coloru.mV[1]; - colors[4*face_index + 2] = 255 - coloru.mV[2]; - colors[4*face_index + 3] = 255 - coloru.mV[3]; - - const LLTextureEntry* te = getTE(face_index); - scale_s[face_index] = (F32) te->mScaleS; - scale_t[face_index] = (F32) te->mScaleT; - offset_s[face_index] = (S16) ll_round((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ; - offset_t[face_index] = (S16) ll_round((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; - image_rot[face_index] = (S16) ll_round(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); - bump[face_index] = te->getBumpShinyFullbright(); - alpha_gamma[face_index] = te->getAlphaGamma(); - media_flags[face_index] = te->getMediaTexGen(); - glow[face_index] = (U8) ll_round((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); - - // Directly sending material_ids is not safe! - memcpy(&material_data[face_index*16],getTE(face_index)->getMaterialID().get(),16); /* Flawfinder: ignore */ - } - - cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)colors, 4 ,last_face_index, MVT_U8); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)scale_s, 4 ,last_face_index, MVT_F32); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)scale_t, 4 ,last_face_index, MVT_F32); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)offset_s, 2 ,last_face_index, MVT_S16Array); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)offset_t, 2 ,last_face_index, MVT_S16Array); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)image_rot, 2 ,last_face_index, MVT_S16Array); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8); - *cur_ptr++ = 0; - cur_ptr += packTEField(cur_ptr, (U8 *) material_data, 16, last_face_index, MVT_LLUUID); - *cur_ptr++ = 0; - *cur_ptr++ = 0x01; - cur_ptr += packTEField(cur_ptr, (U8 *) alpha_gamma, 1, last_face_index, MVT_U8); - } - - dp.packBinaryData(packed_buffer, (S32)(cur_ptr - packed_buffer), "TextureEntry"); + U8 packed_buffer[MAX_TE_BUFFER]; + S32 num_bytes = packTEMessageBuffer(packed_buffer); + mesgsys->addBinaryDataFast(_PREHASH_TextureEntry, packed_buffer, num_bytes); return true; } +// Unpack information about all texture entires and store in LLTEContents S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec) { + U32 data_size; S32 retval = 0; - // temp buffer for material ID processing - // data will end up in tec.material_id[] - material_id_type material_data[LLTEContents::MAX_TES]; if (block_num < 0) { - tec.size = mesgsys->getSizeFast(block_name, _PREHASH_TextureEntry); + data_size = mesgsys->getSizeFast(block_name, _PREHASH_TextureEntry); } else { - tec.size = mesgsys->getSizeFast(block_name, block_num, _PREHASH_TextureEntry); + data_size = mesgsys->getSizeFast(block_name, block_num, _PREHASH_TextureEntry); } - if (tec.size == 0) + if (data_size == 0) { - tec.face_count = 0; return retval; } - else if (tec.size >= LLTEContents::MAX_TE_BUFFER) + else if (data_size >= MAX_TE_BUFFER) { LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL; - tec.size = LLTEContents::MAX_TE_BUFFER - 1; + data_size = MAX_TE_BUFFER - 1; } + U8 packed_buffer[MAX_TE_BUFFER]; + // if block_num < 0 ask for block 0 - mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, std::max(block_num, 0), LLTEContents::MAX_TE_BUFFER - 1); + mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, packed_buffer, 0, std::max(block_num, 0), MAX_TE_BUFFER - 1); // The last field is not zero terminated. // Rather than special case the upack functions. Just make it 0x00 terminated. - tec.packed_buffer[tec.size] = 0x00; - ++tec.size; - - tec.face_count = llmin((U32)getNumTEs(),(U32)LLTEContents::MAX_TES); - - U8 *cur_ptr = tec.packed_buffer; - LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffere sized: " << tec.size << LL_ENDL; - U8 *buffer_end = tec.packed_buffer + tec.size; - - if (!( unpack_TEField(tec.image_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID) && - unpack_TEField(tec.colors, tec.face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(tec.scale_s, tec.face_count, cur_ptr, buffer_end, MVT_F32) && - unpack_TEField(tec.scale_t, tec.face_count, cur_ptr, buffer_end, MVT_F32) && - unpack_TEField(tec.offset_s, tec.face_count, cur_ptr, buffer_end, MVT_S16) && - unpack_TEField(tec.offset_t, tec.face_count, cur_ptr, buffer_end, MVT_S16) && - unpack_TEField(tec.image_rot, tec.face_count, cur_ptr, buffer_end, MVT_S16) && - unpack_TEField(tec.bump, tec.face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(tec.media_flags, tec.face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8))) + packed_buffer[data_size] = 0x00; + ++data_size; + + return parseTEMessage(packed_buffer, data_size, tec); +} + +// static +S32 LLPrimitive::parseTEMessage(U8* packed_buffer, U32 data_size, LLTEContents& tec) +{ + // Note: the last TEFeild is not zero-terminated on the wire but we expect it to be for unpacking. + // This to avoid special-casing the logic in unpack_TEField<>(). + // The external context is required to null-terminate packed_buffer and increment data_size accordingly. + llassert(data_size > 0); + llassert(packed_buffer[data_size - 1] == 0); + + S32 retval = 0; + + U8 *cur_ptr = packed_buffer; + LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffere sized: " << data_size << LL_ENDL; + U8 *buffer_end = packed_buffer + data_size; + + S32 num_textures = tec.getNumTEs(); + if (!( unpack_TEField(tec.image_ids, num_textures, cur_ptr, buffer_end, MVT_LLUUID) && + unpack_TEField(tec.colors, num_textures, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(tec.scale_s, num_textures, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField(tec.scale_t, num_textures, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField(tec.offset_s, num_textures, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(tec.offset_t, num_textures, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(tec.rot, num_textures, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField(tec.bump, num_textures, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(tec.media_flags, num_textures, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField(tec.glow, num_textures, cur_ptr, buffer_end, MVT_U8))) { LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL; return 0; } - if (cur_ptr >= buffer_end || !unpack_TEField(material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID)) + if (cur_ptr < buffer_end) { - memset((void*)material_data, 0, sizeof(material_data)); + if (!unpack_TEField(tec.material_ids, num_textures, cur_ptr, buffer_end, MVT_LLUUID)) + { + LL_INFOS("TEXTUREENTRY") << "Fail parse material_ids." << LL_ENDL; + // material_ids are optional --> we don't consider this a failure + } } - for (U32 i = 0; i < tec.face_count; i++) + // alpha_gamma is optional and has an indicator byte in front + if (cur_ptr < buffer_end && *cur_ptr == EXTRA_PROPERTY_ALPHA_GAMMA) { - tec.material_ids[i].set(&(material_data[i])); + ++cur_ptr; // skip the indicator + if (!unpack_TEField(tec.alpha_gamma, num_textures, cur_ptr, buffer_end, MVT_U8)) + { + LL_INFOS("TEXTUREENTRY") << "Fail parse AlphaGamma TEField." << LL_ENDL; + // alpha_gamma is optional --> we don't consider this a failure + } } - if ((cur_ptr < buffer_end) && (*cur_ptr == 0x01)) + // undo the zero-encode color optimization + const LLColor4U white(255, 255, 255, 255); + for (U8 i = 0; i < num_textures; ++i) { - if (!unpack_TEField(tec.alpha_gamma, tec.face_count, cur_ptr, buffer_end, MVT_U8)) - { - LL_WARNS("TEXTUREENTRY") << "Baddly formed alphagamma unpacking texture entry." << LL_ENDL; - } + tec.colors[i] = white - tec.colors[i]; } retval = 1; return retval; - } +} -S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec) +S32 LLPrimitive::applyParsedTEMessage(const LLTEContents& tec) { S32 retval = 0; - - LLColor4 color; - for (U32 i = 0; i < tec.face_count; i++) + for (U32 i = 0; i < tec.getNumTEs(); i++) { - LLUUID& req_id = ((LLUUID*)tec.image_data)[i]; - retval |= setTETexture(i, req_id); + retval |= setTETexture(i, tec.image_ids[i]); + retval |= setTEColor(i, LLColor4(tec.colors[i])); // already corrected for zero-encode optimization + retval |= setTEMaterialID(i, tec.material_ids[i]); retval |= setTEScale(i, tec.scale_s[i], tec.scale_t[i]); retval |= setTEOffset(i, (F32)tec.offset_s[i] / (F32)0x7FFF, (F32) tec.offset_t[i] / (F32) 0x7FFF); - retval |= setTERotation(i, ((F32)tec.image_rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI); + retval |= setTERotation(i, ((F32)tec.rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI); retval |= setTEBumpShinyFullbright(i, tec.bump[i]); retval |= setTEMediaTexGen(i, tec.media_flags[i]); retval |= setTEGlow(i, (F32)tec.glow[i] / (F32)0xFF); - retval |= setTEMaterialID(i, tec.material_ids[i]); retval |= setTEAlphaGamma(i, tec.alpha_gamma[i]); - - // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f) - // as all zeros. However, the subtraction and addition must be done in unsigned - // byte space, not in float space, otherwise off-by-one errors occur. JC - color.mV[VRED] = F32(255 - tec.colors[i].mV[VRED]) / 255.f; - color.mV[VGREEN] = F32(255 - tec.colors[i].mV[VGREEN]) / 255.f; - color.mV[VBLUE] = F32(255 - tec.colors[i].mV[VBLUE]) / 255.f; - color.mV[VALPHA] = F32(255 - tec.colors[i].mV[VALPHA]) / 255.f; - - retval |= setTEColor(i, color); } - return retval; } S32 LLPrimitive::unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num) { - LLTEContents tec; + LLTEContents tec(getNumTEs()); S32 retval = parseTEMessage(mesgsys, block_name, block_num, tec); if (!retval) return retval; @@ -1505,111 +1498,35 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) // Avoid construction of 32 UUIDs per call static LLMaterialID material_ids[MAX_TES]; - constexpr U32 MAX_TE_BUFFER = 4096; U8 packed_buffer[MAX_TE_BUFFER]; memset((void*)packed_buffer, 0, MAX_TE_BUFFER); - LLUUID image_data[MAX_TES]; - LLColor4U colors[MAX_TES]; - F32 scale_s[MAX_TES]; - F32 scale_t[MAX_TES]; - S16 offset_s[MAX_TES]; - S16 offset_t[MAX_TES]; - S16 image_rot[MAX_TES]; - U8 bump[MAX_TES]; - U8 media_flags[MAX_TES]; - U8 glow[MAX_TES]; - material_id_type material_data[MAX_TES]; - - memset((void*)scale_s, 0, sizeof(scale_s)); - memset((void*)scale_t, 0, sizeof(scale_t)); - memset((void*)offset_s, 0, sizeof(offset_s)); - memset((void*)offset_t, 0, sizeof(offset_t)); - memset((void*)image_rot, 0, sizeof(image_rot)); - memset((void*)bump, 0, sizeof(bump)); - memset((void*)media_flags, 0, sizeof(media_flags)); - memset((void*)glow, 0, sizeof(glow)); - - S32 size; - U32 face_count = 0; - - if (!dp.unpackBinaryData(packed_buffer, size, "TextureEntry")) + S32 data_size; + if (!dp.unpackBinaryData(packed_buffer, data_size, "TextureEntry")) { retval = TEM_INVALID; LL_WARNS() << "Bad texture entry block! Abort!" << LL_ENDL; return retval; } - if (size == 0) + if (data_size == 0) { return retval; } - else if (size >= MAX_TE_BUFFER) + else if (data_size >= MAX_TE_BUFFER) { LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL; - size = MAX_TE_BUFFER - 1; + data_size = MAX_TE_BUFFER - 1; } // The last field is not zero terminated. // Rather than special case the upack functions. Just make it 0x00 terminated. - packed_buffer[size] = 0x00; - ++size; - face_count = llmin((U32) getNumTEs(), MAX_TES); - U32 i; + packed_buffer[data_size] = 0x00; + ++data_size; - U8 *cur_ptr = packed_buffer; - LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffer sized: " << size << LL_ENDL; - U8 *buffer_end = packed_buffer + size; - - if (!( unpack_TEField(image_data, face_count, cur_ptr, buffer_end, MVT_LLUUID) && - unpack_TEField(colors, face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(scale_s, face_count, cur_ptr, buffer_end, MVT_F32) && - unpack_TEField(scale_t, face_count, cur_ptr, buffer_end, MVT_F32) && - unpack_TEField(offset_s, face_count, cur_ptr, buffer_end, MVT_S16) && - unpack_TEField(offset_t, face_count, cur_ptr, buffer_end, MVT_S16) && - unpack_TEField(image_rot, face_count, cur_ptr, buffer_end, MVT_S16) && - unpack_TEField(bump, face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(media_flags, face_count, cur_ptr, buffer_end, MVT_U8) && - unpack_TEField(glow, face_count, cur_ptr, buffer_end, MVT_U8))) - { - LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL; - return 0; - } - - if (cur_ptr >= buffer_end || !unpack_TEField(material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) - { - memset((void*)material_data, 0, sizeof(material_data)); - } - - for (i = 0; i < face_count; i++) - { - material_ids[i].set(&(material_data[i])); - } - - LLColor4 color; - for (i = 0; i < face_count; i++) - { - retval |= setTETexture(i, ((LLUUID*)image_data)[i]); - retval |= setTEScale(i, scale_s[i], scale_t[i]); - retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF); - retval |= setTERotation(i, ((F32)image_rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI); - retval |= setTEBumpShinyFullbright(i, bump[i]); - retval |= setTEMediaTexGen(i, media_flags[i]); - retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF); - retval |= setTEMaterialID(i, material_ids[i]); - - // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f) - // as all zeros. However, the subtraction and addition must be done in unsigned - // byte space, not in float space, otherwise off-by-one errors occur. JC - color.mV[VRED] = F32(255 - colors[i].mV[VRED]) / 255.f; - color.mV[VGREEN] = F32(255 - colors[i].mV[VGREEN]) / 255.f; - color.mV[VBLUE] = F32(255 - colors[i].mV[VBLUE]) / 255.f; - color.mV[VALPHA] = F32(255 - colors[i].mV[VALPHA]) / 255.f; - - retval |= setTEColor(i, color); - } - - return retval; + LLTEContents tec(getNumTEs()); + parseTEMessage(packed_buffer, data_size, tec); + return applyParsedTEMessage(tec); } U8 LLPrimitive::getExpectedNumTEs() const diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index f7a8a9916c..e5bddc910d 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -399,28 +399,42 @@ class LLRenderMaterialParams : public LLNetworkData // more obvious. This should be refactored to remove the duplication, at which // point we can fix the names as well. // - Vir -struct LLTEContents +class LLTEContents { - static const U32 MAX_TES = 45; - - LLUUID image_data[MAX_TES]; - LLColor4U colors[MAX_TES]; - F32 scale_s[MAX_TES]; - F32 scale_t[MAX_TES]; - S16 offset_s[MAX_TES]; - S16 offset_t[MAX_TES]; - S16 image_rot[MAX_TES]; - U8 bump[MAX_TES]; - U8 alpha_gamma[MAX_TES]; - U8 media_flags[MAX_TES]; - U8 glow[MAX_TES]; - LLMaterialID material_ids[MAX_TES]; - - static const U32 MAX_TE_BUFFER = 4096; - U8 packed_buffer[MAX_TE_BUFFER]; - - U32 size; - U32 face_count; +public: + static const size_t MAX_TES = 45; + static const size_t MAX_TE_BUFFER = 4096; + + // delete the default ctor + LLTEContents() = delete; + + // please use ctor which expects the number of textures as argument + LLTEContents(size_t N); + + ~LLTEContents(); + + U8 getNumTEs() const { return (U8)(num_textures); } + +private: + U8* data; // one big chunk of data + size_t num_textures; + +public: + // re-cast offsets into data + LLUUID* image_ids; + LLMaterialID* material_ids; + LLColor4U* colors; + F32* scale_s; + F32* scale_t; + S16* offset_s; + S16* offset_t; + S16* rot; + U8* bump; + U8* media_flags; + U8* glow; + U8* alpha_gamma; + // Note: we keep larger elements near the front so they are always 16-byte aligned, + // even for odd num_textures, and byte-sized elements to the back. }; class LLPrimitive : public LLXform @@ -498,12 +512,15 @@ class LLPrimitive : public LLXform void copyTEs(const LLPrimitive *primitive); S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const; + + S32 packTEMessageBuffer(U8* packed_buffer) const; bool packTEMessage(LLMessageSystem *mesgsys) const; - bool packTEMessage(LLDataPacker &dp) const; + S32 unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num); // Variable num of blocks S32 unpackTEMessage(LLDataPacker &dp); S32 parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec); - S32 applyParsedTEMessage(LLTEContents& tec); + static S32 parseTEMessage(U8* packed_buffer, U32 data_size, LLTEContents& tec); + S32 applyParsedTEMessage(const LLTEContents& tec); #ifdef CHECK_FOR_FINITE inline void setPosition(const LLVector3& pos); diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index 939957e650..b19a1049bb 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -134,7 +134,7 @@ S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) return TEM_CHANGE_NONE; } - // we're changing an existing entry + // we're changing an existing entry llassert(mEntryList[index]); delete (mEntryList[index]); if (&te) diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index ae351d9337..23d8dce637 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -139,7 +139,7 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump, U8 alphagamma) { - setID(tex_id); + mID = tex_id; mScaleS = scale_s; mScaleT = scale_t; diff --git a/indra/llprimitive/tests/llprimitive_test.cpp b/indra/llprimitive/tests/llprimitive_test.cpp index 0213a3e8b6..906b2a3f9e 100644 --- a/indra/llprimitive/tests/llprimitive_test.cpp +++ b/indra/llprimitive/tests/llprimitive_test.cpp @@ -32,6 +32,10 @@ #include "../../llmath/llvolumemgr.h" +#include "../llmaterialid.cpp" +#include "lltextureentry_stub.cpp" +#include "llprimtexturelist_stub.cpp" + class DummyVolumeMgr : public LLVolumeMgr { public: @@ -71,45 +75,6 @@ class DummyVolumeMgr : public LLVolumeMgr S32 mCurrDetailTest; }; -LLMaterialID::LLMaterialID() {} -LLMaterialID::LLMaterialID(LLMaterialID const &m) = default; -LLMaterialID::~LLMaterialID() {} -void LLMaterialID::set(void const*) { } -U8 const * LLMaterialID::get() const { return mID; } - -LLPrimTextureList::LLPrimTextureList() { } -LLPrimTextureList::~LLPrimTextureList() { } -S32 LLPrimTextureList::setBumpMap(const U8 index, const U8 bump) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setOffsetS(const U8 index, const F32 s) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setOffsetT(const U8 index, const F32 t) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry &te) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setRotation(const U8 index, const F32 r) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setBumpShiny(const U8 index, const U8 bump_shiny) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setFullbright(const U8 index, const U8 t) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMaterialID) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setMediaFlags(const U8 index, const U8 media_flags) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setMediaTexGen(const U8 index, const U8 media) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setBumpShinyFullbright(const U8 index, const U8 bump) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setID(const U8 index, const LLUUID& id) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setGlow(const U8 index, const F32 glow) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setAlpha(const U8 index, const F32 alpha) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setColor(const U8 index, const LLColor3& color) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setColor(const U8 index, const LLColor4& color) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setScale(const U8 index, const F32 s, const F32 t) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setScaleS(const U8 index, const F32 s) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setScaleT(const U8 index, const F32 t) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setShiny(const U8 index, const U8 shiny) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setOffset(const U8 index, const F32 s, const F32 t) { return TEM_CHANGE_NONE; } -S32 LLPrimTextureList::setTexGen(const U8 index, const U8 texgen) { return TEM_CHANGE_NONE; } - -LLMaterialPtr LLPrimTextureList::getMaterialParams(const U8 index) { return LLMaterialPtr(); } -void LLPrimTextureList::copy(LLPrimTextureList const & ptl) { mEntryList = ptl.mEntryList; } // do we need to call getTexture()->newCopy()? -void LLPrimTextureList::take(LLPrimTextureList &other_list) { } -void LLPrimTextureList::setSize(S32 new_size) { mEntryList.resize(new_size); } -void LLPrimTextureList::setAllIDs(const LLUUID &id) { } -LLTextureEntry * LLPrimTextureList::getTexture(const U8 index) const { return nullptr; } -S32 LLPrimTextureList::size() const { return static_cast(mEntryList.size()); } class PRIMITIVE_TEST_SETUP { @@ -266,6 +231,170 @@ namespace tut // Ensure that we now have a different volume ensure(new_volume != primitive.getVolume()); } + + template<> template<> + void llprimitive_object_t::test<7>() + { + set_test_name("Test LLPrimitive pack/unpackTEMessageBuffer()."); + + // init some values + LLUUID image_id; + LLUUID material_uuid; + LLColor4 color(0.0f, 0.0f, 0.0f, 0.0f); + F32 scale_s = 1.0; + F32 scale_t = 1.0; + S16 offset_s = 0; + S16 offset_t = 0; + S16 rot = 0; + U8 bump = 0; + U8 media_flags = 0; + U8 glow = 0; + U8 alpha_gamma = 31; + + // init some deltas + LLColor4 d_color(0.05f, 0.07f, 0.11f, 0.13f); + F32 d_scale_s = 0.1f; + F32 d_scale_t = 0.3f; + S16 d_offset_s = 5; + S16 d_offset_t = 7; + S16 d_rot = 11; + U8 d_bump = 3; + U8 d_media_flags = 5; + U8 d_glow = 7; + U8 d_alpha_gamma = 11; + + // prep the containers + U8 num_textures = 5; + LLPrimitive primitive_A; + primitive_A.setNumTEs(num_textures); + LLTextureEntry texture_entry; + LLTEContents contents_A(num_textures); + LLTEContents contents_B(num_textures); + + // fill contents_A and primitive_A + for (U8 i = 0; i < num_textures; ++i) + { + // generate fake texture data + image_id.generate(); + material_uuid.generate(); + color += d_color; + scale_s += d_scale_s; + scale_t -= d_scale_t; + offset_s += d_offset_s; + offset_t -= d_offset_t; + rot += d_rot; + bump += d_bump; + media_flags += d_media_flags; + glow += d_glow; + alpha_gamma += d_alpha_gamma; + + // store the fake texture data in contents + contents_A.image_ids[i] = image_id; + + LLMaterialID material_id; + material_id.set(material_uuid.mData); + contents_A.material_ids[i] = material_id; + + contents_A.colors[i].setVecScaleClamp(color); + + contents_A.scale_s[i] = scale_s; + contents_A.scale_t[i] = scale_t; + contents_A.offset_s[i] = offset_s; + contents_A.offset_t[i] = offset_t; + contents_A.rot[i] = rot; + contents_A.bump[i] = bump; + contents_A.glow[i] = glow; + contents_A.media_flags[i] = media_flags & TEM_MEDIA_MASK; + contents_A.alpha_gamma[i] = alpha_gamma; + + // store the fake texture data in texture_entry + F32 f_offset_s = (F32)offset_s / (F32)0x7FFF; + F32 f_offset_t = (F32)offset_t / (F32)0x7FFF; + + // Texture rotations are sent over the wire as a S16. This is used to scale the actual float + // value to a S16. Don't use 7FFF as it introduces some odd rounding with 180 since it + // can't be divided by 2. See DEV-19108 + constexpr F32 TEXTURE_ROTATION_PACK_FACTOR = ((F32) 0x08000); + F32 f_rotation = ((F32)rot / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI; + + F32 f_glow = (F32)glow / (F32)0xFF; + + texture_entry.init(image_id, scale_s, scale_t, f_offset_s, f_offset_t, f_rotation, bump, alpha_gamma); + texture_entry.setMaterialID(material_id); + texture_entry.setColor(color); + texture_entry.setMediaFlags(media_flags); + texture_entry.setGlow(f_glow); + texture_entry.setAlphaGamma(alpha_gamma); + + // store texture_entry in primitive_A + primitive_A.setTE(i, texture_entry); + } + + // pack buffer from primitive_A + constexpr size_t MAX_TE_BUFFER = 4096; + U8 buffer[MAX_TE_BUFFER]; + S32 num_bytes = primitive_A.packTEMessageBuffer(buffer); + ensure_not_equals(num_bytes, 0); + + // unpack buffer into contents_B + // but first manually null-terminate the buffer as required by LLPrimitive::parseTEMessage() + // because last TEField is not null-terminated in the message, + // but it needs to be null-terminated for unpacking + buffer[num_bytes] = 0; + ++num_bytes; + bool success = LLPrimitive::parseTEMessage(buffer, num_bytes, contents_B); + ensure(success); + + // compare contents + for (U8 i = 0; i < num_textures; ++i) + { + ensure_equals(contents_A.image_ids[i], contents_B.image_ids[i]); + ensure_equals(contents_A.material_ids[i], contents_B.material_ids[i]); + ensure_equals(contents_A.colors[i], contents_B.colors[i]); + ensure_equals(contents_A.scale_s[i], contents_B.scale_s[i]); + ensure_equals(contents_A.scale_t[i], contents_B.scale_t[i]); + ensure_equals(contents_A.offset_s[i], contents_B.offset_s[i]); + ensure_equals(contents_A.offset_t[i], contents_B.offset_t[i]); + ensure_equals(contents_A.rot[i], contents_B.rot[i]); + ensure_equals(contents_A.bump[i], contents_B.bump[i]); + ensure_equals(contents_A.media_flags[i], contents_B.media_flags[i]); + ensure_equals(contents_A.glow[i], contents_B.glow[i]); + ensure_equals(contents_A.alpha_gamma[i], contents_B.alpha_gamma[i]); + } + + // create primitive_B + LLPrimitive primitive_B; + primitive_B.setNumTEs(num_textures); + + // apply contents_B + primitive_B.applyParsedTEMessage(contents_B); + + // compare primitives + for (U8 i = 0; i < num_textures; ++i) + { + LLTextureEntry* te_A = primitive_A.getTE(i); + LLTextureEntry* te_B = primitive_B.getTE(i); + + ensure_equals(te_A->getID(), te_B->getID()); + ensure_equals(te_A->getMaterialID(), te_B->getMaterialID()); + + // color can experience quantization error after pack/unpack, so we check for proximity + ensure(distVec(te_A->getColor(), te_B->getColor()) < 0.005f); + + // Note: ;scale, offset, and rotation can also experience a little quantization error + // however it happens to be zero for the values we use in this test + ensure_equals(te_A->getScaleS(), te_B->getScaleS()); + ensure_equals(te_A->getScaleT(), te_B->getScaleT()); + ensure_equals(te_A->getOffsetS(), te_B->getOffsetS()); + ensure_equals(te_A->getOffsetT(), te_B->getOffsetT()); + ensure_equals(te_A->getRotation(), te_B->getRotation()); + + ensure_equals(te_A->getBumpShinyFullbright(), te_B->getBumpShinyFullbright()); + ensure_equals(te_A->getMediaFlags(), te_B->getMediaFlags()); + ensure_equals(te_A->getGlow(), te_B->getGlow()); + ensure_equals(te_A->getAlphaGamma(), te_B->getAlphaGamma()); + } + } } #include "llmessagesystem_stub.cpp" diff --git a/indra/llprimitive/tests/llprimtexturelist_stub.cpp b/indra/llprimitive/tests/llprimtexturelist_stub.cpp new file mode 100644 index 0000000000..f78c9b0120 --- /dev/null +++ b/indra/llprimitive/tests/llprimtexturelist_stub.cpp @@ -0,0 +1,292 @@ +/** + * @file llprimtexturelist_stub.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +#pragma once + +LLTextureEntry* LLPrimTextureList::newTextureEntry() +{ + return new LLTextureEntry(); +} + +LLPrimTextureList::LLPrimTextureList() { } +LLPrimTextureList::~LLPrimTextureList() { } + +S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) +{ + if (size_t(index) >= mEntryList.size()) + { + auto current_size = mEntryList.size(); + return TEM_CHANGE_NONE; + } + + // we're changing an existing entry + llassert(mEntryList[index]); + delete (mEntryList[index]); + if (&te) + { + mEntryList[index] = te.newCopy(); + } + else + { + mEntryList[index] = LLPrimTextureList::newTextureEntry(); + } + return TEM_CHANGE_TEXTURE; +} + +S32 LLPrimTextureList::setFullbright(const U8 index, const U8 t) { return TEM_CHANGE_NONE; } +S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams) { return TEM_CHANGE_NONE; } +S32 LLPrimTextureList::setShiny(const U8 index, const U8 shiny) { return TEM_CHANGE_NONE; } +S32 LLPrimTextureList::setTexGen(const U8 index, const U8 texgen) { return TEM_CHANGE_NONE; } + +LLMaterialPtr LLPrimTextureList::getMaterialParams(const U8 index) { return LLMaterialPtr(); } +void LLPrimTextureList::copy(LLPrimTextureList const & ptl) { mEntryList = ptl.mEntryList; } // do we need to call getTexture()->newCopy()? +void LLPrimTextureList::take(LLPrimTextureList &other_list) { } + +// sets the size of the mEntryList container +void LLPrimTextureList::setSize(S32 new_size) +{ + if (new_size < 0) + { + new_size = 0; + } + + auto current_size = mEntryList.size(); + + if (new_size > current_size) + { + mEntryList.resize(new_size); + for (size_t index = current_size; index < new_size; ++index) + { + if (current_size > 0 + && mEntryList[current_size - 1]) + { + // copy the last valid entry for the new one + mEntryList[index] = mEntryList[current_size - 1]->newCopy(); + } + else + { + // no valid enries to copy, so we new one up + LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry(); + mEntryList[index] = new_entry; + } + } + } + else if (new_size < current_size) + { + for (size_t index = current_size-1; index >= new_size; --index) + { + delete mEntryList[index]; + } + mEntryList.resize(new_size); + } +} + +void LLPrimTextureList::setAllIDs(const LLUUID &id) +{ + llassert(false); // implement this if you get here +} + +// returns pointer to texture at 'index' slot +LLTextureEntry* LLPrimTextureList::getTexture(const U8 index) const +{ + if (index < mEntryList.size()) + { + return mEntryList[index]; + } + return nullptr; +} + +S32 LLPrimTextureList::size() const { return static_cast(mEntryList.size()); } + +S32 LLPrimTextureList::setID(const U8 index, const LLUUID& id) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setID(id); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setColor(const U8 index, const LLColor3& color) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setColor(color); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setColor(const U8 index, const LLColor4& color) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setColor(color); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setAlpha(const U8 index, const F32 alpha) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setAlpha(alpha); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setScale(const U8 index, const F32 s, const F32 t) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setScale(s, t); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setScaleS(const U8 index, const F32 s) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setScaleS(s); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setScaleT(const U8 index, const F32 t) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setScaleT(t); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setOffset(const U8 index, const F32 s, const F32 t) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setOffset(s, t); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setOffsetS(const U8 index, const F32 s) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setOffsetS(s); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setOffsetT(const U8 index, const F32 t) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setOffsetT(t); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setRotation(const U8 index, const F32 r) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setRotation(r); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setBumpShinyFullbright(const U8 index, const U8 bump) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setBumpShinyFullbright(bump); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setMediaTexGen(const U8 index, const U8 media) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setMediaTexGen(media); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setBumpMap(const U8 index, const U8 bump) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setBumpmap(bump); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setBumpShiny(const U8 index, const U8 bump_shiny) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setBumpShiny(bump_shiny); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setMediaFlags(const U8 index, const U8 media_flags) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setMediaFlags(media_flags); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setGlow(const U8 index, const F32 glow) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setGlow(glow); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMaterialID) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setMaterialID(pMaterialID); + } + return TEM_CHANGE_NONE; +} + +S32 LLPrimTextureList::setAlphaGamma(const U8 index, const U8 gamma) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->setAlphaGamma(gamma); + } + return TEM_CHANGE_NONE; +} diff --git a/indra/llprimitive/tests/lltextureentry_stub.cpp b/indra/llprimitive/tests/lltextureentry_stub.cpp new file mode 100644 index 0000000000..03a1db615d --- /dev/null +++ b/indra/llprimitive/tests/lltextureentry_stub.cpp @@ -0,0 +1,316 @@ +/** + * @file lltextueentry_stub.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +#pragma once + +LLTextureEntry::LLTextureEntry() + : mMediaEntry(NULL) + , mSelected(false) + , mMaterialUpdatePending(false) +{ + constexpr U8 DEFAULT_BUMP_CODE = 0; // no bump or shininess + constexpr U8 DEFAULT_ALPHA_GAMMA = 100; // Gamma 1 (linear) for alpha blending + init(LLUUID::null, 1.f, 1.f, 0.f, 0.f, 0.f, DEFAULT_BUMP_CODE, DEFAULT_ALPHA_GAMMA); +} + +LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs) + : mMediaEntry(NULL) + , mSelected(false) + , mMaterialUpdatePending(false) +{ + *this = rhs; +} + +LLTextureEntry::~LLTextureEntry() +{ +} + +// virtual +LLTextureEntry* LLTextureEntry::newBlank() const +{ + return new LLTextureEntry(); +} + +// virtual +LLTextureEntry* LLTextureEntry::newCopy() const +{ + return new LLTextureEntry(*this); +} + +LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs) +{ + if (this != &rhs) + { + mID = rhs.mID; + mScaleS = rhs.mScaleS; + mScaleT = rhs.mScaleT; + mOffsetS = rhs.mOffsetS; + mOffsetT = rhs.mOffsetT; + mRotation = rhs.mRotation; + mColor = rhs.mColor; + mBump = rhs.mBump; + mAlphaGamma = rhs.mAlphaGamma; + mMediaFlags = rhs.mMediaFlags; + mGlow = rhs.mGlow; + mMaterialID = rhs.mMaterialID; + } + + return *this; +} + +void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump, U8 alphagamma) +{ + mID = tex_id; + + mScaleS = scale_s; + mScaleT = scale_t; + mOffsetS = offset_s; + mOffsetT = offset_t; + mRotation = rotation; + mBump = bump; + mAlphaGamma = alphagamma; + mMediaFlags = 0x0; + mGlow = 0; + mMaterialID.clear(); + + mColor = LLColor4(1.f, 1.f, 1.f, 1.f); +} + +S32 LLTextureEntry::setID(const LLUUID &tex_id) +{ + if (mID != tex_id) + { + mID = tex_id; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setColor(const LLColor4 &color) +{ + if (mColor != color) + { + mColor = color; + return TEM_CHANGE_COLOR; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setColor(const LLColor3 &color) +{ + if (mColor != color) + { + // This preserves alpha. + mColor.setVec(color); + return TEM_CHANGE_COLOR; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setAlpha(const F32 alpha) +{ + if (mColor.mV[VALPHA] != alpha) + { + mColor.mV[VALPHA] = alpha; + return TEM_CHANGE_COLOR; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setScale(F32 s, F32 t) +{ + S32 retval = 0; + + if ( (mScaleS != s) + ||(mScaleT != t)) + { + mScaleS = s; + mScaleT = t; + + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + +S32 LLTextureEntry::setScaleS(F32 s) +{ + S32 retval = TEM_CHANGE_NONE; + if (mScaleS != s) + { + mScaleS = s; + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + +S32 LLTextureEntry::setScaleT(F32 s) +{ + S32 retval = TEM_CHANGE_NONE; + if (mScaleT != s) + { + mScaleT = s; + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + +S32 LLTextureEntry::setOffset(F32 s, F32 t) +{ + S32 retval = 0; + + if ( (mOffsetS != s) + ||(mOffsetT != t)) + { + mOffsetS = s; + mOffsetT = t; + + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + +S32 LLTextureEntry::setOffsetS(F32 s) +{ + S32 retval = 0; + if (mOffsetS != s) + { + mOffsetS = s; + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + +S32 LLTextureEntry::setOffsetT(F32 t) +{ + S32 retval = 0; + if (mOffsetT != t) + { + mOffsetT = t; + retval = TEM_CHANGE_TEXTURE; + } + return retval; +} + +S32 LLTextureEntry::setRotation(F32 theta) +{ + if (mRotation != theta && llfinite(theta)) + { + mRotation = theta; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setBumpmap(U8 bump) +{ + bump &= TEM_BUMP_MASK; + if (getBumpmap() != bump) + { + mBump &= ~TEM_BUMP_MASK; + mBump |= bump; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setGlow(F32 glow) +{ + if (mGlow != glow) + { + mGlow = glow; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setMaterialID(const LLMaterialID& pMaterialID) +{ + if (mMaterialID != pMaterialID) + { + mMaterialID = pMaterialID; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setBumpShinyFullbright(U8 bump) +{ + if (mBump != bump) + { + mBump = bump; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setBumpShiny(U8 bump_shiny) +{ + bump_shiny &= TEM_BUMP_SHINY_MASK; + if (getBumpShiny() != bump_shiny) + { + mBump &= ~TEM_BUMP_SHINY_MASK; + mBump |= bump_shiny; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setAlphaGamma(U8 alpha_gamma) +{ + if (mAlphaGamma != alpha_gamma) + { + mAlphaGamma = alpha_gamma; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setMediaTexGen(U8 media) +{ + S32 result = TEM_CHANGE_NONE; + result |= setTexGen(media & TEM_TEX_GEN_MASK); + result |= setMediaFlags(media & TEM_MEDIA_MASK); + return result; +} + +S32 LLTextureEntry::setTexGen(U8 tex_gen) +{ + tex_gen &= TEM_TEX_GEN_MASK; + if (getTexGen() != tex_gen) + { + mMediaFlags &= ~TEM_TEX_GEN_MASK; + mMediaFlags |= tex_gen; + return TEM_CHANGE_TEXTURE; + } + return TEM_CHANGE_NONE; +} + +S32 LLTextureEntry::setMediaFlags(U8 media_flags) +{ + media_flags &= TEM_MEDIA_MASK; + mMediaFlags &= ~TEM_MEDIA_MASK; + mMediaFlags |= media_flags; + return TEM_CHANGE_NONE; +} diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 9e212dc9c5..d65bd30925 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -421,7 +421,6 @@ bool LLPanelFace::postBuild() getChildSetCommitCallback(mCheckFullbright, "checkbox fullbright", [&](LLUICtrl*, const LLSD&) { onCommitFullbright(); }); - mLabelTexGen = getChild("alpha gamma"); getChildSetCommitCallback(mComboAlphaGamma, "combobox alpha gamma", [&](LLUICtrl *, const LLSD &) { onCommitAlphaGamma(); }); mComboAlphaGamma->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); @@ -1325,14 +1324,6 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } - // Alpha gamma. This should always be enabled, no matter if the object is mod or not. - { - U8 alpha_gamma = 100; - bool identical_alpha_gamma = false; - LLSelectedTE::getAlphaGamma(alpha_gamma, identical_alpha_gamma); - mComboAlphaGamma->getSelectionInterface()->selectByValue(alpha_gamma); - mComboAlphaGamma->setEnabled(true); - } // planar align bool align_planar = mPlanarAlign->get(); @@ -1820,6 +1811,15 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) calcp->clearVar(LLCalc::TEX_TRANSPARENCY); calcp->clearVar(LLCalc::TEX_GLOW); } + if (objectp && (objectp->permModify() || objectp->permYouOwner())) + { + // AlphaGamma should enabled when modable or owned + U8 alpha_gamma = 100; + bool identical_alpha_gamma = false; + LLSelectedTE::getAlphaGamma(alpha_gamma, identical_alpha_gamma); + mComboAlphaGamma->getSelectionInterface()->selectByValue(alpha_gamma); + mComboAlphaGamma->setEnabled(true); + } } // One-off listener that updates the build floater UI when the agent inventory adds or removes an item diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index fab3698833..f1e2c7d7d4 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1728,6 +1728,18 @@ struct LLSelectMgrSendFunctor : public LLSelectedObjectFunctor } }; +struct LLSelectMgrAlphaGammaBypassFunctor : public LLSelectedObjectFunctor +{ + virtual bool apply(LLViewerObject* object) + { + if (object->permYouOwner()) + { + LLSelectMgr::packAlphaGammaBypass(object); + } + return true; + } +}; + void LLObjectSelection::applyNoCopyTextureToTEs(LLViewerInventoryItem* item) { if (!item) @@ -2330,21 +2342,18 @@ void LLSelectMgr::selectionSetAlphaGamma(U8 gamma) f(const U8 &t) : mAlphaGamma(t) {} bool apply(LLViewerObject *object, S32 te) { - if (object->permModify()) + bool can_modify = object->permModify(); + if (can_modify || object->permYouOwner()) { // update viewer side color in anticipation of update from simulator object->setTEAlphaGamma(te, mAlphaGamma); } - else - { - packAlphaGammaOverride(object); - } return true; } } setfunc(gamma); getSelection()->applyToTEs(&setfunc); - LLSelectMgrSendFunctor sendfunc; + LLSelectMgrAlphaGammaBypassFunctor sendfunc; getSelection()->applyToObjects(&sendfunc); } @@ -5798,7 +5807,8 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, // LL_INFOS() << "sendListToRegions " << message_name << " obj " << objects_sent << " pkt " << packets_sent << LL_ENDL; } -void LLSelectMgr::packAlphaGammaOverride(LLViewerObject* object) +// static +void LLSelectMgr::packAlphaGammaBypass(LLViewerObject* object) { gMessageSystem->newMessageFast(_PRHASH_ObjectBypassModUpdate); gMessageSystem->nextBlockFast(_PREHASH_AgentData); @@ -5813,7 +5823,7 @@ void LLSelectMgr::packAlphaGammaOverride(LLViewerObject* object) U8 packed_buffer[LLTEContents::MAX_TE_BUFFER]; U8* cur_ptr = packed_buffer; - S32 last_face_index = llmin((U32) object->getNumTEs(), LLTEContents::MAX_TES) - 1; + S32 last_face_index = (S32)llmin(object->getNumTEs(), (U8)LLTEContents::MAX_TES) - 1; if (last_face_index > -1) { diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 2c8b36e704..fa54fd0637 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -901,12 +901,13 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton static void logAttachmentRequest(LLSelectNode* node, void *user_data); static void logDetachRequest(LLSelectNode* node, void *user_data); static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle); - static void packAlphaGammaOverride(LLViewerObject* object); // Get the first ID that matches test and whether or not all ids are identical in selected objects. void getFirst(LLSelectGetFirstTest* test); public: + static void packAlphaGammaBypass(LLViewerObject* object); + // Observer/callback support for when object selection changes or // properties are received/updated typedef boost::signals2::signal< void ()> update_signal_t; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 86440fca48..e16663ff08 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3114,8 +3114,8 @@ struct LLFilenameAndTask LL_DEBUGS() << "Destroying LLFilenameAndTask: " << sCount << LL_ENDL; } private: - LLFilenameAndTask(const LLFilenameAndTask& rhs); - const LLFilenameAndTask& operator=(const LLFilenameAndTask& rhs) const; + LLFilenameAndTask(const LLFilenameAndTask& rhs) = delete; + const LLFilenameAndTask& operator=(const LLFilenameAndTask& rhs) = delete; #endif }; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b6a2dac1e9..0a790f0703 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -242,7 +242,8 @@ struct LLTextureMaskData struct LLAppearanceMessageContents: public LLRefCount { - LLAppearanceMessageContents(): + LLAppearanceMessageContents(U8 num_tes): + mTEContents(num_tes), mAppearanceVersion(-1), mParamAppearanceVersion(-1), mCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN) @@ -9433,10 +9434,10 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, apr_file_printf(file, "\n"); apr_file_printf(file, "\n\n"); - for (U32 i = 0; i < tec.face_count; i++) + for (U32 i = 0; i < tec.getNumTEs(); i++) { std::string uuid_str; - ((LLUUID*)tec.image_data)[i].toString(uuid_str); + tec.image_ids[i].toString(uuid_str); apr_file_printf( file, "\t\t\n", i, uuid_str.c_str()); } apr_file_printf(file, "\n"); @@ -9621,7 +9622,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) mLastAppearanceMessageTimer.reset(); - LLPointer contents(new LLAppearanceMessageContents); + S32 num_tes = getNumTEs(); + LLPointer contents(new LLAppearanceMessageContents(num_tes)); parseAppearanceMessage(mesgsys, *contents); if (enable_verbose_dumps) { From 0a879c4eec43a4a587d66fe0da447db263b3dabc Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Mon, 23 Sep 2024 11:00:18 -0400 Subject: [PATCH 07/15] #2323 Make sure DrawInfos are working mostly as intended. Selection is still wonky. --- indra/llrender/llshadermgr.cpp | 1 + indra/llrender/llshadermgr.h | 1 + .../app_settings/shaders/class2/deferred/alphaF.glsl | 3 ++- .../app_settings/shaders/class3/deferred/materialF.glsl | 4 +++- indra/newview/lldrawpoolalpha.cpp | 5 +++++ indra/newview/llspatialpartition.cpp | 3 ++- indra/newview/llspatialpartition.h | 3 ++- indra/newview/llvograss.cpp | 3 ++- indra/newview/llvopartgroup.cpp | 8 ++++++-- indra/newview/llvovolume.cpp | 6 ++++-- 10 files changed, 28 insertions(+), 9 deletions(-) diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 150277c8df..43ae5d81f0 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1295,6 +1295,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("minimum_alpha"); mReservedUniforms.push_back("emissive_brightness"); + mReservedUniforms.push_back("alpha_gamma"); // Deferred mReservedUniforms.push_back("shadow_matrix"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 0eb9db6715..a14308076c 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -153,6 +153,7 @@ class LLShaderMgr MINIMUM_ALPHA, // "minimum_alpha" EMISSIVE_BRIGHTNESS, // "emissive_brightness" + ALPHA_GAMMA, DEFERRED_SHADOW_MATRIX, // "shadow_matrix" DEFERRED_ENV_MAT, // "env_mat" diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 210ecce8db..3a10e74608 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -36,6 +36,7 @@ out vec4 frag_color; uniform mat3 env_mat; uniform vec3 sun_dir; uniform vec3 moon_dir; +uniform float alpha_gamma; #ifdef USE_DIFFUSE_TEX uniform sampler2D diffuseMap; @@ -258,7 +259,7 @@ void main() vec4 color = vec4(0.0); - color.a = final_alpha; + color.a = pow(final_alpha, alpha_gamma); vec3 sun_contrib = min(final_da, shadow) * sunlit_linear; diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index 26ab0406f6..79ad3b1e3e 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -87,6 +87,8 @@ uniform vec3 light_direction[8]; uniform vec4 light_attenuation[8]; uniform vec3 light_diffuse[8]; +uniform float alpha_gamma; + float getAmbientClamp(); void waterClip(vec3 pos); @@ -403,7 +405,7 @@ void main() glare *= 1.0-emissive; glare = min(glare, 1.0); - float al = max(diffcol.a, glare) * vertex_color.a; + float al = pow(max(diffcol.a, glare) * vertex_color.a, alpha_gamma); frag_color = max(vec4(color, al), vec4(0)); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 87b6ce6cb3..3c3419c466 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -746,6 +746,10 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) LLVector4 spec_color(1, 1, 1, 1); F32 env_intensity = 0.0f; F32 brightness = 1.0f; + F32 alpha_gam = 1.f; + + if (params.mAlphaGamma != 0) + alpha_gam = (F32)params.mAlphaGamma * 0.01f; // We have a material. Supply the appropriate data here. if (mat) @@ -757,6 +761,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) if (current_shader) { + current_shader->uniform1f(LLShaderMgr::ALPHA_GAMMA, alpha_gam); current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[VRED], spec_color.mV[VGREEN], spec_color.mV[VBLUE], spec_color.mV[VALPHA]); current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity); current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index a1a67c319c..684bb6cd85 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -3838,7 +3838,7 @@ LLDrawable* LLSpatialGroup::lineSegmentIntersect(const LLVector4a& start, const LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, LLViewerTexture* texture, LLVertexBuffer* buffer, - bool fullbright, U8 bump) + bool fullbright, U8 bump, U8 alpha_gamma) : mVertexBuffer(buffer), mTexture(texture), mStart(start), @@ -3847,6 +3847,7 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, mOffset(offset), mFullbright(fullbright), mBump(bump), + mAlphaGamma(alpha_gamma), mBlendFuncSrc(LLRender::BF_SOURCE_ALPHA), mBlendFuncDst(LLRender::BF_ONE_MINUS_SOURCE_ALPHA), mHasGlow(false), diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 3aaa3d60e8..db27cd566d 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -87,7 +87,7 @@ class LLDrawInfo final : public LLRefCount LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, LLViewerTexture* image, LLVertexBuffer* buffer, - bool fullbright = false, U8 bump = 0); + bool fullbright = false, U8 bump = 0, U8 alpha_gamma = 100); void validate(); @@ -134,6 +134,7 @@ class LLDrawInfo final : public LLRefCount U8 mDiffuseAlphaMode = 0; U8 mBump = 0; U8 mShiny = 0; + U8 mAlphaGamma = 100; bool mFullbright = false; bool mHasGlow = false; diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index fdd39a0e30..bf76b2cc8a 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -702,6 +702,7 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group) S32 idx = static_cast(draw_vec.size()) - 1; bool fullbright = facep->isState(LLFace::FULLBRIGHT); + U8 alpha_gamma = 100; if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && draw_vec[idx]->mTexture == facep->getTexture() && @@ -721,7 +722,7 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group) U32 count = facep->getIndicesCount(); LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), //facep->getTexture(), - buffer, object->isSelected(), fullbright); + buffer, object->isSelected(), fullbright, (F32)alpha_gamma * 0.01f); draw_vec.push_back(info); //for alpha sorting diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index ec32a79829..d95c0a4251 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -845,6 +845,9 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) S32 idx = static_cast(draw_vec.size()) - 1; bool fullbright = facep->isState(LLFace::FULLBRIGHT); + U8 alpha_gamma = 100; + if (facep->getTextureEntry()) + alpha_gamma = facep->getTextureEntry()->getAlphaGamma(); bool batched = false; @@ -862,7 +865,8 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) info->mHasGlow == has_glow && info->mFullbright == fullbright && info->mBlendFuncDst == bf_dst && - info->mBlendFuncSrc == bf_src) + info->mBlendFuncSrc == bf_src && + info->mAlphaGamma == alpha_gamma) { if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1) { @@ -887,7 +891,7 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) U32 offset = facep->getIndicesStart(); U32 count = facep->getIndicesCount(); LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), - buffer, fullbright); + buffer, fullbright, 0, alpha_gamma); info->mBlendFuncDst = bf_dst; info->mBlendFuncSrc = bf_src; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 2859f8b1c2..a92e0de2cf 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5288,6 +5288,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, const LLTextureEntry* te = facep->getTextureEntry(); U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? te->getBumpmap() : 0; U8 shiny = te->getShiny(); + U8 alpha_gamma = te->getAlphaGamma(); LLViewerTexture* tex = facep->getTexture(); @@ -5370,6 +5371,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, info->mMaterialID == mat_id && info->mFullbright == fullbright && info->mBump == bump && + info->mAlphaGamma == alpha_gamma && (!mat || (info->mShiny == shiny)) && // need to break batches when a material is shared, but legacy settings are different info->mTextureMatrix == tex_mat && info->mModelMatrix == model_mat && @@ -5393,8 +5395,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 end = start + facep->getGeomCount()-1; U32 offset = facep->getIndicesStart(); U32 count = facep->getIndicesCount(); - LLPointer draw_info = new LLDrawInfo(start,end,count,offset, tex, - facep->getVertexBuffer(), fullbright, bump); + LLPointer draw_info = new LLDrawInfo(start,end,count,offset, tex, facep->getVertexBuffer(), fullbright, bump, alpha_gamma); info = draw_info; @@ -5422,6 +5423,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_info->mShaderMask = shader_mask; draw_info->mAvatar = facep->mAvatar; draw_info->mSkinInfo = facep->mSkinInfo; + draw_info->mAlphaGamma = alpha_gamma; if (gltf_mat) { From 53958ec99c84defba1c02d2871600dcb7814881a Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Mon, 23 Sep 2024 11:13:05 -0400 Subject: [PATCH 08/15] #2323 Make sure we're registering alpha gamma with face registration. --- indra/newview/llvograss.cpp | 3 +-- indra/newview/llvovolume.cpp | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index bf76b2cc8a..f301b24e36 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -702,7 +702,6 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group) S32 idx = static_cast(draw_vec.size()) - 1; bool fullbright = facep->isState(LLFace::FULLBRIGHT); - U8 alpha_gamma = 100; if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && draw_vec[idx]->mTexture == facep->getTexture() && @@ -722,7 +721,7 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group) U32 count = facep->getIndicesCount(); LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), //facep->getTexture(), - buffer, object->isSelected(), fullbright, (F32)alpha_gamma * 0.01f); + buffer, object->isSelected(), fullbright, 100); draw_vec.push_back(info); //for alpha sorting diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index a92e0de2cf..08e4d9e825 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5377,6 +5377,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, info->mModelMatrix == model_mat && info->mShaderMask == shader_mask && info->mAvatar == facep->mAvatar && + info->mAlphaGamma == alpha_gamma && info->getSkinHash() == facep->getSkinHash()) { info->mCount += facep->getIndicesCount(); From 3288bba975a59820586f7314a19bb7435738f487 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Mon, 23 Sep 2024 13:37:58 -0400 Subject: [PATCH 09/15] Switch to use TEM_CHANGE_COLOR --- indra/llprimitive/lltextureentry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 23d8dce637..939012f60b 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -488,7 +488,7 @@ S32 LLTextureEntry::setAlphaGamma(U8 alpha_gamma) if (mAlphaGamma != alpha_gamma) { mAlphaGamma = alpha_gamma; - return TEM_CHANGE_TEXTURE; + return TEM_CHANGE_COLOR; } return TEM_CHANGE_NONE; } From 44344e89a45f0edf61ea91d74954915ec04050f9 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 24 Sep 2024 14:59:39 +0300 Subject: [PATCH 10/15] #2655 update alpha gamma drop down position --- indra/newview/llpanelface.cpp | 4 +- indra/newview/llpanelface.h | 1 + .../default/xui/en/panel_tools_texture.xml | 72 +++++++++---------- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index d65bd30925..98f6406852 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -421,7 +421,7 @@ bool LLPanelFace::postBuild() getChildSetCommitCallback(mCheckFullbright, "checkbox fullbright", [&](LLUICtrl*, const LLSD&) { onCommitFullbright(); }); - mLabelTexGen = getChild("alpha gamma"); + mLabelAlphaGamma = getChild("alpha gamma"); getChildSetCommitCallback(mComboAlphaGamma, "combobox alpha gamma", [&](LLUICtrl *, const LLSD &) { onCommitAlphaGamma(); }); mComboAlphaGamma->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); @@ -1819,6 +1819,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) LLSelectedTE::getAlphaGamma(alpha_gamma, identical_alpha_gamma); mComboAlphaGamma->getSelectionInterface()->selectByValue(alpha_gamma); mComboAlphaGamma->setEnabled(true); + mLabelAlphaGamma->setEnabled(true); } } @@ -2845,7 +2846,6 @@ void LLPanelFace::updateVisibility(LLViewerObject* objectp /* = nullptr */) // Shared material controls mComboAlphaGamma->setVisible(true); - mComboAlphaGamma->setEnabled(true); mCheckSyncSettings->setVisible(show_material || show_media); mLabelTexGen->setVisible(show_material || show_media || show_pbr_asset); mComboTexGen->setVisible(show_material || show_media || show_pbr_asset); diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 399456e269..2747f1b6a3 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -306,6 +306,7 @@ class LLPanelFace : public LLPanel LLTextBox* mLabelTexGen { nullptr }; LLComboBox* mComboTexGen { nullptr }; + LLTextBox* mLabelAlphaGamma{ nullptr }; LLComboBox *mComboAlphaGamma {nullptr}; LLRadioGroup* mRadioMaterialType { nullptr }; diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index b706b06620..0498afc657 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -641,39 +641,6 @@ tool_tip="Click to open color picker" top_delta="-4" width="64" /> - - Alpha Gamma - - - - - - + + Alpha Gamma + + + + + + Mapping @@ -959,7 +959,7 @@ left="7" name="checkbox planar align" tool_tip="Align textures on all selected faces with the last selected face. Requires Planar texture mapping." - top_delta="20" + top_delta="16" width="260" />