diff -r 8e8309d7f784 indra/newview/CMakeLists.txt
--- a/indra/newview/CMakeLists.txt	Thu Jun 27 13:06:10 2013 -0500
+++ b/indra/newview/CMakeLists.txt	Fri Jul 05 15:41:46 2013 -0500
@@ -391,6 +391,7 @@
     llmediadataclient.cpp
     llmemoryview.cpp
     llmeshrepository.cpp
+    llmeshsearch.cpp
     llmimetypes.cpp
     llmorphview.cpp
     llmoveview.cpp
@@ -1040,6 +1041,7 @@
     llmediadataclient.h
     llmemoryview.h
     llmeshrepository.h
+    llmeshsearch.h
     llmimetypes.h
     llmorphview.h
     llmoveview.h
diff -r 8e8309d7f784 indra/newview/llmeshsearch.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/indra/newview/llmeshsearch.cpp	Fri Jul 05 15:41:46 2013 -0500
@@ -0,0 +1,222 @@
+/**
+ * @file llmeshsearch.cpp
+ * @brief Search meshes efficiently
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Copyright (C) 2013 Karl Stiefvater
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+
+
+#include "llmeshsearch.h"
+
+#include "llrand.h"
+#include "llvolume.h"
+
+
+LLMeshSearch::LLMeshSearch(std::vector<LLVector3>& positions, std::vector<S32>& indices) :
+    mPositions(positions), mIndices(indices)
+{
+    // compute bounding box
+    mBBox.setMin(mPositions[0]);
+    mBBox.setMax(mPositions[0]);
+    for (S32 i = 0; i < mPositions.size(); i++)
+    {
+        mBBox.addPoint(mPositions[i]);
+    }
+    
+    // size of each voxel - emperically determined to give good performance
+    mVoxelSize = 0.05;
+    
+    mWidth = (S32)ceil(mBBox.getExtent().mV[VX] / mVoxelSize);
+    mHeight = (S32)ceil(mBBox.getExtent().mV[VY] / mVoxelSize);
+    mDepth = (S32)ceil(mBBox.getExtent().mV[VZ] / mVoxelSize);
+
+    // the voxel table
+    mVoxels.resize(mWidth * mHeight * mDepth, NULL);
+    
+    
+    // insert triangles into voxel table
+    for (S32 triangle_index = 0; triangle_index < mIndices.size(); triangle_index += 3)
+    {
+        S32 index0 = mIndices[triangle_index];
+        S32 index1 = mIndices[triangle_index+1];
+        S32 index2 = mIndices[triangle_index+2];
+        
+        LLVector3& position0 = mPositions[index0];
+        LLVector3& position1 = mPositions[index1];
+        LLVector3& position2 = mPositions[index2];
+        
+        S32 x, y, z;
+        
+        cellLocation(position0, x, y, z);
+        insertTriangle(triangle_index, x, y, z);
+        cellLocation(position1, x, y, z);
+        insertTriangle(triangle_index, x, y, z);
+        cellLocation(position2, x, y, z);
+        insertTriangle(triangle_index, x, y, z);
+    }
+}
+
+
+LLMeshSearch::~LLMeshSearch()
+{
+    for (S32 i = 0; i < mVoxels.size(); i++)
+    {
+        if (mVoxels[i])
+        {
+            delete mVoxels[i];
+        }
+    }
+}
+
+// given a point in space, find it's entry coordinates in the voxel table
+void LLMeshSearch::cellLocation(LLVector3& position, S32& x, S32& y, S32& z)
+{
+    LLVector3 local_position = position - mBBox.getMin();
+    x = (S32)floor(local_position.mV[VX] / mVoxelSize);
+    y = (S32)floor(local_position.mV[VY] / mVoxelSize);
+    z = (S32)floor(local_position.mV[VZ] / mVoxelSize);
+}
+
+
+// insert a new triangle into the voxel table
+void LLMeshSearch::insertTriangle(S32 triangle_index, S32 x, S32 y, S32 z)
+{
+    S32 voxel_index = (x * mHeight + y) * mDepth + z;
+    
+    std::vector<S32>* vector_pointer = mVoxels[voxel_index];
+    
+    if (!vector_pointer)
+    {
+        vector_pointer = new std::vector<S32>;
+        mVoxels[voxel_index] = vector_pointer;
+    }
+    
+    // don't insert dupes (which will only appear sequentially so this test catches them all)
+    if ((vector_pointer->size() == 0) || (vector_pointer->back() != triangle_index))
+    {
+        vector_pointer->push_back(triangle_index);
+    }
+}
+
+
+// find point on mesh which is closest to target mesh, within a given distance, return TRUE if found
+
+BOOL LLMeshSearch::findClosestPoint(LLVector3 target, F32 within,
+                                    F32& distance, S32& index0, S32& index1, S32& index2, F32& bary_a, F32& bary_b)
+{
+    BOOL found = FALSE;
+    
+    F32 closest_distance_squared = powf(within, 2.0f);
+    
+    S32 target_x, target_y, target_z;
+    cellLocation(target, target_x, target_y, target_z);
+    
+    // cycle over all voxels
+    for (S32 x = 0; x < mWidth; x++)
+    {
+        F32 delta_x = llmax(abs(x-target_x)-1, 0) * mVoxelSize;
+        F32 delta_x_squared = delta_x * delta_x;
+        
+        // if this plane is too far away, skip it
+        if ((delta_x_squared) > closest_distance_squared)
+            continue;
+        
+
+        for (S32 y = 0; y < mHeight; y++)
+        {
+            F32 delta_y = llmax(abs(y-target_y)-1, 0) * mVoxelSize;
+            F32 delta_y_squared = delta_y * delta_y;
+        
+            // if this line is too far away, skip it
+            if ((delta_x_squared + delta_y_squared) > closest_distance_squared)
+                continue;
+            
+
+            for (S32 z = 0; z < mDepth; z++)
+            {
+                F32 delta_z = llmax(abs(z-target_z)-1, 0) * mVoxelSize;
+                F32 delta_z_squared = delta_z * delta_z;
+                
+                // if this voxel is too far away, skip it
+                if ((delta_x_squared + delta_y_squared + delta_z_squared) > closest_distance_squared)
+                    continue;
+                
+                S32 voxel_index = (x * mHeight + y) * mDepth + z;
+                
+                std::vector<S32>* vector_pointer = mVoxels[voxel_index];
+                
+                // if the voxel is empty, skip it
+                if (!vector_pointer)
+                    continue;
+
+                
+                // cycle over all triangles
+                for (S32 j = 0; j < vector_pointer->size(); j++)
+                {
+                    S32 triangle_index = (*vector_pointer)[j];
+                    
+                    // indices for triangle corners
+                    S32 this_index0 = mIndices[triangle_index+0];
+                    S32 this_index1 = mIndices[triangle_index+1];
+                    S32 this_index2 = mIndices[triangle_index+2];
+                    
+                    // positions of triangle corners
+                    LLVector3 this_position0 = mPositions[this_index0];
+                    LLVector3 this_position1 = mPositions[this_index1];
+                    LLVector3 this_position2 = mPositions[this_index2];
+                    
+                    // barycentric coord of closest point
+                    F32 this_bary_a;
+                    F32 this_bary_b;
+                    
+                    F32 this_distance_squared = LLTriangleClosestPoint(this_position0, this_position1, this_position2,
+                                                                       target, this_bary_a, this_bary_b);
+                    
+                    
+                    if (this_distance_squared < closest_distance_squared)
+                    {
+                        found = TRUE;
+                        
+                        // record corner indices of this triangle
+                        index0 = this_index0;
+                        index1 = this_index1;
+                        index2 = this_index2;
+                        
+                        // compute weights from barycentric coordinates
+                        bary_a = this_bary_a;
+                        bary_b = this_bary_b;
+                        
+                        closest_distance_squared = this_distance_squared;
+                    }
+                    
+                    
+                }
+
+            }
+        }
+    }
+    
+      
+    if (found)
+    {
+        distance = sqrt(closest_distance_squared);
+    }
+     
+    
+    return found;
+}
diff -r 8e8309d7f784 indra/newview/llmeshsearch.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/indra/newview/llmeshsearch.h	Fri Jul 05 15:41:46 2013 -0500
@@ -0,0 +1,47 @@
+/**
+ * @file llmeshsearch.cpp
+ * @brief Search meshes efficiently
+ */
+
+class LLVector3;
+class LLBBox;
+
+#ifndef LL_MESHSEARCH_H
+#define LL_MESHSEARCH_H
+
+class LLMeshSearch
+{
+	std::vector<LLVector3> mPositions;
+    std::vector<S32> mIndices;
+    LLBBoxLocal mBBox;
+    
+    // voxel table
+    F32 mVoxelSize;
+    U32 mWidth;
+    U32 mHeight;
+    U32 mDepth;
+    
+    std::vector<std::vector<S32>* > mVoxels;
+      
+    
+public:
+    LLMeshSearch(std::vector<LLVector3>& positions, std::vector<S32>& indices);
+    ~LLMeshSearch();
+    
+    void cellLocation(LLVector3& position, S32& x, S32& y, S32& z);
+    void insertTriangle(S32 triangle_index, S32 x, S32 y, S32 z);
+
+    
+    BOOL findClosestPoint(LLVector3 target, F32 within, F32& distance, S32& index0, S32& index1, S32& index2, F32& bary_a, F32& bary_b);
+};
+
+
+#endif // LL_MESHSEARCH_H
+
+
+
+
+
+
+
+
diff -r 8e8309d7f784 indra/newview/llvovolume.cpp
--- a/indra/newview/llvovolume.cpp	Thu Jun 27 13:06:10 2013 -0500
+++ b/indra/newview/llvovolume.cpp	Fri Jul 05 15:41:46 2013 -0500
@@ -85,6 +85,7 @@
 #include "rlvlocks.h"
 // [/RLVa:KB]
 #include "lldeformerworker.h"
