From 15235061e8a8f64dd94640d27eadfce23ccb76f6 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Sat, 18 Jun 2011 01:02:03 -0500
Subject: SH-828 Fix for using uninitialized data when normals or texture
 coordinates are absent from collada file (can now upload meshes without
 normals or texture coordinates).

---
 indra/llprimitive/llmodel.cpp | 355 +++++++++++++++++++-----------------------
 1 file changed, 163 insertions(+), 192 deletions(-)

(limited to 'indra/llprimitive')

diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index e0cfa07614..7c9dba9597 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"
@@ -71,88 +72,10 @@ 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 << "Vertex array offset MUST be zero." << 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 << "Vertex array stride MUST be three." << 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]);
-			}
-		}
-	}
-}
 
 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;
 
 	for (U32 j = 0; j < inputs.getCount(); ++j)
@@ -271,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;
 			
@@ -329,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(face.mTexCoords);
+				new_face.mTexCoords = NULL;
+			}
+
 			face = LLVolumeFace();
 			point_map.clear();
 		}
-
 	}
 
 	if (!verts.empty())
@@ -348,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(face.mTexCoords);
+			new_face.mTexCoords = NULL;
+		}
 	}
 
 	return LLModel::NO_ERRORS ;
@@ -433,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;
@@ -524,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(face.mTexCoords);
+					new_face.mTexCoords = NULL;
+				}
+
 				face = LLVolumeFace();
 				verts.clear();
 				indices.clear();
@@ -540,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(face.mTexCoords);
+			new_face.mTexCoords = NULL;
+		}
 	}
 
 	return LLModel::NO_ERRORS ;
@@ -557,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;
@@ -662,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);
 		}
 	}
@@ -733,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(face.mTexCoords);
+			new_face.mTexCoords = NULL;
+		}
 	}
 
 	return LLModel::NO_ERRORS ;
@@ -817,9 +800,9 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
 		
 		if (getNumVolumeFaces() > 0)
 		{
-			optimizeVolumeFaces();
 			normalizeVolumeFaces();
-
+			optimizeVolumeFaces();
+			
 			if (getNumVolumeFaces() > 0)
 			{
 				return TRUE;
@@ -853,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
@@ -962,6 +874,25 @@ void LLModel::normalizeVolumeFaces()
 
 			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
@@ -1029,8 +960,11 @@ void LLModel::normalizeVolumeFaces()
 			{
 			 	pos[j].add(trans);
 				pos[j].mul(scale);
-				norm[j].mul(inv_scale);
-				norm[j].normalize3();
+				if (norm && !norm[j].equals3(LLVector4a::getZero()))
+				{
+					norm[j].mul(inv_scale);
+					norm[j].normalize3();
+				}
 			}
 		}
 
@@ -1073,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);
 }
@@ -1477,9 +1429,8 @@ 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
@@ -1489,29 +1440,41 @@ 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];
+					if (face.mNormals)
+					{ //normals
+						F32* norm = face.mNormals[j].getF32ptr();
+
+						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;
+
+							//write to binary buffer
+							normals[norm_idx++] = buff[0];
+							normals[norm_idx++] = buff[1];
+						}
 					}
 
+
 					F32* src_tc = (F32*) face.mTexCoords[j].mV;
 
 					//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);
-
-						U8* buff = (U8*) &val;
-						//write to binary buffer
-						tc[tc_idx++] = buff[0];
-						tc[tc_idx++] = buff[1];
+					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;
@@ -1525,12 +1488,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]["TexCoord0Domain"]["Min"] = min_tc.getValue();
-				mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue();
-
 				mdl[model_names[idx]][i]["Position"] = verts;
-				mdl[model_names[idx]][i]["Normal"] = normals;
-				mdl[model_names[idx]][i]["TexCoord0"] = tc;
+				
+				if (face.mNormals)
+				{
+					mdl[model_names[idx]][i]["Normal"] = normals;
+				}
+
+				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]["TriangleList"] = indices;
 
 				if (skinning)
-- 
cgit v1.2.3