summaryrefslogtreecommitdiff
path: root/indra/llprimitive
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llprimitive')
-rw-r--r--indra/llprimitive/llmodel.cpp674
-rw-r--r--indra/llprimitive/llmodel.h12
-rw-r--r--indra/llprimitive/llprimitive.h2
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: