summaryrefslogtreecommitdiff
path: root/indra/llprimitive/llmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llprimitive/llmodel.cpp')
-rwxr-xr-x[-rw-r--r--]indra/llprimitive/llmodel.cpp275
1 files changed, 231 insertions, 44 deletions
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 28ed051c55..1571427d51 100644..100755
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -44,7 +44,7 @@
#pragma warning (default : 4264)
#endif
-#ifdef LL_STANDALONE
+#ifdef LL_USESYSTEMLIBS
# include <zlib.h>
#else
# include "zlib/zlib.h"
@@ -166,47 +166,107 @@ 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) || !pos_source )
{
+ LL_WARNS() << "Could not find dom sources for basic geo data; invalid model." << LL_ENDL;
return LLModel::BAD_ELEMENT;
}
+ if (!pos_source)
+ {
+ LL_WARNS() << "Unable to process mesh without position data; invalid model; invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
domPRef p = tri->getP();
domListOfUInts& idx = p->getValue();
domListOfFloats dummy ;
- domListOfFloats& v = pos_source ? pos_source->getFloat_array()->getValue() : dummy ;
- domListOfFloats& tc = tc_source ? tc_source->getFloat_array()->getValue() : dummy ;
- domListOfFloats& n = norm_source ? norm_source->getFloat_array()->getValue() : dummy ;
+ domListOfFloats& v = (pos_source && pos_source->getFloat_array()) ? pos_source->getFloat_array()->getValue() : dummy ;
+ domListOfFloats& tc = (tc_source && tc_source->getFloat_array()) ? tc_source->getFloat_array()->getValue() : dummy ;
+ domListOfFloats& n = (norm_source && norm_source->getFloat_array()) ? norm_source->getFloat_array()->getValue() : dummy ;
- if (pos_source)
+ LLVolumeFace::VertexMapData::PointMap point_map;
+
+ U32 index_count = idx.getCount();
+ U32 vertex_count = (pos_source && pos_source->getFloat_array()) ? v.getCount() : 0;
+ U32 tc_count = (tc_source && tc_source->getFloat_array()) ? tc.getCount() : 0;
+ U32 norm_count = (norm_source && norm_source->getFloat_array()) ? n.getCount(): 0;
+
+ if (vertex_count == 0)
{
- face.mExtents[0].set(v[0], v[1], v[2]);
- face.mExtents[1].set(v[0], v[1], v[2]);
+ LL_WARNS() << "Unable to process mesh with empty position array; invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
}
+
+ face.mExtents[0].set(v[0], v[1], v[2]);
+ face.mExtents[1].set(v[0], v[1], v[2]);
- LLVolumeFace::VertexMapData::PointMap point_map;
-
- for (U32 i = 0; i < idx.getCount(); i += idx_stride)
+ for (U32 i = 0; i < index_count; i += idx_stride)
{
LLVolumeFace::VertexData cv;
if (pos_source)
{
+ // guard against model data specifiying out of range indices or verts
+ //
+ if (((i + pos_offset) > index_count)
+ || ((idx[i+pos_offset]*3+2) > vertex_count))
+ {
+ LL_WARNS() << "Out of range index data; invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+
cv.setPosition(LLVector4a(v[idx[i+pos_offset]*3+0],
v[idx[i+pos_offset]*3+1],
v[idx[i+pos_offset]*3+2]));
+
+ if (!cv.getPosition().isFinite3())
+ {
+ LL_WARNS() << "Nan positional data, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
}
if (tc_source)
{
+ // guard against model data specifiying out of range indices or tcs
+ //
+
+ if (((i + tc_offset) > index_count)
+ || ((idx[i+tc_offset]*2+1) > tc_count))
+ {
+ LL_WARNS() << "Out of range TC indices." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+
cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0],
tc[idx[i+tc_offset]*2+1]);
+
+ if (!cv.mTexCoord.isFinite())
+ {
+ LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
}
if (norm_source)
{
+ // guard against model data specifiying out of range indices or norms
+ //
+ if (((i + norm_offset) > index_count)
+ || ((idx[i+norm_offset]*3+2) > norm_count))
+ {
+ LL_WARNS() << "Found out of range norm indices, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+
cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0],
n[idx[i+norm_offset]*3+1],
n[idx[i+norm_offset]*3+2]));
+
+ if (!cv.getNormal().isFinite3())
+ {
+ LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
}
BOOL found = FALSE;
@@ -233,7 +293,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
verts.push_back(cv);
if (verts.size() >= 65535)
{
- //llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << llendl;
+ //LL_ERRS() << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL;
return LLModel::VERTEX_NUMBER_OVERFLOW ;
}
U16 index = (U16) (verts.size()-1);
@@ -261,13 +321,13 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
LLVolumeFace& new_face = *face_list.rbegin();
if (!norm_source)
{
- ll_aligned_free_16(new_face.mNormals);
+ //ll_aligned_free_16(new_face.mNormals);
new_face.mNormals = NULL;
}
if (!tc_source)
{
- ll_aligned_free_16(new_face.mTexCoords);
+ //ll_aligned_free_16(new_face.mTexCoords);
new_face.mTexCoords = NULL;
}
@@ -292,13 +352,13 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
LLVolumeFace& new_face = *face_list.rbegin();
if (!norm_source)
{
- ll_aligned_free_16(new_face.mNormals);
+ //ll_aligned_free_16(new_face.mNormals);
new_face.mNormals = NULL;
}
if (!tc_source)
{
- ll_aligned_free_16(new_face.mTexCoords);
+ //ll_aligned_free_16(new_face.mTexCoords);
new_face.mTexCoords = NULL;
}
}
@@ -333,6 +393,7 @@ 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() << "Could not get DOM sources for basic geo data, invalid model." << LL_ENDL;
return LLModel::BAD_ELEMENT;
}
@@ -364,6 +425,11 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
LLVolumeFace::VertexMapData::PointMap point_map;
+ U32 index_count = idx.getCount();
+ U32 vertex_count = pos_source ? v.getCount() : 0;
+ U32 tc_count = tc_source ? tc.getCount() : 0;
+ U32 norm_count = norm_source ? n.getCount() : 0;
+
U32 cur_idx = 0;
for (U32 i = 0; i < vcount.getCount(); ++i)
{ //for each polygon
@@ -376,22 +442,68 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
if (pos_source)
{
+ // guard against model data specifiying out of range indices or verts
+ //
+ if (((cur_idx + pos_offset) > index_count)
+ || ((idx[cur_idx+pos_offset]*3+2) > vertex_count))
+ {
+ LL_WARNS() << "Out of range position indices, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+
cv.getPosition().set(v[idx[cur_idx+pos_offset]*3+0],
v[idx[cur_idx+pos_offset]*3+1],
v[idx[cur_idx+pos_offset]*3+2]);
+
+ if (!cv.getPosition().isFinite3())
+ {
+ LL_WARNS() << "Found NaN while loading positions from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+
}
if (tc_source)
{
+ // guard against model data specifiying out of range indices or tcs
+ //
+ if (((cur_idx + tc_offset) > index_count)
+ || ((idx[cur_idx+tc_offset]*2+1) > tc_count))
+ {
+ LL_WARNS() << "Out of range TC indices, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+
cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0],
tc[idx[cur_idx+tc_offset]*2+1]);
+
+ if (!cv.mTexCoord.isFinite())
+ {
+ LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
}
if (norm_source)
{
+ // guard against model data specifiying out of range indices or norms
+ //
+ if (((cur_idx + norm_offset) > index_count)
+ || ((idx[cur_idx+norm_offset]*3+2) > norm_count))
+ {
+ LL_WARNS() << "Out of range norm indices, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+
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]);
+
+ if (!cv.getNormal().isFinite3())
+ {
+ LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
}
cur_idx += idx_stride;
@@ -437,7 +549,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
verts.push_back(cv);
if (verts.size() >= 65535)
{
- //llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << llendl;
+ //LL_ERRS() << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL;
return LLModel::VERTEX_NUMBER_OVERFLOW ;
}
U16 index = (U16) (verts.size()-1);
@@ -480,13 +592,13 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
LLVolumeFace& new_face = *face_list.rbegin();
if (!norm_source)
{
- ll_aligned_free_16(new_face.mNormals);
+ //ll_aligned_free_16(new_face.mNormals);
new_face.mNormals = NULL;
}
if (!tc_source)
{
- ll_aligned_free_16(new_face.mTexCoords);
+ //ll_aligned_free_16(new_face.mTexCoords);
new_face.mTexCoords = NULL;
}
@@ -514,13 +626,13 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
LLVolumeFace& new_face = *face_list.rbegin();
if (!norm_source)
{
- ll_aligned_free_16(new_face.mNormals);
+ //ll_aligned_free_16(new_face.mNormals);
new_face.mNormals = NULL;
}
if (!tc_source)
{
- ll_aligned_free_16(new_face.mTexCoords);
+ //ll_aligned_free_16(new_face.mTexCoords);
new_face.mTexCoords = NULL;
}
}
@@ -558,6 +670,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
domVertices* vertices = (domVertices*) elem.cast();
if (!vertices)
{
+ LL_WARNS() << "Could not find vertex source, invalid model." << LL_ENDL;
return LLModel::BAD_ELEMENT;
}
domInputLocal_Array& v_inp = vertices->getInput_array();
@@ -571,6 +684,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
domSource* src = (domSource*) elem.cast();
if (!src)
{
+ LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL;
return LLModel::BAD_ELEMENT;
}
v = &(src->getFloat_array()->getValue());
@@ -586,6 +700,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
domSource* src = (domSource*) elem.cast();
if (!src)
{
+ LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL;
return LLModel::BAD_ELEMENT;
}
n = &(src->getFloat_array()->getValue());
@@ -598,6 +713,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
domSource* src = (domSource*) elem.cast();
if (!src)
{
+ LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL;
return LLModel::BAD_ELEMENT;
}
t = &(src->getFloat_array()->getValue());
@@ -628,25 +744,59 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
if (v)
{
U32 v_idx = idx[j*stride+v_offset]*3;
+ v_idx = llclamp(v_idx, (U32) 0, (U32) v->getCount());
vert.getPosition().set(v->get(v_idx),
v->get(v_idx+1),
v->get(v_idx+2));
+
+ if (!vert.getPosition().isFinite3())
+ {
+ LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
}
- if (n)
+ //bounds check n and t lookups because some FBX to DAE converters
+ //use negative indices and empty arrays to indicate data does not exist
+ //for a particular channel
+ if (n && n->getCount() > 0)
{
U32 n_idx = idx[j*stride+n_offset]*3;
+ n_idx = llclamp(n_idx, (U32) 0, (U32) n->getCount());
vert.getNormal().set(n->get(n_idx),
n->get(n_idx+1),
n->get(n_idx+2));
+
+ if (!vert.getNormal().isFinite3())
+ {
+ LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+ }
+ else
+ {
+ vert.getNormal().clear();
}
+
- if (t)
+ if (t && t->getCount() > 0)
{
U32 t_idx = idx[j*stride+t_offset]*2;
+ t_idx = llclamp(t_idx, (U32) 0, (U32) t->getCount());
vert.mTexCoord.setVec(t->get(t_idx),
t->get(t_idx+1));
+
+ if (!vert.mTexCoord.isFinite())
+ {
+ LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL;
+ return LLModel::BAD_ELEMENT;
+ }
+ }
+ else
+ {
+ vert.mTexCoord.clear();
}
+
verts.push_back(vert);
}
@@ -714,13 +864,13 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
LLVolumeFace& new_face = *face_list.rbegin();
if (!n)
{
- ll_aligned_free_16(new_face.mNormals);
+ //ll_aligned_free_16(new_face.mNormals);
new_face.mNormals = NULL;
}
if (!t)
{
- ll_aligned_free_16(new_face.mTexCoords);
+ //ll_aligned_free_16(new_face.mTexCoords);
new_face.mTexCoords = NULL;
}
}
@@ -737,12 +887,12 @@ std::string LLModel::getStatusString(U32 status)
{
if(status_strings[status] == std::string())
{
- llerrs << "No valid status string for this status: " << (U32)status << llendl ;
+ LL_ERRS() << "No valid status string for this status: " << (U32)status << LL_ENDL ;
}
return status_strings[status] ;
}
- llerrs << "Invalid model status: " << (U32)status << llendl ;
+ LL_ERRS() << "Invalid model status: " << (U32)status << LL_ENDL ;
return std::string() ;
}
@@ -818,7 +968,7 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
}
else
{
- llwarns << "no mesh found" << llendl;
+ LL_WARNS() << "no mesh found" << LL_ENDL;
}
return FALSE;
@@ -994,6 +1144,43 @@ void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& tra
translation_out = mNormalizedTranslation;
}
+LLVector3 LLModel::getTransformedCenter(const LLMatrix4& mat)
+{
+ LLVector3 ret;
+
+ if (!mVolumeFaces.empty())
+ {
+ LLMatrix4a m;
+ m.loadu(mat);
+
+ LLVector4a minv,maxv;
+
+ LLVector4a t;
+ m.affineTransform(mVolumeFaces[0].mPositions[0], t);
+ minv = maxv = t;
+
+ for (S32 i = 0; i < mVolumeFaces.size(); ++i)
+ {
+ LLVolumeFace& face = mVolumeFaces[i];
+
+ for (U32 j = 0; j < face.mNumVertices; ++j)
+ {
+ m.affineTransform(face.mPositions[j],t);
+ update_min_max(minv, maxv, t);
+ }
+ }
+
+ minv.add(maxv);
+ minv.mul(0.5f);
+
+ ret.set(minv.getF32ptr());
+ }
+
+ return ret;
+}
+
+
+
void LLModel::setNumVolumeFaces(S32 count)
{
mVolumeFaces.resize(count);
@@ -1020,7 +1207,7 @@ void LLModel::setVolumeFaceData(
}
else
{
- ll_aligned_free_16(face.mNormals);
+ //ll_aligned_free_16(face.mNormals);
face.mNormals = NULL;
}
@@ -1031,7 +1218,7 @@ void LLModel::setVolumeFaceData(
}
else
{
- ll_aligned_free_16(face.mTexCoords);
+ //ll_aligned_free_16(face.mTexCoords);
face.mTexCoords = NULL;
}
@@ -1077,14 +1264,14 @@ void LLModel::addFace(const LLVolumeFace& face)
{
if (face.mNumVertices == 0)
{
- llerrs << "Cannot add empty face." << llendl;
+ LL_ERRS() << "Cannot add empty face." << LL_ENDL;
}
mVolumeFaces.push_back(face);
if (mVolumeFaces.size() > MAX_MODEL_FACES)
{
- llerrs << "Model prims cannot have more than " << MAX_MODEL_FACES << " faces!" << llendl;
+ LL_ERRS() << "Model prims cannot have more than " << MAX_MODEL_FACES << " faces!" << LL_ENDL;
}
}
@@ -1106,7 +1293,7 @@ void LLModel::generateNormals(F32 angle_cutoff)
if (vol_face.mNumIndices > 65535)
{
- llwarns << "Too many vertices for normal generation to work." << llendl;
+ LL_WARNS() << "Too many vertices for normal generation to work." << LL_ENDL;
continue;
}
@@ -1230,7 +1417,7 @@ void LLModel::generateNormals(F32 angle_cutoff)
}
else
{
- ll_aligned_free_16(new_face.mTexCoords);
+ //ll_aligned_free_16(new_face.mTexCoords);
new_face.mTexCoords = NULL;
}
@@ -1494,11 +1681,11 @@ LLSD LLModel::writeModel(
}
}
- F32* src_tc = (F32*) face.mTexCoords[j].mV;
-
//texcoord
if (face.mTexCoords)
{
+ F32* src_tc = (F32*) face.mTexCoords[j].mV;
+
for (U32 k = 0; k < 2; ++k)
{ //for each component
//convert to 16-bit normalized
@@ -1706,7 +1893,7 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
{
if ((iter->first - pos).magVec() > 0.1f)
{
- llerrs << "Couldn't find weight list." << llendl;
+ LL_ERRS() << "Couldn't find weight list." << LL_ENDL;
}
return iter->second;
@@ -1811,7 +1998,7 @@ bool LLModel::loadModel(std::istream& is)
{
if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
{
- llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl;
+ LL_WARNS() << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL;
return false;
}
}
@@ -1825,7 +2012,7 @@ bool LLModel::loadModel(std::istream& is)
}
}
- std::string nm[] =
+ static const std::string nm[] =
{
"lowest_lod",
"low_lod",
@@ -1841,7 +2028,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;
+ LL_WARNS() << "LoD data is invalid!" << LL_ENDL;
return false;
}
@@ -1904,7 +2091,7 @@ bool LLModel::loadModel(std::istream& is)
}
else
{
- llwarns << "unpackVolumeFaces failed!" << llendl;
+ LL_WARNS() << "unpackVolumeFaces failed!" << LL_ENDL;
}
return false;
@@ -1922,7 +2109,7 @@ bool LLModel::isMaterialListSubset( LLModel* ref )
for (U32 dst = 0; dst < refCnt; ++dst)
{
- //llinfos<<mMaterialList[src]<<" "<<ref->mMaterialList[dst]<<llendl;
+ //LL_INFOS()<<mMaterialList[src]<<" "<<ref->mMaterialList[dst]<<LL_ENDL;
foundRef = mMaterialList[src] == ref->mMaterialList[dst];
if ( foundRef )
@@ -1967,7 +2154,7 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn
bool isASubset = isMaterialListSubset( ref );
if ( !isASubset )
{
- llinfos<<"Material of model is not a subset of reference."<<llendl;
+ LL_INFOS()<<"Material of model is not a subset of reference."<<LL_ENDL;
return false;
}
@@ -2418,7 +2605,7 @@ LLSD LLModel::Decomposition::asLLSD() const
if (vert_idx > p.size())
{
- llerrs << "Index out of bounds" << llendl;
+ LL_ERRS() << "Index out of bounds" << LL_ENDL;
}
}
}
@@ -2438,7 +2625,7 @@ void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs)
if (mMeshID != rhs->mMeshID)
{
- llerrs << "Attempted to merge with decomposition of some other mesh." << llendl;
+ LL_ERRS() << "Attempted to merge with decomposition of some other mesh." << LL_ENDL;
}
if (mBaseHull.empty())