diff options
Diffstat (limited to 'indra/llprimitive')
-rw-r--r-- | indra/llprimitive/lldaeloader.cpp | 105 | ||||
-rw-r--r-- | indra/llprimitive/llmaterialtable.cpp | 17 | ||||
-rw-r--r-- | indra/llprimitive/llmaterialtable.h | 2 | ||||
-rw-r--r-- | indra/llprimitive/llmediaentry.cpp | 5 | ||||
-rw-r--r-- | indra/llprimitive/llmodel.cpp | 113 | ||||
-rw-r--r-- | indra/llprimitive/llmodel.h | 33 | ||||
-rw-r--r-- | indra/llprimitive/llprimitive.cpp | 348 | ||||
-rw-r--r-- | indra/llprimitive/llprimitive.h | 5 |
8 files changed, 450 insertions, 178 deletions
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index dfa29fb539..68654486a4 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -149,7 +149,11 @@ bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S return true; } -LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri) +LLModel::EModelStatus load_face_from_dom_triangles( + std::vector<LLVolumeFace>& face_list, + std::vector<std::string>& materials, + domTrianglesRef& tri, + LLSD& log_msg) { LLVolumeFace face; std::vector<LLVolumeFace::VertexData> verts; @@ -169,12 +173,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) { + LLSD args; + args["Message"] = "ParsingErrorBadElement"; + log_msg.append(args); return LLModel::BAD_ELEMENT; } if (!pos_source || !pos_source->getFloat_array()) { LL_WARNS() << "Unable to process mesh without position data; invalid model; invalid model." << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorPositionInvalidModel"; + log_msg.append(args); return LLModel::BAD_ELEMENT; } @@ -198,6 +208,17 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa } LLVolumeFace::VertexMapData::PointMap point_map; + + if (idx_stride <= 0 + || (pos_source && pos_offset >= idx_stride) + || (tc_source && tc_offset >= idx_stride) + || (norm_source && norm_offset >= idx_stride)) + { + // Looks like these offsets should fit inside idx_stride + // Might be good idea to also check idx.getCount()%idx_stride != 0 + LL_WARNS() << "Invalid pos_offset " << pos_offset << ", tc_offset " << tc_offset << " or norm_offset " << norm_offset << LL_ENDL; + return LLModel::BAD_ELEMENT; + } for (U32 i = 0; i < idx.getCount(); i += idx_stride) { @@ -343,7 +364,11 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa return LLModel::NO_ERRORS ; } -LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg) +LLModel::EModelStatus load_face_from_dom_polylist( + std::vector<LLVolumeFace>& face_list, + std::vector<std::string>& materials, + domPolylistRef& poly, + LLSD& log_msg) { domPRef p = poly->getP(); domListOfUInts& idx = p->getValue(); @@ -370,6 +395,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) { + LL_WARNS() << "Bad element." << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorBadElement"; + log_msg.append(args); return LLModel::BAD_ELEMENT; } @@ -421,6 +450,9 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac if (!cv.getPosition().isFinite3()) { LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL; + LLSD args; + args["Message"] = "PositionNaN"; + log_msg.append(args); return LLModel::BAD_ELEMENT; } } @@ -453,6 +485,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac if (!cv.getNormal().isFinite3()) { LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; + LLSD args; + args["Message"] = "NormalsNaN"; + log_msg.append(args); + return LLModel::BAD_ELEMENT; } } @@ -770,6 +806,9 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac } } + // Viewer can only fit U16 vertices, shouldn't we do some checks here and return overflow if result has more? + llassert(vert_idx.size() < U16_MAX); + //build vertex array from map std::vector<LLVolumeFace::VertexData> new_verts; new_verts.resize(vert_idx.size()); @@ -787,7 +826,12 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac for (U32 i = 0; i < verts.size(); ++i) { indices[i] = vert_idx[verts[i]]; - llassert(!i || (indices[i-1] != indices[i])); + if (i % 3 != 0) // assumes GL_TRIANGLES, compare 0-1, 1-2, 3-4, 4-5 but not 2-3 or 5-6 + { + // A faulty degenerate triangle detection (triangle with 0 area), + // probably should be a warning and not an assert + llassert(!i || (indices[i-1] != indices[i])); + } } // DEBUG just build an expanded triangle list @@ -907,6 +951,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!dom) { LL_INFOS() <<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorCorrupt"; + mWarningsArray.append(args); setLoadState( ERROR_PARSING ); return false; } @@ -934,6 +981,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!doc) { LL_WARNS() << "can't find internal doc" << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorNoDoc"; + mWarningsArray.append(args); return false; } @@ -941,6 +991,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!root) { LL_WARNS() << "document has no root" << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorNoRoot"; + mWarningsArray.append(args); return false; } @@ -956,6 +1009,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!result) { LL_INFOS() << "Could not verify controller" << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorBadElement"; + mWarningsArray.append(args); setLoadState( ERROR_PARSING ); return true; } @@ -1089,6 +1145,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!scene) { LL_WARNS() << "document has no visual_scene" << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorNoScene"; + mWarningsArray.append(args); setLoadState( ERROR_PARSING ); return true; } @@ -1097,11 +1156,14 @@ bool LLDAELoader::OpenFile(const std::string& filename) bool badElement = false; - processElement( scene, badElement, &dae ); + processElement( scene, badElement, &dae); if ( badElement ) { LL_INFOS()<<"Scene could not be parsed"<<LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorCantParseScene"; + mWarningsArray.append(args); setLoadState( ERROR_PARSING ); } @@ -1173,17 +1235,19 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do LLMeshSkinInfo& skin_info = model->mSkinInfo; + LLMatrix4 mat; for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { - skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + mat.mMatrix[i][j] = dom_value[i + j*4]; } } - LLMatrix4 trans = normalized_transformation; - trans *= skin_info.mBindShapeMatrix; - skin_info.mBindShapeMatrix = trans; + skin_info.mBindShapeMatrix.loadu(mat); + + LLMatrix4a trans(normalized_transformation); + matMul(trans, skin_info.mBindShapeMatrix, skin_info.mBindShapeMatrix); } @@ -1401,7 +1465,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do mat.mMatrix[i][j] = transform[k*16 + i + j*4]; } } - model->mSkinInfo.mInvBindMatrix.push_back(mat); + model->mSkinInfo.mInvBindMatrix.push_back(LLMatrix4a(mat)); } } } @@ -1475,9 +1539,9 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do if (mJointMap.find(lookingForJoint) != mJointMap.end() && model->mSkinInfo.mInvBindMatrix.size() > i) { - LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; + LLMatrix4 newInverse = LLMatrix4(model->mSkinInfo.mInvBindMatrix[i].getF32ptr()); newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() ); - model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse ); + model->mSkinInfo.mAlternateBindMatrix.push_back( LLMatrix4a(newInverse) ); } else { @@ -1940,7 +2004,7 @@ daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string return NULL; } -void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae ) +void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae) { LLMatrix4 saved_transform; bool pushed_mat = false; @@ -2034,6 +2098,11 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da if (mTransform.determinant() < 0) { //negative scales are not supported LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL; + LLSD args; + args["Message"] = "NegativeScaleTrans"; + args["LABEL"] = getElementLabel(instance_geo); + mWarningsArray.append(args); + badElement = true; } @@ -2057,6 +2126,10 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da if (transformation.determinant() < 0) { //negative scales are not supported LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL; + LLSD args; + args["Message"] = "NegativeScaleNormTrans"; + args["LABEL"] = getElementLabel(instance_geo); + mWarningsArray.append(args); badElement = true; } @@ -2098,6 +2171,9 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da else { LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL; + LLSD args; + args["Message"] = "CantResolveGeometryUrl"; + mWarningsArray.append(args); badElement = true; } @@ -2388,7 +2464,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD& { domTrianglesRef& tri = tris.get(i); - status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri); + status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, log_msg); pModel->mStatus = status; if(status != LLModel::NO_ERRORS) { @@ -2415,6 +2491,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD& for (U32 i = 0; i < polygons.getCount(); ++i) { domPolygonsRef& poly = polygons.get(i); + status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly); if(status != LLModel::NO_ERRORS) @@ -2500,7 +2577,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo if (!mNoOptimize) { - ret->optimizeVolumeFaces(); + ret->remapVolumeFaces(); } volume_faces = remainder.size(); diff --git a/indra/llprimitive/llmaterialtable.cpp b/indra/llprimitive/llmaterialtable.cpp index 37c718b4c6..58b2d00d44 100644 --- a/indra/llprimitive/llmaterialtable.cpp +++ b/indra/llprimitive/llmaterialtable.cpp @@ -559,6 +559,23 @@ LLUUID LLMaterialTable::getCollisionSoundUUID(U8 mcode, U8 mcode2) } } +bool LLMaterialTable::isCollisionSound(const LLUUID &uuid) +{ + for (U8 i = 0; i < LL_MCODE_END; i++) + { + for (U8 j = 0; j < LL_MCODE_END; j++) + { + i &= LL_MCODE_MASK; + j &= LL_MCODE_MASK; + if (mCollisionSoundMatrix[i * LL_MCODE_END + j] == uuid) + { + return true; + } + } + } + return false; +} + LLUUID LLMaterialTable::getSlidingSoundUUID(U8 mcode, U8 mcode2) { mcode &= LL_MCODE_MASK; diff --git a/indra/llprimitive/llmaterialtable.h b/indra/llprimitive/llmaterialtable.h index a17e0103ff..0cf5e626ef 100644 --- a/indra/llprimitive/llmaterialtable.h +++ b/indra/llprimitive/llmaterialtable.h @@ -128,6 +128,8 @@ public: F32 getDamageMod(U8 mcode); F32 getEPMod(U8 mcode); + bool isCollisionSound(const LLUUID &uuid); + LLUUID getCollisionSoundUUID(U8 mcode, U8 mcode2); LLUUID getSlidingSoundUUID(U8 mcode, U8 mcode2); LLUUID getRollingSoundUUID(U8 mcode, U8 mcode2); diff --git a/indra/llprimitive/llmediaentry.cpp b/indra/llprimitive/llmediaentry.cpp index 02aba2bd83..53e9555c6a 100644 --- a/indra/llprimitive/llmediaentry.cpp +++ b/indra/llprimitive/llmediaentry.cpp @@ -27,8 +27,7 @@ #include "linden_common.h" #include "llmediaentry.h" #include "lllslconstants.h" - -#include <boost/regex.hpp> +#include "llregex.h" // LLSD key defines // DO NOT REORDER OR REMOVE THESE! @@ -456,7 +455,7 @@ static bool pattern_match(const std::string &candidate_str, const std::string &p // case-insensitive matching: boost::regex regexp(expression, boost::regex::perl|boost::regex::icase); - return boost::regex_match(candidate_str, regexp); + return ll_regex_match(candidate_str, regexp); } bool LLMediaEntry::checkCandidateUrl(const std::string& url) const diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 702a1b5238..805af55299 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -31,11 +31,12 @@ #include "llconvexdecomposition.h" #include "llsdserialize.h" #include "llvector4a.h" +#include "llmd5.h" #ifdef LL_USESYSTEMLIBS # include <zlib.h> #else -# include "zlib/zlib.h" +# include "zlib-ng/zlib.h" #endif std::string model_names[] = @@ -106,6 +107,14 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint ) } } +void LLModel::remapVolumeFaces() +{ + for (U32 i = 0; i < getNumVolumeFaces(); ++i) + { + mVolumeFaces[i].remap(); + } +} + void LLModel::optimizeVolumeFaces() { for (U32 i = 0; i < getNumVolumeFaces(); ++i) @@ -370,6 +379,8 @@ void LLModel::setVolumeFaceData( U32 num_verts, U32 num_indices) { + llassert(num_indices % 3 == 0); + LLVolumeFace& face = mVolumeFaces[f]; face.resizeVertices(num_verts); @@ -834,7 +845,7 @@ LLSD LLModel::writeModel( { LLVector3 pos(face.mPositions[j].getF32ptr()); - weight_list& weights = high->getJointInfluences(pos); + weight_list& weights = model[idx]->getJointInfluences(pos); S32 count = 0; for (weight_list::iterator iter = weights.begin(); iter != weights.end(); ++iter) @@ -880,8 +891,6 @@ LLSD LLModel::writeModel( LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BOOL as_slm) { - U32 bytes = 0; - std::string::size_type cur_offset = 0; LLSD header; @@ -903,7 +912,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO header["skin"]["offset"] = (LLSD::Integer) cur_offset; header["skin"]["size"] = (LLSD::Integer) size; cur_offset += size; - bytes += size; } } @@ -919,7 +927,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO header["physics_convex"]["offset"] = (LLSD::Integer) cur_offset; header["physics_convex"]["size"] = (LLSD::Integer) size; cur_offset += size; - bytes += size; } } @@ -941,7 +948,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO header[model_names[i]]["offset"] = (LLSD::Integer) cur_offset; header[model_names[i]]["size"] = (LLSD::Integer) size; cur_offset += size; - bytes += size; } } @@ -1262,6 +1268,14 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn LL_INFOS("MESHSKININFO")<<"Material of model is not a subset of reference."<<LL_ENDL; return false; } + + if (mMaterialList.size() > ref->mMaterialList.size()) + { + LL_INFOS("MESHSKININFO") << "Material of model has more materials than a reference." << LL_ENDL; + // We passed isMaterialListSubset, so materials are a subset, but subset isn't supposed to be + // larger than original and if we keep going, reordering will cause a crash + return false; + } std::map<std::string, U32> index_map; @@ -1396,7 +1410,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) } } - mInvBindMatrix.push_back(mat); + mInvBindMatrix.push_back(LLMatrix4a(mat)); } if (mJointNames.size() != mInvBindMatrix.size()) @@ -1410,13 +1424,15 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) if (skin.has("bind_shape_matrix")) { + LLMatrix4 mat; for (U32 j = 0; j < 4; j++) { for (U32 k = 0; k < 4; k++) { - mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal(); + mat.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal(); } } + mBindShapeMatrix.loadu(mat); } if (skin.has("alt_inverse_bind_matrix")) @@ -1432,7 +1448,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) } } - mAlternateBindMatrix.push_back(mat); + mAlternateBindMatrix.push_back(LLMatrix4a(mat)); } } @@ -1449,6 +1465,8 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) { mLockScaleIfJointPosition = false; } + + updateHash(); } LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_position) const @@ -1500,6 +1518,57 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi return ret; } +void LLMeshSkinInfo::updateHash() +{ + // get hash of data relevant to render batches + LLMD5 hash; + + //mJointNames + for (auto& name : mJointNames) + { + hash.update(name); + } + + //mJointNums + hash.update((U8*)&(mJointNums[0]), sizeof(S32) * mJointNums.size()); + + //mInvBindMatrix + F32* src = mInvBindMatrix[0].getF32ptr(); + + for (int i = 0; i < mInvBindMatrix.size() * 16; ++i) + { + S32 t = llround(src[i] * 10000.f); + hash.update((U8*)&t, sizeof(S32)); + } + //hash.update((U8*)&(mInvBindMatrix[0]), sizeof(LLMatrix4a) * mInvBindMatrix.size()); + + hash.finalize(); + + U64 digest[2]; + hash.raw_digest((U8*) digest); + + mHash = digest[0]; +} + +U32 LLMeshSkinInfo::sizeBytes() const +{ + U32 res = sizeof(LLUUID); // mMeshID + + res += sizeof(std::vector<std::string>) + sizeof(std::string) * mJointNames.size(); + for (U32 i = 0; i < mJointNames.size(); ++i) + { + res += mJointNames[i].size(); // actual size, not capacity + } + + res += sizeof(std::vector<S32>) + sizeof(S32) * mJointNums.size(); + res += sizeof(std::vector<LLMatrix4>) + 16 * sizeof(float) * mInvBindMatrix.size(); + res += sizeof(std::vector<LLMatrix4>) + 16 * sizeof(float) * mAlternateBindMatrix.size(); + res += 16 * sizeof(float); //mBindShapeMatrix + res += sizeof(float) + 3 * sizeof(bool); + + return res; +} + LLModel::Decomposition::Decomposition(LLSD& data) { fromLLSD(data); @@ -1606,6 +1675,30 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp) } } +U32 LLModel::Decomposition::sizeBytes() const +{ + U32 res = sizeof(LLUUID); // mMeshID + + res += sizeof(LLModel::convex_hull_decomposition) + sizeof(std::vector<LLVector3>) * mHull.size(); + for (U32 i = 0; i < mHull.size(); ++i) + { + res += mHull[i].size() * sizeof(LLVector3); + } + + res += sizeof(LLModel::hull) + sizeof(LLVector3) * mBaseHull.size(); + + res += sizeof(std::vector<LLModel::PhysicsMesh>) + sizeof(std::vector<LLModel::PhysicsMesh>) * mMesh.size(); + for (U32 i = 0; i < mMesh.size(); ++i) + { + res += mMesh[i].sizeBytes(); + } + + res += sizeof(std::vector<LLModel::PhysicsMesh>) * 2; + res += mBaseHullMesh.sizeBytes() + mPhysicsShapeMesh.sizeBytes(); + + return res; +} + bool LLModel::Decomposition::hasHullList() const { return !mHull.empty() ; diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 51fa2f8079..a6ab96ab18 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -33,34 +33,45 @@ #include "m4math.h" #include <queue> +#include <boost/align/aligned_allocator.hpp> + class daeElement; class domMesh; #define MAX_MODEL_FACES 8 +LL_ALIGN_PREFIX(16) class LLMeshSkinInfo { + LL_ALIGN_NEW public: LLMeshSkinInfo(); LLMeshSkinInfo(LLSD& data); void fromLLSD(LLSD& data); LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const; + void updateHash(); + U32 sizeBytes() const; LLUUID mMeshID; std::vector<std::string> mJointNames; mutable std::vector<S32> mJointNums; - std::vector<LLMatrix4> mInvBindMatrix; - std::vector<LLMatrix4> mAlternateBindMatrix; + typedef std::vector<LLMatrix4a, boost::alignment::aligned_allocator<LLMatrix4a, 16>> matrix_list_t; + matrix_list_t mInvBindMatrix; + matrix_list_t mAlternateBindMatrix; + + LL_ALIGN_16(LLMatrix4a mBindShapeMatrix); - LLMatrix4 mBindShapeMatrix; float mPelvisOffset; bool mLockScaleIfJointPosition; bool mInvalidJointsScrubbed; bool mJointNumsInitialized; -}; + U64 mHash = 0; +} LL_ALIGN_POSTFIX(16); +LL_ALIGN_PREFIX(16) class LLModel : public LLVolume { + LL_ALIGN_NEW public: enum @@ -102,6 +113,14 @@ public: { return mPositions.empty(); } + + U32 sizeBytes() const + { + U32 res = sizeof(std::vector<LLVector3>) * 2; + res += sizeof(LLVector3) * mPositions.size(); + res += sizeof(LLVector3) * mNormals.size(); + return res; + } }; class Decomposition @@ -112,6 +131,7 @@ public: void fromLLSD(LLSD& data); LLSD asLLSD() const; bool hasHullList() const; + U32 sizeBytes() const; void merge(const Decomposition* rhs); @@ -174,6 +194,7 @@ public: void sortVolumeFacesByMaterialName(); void normalizeVolumeFaces(); void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL); + void remapVolumeFaces(); void optimizeVolumeFaces(); void offsetMesh( const LLVector3& pivotPoint ); void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out); @@ -281,8 +302,10 @@ public: EModelStatus mStatus ; + // A model/object can only have 8 faces, spillover faces will + // be moved to new model/object and assigned a submodel id. int mSubmodelID; -}; +} LL_ALIGN_POSTFIX(16); typedef std::vector<LLPointer<LLModel> > model_list; typedef std::queue<LLPointer<LLModel> > model_queue; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 53b83a40d7..67c225d25d 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -114,6 +114,35 @@ const char *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); +struct material_id_type // originally from llrendermaterialtable +{ + material_id_type() + { + memset((void*)m_value, 0, sizeof(m_value)); + } + + bool operator==(const material_id_type& other) const + { + return (memcmp(m_value, other.m_value, sizeof(m_value)) == 0); + } + + bool operator!=(const material_id_type& other) const + { + return !operator==(other); + } + + bool isNull() const + { + return (memcmp(m_value, s_null_id, sizeof(m_value)) == 0); + } + + U8 m_value[MATERIAL_ID_SIZE]; // server side this is MD5RAW_BYTES + + static const U8 s_null_id[MATERIAL_ID_SIZE]; +}; + +const U8 material_id_type::s_null_id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + //static // LEGACY: by default we use the LLVolumeMgr::gVolumeMgr global // TODO -- eliminate this global from the codebase! @@ -1079,50 +1108,85 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa return (S32)(cur_ptr - start_loc); } -S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type) -{ - U8 *start_loc = cur_ptr; - U64 i; - htolememcpy(data_ptr,cur_ptr, type,data_size); - cur_ptr += data_size; - - for (i = 1; i < face_count; i++) - { - // Already unswizzled, don't need to unswizzle it again! - memcpy(data_ptr+(i*data_size),data_ptr,data_size); /* Flawfinder: ignore */ - } - - while ((cur_ptr < buffer_end) && (*cur_ptr != 0)) - { - LL_DEBUGS("TEFieldDecode") << "TE exception" << LL_ENDL; - i = 0; - while (*cur_ptr & 0x80) - { - i |= ((*cur_ptr++) & 0x7F); - i = i << 7; - } - - i |= *cur_ptr++; - - for (S32 j = 0; j < face_count; j++) - { - if (i & 0x01) - { - htolememcpy(data_ptr+(j*data_size),cur_ptr,type,data_size); - LL_DEBUGS("TEFieldDecode") << "Assigning " ; - char foo[64]; - sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1)); - LL_CONT << foo << " to face " << j << LL_ENDL; - } - i = i >> 1; - } - cur_ptr += data_size; - } - llassert(cur_ptr <= buffer_end); // buffer underrun - return (S32)(cur_ptr - start_loc); +namespace +{ + template< typename T > + bool unpack_TEField(T dest[], U8 dest_count, U8 * &source, U8 *source_end, EMsgVariableType type) + { + const size_t size(sizeof(T)); + + LL_DEBUGS("TEXTUREENTRY") << "Request to read items of size " << size << " with swizzle " << type << " froum buffer sized " << (source_end - source) << LL_ENDL; + + if ((source + size + 1) > source_end) + { + // we add 1 above to take into account the byte that we know must follow the value. + LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL; + source = source_end; + return false; + } + + // Extract the default value and fill the array. + htolememcpy(dest, source, type, size); + source += size; + for (S32 idx = 1; idx < dest_count; ++idx) + { + dest[idx] = dest[0]; + } + + while (source < source_end) + { + U64 index_flags(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) + { + LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Reading index flags." << LL_ENDL; + source = source_end; + return false; + } + + sbit = *source++; + index_flags <<= 7; // original code had this after? + index_flags |= (sbit & 0x7F); + } while (sbit & 0x80); + + if (!index_flags) + { // We've hit the terminating 0 byte. + break; + } + + if ((source + size + 1) > source_end) + { + // we add 1 above to take into account the byte that we know must follow the value. + LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL; + source = source_end; + return false; + } + + // get the value for the indexs. + T value; + htolememcpy(&value, source, type, size); + source += size; + + for (S32 idx = 0; idx < dest_count; idx++) + { + if (index_flags & 1ULL << idx) + { + dest[idx] = value; + } + } + + } + return true; + } } + // 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 @@ -1298,9 +1362,9 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const 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[] - U8 material_data[LLTEContents::MAX_TES*16]; + // 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) { @@ -1316,54 +1380,49 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name tec.face_count = 0; return retval; } + 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; + } - if (block_num < 0) - { - mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, 0, LLTEContents::MAX_TE_BUFFER); - } - else - { - mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, block_num, LLTEContents::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); - + // 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; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_data, 16, tec.face_count, MVT_LLUUID); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.colors, 4, tec.face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_s, 4, tec.face_count, MVT_F32); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_t, 4, tec.face_count, MVT_F32); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_s, 2, tec.face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_t, 2, tec.face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_rot, 2, tec.face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.bump, 1, tec.face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.media_flags, 1, tec.face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.glow, 1, tec.face_count, MVT_U8); - - if (cur_ptr < tec.packed_buffer + tec.size) - { - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)material_data, 16, tec.face_count, MVT_LLUUID); - } - else - { - memset(material_data, 0, sizeof(material_data)); + LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffere sized: " << tec.size << LL_ENDL; + U8 *buffer_end = tec.packed_buffer + tec.size; + + if (!( unpack_TEField<LLUUID>(tec.image_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID) && + unpack_TEField<LLColor4U>(tec.colors, tec.face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField<F32>(tec.scale_s, tec.face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField<F32>(tec.scale_t, tec.face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField<S16>(tec.offset_s, tec.face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField<S16>(tec.offset_t, tec.face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField<S16>(tec.image_rot, tec.face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField<U8>(tec.bump, tec.face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField<U8>(tec.media_flags, tec.face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField<U8>(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_id_type>(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 * 16]); + tec.material_ids[i].set(&(material_data[i])); } retval = 1; @@ -1375,7 +1434,6 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec) S32 retval = 0; LLColor4 color; - LLColor4U coloru; for (U32 i = 0; i < tec.face_count; i++) { LLUUID& req_id = ((LLUUID*)tec.image_data)[i]; @@ -1388,20 +1446,15 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec) retval |= setTEGlow(i, (F32)tec.glow[i] / (F32)0xFF); retval |= setTEMaterialID(i, tec.material_ids[i]); - coloru = LLColor4U(tec.colors + 4*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 - coloru.mV[VRED]) / 255.f; - color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f; - color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f; - color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f; + color.mV[VRED] = F32(255 - tec.colors[i].mV[VRED]) / 255.f; + color.mV[VGREEN] = F32(255 - tec.colors[i].mV[VGREEN]) / 255.f; + color.mV[VBLUE] = F32(255 - tec.colors[i].mV[VBLUE]) / 255.f; + color.mV[VALPHA] = F32(255 - tec.colors[i].mV[VALPHA]) / 255.f; retval |= setTEColor(i, color); - - - } return retval; @@ -1423,24 +1476,32 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) const U32 MAX_TES = 45; // Avoid construction of 32 UUIDs per call - static LLUUID image_ids[MAX_TES]; static LLMaterialID material_ids[MAX_TES]; - U8 image_data[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; + const 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; @@ -1456,50 +1517,52 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) { 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; + } + // 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; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 4, face_count, MVT_F32); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 4, face_count, MVT_F32); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8); - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8); - if (cur_ptr < packed_buffer + size) - { - cur_ptr++; - cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)material_data, 16, face_count, MVT_LLUUID); - } - else + 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<LLUUID>(image_data, face_count, cur_ptr, buffer_end, MVT_LLUUID) && + unpack_TEField<LLColor4U>(colors, face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField<F32>(scale_s, face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField<F32>(scale_t, face_count, cur_ptr, buffer_end, MVT_F32) && + unpack_TEField<S16>(offset_s, face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField<S16>(offset_t, face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField<S16>(image_rot, face_count, cur_ptr, buffer_end, MVT_S16) && + unpack_TEField<U8>(bump, face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField<U8>(media_flags, face_count, cur_ptr, buffer_end, MVT_U8) && + unpack_TEField<U8>(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_id_type>(material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID)) { - memset(material_data, 0, sizeof(material_data)); + memset((void*)material_data, 0, sizeof(material_data)); } for (i = 0; i < face_count; i++) { - memcpy(image_ids[i].mData,&image_data[i*16],16); /* Flawfinder: ignore */ - material_ids[i].set(&material_data[i * 16]); + material_ids[i].set(&(material_data[i])); } LLColor4 color; - LLColor4U coloru; for (i = 0; i < face_count; i++) { - retval |= setTETexture(i, image_ids[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); @@ -1507,15 +1570,14 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) retval |= setTEMediaTexGen(i, media_flags[i]); retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF); retval |= setTEMaterialID(i, material_ids[i]); - coloru = LLColor4U(colors + 4*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 - coloru.mV[VRED]) / 255.f; - color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f; - color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f; - color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f; + 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); } diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index b1f8112223..309b18faa9 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -330,8 +330,8 @@ struct LLTEContents { static const U32 MAX_TES = 45; - U8 image_data[MAX_TES*16]; - U8 colors[MAX_TES*4]; + LLUUID image_data[MAX_TES]; + LLColor4U colors[MAX_TES]; F32 scale_s[MAX_TES]; F32 scale_t[MAX_TES]; S16 offset_s[MAX_TES]; @@ -423,7 +423,6 @@ public: void copyTEs(const LLPrimitive *primitive); S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const; - S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type); 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 |