diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index c74ea3e42b4..f137ab4ebff 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -609,7 +609,7 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, bool flat, F3 mProfile[i] = pt[j--]; } - for (S32 i=0;i<(S32)mFaces.size();i++) + for (U8 i=0;imFaces.size(); + return mIsMeshAssetLoaded ? getNumVolumeFaces() : static_cast(mProfilep->mFaces.size()); } @@ -2785,7 +2784,7 @@ void LLVolume::createVolumeFaces() } else { - S32 num_faces = getNumFaces(); + U8 num_faces = getNumFaces(); bool partial_build = true; if (num_faces != mVolumeFaces.size()) { @@ -2793,7 +2792,7 @@ void LLVolume::createVolumeFaces() mVolumeFaces.resize(num_faces); } // Initialize volume faces with parameter data - for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++) + for (U8 i = 0; i < mVolumeFaces.size(); i++) { LLVolumeFace& vf = mVolumeFaces[i]; LLProfile::Face& face = mProfilep->mFaces[i]; @@ -3714,7 +3713,7 @@ S32 LLVolume::getNumTriangles(S32* vcount) const U32 triangle_count = 0; U32 vertex_count = 0; - for (S32 i = 0; i < getNumVolumeFaces(); ++i) + for (U8 i = 0; i < getNumVolumeFaces(); ++i) { const LLVolumeFace& face = getVolumeFace(i); triangle_count += face.mNumIndices/3; @@ -4227,7 +4226,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en if (face == -1) // ALL_SIDES { start_face = 0; - end_face = getNumVolumeFaces() - 1; + end_face = static_cast(getNumVolumeFaces()) - 1; } else { @@ -4240,7 +4239,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en F32 closest_t = 2.f; // must be larger than 1 - end_face = llmin(end_face, getNumVolumeFaces()-1); + end_face = llmin(end_face, static_cast(getNumVolumeFaces())-1); for (S32 i = start_face; i <= end_face; i++) { @@ -4792,7 +4791,7 @@ LLFaceID LLVolume::generateFaceMask() bool LLVolume::isFaceMaskValid(LLFaceID face_mask) { LLFaceID test_mask = 0; - for(S32 i = 0; i < getNumFaces(); i++) + for(U8 i = 0; i < getNumFaces(); i++) { test_mask |= mProfilep->mFaces[i].mFaceID; } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 3496928f7bb..eaf66266206 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -62,7 +62,7 @@ class LLVolumeOctree; //============================================================================ -constexpr S32 MIN_DETAIL_FACES = 6; +constexpr U8 MIN_DETAIL_FACES = 6; constexpr S32 MIN_LOD = 0; constexpr S32 MAX_LOD = 3; @@ -201,7 +201,7 @@ constexpr U8 LL_SCULPT_FLAG_INVERT = 64; constexpr U8 LL_SCULPT_FLAG_MIRROR = 128; constexpr U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR; -constexpr S32 LL_SCULPT_MESH_MAX_FACES = 8; +constexpr U8 LL_SCULPT_MESH_MAX_FACES = 8; extern bool gDebugGL; @@ -699,7 +699,7 @@ class LLProfile S32 getTotal() const { return mTotal; } S32 getTotalOut() const { return mTotalOut; } // Total number of outside points - bool isFlat(S32 face) const { return (mFaces[face].mCount == 2); } + bool isFlat(U8 face) const { return (mFaces[face].mCount == 2); } bool isOpen() const { return mOpen; } void setDirty() { mDirty = true; } @@ -1027,8 +1027,8 @@ class LLVolume : public LLRefCount U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } U8 getPathType() const { return mParams.getPathParams().getCurveType(); } - S32 getNumFaces() const; - S32 getNumVolumeFaces() const { return static_cast(mVolumeFaces.size()); } + U8 getNumFaces() const; + U8 getNumVolumeFaces() const { return static_cast(mVolumeFaces.size()); } F32 getDetail() const { return mDetail; } F32 getSurfaceArea() const { return mSurfaceArea; } const LLVolumeParams& getParams() const { return mParams; } diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index c5d6076b984..4dcef2f0fa7 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -186,7 +186,6 @@ bool LLPrimitive::cleanupVolumeManager() //=============================================================== LLPrimitive::LLPrimitive() : mTextureList(), - mNumTEs(0), mMiscFlags(0), mNumBumpmapTEs(0) { @@ -741,17 +740,12 @@ std::string LLPrimitive::pCodeToString(const LLPCode pcode) void LLPrimitive::copyTEs(const LLPrimitive *primitivep) { - U32 i; - if (primitivep->getExpectedNumTEs() != getExpectedNumTEs()) + U8 num_tes = llmin(getExpectedNumTEs(), primitivep->getNumTEs()); + if (mTextureList.size() < num_tes) { - LL_WARNS() << "Primitives don't have same expected number of TE's" << LL_ENDL; + mTextureList.setSize(num_tes); } - U32 num_tes = llmin(primitivep->getExpectedNumTEs(), getExpectedNumTEs()); - if (mTextureList.size() < getExpectedNumTEs()) - { - mTextureList.setSize(getExpectedNumTEs()); - } - for (i = 0; i < num_tes; i++) + for (U8 i = 0; i < num_tes; i++) { mTextureList.copyTexture(i, *(primitivep->getTE(i))); } @@ -813,7 +807,6 @@ bool LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai setChanged(GEOMETRY); - if (!mVolumep) { mVolumep = volumep; @@ -1028,7 +1021,12 @@ bool LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai sVolumeManager->unrefVolume(mVolumep); mVolumep = volumep; - setNumTEs(mVolumep->getNumFaces()); + if (getNumTEs() < mVolumep->getNumFaces()) + { + setNumTEs(mVolumep->getNumFaces()); + } + // else: Decreases in the LLVolume's notion of "num_faces" happens for LOD reasons + // which do not reflect actual change of faces of the object, so we ignore them. #endif return true; } @@ -1046,83 +1044,153 @@ bool LLPrimitive::setMaterial(U8 material) } } -S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const +namespace { - S32 face_index; - S32 i; - U64 exception_faces; - U8 *start_loc = cur_ptr; - - htolememcpy(cur_ptr,data_ptr + (last_face_index * data_size), type, data_size); - cur_ptr += data_size; - - for (face_index = last_face_index-1; face_index >= 0; face_index--) + /// Packs up to 64 bits as a variable bitfield into buffer. + /// + /// @param buffer Destination buffer for the packed bitfield. + /// @param bits The bits to pack (up to 64 bits). + /// @return Pointer to the byte that follows the packed bitfield. + U8* pack_TE_variable_bitfield(U8* buffer, U64 bits) { - bool already_sent = false; - for (i = face_index+1; i <= last_face_index; i++) - { - if (!memcmp(data_ptr+(data_size *face_index), data_ptr+(data_size *i), data_size)) - { - already_sent = true; - break; - } - } + // The bits are chunked into 7 per packed byte. The 8th bit of each byte is used + // as a continuation flag: all bytes will have the 8th bit set (1) except for the + // last one which will be unset (0). - if (!already_sent) + if (bits >= ((U64)0x1 << 7)) { - exception_faces = 0; - for (i = face_index; i >= 0; i--) + if (bits >= ((U64)0x1 << 14)) { - if (!memcmp(data_ptr+(data_size *face_index), data_ptr+(data_size *i), data_size)) + if (bits >= ((U64)0x1 << 21)) { - exception_faces |= ((U64)1 << i); - } - } - - //assign exception faces to cur_ptr - if (exception_faces >= ((U64)0x1 << 7)) - { - if (exception_faces >= ((U64)0x1 << 14)) - { - if (exception_faces >= ((U64)0x1 << 21)) + if (bits >= ((U64)0x1 << 28)) { - if (exception_faces >= ((U64)0x1 << 28)) + if (bits >= ((U64)0x1 << 35)) { - if (exception_faces >= ((U64)0x1 << 35)) + if (bits >= ((U64)0x1 << 42)) { - if (exception_faces >= ((U64)0x1 << 42)) + if (bits >= ((U64)0x1 << 49)) { - if (exception_faces >= ((U64)0x1 << 49)) - { - *cur_ptr++ = (U8)(((exception_faces >> 49) & 0x7F) | 0x80); - } - *cur_ptr++ = (U8)(((exception_faces >> 42) & 0x7F) | 0x80); + *buffer++ = (U8)(((bits >> 49) & 0x7F) | 0x80); } - *cur_ptr++ = (U8)(((exception_faces >> 35) & 0x7F) | 0x80); + *buffer++ = (U8)(((bits >> 42) & 0x7F) | 0x80); } - *cur_ptr++ = (U8)(((exception_faces >> 28) & 0x7F) | 0x80); + *buffer++ = (U8)(((bits >> 35) & 0x7F) | 0x80); } - *cur_ptr++ = (U8)(((exception_faces >> 21) & 0x7F) | 0x80); + *buffer++ = (U8)(((bits >> 28) & 0x7F) | 0x80); } - *cur_ptr++ = (U8)(((exception_faces >> 14) & 0x7F) | 0x80); + *buffer++ = (U8)(((bits >> 21) & 0x7F) | 0x80); } - *cur_ptr++ = (U8)(((exception_faces >> 7) & 0x7F) | 0x80); + *buffer++ = (U8)(((bits >> 14) & 0x7F) | 0x80); } + *buffer++ = (U8)(((bits >> 7) & 0x7F) | 0x80); + } + *buffer++ = (U8)(bits & 0x7F); // don't set the continuation bit in the final byte + return buffer; + } + + /// Packs TextureEntry data encoded for wire transport. + /// + /// @param cur_ptr Destination buffer for packed data. + /// @param data_ptr Source array of field values to pack. + /// @param data_size Size in bytes of each field value. + /// @param last_face_index Index of the last face (used as default value). + /// @param type Informs htolememcpy() how to copy bytes to wire format. + /// @return Number of bytes written to the buffer. + S32 pack_TE_field(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) + { + U8 *start_loc = cur_ptr; + + // pack the value at last_face_index as the "default value" which will be assigned to all faces + // that are not flagged as exceptions + htolememcpy(cur_ptr, data_ptr + (last_face_index * data_size), type, data_size); + cur_ptr += data_size; + + // decrementing toward face_index=0 find all unique non-default values and bundle them together + // (variable_bitfield + value) + U64 packed_mask = ((U64)1 << last_face_index); + S32 max_index = static_cast(last_face_index); + for (S32 face_index = max_index-1; face_index >= 0; face_index--) + { + bool already_sent = packed_mask & ((U64)1 << face_index); + if (!already_sent) + { + // exception_faces is a bitmask of indices whose TE field is set to 'value' + U64 exception_faces = 0; + for (S32 i = face_index; i >= 0; i--) + { + if (!memcmp(data_ptr+(data_size *face_index), data_ptr+(data_size *i), data_size)) + { + exception_faces |= ((U64)1 << i); + } + } + // pack the bitfield + cur_ptr = pack_TE_variable_bitfield(cur_ptr, exception_faces); + + // pack the 'value' + htolememcpy(cur_ptr, data_ptr + (face_index * data_size), type, data_size); + cur_ptr += data_size; + + packed_mask |= exception_faces; + } + } + return (S32)(cur_ptr - start_loc); + } + + /// Packs the default value of a 1-byte TextureEntry field in a way that allows + /// the receiving side to unambiguously determine the "number of faces" for the + /// TextureEntry. + /// + /// @param cur_ptr Destination buffer for packed data. + /// @param data_ptr Source array of field values. + /// @param last_face_index Index of the last face. + /// @param type Informs htolememcpy() how to copy bytes to wire format. + /// @return Number of bytes written to the buffer. + S32 pack_TE_facecount(U8 *cur_ptr, U8 *data_ptr, U8 last_face_index, EMsgVariableType type) + { + // BUG: There can be a discrepancy in last_face_index as known to client and server + // (for mesh objects). + // + // WORKAROUND: We can inform the other side of our notion of last_face_index by + // re-packing the TE value of the last_face_index as an exception to the default. + // This is effectively a no-op since the value at last_face_index is, by protocol + // definition, the default (see implementation of the packing/unpacking algorithm + // in pack_TE_field() or unpack_TE_field() for details), however the receiving + // side will notice and interpret this as a declaration the number of faces. + + U8 *start_loc = cur_ptr; + if (last_face_index > 0) + { + // The workaround need only be packed once for any particular update, so it is + // always done for a TE field whose data_size is 1 byte. + // + U8 data_size = 1; - *cur_ptr++ = (U8)(exception_faces & 0x7F); + // store a variable bitfield whose only bit corresponds to last_face_index + U64 bits = (U64)1 << last_face_index; + cur_ptr = pack_TE_variable_bitfield(cur_ptr, bits); - htolememcpy(cur_ptr,data_ptr + (face_index * data_size), type, data_size); + // pack the value + htolememcpy(cur_ptr, data_ptr + (last_face_index * data_size), type, data_size); cur_ptr += data_size; } + + return (S32)(cur_ptr - start_loc); } - return (S32)(cur_ptr - start_loc); -} -namespace -{ + /// Unpacks TextureEntry data encoded for wire transport. + /// + /// @param dest Array where unpacked values will be stored. + /// @param new_face_count Will be updated if data packed was for a larger number of faces. + /// In other words: the variable represents "the smallest number of faces that + /// would fit all of the packed data". + /// @param source Points at the first byte of packed data (will be advanced). + /// @param source_end Points at the last byte of packed data. + /// @param type Informs htolememcpy() how to copy bytes from wire format. + /// @return True on success, false otherwise. template< typename T > - bool unpack_TEField(T dest[], U8 dest_count, U8 * &source, U8 *source_end, EMsgVariableType type) + bool unpack_TE_field(T dest[], U8& min_num_faces, U8 * &source, U8 *source_end, EMsgVariableType type) { const size_t size(sizeof(T)); @@ -1134,21 +1202,27 @@ namespace return false; } - // Extract the default value and fill the array. + // Extract the first value and fill the array with this "default value" + // Note: this corresponds to the property of the last face (client packs it first). + // This also initializes the destination array which is why we don't need to explicitly + // initialize the member arrays in TEData. htolememcpy(dest, source, type, size); source += size; - for (S32 idx = 1; idx < dest_count; ++idx) + for (U32 idx = 1; idx < LLTEContents::MAX_TES; ++idx) { dest[idx] = dest[0]; } while (source < source_end) { + // Unpack the variable length bitfield: + // The flags are stored in the lower 7 bits of each byte while the 8th bit + // signals continuation: the final byte of the flags will have a zero 8th bit. + // Meanwhile each bit in the bitfield represents whether the subsequent value + // will be placed at the corresponding index of the 'dest' array. U64 index_flags(0); + S32 byte_index = 0; U8 sbit(0); - - // Unpack the variable length bitfield. Each bit represents whether the following - // value will be placed at the corresponding array index. do { if (source >= source_end) @@ -1158,9 +1232,14 @@ namespace return false; } + // get ready to load the next 7 bits + index_flags <<= 7; + + // copy 7 bits sbit = *source++; - index_flags <<= 7; // original code had this after? - index_flags |= (sbit & 0x7F); + U8 flags = (sbit & 0x7F); + index_flags |= flags; + byte_index++; } while (sbit & 0x80); if (!index_flags) @@ -1176,19 +1255,28 @@ namespace return false; } - // get the value for the indexs. + // After unpacking the bitfield get the value. T value; htolememcpy(&value, source, type, size); source += size; - for (S32 idx = 0; idx < dest_count; idx++) + // Store the value in the array at the flagged indices + U8 i = 0; + while (index_flags > 0) { - if (index_flags & 1ULL << idx) + if (index_flags & 0x01) { - dest[idx] = value; + dest[i] = value; } + index_flags >>= 1; + i++; } + // update min_num_faces + if (i > min_num_faces) + { + min_num_faces = i; + } } return true; } @@ -1201,180 +1289,29 @@ 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 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 = llmin((U32) getNumTEs(), MAX_TES) - 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); - } + cur_ptr = packTEMessageInternal(cur_ptr); mesgsys->addBinaryDataFast(_PREHASH_TextureEntry, packed_buffer, (S32)(cur_ptr - packed_buffer)); - return true; } 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 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); - } - + cur_ptr = packTEMessageInternal(cur_ptr); dp.packBinaryData(packed_buffer, (S32)(cur_ptr - packed_buffer), "TextureEntry"); return true; } S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec) { - 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); @@ -1387,7 +1324,7 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name if (tec.size == 0) { tec.face_count = 0; - return retval; + return 0; } else if (tec.size >= LLTEContents::MAX_TE_BUFFER) { @@ -1398,52 +1335,16 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name // 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); - // 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))) - { - 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)) - { - memset((void*)material_data, 0, sizeof(material_data)); - } - - for (U32 i = 0; i < tec.face_count; i++) - { - tec.material_ids[i].set(&(material_data[i])); - } - - retval = 1; - return retval; - } + return unpackTEMessageInternal(tec); +} S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec) { S32 retval = 0; LLColor4 color; - for (U32 i = 0; i < tec.face_count; i++) + U8 num_faces = llmin(mTextureList.size(), tec.face_count); + for (U8 i = 0; i < num_faces; i++) { LLUUID& req_id = ((LLUUID*)tec.image_data)[i]; retval |= setTETexture(i, req_id); @@ -1469,137 +1370,128 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec) return retval; } -S32 LLPrimitive::unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num) -{ - LLTEContents tec; - S32 retval = parseTEMessage(mesgsys, block_name, block_num, tec); - if (!retval) - return retval; - return applyParsedTEMessage(tec); -} - -S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) +S32 LLPrimitive::unpackTEMessageInternal(LLTEContents& tec) { - // use a negative block_num to indicate a single-block read (a non-variable block) - S32 retval = 0; - constexpr U32 MAX_TES = 45; - - // Avoid construction of 32 UUIDs per call - static LLMaterialID material_ids[MAX_TES]; + // temp buffer for material ID processing + // data will end up in tec.material_ids[] + material_id_type material_data[LLTEContents::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")) - { - retval = TEM_INVALID; - LL_WARNS() << "Bad texture entry block! Abort!" << LL_ENDL; - return retval; - } + // The last field is not zero terminated. + // Rather than special case the unpack functions, just make it 0x00 terminated. + tec.packed_buffer[tec.size] = 0x00; + ++tec.size; - if (size == 0) - { - return retval; - } - else if (size >= MAX_TE_BUFFER) - { - LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL; - size = MAX_TE_BUFFER - 1; - } + tec.face_count = llmin(getNumTEs(), LLTEContents::MAX_TES); - // 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 = tec.packed_buffer; + LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffer sized: " << tec.size << LL_ENDL; + U8 *buffer_end = tec.packed_buffer + tec.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))) + // unpack_TE_field() will increase new_face_count according to the index flags + // it finds in the packed data. If this Primitive is a mesh and new_face_count ends + // up larger than tec.face_count we'll increase the number of TextureEntries. + U8 new_face_count = 1; + + if (!( unpack_TE_field(tec.image_data, new_face_count, cur_ptr, buffer_end, MVT_LLUUID) && + unpack_TE_field(tec.colors, new_face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TE_field(tec.scale_s, new_face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TE_field(tec.scale_t, new_face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TE_field(tec.offset_s, new_face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TE_field(tec.offset_t, new_face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TE_field(tec.image_rot, new_face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TE_field(tec.bump, new_face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TE_field(tec.media_flags, new_face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TE_field(tec.glow, new_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)) + if (cur_ptr >= buffer_end || !unpack_TE_field(material_data, new_face_count, cur_ptr, buffer_end, MVT_LLUUID)) { memset((void*)material_data, 0, sizeof(material_data)); } - for (i = 0; i < face_count; i++) + // BUG: server and client may disagree as to the face_count on a mesh Primitive. + // + // HISTORY: In the beginning face_count of a Primitive was implicit according to + // its VolumeParams hence the face_count was not encoded in TE field data. Later + // "mesh" Primitives (aka "Scuplties") were added but had only one face. Then + // non-Sculpty mesh Primitives were added with variable face_count (up to 8) and + // multiple LOD, each with a potentially different face_count, and for several + // years the mesh asset upload pipeline suffered a bug where the server-side mesh + // asset would cache the face_count of lower-LOD collision shape rather than of + // the mesh at full glory. The result was: texture adjustments to unknown mesh + // faces would silently fail at the server. There was a similar client side-problem + // when mesh objects are loaded with low LOD shapes and server updates for missing + // faces are silently dropped. + // + // WORKAROUND: face_count as known to each side can be encoded in the TE field + // data without adjusting protocol using a trick (see pack_TE_facecount() for + // details). + // + // TLDR: This is where we adjust our notion of mesh face_count when it is smaller + // than that of the other side. + if (mVolumep && mVolumep->getParams().isMeshSculpt()) { - material_ids[i].set(&(material_data[i])); + U8 num_tes = getNumTEs(); + if (num_tes < new_face_count && new_face_count <= LL_SCULPT_MESH_MAX_FACES) + { + tec.face_count = new_face_count; + setNumTEs(new_face_count); + } } - LLColor4 color; - for (i = 0; i < face_count; i++) + for (U8 i = 0; i < tec.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]); + tec.material_ids[i].set(&(material_data[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; + return 1; +} - retval |= setTEColor(i, color); +S32 LLPrimitive::unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num) +{ + LLTEContents tec; + S32 retval = parseTEMessage(mesgsys, block_name, block_num, tec); + if (!retval) + return retval; + return applyParsedTEMessage(tec); +} + +S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) +{ + LLTEContents tec; + if (!dp.unpackBinaryData(tec.packed_buffer, tec.size, "TextureEntry")) + { + LL_WARNS() << "Bad texture entry block! Abort!" << LL_ENDL; + return TEM_INVALID; } - return retval; + if (tec.size == 0) + { + return 0; + } + else if (tec.size >= LLTEContents::MAX_TE_BUFFER) + { + LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL; + tec.size = LLTEContents::MAX_TE_BUFFER - 1; + } + + S32 retval = unpackTEMessageInternal(tec); + if (!retval) + return retval; + return applyParsedTEMessage(tec); } U8 LLPrimitive::getExpectedNumTEs() const { - U8 expected_face_count = 0; + U8 expected_face_count = mTextureList.size(); if (mVolumep) { - expected_face_count = mVolumep->getNumFaces(); + // for legacy prims the face count is implicit to the Volume params + // and may be larger than mTextureList.size() during initialization. + expected_face_count = llmax(mVolumep->getNumFaces(), expected_face_count); } return expected_face_count; } @@ -1634,6 +1526,90 @@ void LLPrimitive::updateNumBumpmap(const U8 index, const U8 bump) return; } + +U8* LLPrimitive::packTEMessageInternal(U8* cur_ptr) const +{ + U8 num_faces = getNumTEs(); + if (num_faces == 0) + { + return cur_ptr; + } + + 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 media_flags[LLTEContents::MAX_TES]; + U8 glow[LLTEContents::MAX_TES]; + U8 material_data[LLTEContents::MAX_TES*16]; + + U8 last_face_index = llmin(getNumTEs(), LLTEContents::MAX_TES) - 1; + + // ...if we hit the front, send one image id + LLColor4U coloru; + for (U8 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 += pack_TE_field(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)colors, 4 ,last_face_index, MVT_U8); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)scale_s, 4 ,last_face_index, MVT_F32); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)scale_t, 4 ,last_face_index, MVT_F32); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)offset_s, 2 ,last_face_index, MVT_S16Array); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)offset_t, 2 ,last_face_index, MVT_S16Array); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)image_rot, 2 ,last_face_index, MVT_S16Array); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8); + if (mVolumep && mVolumep->getParams().isMeshSculpt()) + { + // workaround for historical num_faces discrepancy between client and server + cur_ptr += pack_TE_facecount(cur_ptr, (U8 *)bump, last_face_index, MVT_U8); + } + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8); + *cur_ptr++ = 0; + cur_ptr += pack_TE_field(cur_ptr, (U8 *)material_data, 16, last_face_index, MVT_LLUUID); + + return cur_ptr; +} //============================================================================ // Moved from llselectmgr.cpp diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index c3e3e19ee94..9e577c1c460 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -393,36 +393,6 @@ class LLRenderMaterialParams : public LLNetworkData bool isEmpty() { return mEntries.empty(); } }; - -// This code is not naming-standards compliant. Leaving it like this for -// now to make the connection to code in -// bool packTEMessage(LLDataPacker &dp) const; -// more obvious. This should be refactored to remove the duplication, at which -// point we can fix the names as well. -// - Vir -struct 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; -}; - class LLPrimitive : public LLXform { public: @@ -496,13 +466,13 @@ class LLPrimitive : public LLXform LLMaterialPtr getTEMaterialParams(const U8 index); void copyTEs(const LLPrimitive *primitive); - S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) 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); + S32 unpackTEMessageInternal(LLTEContents& tec); #ifdef CHECK_FOR_FINITE inline void setPosition(const LLVector3& pos); @@ -581,6 +551,7 @@ class LLPrimitive : public LLXform private: void updateNumBumpmap(const U8 index, const U8 bump); + U8* packTEMessageInternal(U8* cur_ptr) const; protected: LLPCode mPrimitiveCode; // Primitive code @@ -590,7 +561,6 @@ class LLPrimitive : public LLXform LLPointer mVolumep; LLPrimTextureList mTextureList; // list of texture GUIDs, scales, offsets U8 mMaterial; // Material code - U8 mNumTEs; // # of faces on the primitve U8 mNumBumpmapTEs; // number of bumpmap TEs. U32 mMiscFlags; // home for misc bools @@ -789,9 +759,10 @@ void LLPrimitive::setAcceleration(const F32 x, const F32 y, const F32 z) } #endif // CHECK_FOR_FINITE -inline bool LLPrimitive::validTE(const U8 te_num) const +inline bool LLPrimitive::validTE(const U8 te_index) const { - return (mNumTEs && te_num < mNumTEs); + U8 num_tes = mTextureList.size(); + return (num_tes && te_index < num_tes); } #endif diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index 68f3f5ffacb..63f94280edd 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -83,13 +83,17 @@ void LLPrimTextureList::clear() void LLPrimTextureList::copy(const LLPrimTextureList& other_list) { // compare the sizes - auto this_size = mEntryList.size(); - auto other_size = other_list.mEntryList.size(); + U8 this_size = static_cast(mEntryList.size()); + U8 other_size = static_cast(other_list.mEntryList.size()); + + llassert(this_size <= LLTEContents::MAX_TES); + llassert(other_size <= LLTEContents::MAX_TES); + llassert(other_size > 0); if (this_size > other_size) { // remove the extra entries - for (size_t index = this_size; index > other_size; --index) + for (U8 index = this_size; index > other_size; --index) { delete mEntryList[index-1]; } @@ -97,18 +101,18 @@ void LLPrimTextureList::copy(const LLPrimTextureList& other_list) this_size = other_size; } - size_t index = 0; + U8 index = 0; // copy for the entries that already exist for ( ; index < this_size; ++index) { delete mEntryList[index]; - mEntryList[index] = other_list.getTexture(static_cast(index))->newCopy(); + mEntryList[index] = other_list.getTexture(index)->newCopy(); } - // add new entires if needed + // add new entries if needed for ( ; index < other_size; ++index) { - mEntryList.push_back( other_list.getTexture(static_cast(index))->newCopy()); + mEntryList.push_back( other_list.getTexture(index)->newCopy()); } } @@ -122,10 +126,15 @@ void LLPrimTextureList::take(LLPrimTextureList& other_list) other_list.mEntryList.clear(); } +S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) +{ + return copyTexture(index, &te); +} + // virtual // copies LLTextureEntry 'te' // returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE -S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) +S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry* te) { if (size_t(index) >= mEntryList.size()) { @@ -134,12 +143,12 @@ 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) + if (te) { - mEntryList[index] = te.newCopy(); + mEntryList[index] = te->newCopy(); } else { @@ -154,7 +163,7 @@ S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) // IMPORTANT! -- if you use this function you must check the return value S32 LLPrimTextureList::takeTexture(const U8 index, LLTextureEntry* te) { - if (S32(index) >= mEntryList.size()) + if (index >= static_cast(mEntryList.size())) { return TEM_CHANGE_NONE; } @@ -387,25 +396,21 @@ LLMaterialPtr LLPrimTextureList::getMaterialParams(const U8 index) return LLMaterialPtr(); } -S32 LLPrimTextureList::size() const +U8 LLPrimTextureList::size() const { - return static_cast(mEntryList.size()); + return static_cast(mEntryList.size()); } // sets the size of the mEntryList container -void LLPrimTextureList::setSize(S32 new_size) +void LLPrimTextureList::setSize(U8 new_size) { - if (new_size < 0) - { - new_size = 0; - } - - auto current_size = mEntryList.size(); + llassert(new_size > 0); + U8 current_size = static_cast(mEntryList.size()); if (new_size > current_size) { mEntryList.resize(new_size); - for (size_t index = current_size; index < new_size; ++index) + for (U8 index = current_size; index < new_size; ++index) { if (current_size > 0 && mEntryList[current_size - 1]) @@ -415,7 +420,7 @@ void LLPrimTextureList::setSize(S32 new_size) } else { - // no valid enries to copy, so we new one up + // no valid entries to copy, so we new one up LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry(); mEntryList[index] = new_entry; } @@ -423,7 +428,7 @@ void LLPrimTextureList::setSize(S32 new_size) } else if (new_size < current_size) { - for (size_t index = current_size-1; index >= new_size; --index) + for (U8 index = current_size-1; index >= new_size; --index) { delete mEntryList[index]; } diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h index 79744e9f08e..86d491e779a 100644 --- a/indra/llprimitive/llprimtexturelist.h +++ b/indra/llprimitive/llprimtexturelist.h @@ -41,6 +41,35 @@ class LLMaterialID; // are of some derived class: LLFooTextureEntry typedef std::vector texture_list_t; +// This code is not naming-standards compliant. Leaving it like this for +// now to make the connection to code in +// bool packTEMessage(LLDataPacker &dp) const; +// more obvious. This should be refactored to remove the duplication, at which +// point we can fix the names as well. +// - Vir +struct LLTEContents +{ + static const U8 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]; + + S32 size; + U8 face_count; +}; + class LLPrimTextureList { public: @@ -78,8 +107,8 @@ class LLPrimTextureList // IMPORTANT! -- if you use this function you must check the return value S32 takeTexture(const U8 index, LLTextureEntry* te); -// // copies contents of 'entry' and stores it in 'index' slot -// void copyTexture(const U8 index, const LLTextureEntry* entry); + // copies contents of 'entry' and stores it in 'index' slot + S32 copyTexture(const U8 index, const LLTextureEntry* entry); // returns pointer to texture at 'index' slot LLTextureEntry* getTexture(const U8 index) const; @@ -109,10 +138,9 @@ class LLPrimTextureList LLMaterialPtr getMaterialParams(const U8 index); - S32 size() const; + U8 size() const; -// void forceResize(S32 new_size); - void setSize(S32 new_size); + void setSize(U8 new_size); void setAllIDs(const LLUUID& id); protected: diff --git a/indra/llprimitive/tests/llprimitive_test.cpp b/indra/llprimitive/tests/llprimitive_test.cpp index 0213a3e8b67..995e6ec4a92 100644 --- a/indra/llprimitive/tests/llprimitive_test.cpp +++ b/indra/llprimitive/tests/llprimitive_test.cpp @@ -106,10 +106,10 @@ S32 LLPrimTextureList::setTexGen(const U8 index, const U8 texgen) { return TEM_C 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::setSize(U8 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()); } +U8 LLPrimTextureList::size() const { return static_cast(mEntryList.size()); } class PRIMITIVE_TEST_SETUP { diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 018d4c4bba5..dc789e63037 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -607,7 +607,7 @@ void renderFace(LLDrawable* drawable, LLFace *face) volume = vobj->getVolume(); } - if (volume) + if (volume && volume->getNumVolumeFaces() > face->getTEOffset()) { const LLVolumeFace& vol_face = volume->getVolumeFace(face->getTEOffset()); LLVertexBuffer::drawElements(LLRender::TRIANGLES, vol_face.mPositions, NULL, vol_face.mNumIndices, vol_face.mIndices); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index b328d3a414c..48a37d7e704 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2229,32 +2229,33 @@ void LLVOVolume::setNumTEs(const U8 num_tes) { const U8 old_num_tes = getNumTEs() ; - if(old_num_tes && old_num_tes < num_tes) //new faces added + if(old_num_tes) { - LLViewerObject::setNumTEs(num_tes) ; - - if(mMediaImplList.size() >= old_num_tes && mMediaImplList[old_num_tes -1].notNull())//duplicate the last media textures if exists. + if (old_num_tes < num_tes) //new faces added { - mMediaImplList.resize(num_tes) ; - const LLTextureEntry* te = getTE(old_num_tes - 1) ; - for(U8 i = old_num_tes; i < num_tes ; i++) + LLViewerObject::setNumTEs(num_tes) ; + + if(mMediaImplList.size() >= old_num_tes && mMediaImplList[old_num_tes -1].notNull())//duplicate the last media textures if exists. { - setTE(i, *te) ; - mMediaImplList[i] = mMediaImplList[old_num_tes -1] ; + mMediaImplList.resize(num_tes) ; + const LLTextureEntry* te = getTE(old_num_tes - 1) ; + for(U8 i = old_num_tes; i < num_tes ; i++) + { + setTE(i, *te) ; + mMediaImplList[i] = mMediaImplList[old_num_tes -1] ; + } + mMediaImplList[old_num_tes -1]->setUpdated(true) ; } - mMediaImplList[old_num_tes -1]->setUpdated(true) ; } - } - else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed - { - U8 end = (U8)(mMediaImplList.size()) ; - for(U8 i = num_tes; i < end ; i++) + else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed { - removeMediaImpl(i) ; + U8 end = (U8)(mMediaImplList.size()) ; + for(U8 i = num_tes; i < end ; i++) + { + removeMediaImpl(i) ; + } + mMediaImplList.resize(num_tes) ; } - mMediaImplList.resize(num_tes) ; - - LLViewerObject::setNumTEs(num_tes) ; } else {