diff options
Diffstat (limited to 'indra/llprimitive')
-rw-r--r-- | indra/llprimitive/llmodel.cpp | 674 | ||||
-rw-r--r-- | indra/llprimitive/llmodel.h | 12 | ||||
-rw-r--r-- | indra/llprimitive/llprimitive.h | 2 |
3 files changed, 392 insertions, 296 deletions
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 794cdb83d5..ea0ea931af 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include "llmodel.h" +#include "llmemory.h" #include "llconvexdecomposition.h" #include "llsdserialize.h" #include "llvector4a.h" @@ -50,7 +51,7 @@ std::string model_names[] = "low_lod", "medium_lod", "high_lod", - "physics_shape" + "physics_mesh" }; const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string); @@ -71,85 +72,8 @@ LLModel::~LLModel() } } -void load_face_from_dom_inputs(LLVolumeFace& face, const domInputLocalOffset_Array& inputs, U32 min_idx, U32 max_idx) -{ - for (U32 j = 0; j < inputs.getCount(); ++j) - { - if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0) - { //found vertex array - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - domVertices* vertices = (domVertices*) elem.cast(); - - domInputLocal_Array& v_inp = vertices->getInput_array(); - if (inputs[j]->getOffset() != 0) - { - llerrs << "WTF?" << llendl; - } - - for (U32 k = 0; k < v_inp.getCount(); ++k) - { - if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0) - { - const domURIFragmentType& uri = v_inp[k]->getSource(); - - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - - if (src->getTechnique_common()->getAccessor()->getStride() != 3) - { - llerrs << "WTF?" << llendl; - } - - domListOfFloats& v = src->getFloat_array()->getValue(); - - LLVector4a min; - min.set(v[min_idx], v[min_idx+1], v[min_idx+2]); - LLVector4a max = min; - - for (U32 j = min_idx; j <= max_idx; ++j) - { //copy vertex array - face.mPositions[j-min_idx].set(v[j*3+0], v[j*3+1], v[j*3+2]); - update_min_max(min, max, face.mPositions[j-min_idx]); - } - - face.mExtents[0] = min; - face.mExtents[1] = max; - } - } - } - - if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0) - { - //found normal array for this triangle list - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - domListOfFloats& n = src->getFloat_array()->getValue(); - - for (U32 j = min_idx; j <= max_idx; ++j) - { - LLVector4a* norm = (LLVector4a*) face.mNormals + (j-min_idx); - norm->set(n[j*3+0], n[j*3+1], n[j*3+2]); - norm->normalize3(); - } - } - else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0) - { //found texCoords - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - domListOfFloats& u = src->getFloat_array()->getValue(); - - for (U32 j = min_idx; j <= max_idx; ++j) - { - face.mTexCoords[j-min_idx].setVec(u[j*2+0], u[j*2+1]); - } - } - } -} -void get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride, +bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride, domSource* &pos_source, domSource* &tc_source, domSource* &norm_source) { idx_stride = 0; @@ -163,7 +87,11 @@ void get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S const domURIFragmentType& uri = inputs[j]->getSource(); daeElementRef elem = uri.getElement(); domVertices* vertices = (domVertices*) elem.cast(); - + if ( !vertices ) + { + return false; + } + domInputLocal_Array& v_inp = vertices->getInput_array(); @@ -207,6 +135,8 @@ void get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S } idx_stride += 1; + + return true; } LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri) @@ -227,8 +157,12 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa S32 idx_stride = 0; - get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source); + if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source) || !pos_source ) + { + return LLModel::BAD_ELEMENT; + } + domPRef p = tri->getP(); domListOfUInts& idx = p->getValue(); @@ -260,14 +194,13 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0], tc[idx[i+tc_offset]*2+1]); } - + if (norm_source) { cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0], n[idx[i+norm_offset]*3+1], n[idx[i+norm_offset]*3+2])); } - BOOL found = FALSE; @@ -318,10 +251,22 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa { face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(verts, indices); + LLVolumeFace& new_face = *face_list.rbegin(); + if (!norm_source) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + face = LLVolumeFace(); point_map.clear(); } - } if (!verts.empty()) @@ -337,6 +282,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(verts, indices); + LLVolumeFace& new_face = *face_list.rbegin(); + if (!norm_source) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } } return LLModel::NO_ERRORS ; @@ -367,7 +324,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac S32 idx_stride = 0; - get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source); + if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) + { + return LLModel::BAD_ELEMENT; + } LLVolumeFace face; @@ -419,14 +379,14 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0], tc[idx[cur_idx+tc_offset]*2+1]); } - + if (norm_source) { cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0], n[idx[cur_idx+norm_offset]*3+1], n[idx[cur_idx+norm_offset]*3+2]); } - + cur_idx += idx_stride; BOOL found = FALSE; @@ -510,6 +470,19 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac { face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(verts, indices); + LLVolumeFace& new_face = *face_list.rbegin(); + if (!norm_source) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + face = LLVolumeFace(); verts.clear(); indices.clear(); @@ -526,10 +499,23 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac { material = std::string(poly->getMaterial()); } - + materials.push_back(material); face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(verts, indices); + + LLVolumeFace& new_face = *face_list.rbegin(); + if (!norm_source) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } } return LLModel::NO_ERRORS ; @@ -543,7 +529,6 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac const domInputLocalOffset_Array& inputs = poly->getInput_array(); - S32 v_offset = -1; S32 n_offset = -1; S32 t_offset = -1; @@ -564,7 +549,10 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac const domURIFragmentType& uri = inputs[i]->getSource(); daeElementRef elem = uri.getElement(); domVertices* vertices = (domVertices*) elem.cast(); - + if (!vertices) + { + return LLModel::BAD_ELEMENT; + } domInputLocal_Array& v_inp = vertices->getInput_array(); for (U32 k = 0; k < v_inp.getCount(); ++k) @@ -574,6 +562,10 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac const domURIFragmentType& uri = v_inp[k]->getSource(); daeElementRef elem = uri.getElement(); domSource* src = (domSource*) elem.cast(); + if (!src) + { + return LLModel::BAD_ELEMENT; + } v = &(src->getFloat_array()->getValue()); } } @@ -585,6 +577,10 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac const domURIFragmentType& uri = inputs[i]->getSource(); daeElementRef elem = uri.getElement(); domSource* src = (domSource*) elem.cast(); + if (!src) + { + return LLModel::BAD_ELEMENT; + } n = &(src->getFloat_array()->getValue()); } else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[i]->getSemantic()) == 0 && inputs[i]->getSet() == 0) @@ -593,6 +589,10 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac const domURIFragmentType& uri = inputs[i]->getSource(); daeElementRef elem = uri.getElement(); domSource* src = (domSource*) elem.cast(); + if (!src) + { + return LLModel::BAD_ELEMENT; + } t = &(src->getFloat_array()->getValue()); } } @@ -633,15 +633,14 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac n->get(n_idx+1), n->get(n_idx+2)); } - + if (t) { U32 t_idx = idx[j*stride+t_offset]*2; vert.mTexCoord.setVec(t->get(t_idx), t->get(t_idx+1)); } - - + verts.push_back(vert); } } @@ -667,11 +666,6 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac } } - if (cur_idx != vert_idx.size()) - { - llerrs << "WTF?" << llendl; - } - //build vertex array from map std::vector<LLVolumeFace::VertexData> new_verts; new_verts.resize(vert_idx.size()); @@ -709,6 +703,19 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac materials.push_back(material); face_list.push_back(face); face_list.rbegin()->fillFromLegacyData(new_verts, indices); + + LLVolumeFace& new_face = *face_list.rbegin(); + if (!n) + { + ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!t) + { + ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } } return LLModel::NO_ERRORS ; @@ -717,7 +724,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac //static std::string LLModel::getStatusString(U32 status) { - const static std::string status_strings[(S32)INVALID_STATUS] = {"status_no_error", "status_vertex_number_overflow"}; + const static std::string status_strings[(S32)INVALID_STATUS] = {"status_no_error", "status_vertex_number_overflow","bad_element"}; if(status < INVALID_STATUS) { @@ -755,7 +762,6 @@ void LLModel::addVolumeFacesFromDomMesh(domMesh* mesh) for (U32 i = 0; i < polys.getCount(); ++i) { domPolylistRef& poly = polys.get(i); - mStatus = load_face_from_dom_polylist(mVolumeFaces, mMaterialList, poly); if(mStatus != NO_ERRORS) @@ -765,12 +771,12 @@ void LLModel::addVolumeFacesFromDomMesh(domMesh* mesh) return ; //abort } } - + domPolygons_Array& polygons = mesh->getPolygons_array(); + for (U32 i = 0; i < polygons.getCount(); ++i) { domPolygonsRef& poly = polygons.get(i); - mStatus = load_face_from_dom_polygons(mVolumeFaces, mMaterialList, poly); if(mStatus != NO_ERRORS) @@ -780,7 +786,7 @@ void LLModel::addVolumeFacesFromDomMesh(domMesh* mesh) return ; //abort } } - + } BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh) @@ -794,9 +800,9 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh) if (getNumVolumeFaces() > 0) { - optimizeVolumeFaces(); normalizeVolumeFaces(); - + optimizeVolumeFaces(); + if (getNumVolumeFaces() > 0) { return TRUE; @@ -830,81 +836,10 @@ void LLModel::offsetMesh( const LLVector3& pivotPoint ) void LLModel::optimizeVolumeFaces() { -#if 0 //VECTORIZE ? - for (std::vector<LLVolumeFace>::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); ) - { - std::vector<LLVolumeFace>::iterator cur_iter = iter++; - LLVolumeFace& face = *cur_iter; - - for (S32 i = 0; i < (S32) face.mNumIndices; i += 3) - { //remove zero area triangles - U16 i0 = face.mIndices[i+0]; - U16 i1 = face.mIndices[i+1]; - U16 i2 = face.mIndices[i+2]; - - if (i0 == i1 || - i1 == i2 || - i0 == i2) - { //duplicate index in triangle, remove triangle - face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3); - i -= 3; - } - else - { - LLVolumeFace::VertexData& v0 = face.mVertices[i0]; - LLVolumeFace::VertexData& v1 = face.mVertices[i1]; - LLVolumeFace::VertexData& v2 = face.mVertices[i2]; - - if (v0.mPosition == v1.mPosition || - v1.mPosition == v2.mPosition || - v2.mPosition == v0.mPosition) - { //zero area triangle, delete - face.mIndices.erase(face.mIndices.begin()+i, face.mIndices.begin()+i+3); - i-=3; - } - } - } - - //remove unreference vertices - std::vector<bool> ref; - ref.resize(face.mNumVertices); - - for (U32 i = 0; i < ref.size(); ++i) - { - ref[i] = false; - } - - for (U32 i = 0; i < face.mNumIndices; ++i) - { - ref[face.mIndices[i]] = true; - } - - U32 unref_count = 0; - for (U32 i = 0; i < ref.size(); ++i) - { - if (!ref[i]) - { - //vertex is unreferenced - face.mVertices.erase(face.mVertices.begin()+(i-unref_count)); - U16 idx = (U16) (i-unref_count); - - for (U32 j = 0; j < face.mNumIndices; ++j) - { //decrement every index array value greater than idx - if (face.mIndices[j] > idx) - { - --face.mIndices[j]; - } - } - ++unref_count; - } - } - - if (face.mVertices.empty() || face.mIndices.empty()) - { //face is empty, remove it - iter = mVolumeFaces.erase(cur_iter); - } + for (U32 i = 0; i < getNumVolumeFaces(); ++i) + { + mVolumeFaces[i].optimize(); } -#endif } // Shrink the model to fit @@ -926,11 +861,6 @@ void LLModel::normalizeVolumeFaces() { LLVector4a min, max; - if (mVolumeFaces[0].mNumVertices <= 0) - { - llerrs << "WTF?" << llendl; - } - // For all of the volume faces // in the model, loop over // them and see what the extents @@ -942,13 +872,27 @@ void LLModel::normalizeVolumeFaces() { LLVolumeFace& face = mVolumeFaces[i]; - if (face.mNumVertices <= 0) - { - llerrs << "WTF?" << llendl; - } - update_min_max(min, max, face.mExtents[0]); update_min_max(min, max, face.mExtents[1]); + + if (face.mTexCoords) + { + LLVector2& min_tc = face.mTexCoordExtents[0]; + LLVector2& max_tc = face.mTexCoordExtents[1]; + + min_tc = face.mTexCoords[0]; + max_tc = face.mTexCoords[0]; + + for (U32 j = 1; j < face.mNumVertices; ++j) + { + update_min_max(min_tc, max_tc, face.mTexCoords[j]); + } + } + else + { + face.mTexCoordExtents[0].set(0,0); + face.mTexCoordExtents[1].set(1,1); + } } // Now that we have the extents of the model @@ -991,6 +935,9 @@ void LLModel::normalizeVolumeFaces() scale.splat(1.f); scale.div(size); + LLVector4a inv_scale(1.f); + inv_scale.div(scale); + for (U32 i = 0; i < mVolumeFaces.size(); ++i) { LLVolumeFace& face = mVolumeFaces[i]; @@ -1007,10 +954,17 @@ void LLModel::normalizeVolumeFaces() // For all the positions, we scale // the positions to fit within the unit cube. LLVector4a* pos = (LLVector4a*) face.mPositions; + LLVector4a* norm = (LLVector4a*) face.mNormals; + for (U32 j = 0; j < face.mNumVertices; ++j) { pos[j].add(trans); pos[j].mul(scale); + if (norm && !norm[j].equals3(LLVector4a::getZero())) + { + norm[j].mul(inv_scale); + norm[j].normalize3(); + } } } @@ -1053,8 +1007,26 @@ void LLModel::setVolumeFaceData( face.resizeIndices(num_indices); LLVector4a::memcpyNonAliased16((F32*) face.mPositions, (F32*) pos.get(), num_verts*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32)); + if (norm.get()) + { + LLVector4a::memcpyNonAliased16((F32*) face.mNormals, (F32*) norm.get(), num_verts*4*sizeof(F32)); + } + else + { + ll_aligned_free_16(face.mNormals); + face.mNormals = NULL; + } + + if (tc.get()) + { + LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32)); + } + else + { + ll_aligned_free_16(face.mTexCoords); + face.mTexCoords = NULL; + } + U32 size = (num_indices*2+0xF)&~0xF; LLVector4a::memcpyNonAliased16((F32*) face.mIndices, (F32*) ind.get(), size); } @@ -1237,10 +1209,23 @@ void LLModel::generateNormals(F32 angle_cutoff) LLVolumeFace::VertexData v; new_face.mPositions[i] = vol_face.mPositions[idx]; new_face.mNormals[i].clear(); - new_face.mTexCoords[i] = vol_face.mTexCoords[idx]; new_face.mIndices[i] = i; } + if (vol_face.mTexCoords) + { + for (U32 i = 0; i < vol_face.mNumIndices; i++) + { + U32 idx = vol_face.mIndices[i]; + new_face.mTexCoords[i] = vol_face.mTexCoords[idx]; + } + } + else + { + ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + //generate normals for new face for (U32 i = 0; i < new_face.mNumIndices; i += 3) { //for each triangle @@ -1282,11 +1267,6 @@ void LLModel::generateNormals(F32 angle_cutoff) { LLVector4a& n = iter->second[k].getNormal(); - if (!iter->second[k].getPosition().equals3(new_face.mPositions[i])) - { - llerrs << "WTF?" << llendl; - } - F32 cur = n.dot3(ref_norm).getF32(); if (cur > best) @@ -1380,7 +1360,8 @@ LLSD LLModel::writeModel( const LLModel::Decomposition& decomp, BOOL upload_skin, BOOL upload_joints, - BOOL nowrite) + BOOL nowrite, + BOOL as_slm) { LLSD mdl; @@ -1403,7 +1384,19 @@ LLSD LLModel::writeModel( if (!decomp.mBaseHull.empty() || !decomp.mHull.empty()) { - mdl["decomposition"] = decomp.asLLSD(); + mdl["physics_convex"] = decomp.asLLSD(); + if (!decomp.mHull.empty() && !as_slm) + { //convex decomposition exists, physics mesh will not be used (unless this is an slm file) + model[LLModel::LOD_PHYSICS] = NULL; + } + } + + if (as_slm) + { //save material list names + for (U32 i = 0; i < high->mMaterialList.size(); ++i) + { + mdl["material_list"][i] = high->mMaterialList[i]; + } } for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx) @@ -1428,8 +1421,9 @@ LLSD LLModel::writeModel( for (S32 i = 0; i < model[idx]->getNumVolumeFaces(); ++i) { //for each face const LLVolumeFace& face = model[idx]->getVolumeFace(i); - if (!face.mNumVertices) + if (face.mNumVertices < 3) { //don't export an empty face + mdl[model_names[idx]][i]["NoGeometry"] = true; continue; } LLSD::Binary verts(face.mNumVertices*3*2); @@ -1442,13 +1436,19 @@ LLSD LLModel::writeModel( U32 tc_idx = 0; LLVector2* ftc = (LLVector2*) face.mTexCoords; - LLVector2 min_tc = ftc[0]; - LLVector2 max_tc = min_tc; - - //get texture coordinate domain - for (U32 j = 0; j < face.mNumVertices; ++j) + LLVector2 min_tc; + LLVector2 max_tc; + + if (ftc) { - update_min_max(min_tc, max_tc, ftc[j]); + min_tc = ftc[0]; + max_tc = min_tc; + + //get texture coordinate domain + for (U32 j = 0; j < face.mNumVertices; ++j) + { + update_min_max(min_tc, max_tc, ftc[j]); + } } LLVector2 tc_range = max_tc - min_tc; @@ -1457,12 +1457,10 @@ LLSD LLModel::writeModel( { //for each vert F32* pos = face.mPositions[j].getF32ptr(); - F32* norm = face.mNormals[j].getF32ptr(); - - //position + normal + + //position for (U32 k = 0; k < 3; ++k) { //for each component - //convert to 16-bit normalized across domain U16 val = (U16) (((pos[k]-min_pos.mV[k])/pos_range.mV[k])*65535); @@ -1470,29 +1468,40 @@ LLSD LLModel::writeModel( //write to binary buffer verts[vert_idx++] = buff[0]; verts[vert_idx++] = buff[1]; - - //convert to 16-bit normalized - val = (U16) ((norm[k]+1.f)*0.5f*65535); - - //write to binary buffer - normals[norm_idx++] = buff[0]; - normals[norm_idx++] = buff[1]; } - F32* src_tc = (F32*) face.mTexCoords[j].mV; + if (face.mNormals) + { //normals + F32* norm = face.mNormals[j].getF32ptr(); - //texcoord - for (U32 k = 0; k < 2; ++k) - { //for each component - //convert to 16-bit normalized - U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535); + for (U32 k = 0; k < 3; ++k) + { //for each component + //convert to 16-bit normalized + U16 val = (U16) ((norm[k]+1.f)*0.5f*65535); + U8* buff = (U8*) &val; - U8* buff = (U8*) &val; - //write to binary buffer - tc[tc_idx++] = buff[0]; - tc[tc_idx++] = buff[1]; + //write to binary buffer + normals[norm_idx++] = buff[0]; + normals[norm_idx++] = buff[1]; + } } + F32* src_tc = (F32*) face.mTexCoords[j].mV; + + //texcoord + if (face.mTexCoords) + { + for (U32 k = 0; k < 2; ++k) + { //for each component + //convert to 16-bit normalized + U16 val = (U16) ((src_tc[k]-min_tc.mV[k])/tc_range.mV[k]*65535); + + U8* buff = (U8*) &val; + //write to binary buffer + tc[tc_idx++] = buff[0]; + tc[tc_idx++] = buff[1]; + } + } } U32 idx_idx = 0; @@ -1506,13 +1515,20 @@ LLSD LLModel::writeModel( //write out face data mdl[model_names[idx]][i]["PositionDomain"]["Min"] = min_pos.getValue(); mdl[model_names[idx]][i]["PositionDomain"]["Max"] = max_pos.getValue(); + mdl[model_names[idx]][i]["Position"] = verts; + + if (face.mNormals) + { + mdl[model_names[idx]][i]["Normal"] = normals; + } - mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue(); - mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue(); + if (face.mTexCoords) + { + mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue(); + mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue(); + mdl[model_names[idx]][i]["TexCoord0"] = tc; + } - mdl[model_names[idx]][i]["Position"] = verts; - mdl[model_names[idx]][i]["Normal"] = normals; - mdl[model_names[idx]][i]["TexCoord0"] = tc; mdl[model_names[idx]][i]["TriangleList"] = indices; if (skinning) @@ -1532,11 +1548,6 @@ LLSD LLModel::writeModel( weight_list& weights = high->getJointInfluences(pos); - if (weights.size() > 4) - { - llerrs << "WTF?" << llendl; - } - S32 count = 0; for (weight_list::iterator iter = weights.begin(); iter != weights.end(); ++iter) { @@ -1575,10 +1586,10 @@ LLSD LLModel::writeModel( } } - return writeModelToStream(ostr, mdl, nowrite); + return writeModelToStream(ostr, mdl, nowrite, as_slm); } -LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite) +LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BOOL as_slm) { U32 bytes = 0; @@ -1586,6 +1597,11 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite) LLSD header; + if (as_slm && mdl.has("material_list")) + { //save material binding names to header + header["material_list"] = mdl["material_list"]; + } + std::string skin; if (mdl.has("skin")) @@ -1600,23 +1616,19 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite) cur_offset += size; bytes += size; } - else - { - llerrs << "WTF?" << llendl; - } } std::string decomposition; - if (mdl.has("decomposition")) + if (mdl.has("physics_convex")) { //write out convex decomposition - decomposition = zip_llsd(mdl["decomposition"]); + decomposition = zip_llsd(mdl["physics_convex"]); U32 size = decomposition.size(); if (size > 0) { - header["decomposition"]["offset"] = (LLSD::Integer) cur_offset; - header["decomposition"]["size"] = (LLSD::Integer) size; + header["physics_convex"]["offset"] = (LLSD::Integer) cur_offset; + header["physics_convex"]["size"] = (LLSD::Integer) size; cur_offset += size; bytes += size; } @@ -1637,11 +1649,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite) cur_offset += size; bytes += size; } - else - { - header[model_names[i]]["offset"] = -1; - header[model_names[i]]["size"] = 0; - } } if (!nowrite) @@ -1655,7 +1662,7 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite) if (!decomposition.empty()) { //write decomposition block - ostr.write((const char*) decomposition.data(), header["decomposition"]["size"].asInteger()); + ostr.write((const char*) decomposition.data(), header["physics_convex"]["size"].asInteger()); } for (S32 i = 0; i < MODEL_NAMES_LENGTH; i++) @@ -1678,7 +1685,7 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) { if ((iter->first - pos).magVec() > 0.1f) { - llerrs << "WTF?" << llendl; + llerrs << "Couldn't find weight list." << llendl; } return iter->second; @@ -1771,7 +1778,7 @@ void LLModel::updateHullCenters() if (mHullPoints > 0) { mCenterOfHullCenters *= 1.f / mHullPoints; - llassert(mPhysics.asLLSD().has("HullList")); + llassert(mPhysics.hasHullList()); } } @@ -1788,13 +1795,22 @@ bool LLModel::loadModel(std::istream& is) } } + if (header.has("material_list")) + { //load material list names + mMaterialList.clear(); + for (U32 i = 0; i < header["material_list"].size(); ++i) + { + mMaterialList.push_back(header["material_list"][i].asString()); + } + } + std::string nm[] = { "lowest_lod", "low_lod", "medium_lod", "high_lod", - "physics_shape", + "physics_mesh", }; const S32 MODEL_LODS = 5; @@ -1804,6 +1820,7 @@ bool LLModel::loadModel(std::istream& is) if (header[nm[lod]]["offset"].asInteger() == -1 || header[nm[lod]]["size"].asInteger() == 0 ) { //cannot load requested LOD + llwarns << "LoD data is invalid!" << llendl; return false; } @@ -1817,7 +1834,7 @@ bool LLModel::loadModel(std::istream& is) is.seekg(cur_pos); } - if (lod == LLModel::LOD_PHYSICS) + if (lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS) { std::ios::pos_type cur_pos = is.tellg(); loadDecomposition(header, is); @@ -1864,11 +1881,66 @@ bool LLModel::loadModel(std::istream& is) } return true; } + else + { + llwarns << "unpackVolumeFaces failed!" << llendl; + } return false; } +void LLModel::matchMaterialOrder(LLModel* ref) +{ + llassert(ref->mMaterialList.size() == mMaterialList.size()); + + std::map<std::string, U32> index_map; + + //build a map of material slot names to face indexes + bool reorder = false; + std::set<std::string> base_mat; + std::set<std::string> cur_mat; + + for (U32 i = 0; i < mMaterialList.size(); i++) + { + index_map[ref->mMaterialList[i]] = i; + if (!reorder) + { //if any material name does not match reference, we need to reorder + reorder = ref->mMaterialList[i] != mMaterialList[i]; + } + base_mat.insert(ref->mMaterialList[i]); + cur_mat.insert(mMaterialList[i]); + } + + + if (reorder && + base_mat == cur_mat) //don't reorder if material name sets don't match + { + std::vector<LLVolumeFace> new_face_list; + new_face_list.resize(mVolumeFaces.size()); + + std::vector<std::string> new_material_list; + new_material_list.resize(mVolumeFaces.size()); + + //rebuild face list so materials have the same order + //as the reference model + for (U32 i = 0; i < mMaterialList.size(); ++i) + { + U32 ref_idx = index_map[mMaterialList[i]]; + new_face_list[ref_idx] = mVolumeFaces[i]; + + new_material_list[ref_idx] = mMaterialList[i]; + } + + llassert(new_material_list == ref->mMaterialList); + + mVolumeFaces = new_face_list; + } + + //override material list with reference model ordering + mMaterialList = ref->mMaterialList; +} + bool LLModel::loadSkinInfo(LLSD& header, std::istream &is) { @@ -1893,8 +1965,8 @@ bool LLModel::loadSkinInfo(LLSD& header, std::istream &is) bool LLModel::loadDecomposition(LLSD& header, std::istream& is) { - S32 offset = header["decomposition"]["offset"].asInteger(); - S32 size = header["decomposition"]["size"].asInteger(); + S32 offset = header["physics_convex"]["offset"].asInteger(); + S32 size = header["physics_convex"]["size"].asInteger(); if (offset >= 0 && size > 0) { @@ -2030,11 +2102,11 @@ LLModel::Decomposition::Decomposition(LLSD& data) void LLModel::Decomposition::fromLLSD(LLSD& decomp) { - if (decomp.has("HullList")) + if (decomp.has("HullList") && decomp.has("Positions")) { // 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(); + const LLSD::Binary& position = decomp["Positions"].asBinary(); U16* p = (U16*) &position[0]; @@ -2044,11 +2116,19 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp) LLVector3 max; LLVector3 range; - min.setValue(decomp["Min"]); - max.setValue(decomp["Max"]); + if (decomp.has("Min")) + { + min.setValue(decomp["Min"]); + max.setValue(decomp["Max"]); + } + else + { + min.set(-0.5f, -0.5f, -0.5f); + max.set(0.5f, 0.5f, 0.5f); + } + range = max-min; - for (U32 i = 0; i < hulls.size(); ++i) { U16 count = (hulls[i] == 0) ? 256 : hulls[i]; @@ -2064,6 +2144,7 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp) //point must be unique //llassert(valid.find(test) == valid.end()); valid.insert(test); + 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], @@ -2078,9 +2159,9 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp) } } - if (decomp.has("Hull")) + if (decomp.has("BoundingVerts")) { - const LLSD::Binary& position = decomp["Hull"].asBinary(); + const LLSD::Binary& position = decomp["BoundingVerts"].asBinary(); U16* p = (U16*) &position[0]; @@ -2116,10 +2197,15 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp) { //empty base hull mesh to indicate decomposition has been loaded //but contains no base hull - mBaseHullMesh.clear();; + mBaseHullMesh.clear(); } } +bool LLModel::Decomposition::hasHullList() const +{ + return !mHull.empty() ; +} + LLSD LLModel::Decomposition::asLLSD() const { LLSD ret; @@ -2130,11 +2216,9 @@ LLSD LLModel::Decomposition::asLLSD() const } //write decomposition block - // ["decomposition"]["HullList"] -- list of 8 bit integers, each entry represents a hull with specified number of points - // ["decomposition"]["PositionDomain"]["Min"/"Max"] - // ["decomposition"]["Position"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points - // ["decomposition"]["Hull"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points representing a single hull approximation of given shape - + // ["physics_convex"]["HullList"] -- list of 8 bit integers, each entry represents a hull with specified number of points + // ["physics_convex"]["Position"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points + // ["physics_convex"]["BoundingVerts"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points representing a single hull approximation of given shape //get minimum and maximum LLVector3 min; @@ -2174,6 +2258,8 @@ LLSD LLModel::Decomposition::asLLSD() const ret["Min"] = min.getValue(); ret["Max"] = max.getValue(); + LLVector3 range = max-min; + if (!hulls.empty()) { ret["HullList"] = hulls; @@ -2183,8 +2269,6 @@ LLSD LLModel::Decomposition::asLLSD() const { LLSD::Binary p(total*3*2); - LLVector3 range = max-min; - U32 vert_idx = 0; for (U32 i = 0; i < mHull.size(); ++i) @@ -2196,19 +2280,24 @@ LLSD LLModel::Decomposition::asLLSD() const for (U32 j = 0; j < mHull[i].size(); ++j) { U64 test = 0; + const F32* src = mHull[i][j].mV; + for (U32 k = 0; k < 3; k++) { //convert to 16-bit normalized across domain - U16 val = (U16) (((mHull[i][j].mV[k]-min.mV[k])/range.mV[k])*65535); + U16 val = (U16) (((src[k]-min.mV[k])/range.mV[k])*65535); - switch (k) + if(valid.size() < 3) { - case 0: test = test | (U64) val; break; - case 1: test = test | ((U64) val << 16); break; - case 2: test = test | ((U64) val << 32); break; - }; + switch (k) + { + case 0: test = test | (U64) val; break; + case 1: test = test | ((U64) val << 16); break; + case 2: test = test | ((U64) val << 32); break; + }; - valid.insert(test); + valid.insert(test); + } U8* buff = (U8*) &val; //write to binary buffer @@ -2220,26 +2309,28 @@ LLSD LLModel::Decomposition::asLLSD() const } } - //must have at least 4 unique points - llassert(valid.size() > 3); + //must have at least 3 unique points + llassert(valid.size() > 2); } - ret["Position"] = p; + ret["Positions"] = p; } + //llassert(!mBaseHull.empty()); + if (!mBaseHull.empty()) { LLSD::Binary p(mBaseHull.size()*3*2); - LLVector3 range = max-min; - U32 vert_idx = 0; for (U32 j = 0; j < mBaseHull.size(); ++j) { + const F32* v = mBaseHull[j].mV; + for (U32 k = 0; k < 3; k++) { //convert to 16-bit normalized across domain - U16 val = (U16) (((mBaseHull[j].mV[k]-min.mV[k])/range.mV[k])*65535); + U16 val = (U16) (((v[k]-min.mV[k])/range.mV[k])*65535); U8* buff = (U8*) &val; //write to binary buffer @@ -2248,12 +2339,12 @@ LLSD LLModel::Decomposition::asLLSD() const if (vert_idx > p.size()) { - llerrs << "WTF?" << llendl; + llerrs << "Index out of bounds" << llendl; } } } - ret["Hull"] = p; + ret["BoundingVerts"] = p; } return ret; @@ -2283,10 +2374,5 @@ void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs) { //take physics shape mesh from rhs mPhysicsShapeMesh = rhs->mPhysicsShapeMesh; } - - if (!mHull.empty()) - { //verify - llassert(asLLSD().has("HullList")); - } } diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 23f4b5cb42..3f58eba07d 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -73,6 +73,7 @@ public: { NO_ERRORS = 0, VERTEX_NUMBER_OVERFLOW, //vertex number is >= 65535. + BAD_ELEMENT, INVALID_STATUS } ; @@ -106,6 +107,7 @@ public: Decomposition(LLSD& data); void fromLLSD(LLSD& data); LLSD asLLSD() const; + bool hasHullList() const; void merge(const Decomposition* rhs); @@ -135,12 +137,13 @@ public: const LLModel::Decomposition& decomp, BOOL upload_skin, BOOL upload_joints, - BOOL nowrite = FALSE); + BOOL nowrite = FALSE, + BOOL as_slm = FALSE); static LLSD writeModelToStream( std::ostream& ostr, LLSD& mdl, - BOOL nowrite = FALSE); + BOOL nowrite = FALSE, BOOL as_slm = FALSE); static LLModel* loadModelFromDomMesh(domMesh* mesh); static std::string getElementLabel(daeElement* element); @@ -169,6 +172,11 @@ public: void optimizeVolumeFaces(); void offsetMesh( const LLVector3& pivotPoint ); void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out); + + //reorder face list based on mMaterialList in this and reference so + //order matches that of reference (material ordering touchup) + void matchMaterialOrder(LLModel* reference); + std::vector<std::string> mMaterialList; //data used for skin weights diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 76faa1b8c5..998016f8f6 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -103,6 +103,8 @@ public: PARAMS_LIGHT = 0x20, PARAMS_SCULPT = 0x30, PARAMS_LIGHT_IMAGE = 0x40, + PARAMS_RESERVED = 0x50, // Used on server-side + PARAMS_MESH = 0x60, }; public: |