+#include "llmeshsearch.h"
 
 const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -4226,7 +4227,7 @@
 
 
 void LLDeformedVolume::computeDeformTable(LLPointer<LLDeformerWorker::Request> request)
-{
+{    
 	// see if this table is already in the cache.  if so, return (no work needed)
 	LLDeformTableCacheIndex cache_index(request->mMeshID, request->mFace, request->mVertexCount);
 	
@@ -4282,14 +4283,18 @@
 	LLMatrix4a normal_matrix;
 	normal_matrix.loadu(normal_matrix_noA);
 		
+    // build optimized mesh searchers - one for each avatar mesh
+    LLMeshSearch* search[sizeof(MORPH_MESHES)/sizeof(S32)];
+    for (S32 i = 0; i < sizeof(MORPH_MESHES)/sizeof(S32); i++)
+    {
+        search[i] = new LLMeshSearch(request->mAvatarPositions[i], request->mAvatarIndices[i]);
+    }
+    
+    
 	// for each vertex in the volume, find the closest point on the avatar mesh(es)
 	// "closest" is defined to be a mixture of spatial position and distance between
 	// normals.
 
-
-	const F32 position_weight = 1.0;   // weight given to distance in position space
-	const F32 normal_weight   = 0.0;  // weight given to distance in normal space
-
 	for (S32 i = 0; i < request->mVertexCount; i++)
 	{
 		// position to get closest to
@@ -4300,15 +4305,6 @@
 		source_position_transformed.mul(request->mScale);
 		LLVector3 target_position(source_position_transformed.getF32ptr());
 		
-		
-		// normal to get closest to
-		LLVector4a source_normal;
-		source_normal.load3(request->mVolumeNormals[i].mV);
-		LLVector4a source_normal_transformed;
-		normal_matrix.rotate(source_normal, source_normal_transformed);
-		source_normal_transformed.normalize3();
-		LLVector3 target_normal(source_normal_transformed.getF32ptr());
-		
 
 		F32 closest_distance = F32_MAX;
 		S32 closest_mesh = 0;
@@ -4318,72 +4314,35 @@
 		F32 closest_vertex_weights[LL_DEFORMER_WEIGHT_COUNT];
 		
 		for (S32 k = 0; k < sizeof(MORPH_MESHES)/sizeof(S32); k++)
-		{
+		{            
+            F32 this_distance;
+            
+            S32 index0, index1, index2;
+            F32 bary_a, bary_b;
+            
+            BOOL found = search[k]->findClosestPoint(target_position, closest_distance,
+                                                     this_distance, index0, index1, index2, bary_a, bary_b);            
+				
+            if (found)
+            {
+                // record corner indices of this triangle
+                closest_vertex[0] = index0;
+                closest_vertex[1] = index1;
+                closest_vertex[2] = index2;
+                
+                // compute weights from barycentric coordinates
+                closest_vertex_weights[0] = 1.0f - bary_a - bary_b;
+                closest_vertex_weights[1] = bary_a;
+                closest_vertex_weights[2] = bary_b;
+                
+                // and closest mesh
+                closest_mesh = k;
+                
+                closest_distance = this_distance;
+            }
 			
-			// LLPolyFaces are triangles
-			for (S32 j = 0; j < request->mAvatarIndices[k].size(); j += 3)
-			{
-				// indices for triangle corners
-				S32 index0 = request->mAvatarIndices[k][j+0];
-				S32 index1 = request->mAvatarIndices[k][j+1];
-				S32 index2 = request->mAvatarIndices[k][j+2];
-				
-				// positions of triangle corners
-				LLVector3 position0 = request->mAvatarPositions[k][index0];
-				LLVector3 position1 = request->mAvatarPositions[k][index1];
-				LLVector3 position2 = request->mAvatarPositions[k][index2];
-				
-				// normals of triangle corners
-				LLVector3 normal0 = request->mAvatarNormals[k][index0];
-				LLVector3 normal1 = request->mAvatarNormals[k][index1];
-				LLVector3 normal2 = request->mAvatarNormals[k][index2];
-				
-				// barycentric coord of closest point
-				F32 bary_a;
-				F32 bary_b;
-				
-				LLTriangleClosestPoint(position0, position1, position2, target_position, bary_a, bary_b);
-				
-				// compute position/normal of found point
-				LLVector3 closest_position = position0 + bary_a * (position1 - position0) + bary_b * (position2 - position0);
-				LLVector3 closest_normal   = normal0 + bary_a * (normal1 - normal0) + bary_b * (normal2 - normal0);
-
-				LLVector3 position_delta = closest_position - target_position;
-				F32 position_distance = position_delta.length();
-				
-				LLVector3 normal_delta = closest_normal - target_normal;
-				F32 normal_distance = normal_delta.length();
-				
-				// mix the two distances by their weights
-				F32 this_distance = position_weight * position_distance + normal_weight * normal_distance;
-				
-				
-				if (this_distance < closest_distance)
-				{					
-					// record corner indices of this triangle
-					closest_vertex[0] = index0;
-					closest_vertex[1] = index1;
-					closest_vertex[2] = index2;
-					
-					// compute weights from barycentric coordinates
-					closest_vertex_weights[0] = 1.0f - bary_a - bary_b;
-					closest_vertex_weights[1] = bary_a;
-					closest_vertex_weights[2] = bary_b;
-					
-					// and closest mesh
-					closest_mesh = k;
-					
-					closest_distance = this_distance;
-				}
-				
-				
-			}
-			
-			
-		}
-
-
-		
+		}
+
 		
 		// create entry for found vertices
 		for (S32 k = 0; k < LL_DEFORMER_WEIGHT_COUNT; k++)
@@ -4394,15 +4353,20 @@
 		}
 	}
 	
+    // free mesh searchers
+    for (S32 i = 0; i < sizeof(MORPH_MESHES)/sizeof(S32); i++)
+    {
+        delete search[i];
+    }
 	
+    
 	// store base positions for avatar verts
 	deform_table.mBasePositions = request->mAvatarPositions;
 	
 	
 	// now put it in the cache
 	mDeformCache[cache_index] = deform_table;
-
-	
+    
 	return;
 }
 
