diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 7ab25908e2c..2cd650f4441 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -1402,6 +1402,8 @@ 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 _PREHASH_ObjectBypassModUpdate = LLMessageStringTable::getInstance()->getString("ObjectBypassModUpdate"); +char const* const _PREHASH_PropertyID = LLMessageStringTable::getInstance()->getString("PropertyID"); char const* const _PREHASH_GameControlInput = LLMessageStringTable::getInstance()->getString("GameControlInput"); char const* const _PREHASH_AxisData = LLMessageStringTable::getInstance()->getString("AxisData"); char const* const _PREHASH_MetaData = LLMessageStringTable::getInstance()->getString("MetaData"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 88dee7f9616..772e8d2cec3 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -1403,6 +1403,8 @@ 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 _PREHASH_ObjectBypassModUpdate; +extern char const* const _PREHASH_PropertyID; extern char const* const _PREHASH_GameControlInput; extern char const* const _PREHASH_AxisData; extern char const* const _PREHASH_MetaData; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index c5d6076b984..598e8d229ff 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 ) { @@ -385,6 +453,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); @@ -1194,284 +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 -{ - 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 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]; + // 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(), 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(); - 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); - } - 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 { - 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 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 *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(); - 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); - } - - dp.packBinaryData(packed_buffer, (S32)(cur_ptr - packed_buffer), "TextureEntry"); + 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 + } + } + + // undo the zero-encode color optimization + const LLColor4U white(255, 255, 255, 255); + for (U8 i = 0; i < num_textures; ++i) + { + 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]); - - // 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); + retval |= setTEAlphaGamma(i, tec.alpha_gamma[i]); } - 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; @@ -1487,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; - - 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)); - } + packed_buffer[data_size] = 0x00; + ++data_size; - 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 31bc76344c3..e5bddc910d6 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -399,27 +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 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 @@ -482,6 +497,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); @@ -496,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 76322a9d29f..59129b2ca78 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]); mEntryList[index] = te.newCopy(); @@ -298,6 +298,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 79744e9f08e..a9e6b7b38a9 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 ac482ffbf9c..939012f60b1 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,9 +137,9 @@ 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); + mID = tex_id; mScaleS = scale_s; mScaleT = scale_t; @@ -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_COLOR; + } + 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 78c61b4d654..717c3bd0d96 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/llprimitive/tests/llprimitive_test.cpp b/indra/llprimitive/tests/llprimitive_test.cpp index 0213a3e8b67..906b2a3f9ed 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 00000000000..f78c9b01200 --- /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 00000000000..03a1db615df --- /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/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 796805e2a57..0058805991d 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1296,6 +1296,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 ff07ce454ba..e74937cb739 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -154,6 +154,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 e9f849a8c0e..c4d0974ab9e 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 5ee9aea09d6..4a14a7de04c 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 5379bcc985f..05f2528de4b 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -737,6 +737,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) @@ -748,6 +752,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/llpanelface.cpp b/indra/newview/llpanelface.cpp index 7a63c6e10d3..5de5c6b2638 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -93,6 +93,7 @@ #include "llsdutil.h" #include "llsdserialize.h" #include "llinventorymodel.h" +#include "roles_constants.h" using namespace std::literals; @@ -421,6 +422,10 @@ bool LLPanelFace::postBuild() getChildSetCommitCallback(mCheckFullbright, "checkbox fullbright", [&](LLUICtrl*, const LLSD&) { onCommitFullbright(); }); + mLabelAlphaGamma = 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,13 @@ void LLPanelFace::sendBump(U32 bumpiness) LLSelectMgr::getInstance()->selectionSetBumpmap( bump, mBumpyTextureCtrl->getImageItemID() ); } +void LLPanelFace::sendAlphaGamma() +{ + U8 alpha_gamma = (U8) mComboAlphaGamma->getValue().asInteger(); + + LLSelectMgr::getInstance()->selectionSetAlphaGamma(alpha_gamma); +} + void LLPanelFace::sendTexGen() { U8 tex_gen = (U8)mComboTexGen->getCurrentIndex() << TEM_TEX_GEN_SHIFT; @@ -1313,6 +1325,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } + // planar align bool align_planar = mPlanarAlign->get(); bool identical_planar_aligned = false; @@ -1799,6 +1812,38 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) calcp->clearVar(LLCalc::TEX_TRANSPARENCY); calcp->clearVar(LLCalc::TEX_GLOW); } + + bool agent_group_mod = false; + if (objectp && objectp->permGroupOwner()) + { + LLUUID owner_id; + std::string owner_name; + LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); + agent_group_mod = gAgent.hasPowerInGroup(owner_id, GP_OBJECT_MANIPULATE); + } + + if (objectp && (objectp->permModify() + || objectp->permYouOwner() + || agent_group_mod)) + { + // 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); + mComboAlphaGamma->setTentative(!identical_alpha_gamma); + mComboAlphaGamma->setVisible(true); + mLabelAlphaGamma->setEnabled(true); + mLabelAlphaGamma->setVisible(true); + } + else + { + mLabelAlphaGamma->setEnabled(false); + mLabelAlphaGamma->setVisible(false); + mComboAlphaGamma->setEnabled(false); + mComboAlphaGamma->setVisible(false); + } } // One-off listener that updates the build floater UI when the agent inventory adds or removes an item @@ -2914,6 +2959,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 4d2ce208b40..fbeb317618b 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,9 @@ class LLPanelFace : public LLPanel LLTextBox* mLabelTexGen { nullptr }; LLComboBox* mComboTexGen { nullptr }; + LLTextBox* mLabelAlphaGamma{ nullptr }; + LLComboBox *mComboAlphaGamma {nullptr}; + LLRadioGroup* mRadioMaterialType { nullptr }; LLRadioGroup* mRadioPbrType { nullptr }; @@ -700,7 +705,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 d0347c7abf7..0b1c056bf63 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -97,6 +97,7 @@ #include "llpanelface.h" #include "llglheaders.h" #include "llinventoryobserver.h" +#include "roles_constants.h" LLViewerObject* getSelectedParentObject(LLViewerObject *object) ; // @@ -1728,6 +1729,26 @@ struct LLSelectMgrSendFunctor : public LLSelectedObjectFunctor } }; +struct LLSelectMgrAlphaGammaBypassFunctor : public LLSelectedObjectFunctor +{ + LLSelectMgrAlphaGammaBypassFunctor(bool agent_mod_group_obj) : mAgentModGroupObj(agent_mod_group_obj) {} + + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->sendTEUpdate(); + } + else if (object->permYouOwner() || (object->permGroupOwner() && mAgentModGroupObj)) + { + LLSelectMgr::packAlphaGammaBypass(object); + } + return true; + } + + bool mAgentModGroupObj { false }; +}; + void LLObjectSelection::applyNoCopyTextureToTEs(LLViewerInventoryItem* item) { if (!item) @@ -2322,6 +2343,35 @@ void LLSelectMgr::selectionSetBumpmap(U8 bumpmap, const LLUUID &image_id) getSelection()->applyToObjects(&sendfunc); } +void LLSelectMgr::selectionSetAlphaGamma(U8 gamma) +{ + LLUUID owner_id; + std::string owner_name; + LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); + bool agent_mod_group_obj = gAgent.hasPowerInGroup(owner_id, GP_OBJECT_MANIPULATE); + + struct f : public LLSelectedTEFunctor + { + U8 mAlphaGamma; + f(const U8 &t, bool agent_mod_group_obj) : mAlphaGamma(t), mAgentModGroupObj(agent_mod_group_obj) {} + bool apply(LLViewerObject *object, S32 te) + { + bool can_modify = object->permModify(); + if (can_modify || object->permYouOwner() || (object->permGroupOwner() && mAgentModGroupObj)) + { + // update viewer side color in anticipation of update from simulator + object->setTEAlphaGamma(te, mAlphaGamma); + } + return true; + } + bool mAgentModGroupObj { false }; + } setfunc(gamma, agent_mod_group_obj); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrAlphaGammaBypassFunctor sendfunc(agent_mod_group_obj); + getSelection()->applyToObjects(&sendfunc); +} + void LLSelectMgr::selectionSetTexGen(U8 texgen) { struct f : public LLSelectedTEFunctor @@ -5789,6 +5839,41 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, // LL_INFOS() << "sendListToRegions " << message_name << " obj " << objects_sent << " pkt " << packets_sent << LL_ENDL; } +// static +void LLSelectMgr::packAlphaGammaBypass(LLViewerObject* object) +{ + gMessageSystem->newMessageFast(_PREHASH_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 = (S32)llmin(object->getNumTEs(), (U8)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, (S32)(cur_ptr - packed_buffer)); + + gMessageSystem->sendMessage(gAgent.getRegion()->getHost()); +} // // Network communications diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index f2b1e691b57..92dc39469a7 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -662,6 +662,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 ); @@ -907,6 +908,8 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton 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/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index a1a67c319cc..684bb6cd85c 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 016ebff8270..51ca7f265c5 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/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 7741f1fbe77..e5193867410 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3203,8 +3203,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 }; @@ -5489,6 +5489,22 @@ S32 LLViewerObject::setTEBumpmap(const U8 te, const U8 bump) return retval; } +S32 LLViewerObject::setTEAlphaGamma(const U8 te, const U8 gamma) +{ + S32 retval = 0; + const LLTextureEntry* tep = getTE(te); + if (!tep) + { + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; + } + else if (gamma != tep->getAlphaGamma()) + { + retval = LLPrimitive::setTEAlphaGamma(te, gamma); + setChanged(TEXTURE); + } + return retval; +} + S32 LLViewerObject::setTETexGen(const U8 te, const U8 texgen) { S32 retval = 0; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 09f813accca..d930fd3ec0c 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -381,6 +381,7 @@ class LLViewerObject /*virtual*/ S32 setTEOffsetT(const U8 te, const F32 t); /*virtual*/ S32 setTERotation(const U8 te, const F32 r); /*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 setTEMediaTexGen(const U8 te, const U8 media ); // *FIXME: this confusingly acts upon a superset of setTETexGen's flags without absorbing its semantics /*virtual*/ S32 setTEShiny(const U8 te, const U8 shiny ); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 31be509b0bd..d2bca53610b 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -243,7 +243,8 @@ struct LLTextureMaskData struct LLAppearanceMessageContents: public LLRefCount { - LLAppearanceMessageContents(): + LLAppearanceMessageContents(U8 num_tes): + mTEContents(num_tes), mAppearanceVersion(-1), mParamAppearanceVersion(-1), mCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN) @@ -9461,10 +9462,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"); @@ -9649,7 +9650,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) { diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index fdd39a0e303..f301b24e366 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -721,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); + buffer, object->isSelected(), fullbright, 100); draw_vec.push_back(info); //for alpha sorting diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index ec32a798291..d95c0a4251f 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 dec28ad3e89..b6d1acfd75b 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2332,6 +2332,17 @@ S32 LLVOVolume::setTEBumpmap(const U8 te, const U8 bumpmap) return res; } +S32 LLVOVolume::setTEAlphaGamma(const U8 te, const U8 gamma) +{ + S32 res = LLViewerObject::setTEAlphaGamma(te, gamma); + if (res) + { + gPipeline.markTextured(mDrawable); + mFaceMappingChanged = true; + } + return res; +} + S32 LLVOVolume::setTETexGen(const U8 te, const U8 texgen) { S32 res = LLViewerObject::setTETexGen(te, texgen); @@ -5352,6 +5363,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(); @@ -5434,11 +5446,13 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, info->mMaterialHash == 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 && info->mShaderMask == shader_mask && info->mAvatar == facep->mAvatar && + info->mAlphaGamma == alpha_gamma && info->getSkinHash() == facep->getSkinHash()) { info->mCount += facep->getIndicesCount(); @@ -5457,8 +5471,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; @@ -5486,6 +5499,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) { diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 10dbf1349f4..7f093048eb5 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -207,6 +207,7 @@ class LLVOVolume : public LLViewerObject /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color) override; /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color) override; /*virtual*/ S32 setTEBumpmap(const U8 te, const U8 bump) override; + /*virtual*/ S32 setTEAlphaGamma(const U8 te, const U8 alphagamma) override; /*virtual*/ S32 setTEShiny(const U8 te, const U8 shiny) override; /*virtual*/ S32 setTEFullbright(const U8 te, const U8 fullbright) override; /*virtual*/ S32 setTEBumpShinyFullbright(const U8 te, const U8 bump) override; 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 e80f315259f..0498afc657a 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -684,6 +684,39 @@ top_delta="0" tool_tip="Align media texture (must load first)" width="85" /> + + Alpha Gamma + + + + + + Mapping @@ -926,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" />