private void MergeNodes(List<ShapeDesc> shapes)
 {
     int count = shapes.Count;
     Dictionary<string, List<ShapeDesc>> dictionary = new Dictionary<string, List<ShapeDesc>>();
     for (int index = 0; index < shapes.Count; ++index)
     {
         ShapeDesc shape = new ShapeDesc();
         shape = shapes[index];
         string key = shape.textures[0].ToLower();
         // use vertex color flag to seperate?
         // less draw calls more important than reducing a few bytes?
         // overall it is not even reducing bytes... so no
         /*if (useOptimizer && shape.data.HasVertexColors())
         {
             key = key + "_VC";
         }*/
         // use material name from list file, Snow/Ash
         if (!this.ignoreMaterial && shape.material != "")
         {
             key = key + "_" + shape.material;
         }
         // only level 4 should have HD
         if (shape.isHighDetail && (this.quadLevel == 4 || useHDFlag))
         {
             key = key + "_HD";
         }
         // double-sided
         if (shape.isDoubleSided)
         {
             key = key + "_DS";
         }
         // clamp mode
         key = key + "_" + shape.TextureClampMode;
         if (dictionary.ContainsKey(key))
         {
             dictionary[key].Add(shape);
         }
         else
         {
             dictionary.Add(key, new List<ShapeDesc>());
             dictionary[key].Add(shape);
         }
     }
     shapes.Clear();
     foreach (KeyValuePair<string, List<ShapeDesc>> keyValuePair in dictionary)
     {
         if (keyValuePair.Value.Count == 1)
         {
             shapes.Add(keyValuePair.Value[0]);
         }
         else
         {
             SegmentDesc segmentDesc = (SegmentDesc)null;
             uint num1 = 0U;
             uint num2 = 0U;
             int num3 = -1;
             NiTriShape niTriShape = new NiTriShape();
             NiTriShapeData data = new NiTriShapeData();
             List<ShapeDesc> list = keyValuePair.Value;
             string str1 = list[0].textures[0];
             string str2 = list[0].textures[1];
             string str3 = list[0].material;
             //bool isVC = list[0].hasVertexColor;
             bool isHD = list[0].isHighDetail;
             // double-sided
             bool isDS = list[0].isDoubleSided;
             // clamp mode
             uint clampmode = list[0].TextureClampMode;
             bool allwhite = true;
             list.Sort((Comparison<ShapeDesc>)((a, b) =>
             {
                 if (a.segments[0].id > b.segments[0].id)
                     return 1;
                 return a.segments[0].id < b.segments[0].id ? -1 : 0;
             }));
             ShapeDesc shapeDesc = new ShapeDesc();
             shapeDesc.boundingBox.Set(float.MaxValue, float.MinValue, float.MaxValue, float.MinValue, float.MaxValue, float.MinValue);
             for (int index1 = 0; index1 < list.Count; ++index1)
             {
                 NiTriShapeData niTriShapeData = list[index1].data;
                 List<Vector3> vertices = niTriShapeData.GetVertices();
                 List<Triangle> triangles = new List<Triangle>(niTriShapeData.GetTriangles());
                 if ((uint)data.GetNumVertices() + (uint)vertices.Count > (uint)ushort.MaxValue || (uint)data.GetNumTriangles() + (uint)triangles.Count > (uint)ushort.MaxValue)
                 {
                     data.SetCenter(shapeDesc.boundingBox.GetCenter() / (float)this.quadLevel);
                     data.SetRadius(this.CalcRadius(data));
                     shapeDesc.segments.Add(segmentDesc);
                     shapeDesc.shape = niTriShape;
                     shapeDesc.data = data;
                     shapeDesc.textures = new string[2];
                     shapeDesc.textures[0] = str1;
                     shapeDesc.textures[1] = str2;
                     shapeDesc.material = str3;
                     shapeDesc.isHighDetail = isHD;
                     //shapeDesc.hasVertexColor = isVC;
                     // double-sided
                     shapeDesc.isDoubleSided = isDS;
                     //clamp mode
                     shapeDesc.TextureClampMode = clampmode;
                     shapes.Add(shapeDesc);
                     shapeDesc = new ShapeDesc();
                     shapeDesc.boundingBox.Set(float.MaxValue, float.MinValue, float.MaxValue, float.MinValue, float.MaxValue, float.MinValue);
                     niTriShape = new NiTriShape();
                     data = new NiTriShapeData();
                     num1 = 0U;
                     num2 = 0U;
                     num3 = -1;
                 }
                 for (int index2 = 0; index2 < (int)niTriShapeData.GetNumVertices(); ++index2)
                 {
                     Vector3 vector3 = vertices[index2] * (float)this.quadLevel;
                     shapeDesc.boundingBox.GrowByVertex(vector3);
                 }
                 data.AppendVertices(niTriShapeData.GetVertices());
                 data.AppendNormals(niTriShapeData.GetNormals());
                 data.AppendUVCoords(niTriShapeData.GetUVCoords());
                 if (this.generateTangents)
                 {
                     //str3.Length != 0
                     if (!useOptimizer || (useOptimizer && (this.quadLevel == 4 || isHD)))
                     {
                         data.AppendTangents(niTriShapeData.GetTangents());
                         data.AppendBitangents(niTriShapeData.GetBitangents());
                     }
                 }
                 // only level 4 should have vertex colors
                 if (this.generateVertexColors && (this.quadLevel == 4 || isHD))
                 {
                     List<Color4> colors = new List<Color4>();
                     if (niTriShapeData.HasVertexColors())
                     {
                         colors = niTriShapeData.GetVertexColors();
                         data.AppendVertexColors(colors);
                         for (int index2 = 0; index2 < colors.Count; index2++)
                         {
                             if (colors[index2][0] != 1f || colors[index2][2] != 1f || colors[index2][2] != 1f)
                             {
                                 allwhite = false;
                                 break;
                             }
                         }
                     }
                     else
                     {
                         for (int index2 = 0; index2 < vertices.Count; ++index2)
                         {
                             colors.Add(new Color4(1f, 1f, 1f, 1f));
                         }
                         data.AppendVertexColors(colors);
                     }
                 }
                 List<Triangle> trianglesNew = new List<Triangle>();
                 for (int index2 = 0; index2 < (int)niTriShapeData.GetNumTriangles(); ++index2)
                 {
                     trianglesNew.Add(new Triangle((ushort)(triangles[index2][0] + num1), (ushort)(triangles[index2][1] + num1), (ushort)(triangles[index2][2] + num1)));
                 }
                 data.AppendTriangles(trianglesNew);
                 num1 += (uint)niTriShapeData.GetNumVertices();
                 if (list[index1].segments[0].id != num3)
                 {
                     if (num3 != -1)
                     {
                         num2 += (uint)segmentDesc.numTriangles * 3U;
                         shapeDesc.segments.Add(segmentDesc);
                     }
                     segmentDesc = new SegmentDesc();
                     segmentDesc.id = list[index1].segments[0].id;
                     segmentDesc.startTriangle = num2;
                     segmentDesc.numTriangles = list[index1].segments[0].numTriangles;
                     num3 = list[index1].segments[0].id;
                 }
                 else
                     segmentDesc.numTriangles += list[index1].data.GetNumTriangles();
             }
             data.SetCenter(shapeDesc.boundingBox.GetCenter() / (float)this.quadLevel);
             data.SetRadius(this.CalcRadius(data));
             shapeDesc.segments.Add(segmentDesc);
             shapeDesc.shape = niTriShape;
             shapeDesc.data = data;
             shapeDesc.textures = new string[2];
             shapeDesc.textures[0] = str1;
             shapeDesc.textures[1] = str2;
             shapeDesc.material = str3;
             //shapeDesc.hasVertexColor = isVC;
             shapeDesc.isHighDetail = isHD;
             // double-sided
             shapeDesc.isDoubleSided = isDS;
             // clamp mode
             shapeDesc.TextureClampMode = clampmode;
             if (allwhite)
             {
                 shapeDesc.data.SetHasVertexColors(false);
                 shapeDesc.hasVertexColor = false;
             }
             else
             {
                 shapeDesc.data.SetHasVertexColors(true);
                 shapeDesc.hasVertexColor = true;
             }
             shapes.Add(shapeDesc);
         }
     }
 }