public void GenerateLOD(int index, int level, List<StaticDesc> statics)
        {
            this.quadIndex = index;
            if (Game.Mode == "fnv")
            {
                this.quadLevel = 4;
                this.quadOffset = 16384f;
                if (level == 4)
                {
                    return;
                }
            }
            else
            {
                this.quadLevel = level * 4;
                this.quadOffset = (float)level * 16384f;
            }
            if (this.lodLevelToGenerate != -1 && this.lodLevelToGenerate != this.quadLevel)
                return;
            //Console.WriteLine("Level=" + LODLevel + " quadLevel=" + quadLevel + " offset=" + quadOffset);
            List<QuadDesc> list1 = this.SortMeshesIntoQuads(statics);
            if (this.removeUnseenFaces)
            {
                for (int index1 = 0; index1 < list1.Count; index1++)
                {
                    QuadDesc quad = list1[index1];
                    if (this.LoadTerrainQuad(quad, out quad.terrainQuadTree, out quad.waterQuadTree, out quad.boundingBox))
                    {
                        quad.hasTerrainVertices = true;
                        list1[index1] = quad;
                    }
                }
            }
            this.quadList = list1;
            List<Thread> list2 = new List<Thread>();
            for (int index1 = 0; index1 < list1.Count; ++index1)
            {
                QuadDesc quadDesc = list1[index1];
                if ((this.lodX == -1 || this.lodX == quadDesc.x) && (this.lodY == -1 || this.lodY == quadDesc.y))
                {
                    while (list2.Count == 8)
                    {
                        for (int index2 = 0; index2 < list2.Count; ++index2)
                        {
                            if (!list2[index2].IsAlive)
                            {
                                list2.RemoveAt(index2);
                                --index2;
                            }
                        }
                    }
                    list2.Add(new Thread((ParameterizedThreadStart)(state =>
                    {
                        QuadDesc quad = (QuadDesc)state;
                        if (this.verbose)
                        {
                            this.logFile.WriteLog("Started LOD level " + this.quadLevel.ToString() + " coord [" + quad.x.ToString() + ", " + quad.y.ToString() + "]");
                        }
                        NiFile file = new NiFile();
                        NiNode rootNiNode = new NiNode();
                        BSMultiBoundNode rootBSMultiBoundNode = new BSMultiBoundNode();
                        if (Game.Mode != "fnv")
                        {
                            file.AddBlock((NiObject)rootNiNode);
                            rootNiNode.SetNameIndex(file.AddString("obj"));
                        }
                        else
                        {
                            file.AddBlock((NiObject)rootBSMultiBoundNode);
                        }
                        List<ShapeDesc> shapes = new List<ShapeDesc>();
                        for (int index11 = 0; index11 < quad.statics.Count; ++index11)
                        {
                            if (!(quad.statics[index11].staticModels[index] == ""))
                            {
                                if (Game.Mode == "fnv")
                                {
                                    shapes.AddRange((IEnumerable<ShapeDesc>)this.ParseNif(quad, quad.statics[index11], index, file, rootNiNode));
                                }
                                else
                                {
                                    shapes.AddRange((IEnumerable<ShapeDesc>)this.ParseNif(quad, quad.statics[index11], index, file, rootBSMultiBoundNode));
                                }
                            }
                        }
                        if (this.mergeShapes)
                            this.MergeNodes(shapes);
                        if (Game.Mode != "fnv")
                        {
                            this.CreateLODNodes(file, rootNiNode, quad, shapes);
                            if ((int)rootNiNode.GetNumChildren() == 0)
                            {
                                //logFile.WriteLog("quad empty " + quadLevel + " " + quad.x + ", " + quad.y);
                                //return;
                            }
                        }
                        else
                        {
                            this.CreateLODNodesFNV(file, rootBSMultiBoundNode, quad, shapes);
                            if ((int)rootBSMultiBoundNode.GetNumChildren() == 0)
                            {
                                //logFile.WriteLog("quad empty " + quadLevel + " " + quad.x + ", " + quad.y);
                                return;
                            }
                        }

                        if (Game.Mode == "fnv")
                        {
                            if (level == 1)
                            {
                                file.Write(this.outputDir + (object)"\\" + this.worldspaceName + ".Level4.X" + quad.x.ToString() + ".Y" + quad.y.ToString() + ".nif", logFile);
                            }
                            else
                            {
                                file.Write(this.outputDir + (object)"\\" + this.worldspaceName + ".Level4.High.X" + quad.x.ToString() + ".Y" + quad.y.ToString() + ".nif", logFile);
                            }
                        }
                        else
                        {
                            file.Write(this.outputDir + (object)"\\" + this.worldspaceName + "." + this.quadLevel.ToString() + "." + quad.x.ToString() + "." + quad.y.ToString() + ".bto", logFile);
                        }
                        this.logFile.WriteLog("Finished LOD level " + (object)this.quadLevel.ToString() + " coord [" + quad.x.ToString() + ", " + quad.y.ToString() + "] [" + quad.outValues.totalTriCount.ToString() + "/" + quad.outValues.reducedTriCount.ToString() + "]");
                    })));
                    list2[list2.Count - 1].Start((object)quadDesc);
                }
            }
            while (list2.Count > 0)
            {
                for (int index1 = 0; index1 < list2.Count; ++index1)
                {
                    if (!list2[index1].IsAlive)
                    {
                        list2.RemoveAt(index1);
                        --index1;
                    }
                }
            }
            int num1 = 0;
            int num2 = 0;
            foreach (QuadDesc quadDesc in list1)
            {
                num1 += quadDesc.outValues.totalTriCount;
                num2 += quadDesc.outValues.reducedTriCount;
            }
            this.logFile.WriteLog("LOD level " + this.quadLevel.ToString() + " total triangles " + num1.ToString() + " reduced to " + num2.ToString());
        }
        private void CreateLODNodesFNV(NiFile file, BSMultiBoundNode node, QuadDesc quad, List<ShapeDesc> shapes)
        {
            foreach (ShapeDesc shapeDesc in shapes)
            {
                BSSegmentedTriShape segmentedTriShape = new BSSegmentedTriShape((NiGeometry)shapeDesc.shape);
                node.AddChild(file.AddBlock((NiObject)segmentedTriShape));
                node.SetCullMode(1U);
                string str = "obj";
                // use material name from list file, Snow/Ash
                if (!this.ignoreMaterial && shapeDesc.material != "")
                    str = str + shapeDesc.material;
                // only level 4 should have HD
                if (shapeDesc.isHighDetail && (this.quadLevel == 4 || useHDFlag))
                {
                    str = str + "HD";
                }
                //segmentedTriShape.SetNameIndex(file.AddString(str));
                segmentedTriShape.SetFlags((ushort)14);
                segmentedTriShape.SetFlags2((ushort)8);
                //segmentedTriShape.SetBSProperty(1, -1);
                segmentedTriShape.SetTranslation(new Vector3((float)quad.x * 4096f, (float)quad.y * 4096f, 0.0f));
                segmentedTriShape.SetRotation(new Matrix33(true));
                segmentedTriShape.SetScale((float)this.quadLevel);

                BSShaderTextureSet shaderTextureSet = new BSShaderTextureSet();
                BSShaderPPLightingProperty lightingShaderProperty = new BSShaderPPLightingProperty();
                segmentedTriShape.SetProperties(file.AddBlock((NiObject)lightingShaderProperty));
                lightingShaderProperty.SetTextureSet(file.AddBlock((NiObject)shaderTextureSet));
                shaderTextureSet.SetNumTextures(6);
                shaderTextureSet.SetTexture(0, shapeDesc.textures[0]);
                shaderTextureSet.SetTexture(1, shapeDesc.textures[1]);
                segmentedTriShape.SetData(file.AddBlock((NiObject)shapeDesc.data));
                for (int index = 0; index < 16; ++index)
                    segmentedTriShape.AddSegment(new BSSegment(0U, (ushort)0));
                for (int index = 0; index < shapeDesc.segments.Count; ++index)
                {
                    BSSegment segmentAtIndex = segmentedTriShape.GetSegmentAtIndex(shapeDesc.segments[index].id);
                    segmentAtIndex.startTriangle = shapeDesc.segments[index].startTriangle;
                    segmentAtIndex.numTriangles = shapeDesc.segments[index].numTriangles;
                    segmentedTriShape.SetSegment(shapeDesc.segments[index].id, segmentAtIndex);
                }
                for (int index = 15; index >= 0 && (int)segmentedTriShape.GetSegmentAtIndex(index).numTriangles == 0; --index)
                {
                    segmentedTriShape.RemoveSegment(index);
                }
                this.GenerateMultibound(file, node, quad, shapeDesc.boundingBox);
            }
        }
 private void GenerateMultibound(NiFile file, BSMultiBoundNode node, QuadDesc curQuad, BBox bb)
 {
     if ((Game.Mode != "fnv") || (Game.Mode == "fnv" && node.GetMultiBound() == -1))
     {
         BSMultiBound bsMultiBound = new BSMultiBound();
         node.SetMultiBound(file.AddBlock((NiObject)bsMultiBound));
         BSMultiBoundAABB bsMultiBoundAabb = new BSMultiBoundAABB();
         bsMultiBound.SetData(file.AddBlock((NiObject)bsMultiBoundAabb));
         float num1 = (float)curQuad.x * 4096f;
         float num2 = (float)curQuad.y * 4096f;
         bsMultiBoundAabb.SetPosition(new Vector3((float)(((double)num1 + (double)bb.px1 + ((double)num1 + (double)bb.px2)) / 2.0), (float)(((double)num2 + (double)bb.py1 + ((double)num2 + (double)bb.py2)) / 2.0), (float)(((double)bb.pz1 + (double)bb.pz2) / 2.0)));
         bsMultiBoundAabb.SetExtent(new Vector3((float)(((double)bb.px2 - (double)bb.px1) / 2.0), (float)(((double)bb.py2 - (double)bb.py1) / 2.0), (float)(((double)bb.pz2 - (double)bb.pz1) / 2.0)));
     }
 }
 private void CreateLODNodes(NiFile file, NiNode rootNode, QuadDesc quad, List<ShapeDesc> shapes)
 {
     foreach (ShapeDesc shapeDesc in shapes)
     {
         BSMultiBoundNode node = new BSMultiBoundNode();
         rootNode.AddChild(file.AddBlock((NiObject)node));
         BSSegmentedTriShape segmentedTriShape = new BSSegmentedTriShape((NiGeometry)shapeDesc.shape);
         node.AddChild(file.AddBlock((NiObject)segmentedTriShape));
         node.SetCullMode(1U);
         string str = "obj";
         // use material name from list file, Snow/Ash
         if (!this.ignoreMaterial && shapeDesc.material != "")
         {
             str = str + shapeDesc.material;
         }
         // only level 4 should have HD
         if (shapeDesc.isHighDetail && (this.quadLevel == 4 || this.useHDFlag))
         {
             str = str + "HD";
         }
         segmentedTriShape.SetNameIndex(file.AddString(str));
         segmentedTriShape.SetFlags((ushort)14);
         segmentedTriShape.SetFlags2((ushort)8320);
         segmentedTriShape.SetData(file.AddBlock((NiObject)shapeDesc.data));
         segmentedTriShape.SetBSProperty(1, -1);
         segmentedTriShape.SetScale((float)this.quadLevel);
         segmentedTriShape.SetRotation(new Matrix33(true));
         segmentedTriShape.SetTranslation(new Vector3((float)quad.x * 4096f, (float)quad.y * 4096f, 0.0f));
         for (int index = 0; index < 16; ++index)
         {
             segmentedTriShape.AddSegment(new BSSegment(0U, (ushort)0));
         }
         for (int index = 0; index < shapeDesc.segments.Count; ++index)
         {
             BSSegment segmentAtIndex = segmentedTriShape.GetSegmentAtIndex(shapeDesc.segments[index].id);
             segmentAtIndex.startTriangle = shapeDesc.segments[index].startTriangle;
             segmentAtIndex.numTriangles = shapeDesc.segments[index].numTriangles;
             segmentedTriShape.SetSegment(shapeDesc.segments[index].id, segmentAtIndex);
         }
         for (int index = 15; index >= 0 && (int)segmentedTriShape.GetSegmentAtIndex(index).numTriangles == 0; --index)
         {
             segmentedTriShape.RemoveSegment(index);
         }
         BSShaderTextureSet shaderTextureSet = new BSShaderTextureSet();
         BSLightingShaderProperty lightingShaderProperty = new BSLightingShaderProperty();
         segmentedTriShape.SetBSProperty(0, file.AddBlock((NiObject)lightingShaderProperty));
         lightingShaderProperty.SetTextureSet(file.AddBlock((NiObject)shaderTextureSet));
         lightingShaderProperty.SetLightingEffect1(0.0f);
         lightingShaderProperty.SetLightingEffect2(0.0f);
         lightingShaderProperty.SetGlossiness(1f);
         lightingShaderProperty.SetTextureClampMode(shapeDesc.TextureClampMode);
         uint num1 = 2151677952U;
         /*if (this.quadLevel == 4)
         {
             num1 = 2151678720U; // Recieve/Cast Shadows - no worky :(
         }*/
         uint num3 = 1U; // ZBuffer_Write
         if (shapeDesc.isHighDetail && (this.quadLevel == 4 || this.useHDFlag))
         {
             num3 |= 2147483648U; //HD_LOD_Objects
         }
         else
         {
             num3 |= 4U; //LOD_Objects
         }
         if (shapeDesc.data.HasVertexColors())
             num3 |= 32U;
         // set double-sided flag
         if (shapeDesc.isDoubleSided)
             num3 |= 16;
         lightingShaderProperty.SetShaderFlags1(num1);
         lightingShaderProperty.SetShaderFlags2(num3);
         shaderTextureSet.SetNumTextures(9);
         shaderTextureSet.SetTexture(0, shapeDesc.textures[0]);
         shaderTextureSet.SetTexture(1, shapeDesc.textures[1]);
         this.GenerateMultibound(file, node, quad, shapeDesc.boundingBox);
     }
 }