diff options
Diffstat (limited to 'indra/llprimitive')
-rwxr-xr-x | indra/llprimitive/llmodel.cpp | 464 | ||||
-rwxr-xr-x | indra/llprimitive/llmodel.h | 79 |
2 files changed, 425 insertions, 118 deletions
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 3669fef0dc..595f9aa307 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -775,43 +775,6 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh) return FALSE; } - -BOOL LLModel::createVolumeFacesFromFile(const std::string& file_name) -{ - DAE dae; - domCOLLADA* dom = dae.open(file_name); - if (dom) - { - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - mVolumeFaces.clear(); - mMaterialList.clear(); - - for (daeInt idx = 0; idx < count; ++idx) - { - domMesh* mesh = NULL; - - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - - if (mesh) - { - addVolumeFacesFromDomMesh(mesh); - } - } - - if (getNumVolumeFaces() > 0) - { - optimizeVolumeFaces(); - normalizeVolumeFaces(); - return TRUE; - } - } - - return FALSE; -} - void LLModel::offsetMesh( const LLVector3& pivotPoint ) { LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] ); @@ -1352,16 +1315,6 @@ std::string LLModel::getElementLabel(daeElement *element) } //static -LLModel* LLModel::loadModelFromDae(std::string filename) -{ - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - LLModel* ret = new LLModel(volume_params, 0.f); - ret->createVolumeFacesFromFile(filename); - return ret; -} - -//static LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh) { LLVolumeParams volume_params; @@ -1473,49 +1426,7 @@ LLSD LLModel::writeModel( if (skinning) { //write skinning block - if (high->mJointList.size() != high->mInvBindMatrix.size()) - { - llerrs << "WTF?" << llendl; - } - - for (U32 i = 0; i < high->mJointList.size(); ++i) - { - mdl["skin"]["joint_names"][i] = high->mJointList[i]; - - for (U32 j = 0; j < 4; j++) - { - for (U32 k = 0; k < 4; k++) - { - mdl["skin"]["inverse_bind_matrix"][i][j*4+k] = high->mInvBindMatrix[i].mMatrix[j][k]; - } - } - } - - for (U32 i = 0; i < 4; i++) - { - for (U32 j = 0; j < 4; j++) - { - mdl["skin"]["bind_shape_matrix"][i*4+j] = high->mBindShapeMatrix.mMatrix[i][j]; - } - } - - - if ( upload_joints && high->mAlternateBindMatrix.size() > 0 ) - { - for (U32 i = 0; i < high->mJointList.size(); ++i) - { - for (U32 j = 0; j < 4; j++) - { - for (U32 k = 0; k < 4; k++) - { - mdl["skin"]["alt_inverse_bind_matrix"][i][j*4+k] = high->mAlternateBindMatrix[i].mMatrix[j][k]; - } - } - } - - mdl["skin"]["pelvis_offset"] = high->mPelvisOffset; - } - + mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints); } if (!decomp.empty() || !base_hull.empty()) @@ -1897,12 +1808,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite) return header; } -//static -LLModel* LLModel::loadModelFromAsset(std::string filename, S32 lod) -{ - return NULL; -} - LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) { weight_map::iterator iter = mSkinWeights.find(pos); @@ -1976,27 +1881,380 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) void LLModel::setConvexHullDecomposition( const LLModel::convex_hull_decomposition& decomp) { - mConvexHullDecomp = decomp; + mPhysics.mHull = decomp; + mPhysics.mMesh.clear(); + updateHullCenters(); +} - mHullCenter.resize(mConvexHullDecomp.size()); +void LLModel::updateHullCenters() +{ + mHullCenter.resize(mPhysics.mHull.size()); mHullPoints = 0; mCenterOfHullCenters.clear(); - for (U32 i = 0; i < decomp.size(); ++i) + for (U32 i = 0; i < mPhysics.mHull.size(); ++i) { LLVector3 cur_center; - for (U32 j = 0; j < decomp[i].size(); ++j) + for (U32 j = 0; j < mPhysics.mHull[i].size(); ++j) { - cur_center += decomp[i][j]; + cur_center += mPhysics.mHull[i][j]; } mCenterOfHullCenters += cur_center; - cur_center *= 1.f/decomp[i].size(); + cur_center *= 1.f/mPhysics.mHull[i].size(); mHullCenter[i] = cur_center; - mHullPoints += decomp[i].size(); + mHullPoints += mPhysics.mHull[i].size(); } mCenterOfHullCenters *= 1.f / mHullPoints; } +bool LLModel::loadModel(std::istream& is)
+{
+ mSculptLevel = -1; // default is an error occured
+
+ LLSD header;
+ {
+ if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
+ {
+ llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl;
+ return false;
+ }
+ }
+
+ std::string nm[] =
+ {
+ "lowest_lod",
+ "low_lod",
+ "medium_lod",
+ "high_lod",
+ "physics_shape",
+ };
+
+ const S32 MODEL_LODS = 5;
+
+ S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
+
+ if (header[nm[lod]]["offset"].asInteger() == -1 ||
+ header[nm[lod]]["size"].asInteger() == 0 )
+ { //cannot load requested LOD
+ return false;
+ }
+
+ bool has_skin = header["skin"]["offset"].asInteger() >=0 &&
+ header["skin"]["size"].asInteger() > 0;
+
+ if (lod == LLModel::LOD_HIGH)
+ { //try to load skin info and decomp info
+ std::ios::pos_type cur_pos = is.tellg();
+ loadSkinInfo(header, is);
+ is.seekg(cur_pos);
+ }
+
+ if (lod == LLModel::LOD_PHYSICS)
+ {
+ std::ios::pos_type cur_pos = is.tellg();
+ loadDecomposition(header, is);
+ is.seekg(cur_pos);
+ }
+
+ is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+
+ if (unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()))
+ {
+ if (has_skin)
+ {
+ //build out mSkinWeight from face info
+ for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = getVolumeFace(i);
+
+ if (face.mWeights)
+ {
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ LLVector4a& w = face.mWeights[j];
+
+ std::vector<JointWeight> wght;
+
+ for (S32 k = 0; k < 4; ++k)
+ {
+ S32 idx = (S32) w[k];
+ F32 f = w[k] - idx;
+ if (f > 0.f)
+ {
+ wght.push_back(JointWeight(idx, f));
+ }
+ }
+
+ if (!wght.empty())
+ {
+ LLVector3 pos(face.mPositions[j].getF32ptr());
+ mSkinWeights[pos] = wght;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ return false;
+
+}
+ + +bool LLModel::loadSkinInfo(LLSD& header, std::istream &is) +{ + S32 offset = header["skin"]["offset"].asInteger(); + S32 size = header["skin"]["size"].asInteger(); + + if (offset >= 0 && size > 0) + { + is.seekg(offset, std::ios_base::cur); + + LLSD skin_data; + + if (unzip_llsd(skin_data, is, size)) + { + mSkinInfo.fromLLSD(skin_data); + return true; + } + } + + return false; +} + +bool LLModel::loadDecomposition(LLSD& header, std::istream& is) +{ + S32 offset = header["decomposition"]["offset"].asInteger(); + S32 size = header["decomposition"]["size"].asInteger(); + + if (offset >= 0 && size > 0) + { + is.seekg(offset, std::ios_base::cur); + + LLSD data; + + if (unzip_llsd(data, is, size)) + { + mPhysics.fromLLSD(data); + updateHullCenters(); + } + } + + return true; +} + + +LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin) +{ + fromLLSD(skin); +} + +void LLMeshSkinInfo::fromLLSD(LLSD& skin) +{ + if (skin.has("joint_names")) + { + for (U32 i = 0; i < skin["joint_names"].size(); ++i) + { + mJointNames.push_back(skin["joint_names"][i]); + } + } + + if (skin.has("inverse_bind_matrix")) + { + for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i) + { + LLMatrix4 mat; + for (U32 j = 0; j < 4; j++) + { + for (U32 k = 0; k < 4; k++) + { + mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal(); + } + } + + mInvBindMatrix.push_back(mat); + } + } + + if (skin.has("bind_shape_matrix")) + { + 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(); + } + } + } + + if (skin.has("alt_inverse_bind_matrix")) + { + for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i) + { + LLMatrix4 mat; + for (U32 j = 0; j < 4; j++) + { + for (U32 k = 0; k < 4; k++) + { + mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal(); + } + } + + mAlternateBindMatrix.push_back(mat); + } + } + + if (skin.has("pelvis_offset")) + { + mPelvisOffset = skin["pelvis_offset"].asReal(); + } +} + +LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const +{ + LLSD ret; + + for (U32 i = 0; i < mJointNames.size(); ++i) + { + ret["joint_names"][i] = mJointNames[i]; + + for (U32 j = 0; j < 4; j++) + { + for (U32 k = 0; k < 4; k++) + { + ret["inverse_bind_matrix"][i][j*4+k] = mInvBindMatrix[i].mMatrix[j][k]; + } + } + } + + for (U32 i = 0; i < 4; i++) + { + for (U32 j = 0; j < 4; j++) + { + ret["bind_shape_matrix"][i*4+j] = mBindShapeMatrix.mMatrix[i][j]; + } + } + + if ( include_joints && mAlternateBindMatrix.size() > 0 ) + { + for (U32 i = 0; i < mJointNames.size(); ++i) + { + for (U32 j = 0; j < 4; j++) + { + for (U32 k = 0; k < 4; k++) + { + ret["alt_inverse_bind_matrix"][i][j*4+k] = mAlternateBindMatrix[i].mMatrix[j][k]; + } + } + } + + ret["pelvis_offset"] = mPelvisOffset; + } + + return ret; +} + +LLModel::Decomposition::Decomposition(LLSD& data) +{ + fromLLSD(data); +} + +void LLModel::Decomposition::fromLLSD(LLSD& decomp) +{ + if (decomp.has("HullList")) + { + // updated for const-correctness. gcc is picky about this type of thing - Nyx + const LLSD::Binary& hulls = decomp["HullList"].asBinary(); + const LLSD::Binary& position = decomp["Position"].asBinary(); + + U16* p = (U16*) &position[0]; + + mHull.resize(hulls.size()); + + LLVector3 min; + LLVector3 max; + LLVector3 range; + + min.setValue(decomp["Min"]); + max.setValue(decomp["Max"]); + range = max-min; + + for (U32 i = 0; i < hulls.size(); ++i) + { + U16 count = (hulls[i] == 0) ? 256 : hulls[i]; + + for (U32 j = 0; j < count; ++j) + { + mHull[i].push_back(LLVector3( + (F32) p[0]/65535.f*range.mV[0]+min.mV[0], + (F32) p[1]/65535.f*range.mV[1]+min.mV[1], + (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); + p += 3; + } + + } + } + + if (decomp.has("Hull")) + { + const LLSD::Binary& position = decomp["Hull"].asBinary(); + + U16* p = (U16*) &position[0]; + + LLVector3 min; + LLVector3 max; + LLVector3 range; + + min.setValue(decomp["Min"]); + max.setValue(decomp["Max"]); + range = max-min; + + U16 count = position.size()/6; + + for (U32 j = 0; j < count; ++j) + { + mBaseHull.push_back(LLVector3( + (F32) p[0]/65535.f*range.mV[0]+min.mV[0], + (F32) p[1]/65535.f*range.mV[1]+min.mV[1], + (F32) p[2]/65535.f*range.mV[2]+min.mV[2])); + p += 3; + } + } + else + { + //empty base hull mesh to indicate decomposition has been loaded + //but contains no base hull + mBaseHullMesh.clear();; + } + +} + +void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs) +{ + if (!rhs) + { + return; + } + + if (mMeshID != rhs->mMeshID) + { + llerrs << "Attempted to merge with decomposition of some other mesh." << llendl; + } + + if (mBaseHull.empty()) + { //take base hull and decomposition from rhs + mHull = rhs->mHull; + mBaseHull = rhs->mBaseHull; + mMesh = rhs->mMesh; + mBaseHullMesh = rhs->mBaseHullMesh; + } + + if (mPhysicsShapeMesh.empty()) + { //take physics shape mesh from rhs + mPhysicsShapeMesh = rhs->mPhysicsShapeMesh; + } +} diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index addf527d8d..e9450d2967 100755 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -27,6 +27,7 @@ #ifndef LL_LLMODEL_H #define LL_LLMODEL_H +#include "llpointer.h" #include "llvolume.h" #include "v4math.h" #include "m4math.h" @@ -36,6 +37,24 @@ class domMesh; #define MAX_MODEL_FACES 8 + +class LLMeshSkinInfo +{ +public: + LLUUID mMeshID; + std::vector<std::string> mJointNames; + std::vector<LLMatrix4> mInvBindMatrix; + std::vector<LLMatrix4> mAlternateBindMatrix; + std::map<std::string, U32> mJointMap; + + LLMeshSkinInfo() { } + LLMeshSkinInfo(LLSD& data); + void fromLLSD(LLSD& data); + LLSD asLLSD(bool include_joints) const; + LLMatrix4 mBindShapeMatrix; + float mPelvisOffset; +}; + class LLModel : public LLVolume { public: @@ -58,6 +77,9 @@ public: LLModel(LLVolumeParams& params, F32 detail); ~LLModel(); + bool loadModel(std::istream& is); + bool loadSkinInfo(LLSD& header, std::istream& is); + bool loadDecomposition(LLSD& header, std::istream& is); static LLSD writeModel( std::string filename, LLModel* physics, @@ -98,8 +120,6 @@ public: LLSD& mdl, BOOL nowrite = FALSE); - static LLModel* loadModelFromAsset(std::string filename, S32 lod); - static LLModel* loadModelFromDae(std::string filename); static LLModel* loadModelFromDomMesh(domMesh* mesh); static std::string getElementLabel(daeElement* element); std::string getName() const; @@ -177,17 +197,8 @@ public: //get list of weight influences closest to given position weight_list& getJointInfluences(const LLVector3& pos); - //should always be true that mJointList[mJointMap["foo"]] == "foo" - - //map of joint names to joint index - std::map<std::string, U32> mJointMap; - - //list of joint names - std::vector<std::string> mJointList; - - LLMatrix4 mBindShapeMatrix; - std::vector<LLMatrix4> mInvBindMatrix; - std::vector<LLMatrix4> mAlternateBindMatrix; + LLMeshSkinInfo mSkinInfo; + std::string mRequestedLabel; // name requested in UI, if any. std::string mLabel; // name computed from dae. @@ -197,9 +208,10 @@ public: float mPelvisOffset; // convex hull decomposition S32 mDecompID; - convex_hull_decomposition mConvexHullDecomp; + void setConvexHullDecomposition( const convex_hull_decomposition& decomp); + void updateHullCenters(); LLVector3 mCenterOfHullCenters; std::vector<LLVector3> mHullCenter; @@ -208,9 +220,46 @@ public: //ID for storing this model in a .slm file S32 mLocalID; + class PhysicsMesh + { + public: + std::vector<LLVector3> mPositions; + std::vector<LLVector3> mNormals; + + void clear() + { + mPositions.clear(); + mNormals.clear(); + } + + bool empty() const + { + return mPositions.empty(); + } + }; + + class Decomposition + { + public: + Decomposition() { } + Decomposition(LLSD& data); + void fromLLSD(LLSD& data); + + void merge(const Decomposition* rhs); + + LLUUID mMeshID; + LLModel::convex_hull_decomposition mHull; + LLModel::hull mBaseHull; + + std::vector<LLModel::PhysicsMesh> mMesh; + LLModel::PhysicsMesh mBaseHullMesh; + LLModel::PhysicsMesh mPhysicsShapeMesh; + }; + + Decomposition mPhysics; + protected: void addVolumeFacesFromDomMesh(domMesh* mesh); - virtual BOOL createVolumeFacesFromFile(const std::string& file_name); virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh); }; |