private static GrannyModelInfo loadModelInfo(string filename)
        {
            string currentLine = "";
            string numberRegex = "([-+]?[0-9]+\\.?[0-9]*) ";

            StreamReader streamReader = new StreamReader(filename);

            while (!currentLine.StartsWith("skeleton"))
            {
                currentLine = streamReader.ReadLine();
            }

            GrannyModelInfo modelInfo = new GrannyModelInfo();

            GrannySkeletonInfo    skeletonInfo  = new GrannySkeletonInfo();
            List <GrannyBoneInfo> skeletonBones = new List <GrannyBoneInfo>();

            while (!currentLine.StartsWith("meshes"))
            {
                currentLine = streamReader.ReadLine();
                if (!currentLine.StartsWith("meshes"))
                {
                    string regexString = "([0-9]+) \"(.+)\" ";
                    for (int i = 0; i < 24; i++)
                    {
                        regexString = regexString + numberRegex;
                    }

                    Regex           regex = new Regex(regexString.Trim());
                    MatchCollection mc    = regex.Matches(currentLine);
                    foreach (Match m in mc)
                    {
                        GrannyBoneInfo      boneInfo      = new GrannyBoneInfo();
                        GrannyTransformInfo transformInfo = new GrannyTransformInfo();

                        //int boneindex = NumberUtils.parseInt(m.Groups[1].Value.Trim());
                        string boneName    = m.Groups[2].Value;
                        int    parentIndex = NumberUtils.parseInt(m.Groups[3].Value.Trim());

                        float[] position = new float[3];
                        position[0] = NumberUtils.parseFloat(m.Groups[4].Value.Trim());
                        position[1] = NumberUtils.parseFloat(m.Groups[5].Value.Trim());
                        position[2] = NumberUtils.parseFloat(m.Groups[6].Value.Trim());

                        float[] orientation = new float[4];
                        orientation[0] = NumberUtils.parseFloat(m.Groups[7].Value.Trim());
                        orientation[1] = NumberUtils.parseFloat(m.Groups[8].Value.Trim());
                        orientation[2] = NumberUtils.parseFloat(m.Groups[9].Value.Trim());
                        orientation[3] = NumberUtils.parseFloat(m.Groups[10].Value.Trim());

                        float[] scaleShear = new float[9];
                        scaleShear[0] = 1.0f;
                        scaleShear[1] = 0.0f;
                        scaleShear[2] = 0.0f;
                        scaleShear[3] = 0.0f;
                        scaleShear[4] = 1.0f;
                        scaleShear[5] = 0.0f;
                        scaleShear[6] = 0.0f;
                        scaleShear[7] = 0.0f;
                        scaleShear[8] = 1.0f;

                        float[] invWorld = new float[16];

                        for (int j = 0; j < 16; j++)
                        {
                            invWorld[j] = NumberUtils.parseFloat(m.Groups[j + 11].Value.Trim());
                        }


                        bool hasPosition    = true;
                        bool hasOrientation = true;
                        int  flags          = 0;

                        if (NumberUtils.almostEquals(position[0], 0.0f, 4) && NumberUtils.almostEquals(position[1], 0.0f, 4) && NumberUtils.almostEquals(position[2], 0.0f, 4))
                        {
                            hasPosition = false;
                        }

                        if (NumberUtils.almostEquals(orientation[0], 0.0f, 5) && NumberUtils.almostEquals(orientation[1], 0.0f, 5) &&
                            NumberUtils.almostEquals(orientation[2], 0.0f, 5) && NumberUtils.almostEquals(orientation[3], 1.0f, 5))
                        {
                            hasOrientation = false;
                        }

                        if (hasPosition)
                        {
                            flags = flags + 1;
                        }

                        if (hasOrientation)
                        {
                            flags = flags + 2;
                        }

                        transformInfo.flags       = flags;
                        transformInfo.position    = position;
                        transformInfo.orientation = orientation;
                        transformInfo.scaleShear  = scaleShear;

                        boneInfo.name                  = boneName;
                        boneInfo.parentIndex           = parentIndex;
                        boneInfo.localTransform        = transformInfo;
                        boneInfo.inverseWorldTransform = invWorld;
                        boneInfo.LODError              = 0;

                        skeletonBones.Add(boneInfo);
                    }
                }
            }

            skeletonInfo.bones = skeletonBones;

            // Read Meshes
            int numMeshes = NumberUtils.parseInt(currentLine.Replace("meshes:", ""));
            List <GrannyMeshInfo> meshInfos = new List <GrannyMeshInfo>();

            for (int meshId = 0; meshId < numMeshes; meshId++)
            {
                string meshName = "";
                while (!currentLine.StartsWith("mesh:"))
                {
                    currentLine = streamReader.ReadLine();
                }

                string          regexString = "\"(.+)\"";
                Regex           regex       = new Regex(regexString);
                MatchCollection mc          = regex.Matches(currentLine);

                foreach (Match m in mc)
                {
                    meshName = m.Groups[1].Value;
                }

                // Read Vertices
                List <GrannyVertexInfo> vertexInfos = new List <GrannyVertexInfo>();
                while (!currentLine.StartsWith("triangles"))
                {
                    currentLine = streamReader.ReadLine();
                    if (!currentLine.StartsWith("vertices") && !currentLine.StartsWith("triangles"))
                    {
                        int spacesCount = 0;
                        foreach (char c in currentLine)
                        {
                            if (c == ' ')
                            {
                                spacesCount++;
                            }
                        }
                        bool hasBinormalsAndTangents = spacesCount > 15;

                        regexString = "";
                        for (int i = 0; i < 16; i++)
                        {
                            regexString = regexString + numberRegex;
                        }

                        if (hasBinormalsAndTangents)
                        {
                            for (int i = 0; i < 6; i++)
                            {
                                regexString = regexString + numberRegex;
                            }
                        }

                        regex = new Regex(regexString.Trim());
                        mc    = regex.Matches(currentLine);
                        foreach (Match m in mc)
                        {
                            GrannyVertexInfo vertexInfo = new GrannyVertexInfo();

                            float[] position = new float[3];
                            position[0] = NumberUtils.parseFloat(m.Groups[1].Value.Trim());
                            position[1] = NumberUtils.parseFloat(m.Groups[2].Value.Trim());
                            position[2] = NumberUtils.parseFloat(m.Groups[3].Value.Trim());

                            float[] normal = new float[3];
                            normal[0] = NumberUtils.parseFloat(m.Groups[4].Value.Trim());
                            normal[1] = NumberUtils.parseFloat(m.Groups[5].Value.Trim());
                            normal[2] = NumberUtils.parseFloat(m.Groups[6].Value.Trim());

                            float[] uv = new float[2];
                            uv[0] = NumberUtils.parseFloat(m.Groups[7].Value.Trim());
                            uv[1] = NumberUtils.parseFloat(m.Groups[8].Value.Trim());

                            int[] boneIndices = new int[4];
                            boneIndices[0] = NumberUtils.parseInt(m.Groups[9].Value.Trim());
                            boneIndices[1] = NumberUtils.parseInt(m.Groups[10].Value.Trim());
                            boneIndices[2] = NumberUtils.parseInt(m.Groups[11].Value.Trim());
                            boneIndices[3] = NumberUtils.parseInt(m.Groups[12].Value.Trim());

                            int[] boneWeights = new int[4];
                            boneWeights[0] = NumberUtils.parseInt(m.Groups[13].Value.Trim());
                            boneWeights[1] = NumberUtils.parseInt(m.Groups[14].Value.Trim());
                            boneWeights[2] = NumberUtils.parseInt(m.Groups[15].Value.Trim());
                            boneWeights[3] = NumberUtils.parseInt(m.Groups[16].Value.Trim());

                            if (hasBinormalsAndTangents)
                            {
                                float[] tangent = new float[3];
                                tangent[0] = NumberUtils.parseFloat(m.Groups[17].Value.Trim());
                                tangent[1] = NumberUtils.parseFloat(m.Groups[18].Value.Trim());
                                tangent[2] = NumberUtils.parseFloat(m.Groups[19].Value.Trim());

                                float[] binormal = new float[3];
                                binormal[0] = NumberUtils.parseFloat(m.Groups[20].Value.Trim());
                                binormal[1] = NumberUtils.parseFloat(m.Groups[21].Value.Trim());
                                binormal[2] = NumberUtils.parseFloat(m.Groups[22].Value.Trim());

                                vertexInfo.binormal = binormal;
                                vertexInfo.tangent  = tangent;
                            }

                            vertexInfo.position    = position;
                            vertexInfo.normal      = normal;
                            vertexInfo.boneIndices = boneIndices;
                            vertexInfo.boneWeights = boneWeights;
                            vertexInfo.uv          = uv;

                            vertexInfos.Add(vertexInfo);
                        }
                    }
                }

                // Read Triangles
                List <int[]> triangles = new List <int[]>();
                while (!currentLine.StartsWith("mesh") && !currentLine.StartsWith("end"))
                {
                    currentLine = streamReader.ReadLine();
                    if (!currentLine.StartsWith("mesh") && !currentLine.StartsWith("end"))
                    {
                        regexString = "";
                        for (int i = 0; i < 3; i++)
                        {
                            regexString = regexString + "([-+]?[0-9]+\\.?[0-9]*) ";
                        }

                        regex = new Regex(regexString.Trim());
                        mc    = regex.Matches(currentLine);
                        foreach (Match m in mc)
                        {
                            int[] triangle = new int[3];
                            triangle[0] = NumberUtils.parseInt(m.Groups[1].Value.Trim());
                            triangle[1] = NumberUtils.parseInt(m.Groups[2].Value.Trim());
                            triangle[2] = NumberUtils.parseInt(m.Groups[3].Value.Trim());

                            triangles.Add(triangle);
                        }
                    }
                }

                List <PrimaryTopologyGroupInfo> groupInfos = new List <PrimaryTopologyGroupInfo>();
                groupInfos.Add(new PrimaryTopologyGroupInfo(0, 0, triangles.Count));

                GrannyMeshInfo meshInfo = new GrannyMeshInfo();
                meshInfo.name      = meshName;
                meshInfo.vertices  = vertexInfos;
                meshInfo.triangles = triangles;
                meshInfo.primaryTopologyGroupInfos = groupInfos;
                meshInfo.materialBindingNames      = new List <string> {
                    "DefaultMaterialBinding"
                };
                meshInfos.Add(meshInfo);
            }

            modelInfo.skeleton     = skeletonInfo;
            modelInfo.meshBindings = meshInfos;

            streamReader.Close();

            return(modelInfo);
        }
        public static void br2Export(IGrannyFile grannyFile, int currentModelIndex)
        {
            string fileExtension  = ".br2";
            string outputFilename = "";
            string numberFormat   = "f8";

            if (grannyFile.Models.Count > 1)
            {
                outputFilename = grannyFile.Filename.Replace(".fgx", "_model" + currentModelIndex + fileExtension);
                outputFilename = outputFilename.Replace(".FGX", "_model" + currentModelIndex + fileExtension);
            }
            else
            {
                outputFilename = grannyFile.Filename.Replace(".fgx", fileExtension);
                outputFilename = outputFilename.Replace(".FGX", fileExtension);
            }

            StreamWriter outputWriter = new StreamWriter(new FileStream(outputFilename, FileMode.Create));

            IGrannyModel    model    = grannyFile.Models[currentModelIndex];
            IGrannySkeleton skeleton = model.Skeleton;

            // Lookup so we can identify the meshes belonging the current model in the list of file meshes
            Dictionary <int, int> meshBindingToMesh = new Dictionary <int, int>();
            HashSet <string>      distinctMeshNames = new HashSet <string>();

            for (int i = 0; i < model.MeshBindings.Count; i++)
            {
                for (int j = 0; j < grannyFile.Meshes.Count; j++)
                {
                    GrannyMeshWrapper modelMesh = new GrannyMeshWrapper(model.MeshBindings[i]);
                    IGrannyMesh       fileMesh  = grannyFile.Meshes[j];
                    if (modelMesh.meshEqual(fileMesh))
                    {
                        meshBindingToMesh.Add(i, j);
                    }
                }
                distinctMeshNames.Add(model.MeshBindings[i].Name);
            }

            // Used to give meshes distinct names where we have multiple meshes with the same name in our source gr2
            Dictionary <string, int> meshNameCount = new Dictionary <string, int>();

            foreach (string meshName in distinctMeshNames)
            {
                meshNameCount.Add(meshName, 0);
            }

            List <GrannyMeshInfo> grannyMeshInfos = new List <GrannyMeshInfo>();

            for (int i = 0; i < model.MeshBindings.Count; i++)
            {
                GrannyMeshWrapper meshWrapper = new GrannyMeshWrapper(model.MeshBindings[i]);
                grannyMeshInfos.Add(meshWrapper.getMeshInfo());
            }

            BiLookup <int, string> boneLookup = new BiLookup <int, string>();

            for (int i = 0; i < skeleton.Bones.Count; i++)
            {
                boneLookup.Add(i, skeleton.Bones[i].Name);
            }

            Dictionary <string, double[]> boneNameToPositionMap = new Dictionary <string, double[]>();

            foreach (IGrannyBone bone in skeleton.Bones)
            {
                double[] bonePosition = NB2NA2FileOps.getBoneWorldPosition(bone);
                boneNameToPositionMap.Add(bone.Name, bonePosition);

                //MemoryUtil.memLogLine("boneName: " + bone.Name + " bone position:" + bonePosition[0] + " " + bonePosition[1] + " " + bonePosition[2]);
            }

            outputWriter.WriteLine("// Nexus Buddy BR2 - Exported from Nexus Buddy 2");
            outputWriter.WriteLine("skeleton");

            // Write Bones
            //outputWriter.WriteLine("Bones: " + skeleton.Bones.Count);
            for (int boneIndex = 0; boneIndex < skeleton.Bones.Count; boneIndex++)
            {
                IGrannyBone      bone              = skeleton.Bones[boneIndex];
                string           boneName          = bone.Name;
                IGrannyTransform transform         = bone.LocalTransform;
                float[]          orientation       = transform.Orientation;
                float[]          position          = transform.Position;
                float[]          invWorldTransform = bone.InverseWorldTransform;

                StringBuilder boneStringBuilder = new StringBuilder(boneIndex + " \"" + boneName + "\" " + bone.ParentIndex + " " + position[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + position[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + position[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                                                    orientation[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[3].ToString(numberFormat, CultureInfo.InvariantCulture));

                foreach (float j in invWorldTransform)
                {
                    boneStringBuilder.Append(" " + j.ToString(numberFormat, CultureInfo.InvariantCulture));
                }

                outputWriter.WriteLine(boneStringBuilder);
            }

            // Write Meshes
            outputWriter.WriteLine("meshes: " + model.MeshBindings.Count);
            for (int mi = 0; mi < grannyMeshInfos.Count; mi++)
            {
                GrannyMeshInfo grannyMeshInfo = grannyMeshInfos[mi];
                string         meshName       = model.MeshBindings[mi].Name;

                meshNameCount[meshName]++;
                if (meshNameCount[meshName] > 1)
                {
                    meshName += meshNameCount[meshName];
                }
                //StringBuilder boneStringBuilder = new StringBuilder();


                outputWriter.WriteLine("mesh:\"" + meshName + "\"");

                // Write Vertices
                outputWriter.WriteLine("vertices");
                for (int vi = 0; vi < grannyMeshInfo.vertices.Count; vi++)
                {
                    GrannyVertexInfo vertex = grannyMeshInfo.vertices[vi];

                    string boneName0   = grannyMeshInfo.boneBindings[vertex.boneIndices[0]];
                    float  boneWeight0 = (float)vertex.boneWeights[0] / 255;
                    int    boneId0     = NB2NA2FileOps.getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName0, boneWeight0, vertex.position);

                    string boneName1   = grannyMeshInfo.boneBindings[vertex.boneIndices[1]];
                    float  boneWeight1 = (float)vertex.boneWeights[1] / 255;
                    int    boneId1     = NB2NA2FileOps.getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName1, boneWeight1, vertex.position);

                    string boneName2   = grannyMeshInfo.boneBindings[vertex.boneIndices[2]];
                    float  boneWeight2 = (float)vertex.boneWeights[2] / 255;
                    int    boneId2     = NB2NA2FileOps.getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName2, boneWeight2, vertex.position);

                    string boneName3   = grannyMeshInfo.boneBindings[vertex.boneIndices[3]];
                    float  boneWeight3 = (float)vertex.boneWeights[3] / 255;
                    int    boneId3     = NB2NA2FileOps.getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName3, boneWeight3, vertex.position);

                    float[] tangents = new float[3];
                    if (vertex.tangent == null)
                    {
                        tangents[0] = vertex.normal[0];
                        tangents[1] = vertex.normal[1];
                        tangents[2] = vertex.normal[2];
                    }
                    else
                    {
                        tangents[0] = vertex.tangent[0];
                        tangents[1] = vertex.tangent[1];
                        tangents[2] = vertex.tangent[2];
                    }

                    float[] binormals = new float[3];
                    if (vertex.binormal == null)
                    {
                        binormals[0] = vertex.normal[0];
                        binormals[1] = vertex.normal[1];
                        binormals[2] = vertex.normal[2];
                    }
                    else
                    {
                        binormals[0] = vertex.binormal[0];
                        binormals[1] = vertex.binormal[1];
                        binormals[2] = vertex.binormal[2];
                    }

                    outputWriter.WriteLine(vertex.position[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.position[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.position[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                           vertex.normal[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.normal[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.normal[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                           vertex.uv[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.uv[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " "
                                           + boneId0 + " " + boneId1 + " " + boneId2 + " " + boneId3 + " "
                                           + vertex.boneWeights[0] + " " + vertex.boneWeights[1] + " " + vertex.boneWeights[2] + " " + vertex.boneWeights[3] + " "
                                           + tangents[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + tangents[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + tangents[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " "
                                           + binormals[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + binormals[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + binormals[2].ToString(numberFormat, CultureInfo.InvariantCulture)
                                           );
                }

                // Write Triangles
                outputWriter.WriteLine("triangles");
                for (int ti = 0; ti < grannyMeshInfo.triangles.Count; ti++)
                {
                    int[] triangle = grannyMeshInfo.triangles[ti];
                    outputWriter.WriteLine(triangle[0] + " " + triangle[1] + " " + triangle[2]);
                }
            }
            outputWriter.WriteLine("end");

            outputWriter.Close();
        }
Exemple #3
0
        //public int getGroup0TriCount()
        //{
        //    return *(int*)(*(int*)(*(int*)(getPrimaryTopologyPtr()) + 4) + 8);
        //}

        //public void setGroup0TriCount(int num)
        //{
        //    *(int*)(*(int*)(*(int*)(getPrimaryTopologyPtr()) + 4) + 8) = num;
        //}

        public unsafe GrannyMeshInfo getMeshInfo()
        {
            GrannyMeshInfo meshInfo = new GrannyMeshInfo();

            meshInfo.name = Marshal.PtrToStringAnsi((IntPtr)(sbyte *)*(int *)(m_pkMesh));

            List <string> boneBindings = new List <string>();

            for (int i = 0; i < getNumBoneBindings(); i++)
            {
                boneBindings.Add(Marshal.PtrToStringAnsi((IntPtr)(sbyte *)*(int *)(*(int *)(getBoneBindingsPtr()) + i * 44)));
            }
            meshInfo.boneBindings = boneBindings;

            meshInfo.setVertexStructInfos(getVertexStructInfos());

            int    vertexCount = getNumVertices();
            IntPtr vertexPtr   = getVerticesPtr();

            int vertexSize = meshInfo.bytesPerVertex;

            List <GrannyVertexInfo> vertexInfos = new List <GrannyVertexInfo>();

            for (int i = 0; i < vertexCount; i++)
            {
                GrannyVertexInfo currentVertex = new GrannyVertexInfo();

                GrannyMeshVertexStructInfo structInfo = meshInfo.getVertexStructInfoByName("Position");
                if (structInfo != null)
                {
                    currentVertex.position    = new float[3];
                    currentVertex.position[0] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 0));
                    currentVertex.position[1] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 1));
                    currentVertex.position[2] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 2));
                }

                structInfo = meshInfo.getVertexStructInfoByName("BoneWeights");
                if (structInfo != null)
                {
                    currentVertex.boneWeights = new int[structInfo.count];
                    for (int j = 0; j < structInfo.count; j++)
                    {
                        currentVertex.boneWeights[j] = (byte)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * j));
                    }
                }
                else
                {
                    int structInfoCount = 8;
                    currentVertex.boneWeights    = new int[structInfoCount];
                    currentVertex.boneWeights[0] = 255;
                    for (int j = 1; j < structInfoCount; j++)
                    {
                        currentVertex.boneWeights[j] = 0;
                    }
                }

                structInfo = meshInfo.getVertexStructInfoByName("BoneIndices");
                if (structInfo != null)
                {
                    currentVertex.boneIndices = new int[structInfo.count];
                    for (int j = 0; j < structInfo.count; j++)
                    {
                        currentVertex.boneIndices[j] = (byte)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * j));
                    }
                }
                else
                {
                    int structInfoCount = 8;
                    currentVertex.boneIndices = new int[structInfoCount];
                    for (int j = 0; j < structInfoCount; j++)
                    {
                        currentVertex.boneIndices[j] = 0;
                    }
                }

                structInfo = meshInfo.getVertexStructInfoByName("Normal");
                if (structInfo != null)
                {
                    currentVertex.normal    = new float[3];
                    currentVertex.normal[0] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 0));
                    currentVertex.normal[1] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 1));
                    currentVertex.normal[2] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 2));
                }

                structInfo = meshInfo.getVertexStructInfoByName("Binormal");
                if (structInfo != null)
                {
                    currentVertex.binormal    = new float[3];
                    currentVertex.binormal[0] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 0));
                    currentVertex.binormal[1] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 1));
                    currentVertex.binormal[2] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 2));
                }

                structInfo = meshInfo.getVertexStructInfoByName("Tangent");
                if (structInfo != null)
                {
                    currentVertex.tangent    = new float[3];
                    currentVertex.tangent[0] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 0));
                    currentVertex.tangent[1] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 1));
                    currentVertex.tangent[2] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 2));
                }

                structInfo       = meshInfo.getVertexStructInfoByName("TextureCoordinates0");
                currentVertex.uv = new float[2];
                if (structInfo != null)
                {
                    currentVertex.uv[0] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 0));
                    currentVertex.uv[1] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 1));
                }

                structInfo        = meshInfo.getVertexStructInfoByName("TextureCoordinates1");
                currentVertex.uv2 = new float[2];
                if (structInfo != null)
                {
                    currentVertex.uv2[0] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 0));
                    currentVertex.uv2[1] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 1));
                }
                else
                {
                    currentVertex.uv2[0] = 0f;
                    currentVertex.uv2[1] = 0f;
                }

                structInfo        = meshInfo.getVertexStructInfoByName("TextureCoordinates2");
                currentVertex.uv3 = new float[2];
                if (structInfo != null)
                {
                    currentVertex.uv3[0] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 0));
                    currentVertex.uv3[1] = (float)structInfo.convert(*(int *)(vertexPtr) + (i * vertexSize) + structInfo.offset + (structInfo.length * 1));
                }
                else
                {
                    currentVertex.uv3[0] = 0f;
                    currentVertex.uv3[1] = 0f;
                }

                vertexInfos.Add(currentVertex);
            }

            meshInfo.vertices = vertexInfos;

            if (*(int *)(getMaterialBindingsPtr()) != 0)
            {
                string materialName = Marshal.PtrToStringAnsi((IntPtr)(sbyte *)*(int *)*(int *)*(int *)(getMaterialBindingsPtr()));
                meshInfo.materialName = materialName;
            }

            int numTriangleGroups = *(int *)*(int *)getPrimaryTopologyPtr();
            List <PrimaryTopologyGroupInfo> primaryTopologyGroupInfos = new List <PrimaryTopologyGroupInfo>();

            for (int i = 0; i < numTriangleGroups; i++)
            {
                PrimaryTopologyGroupInfo primaryTopologyGroupInfo = new PrimaryTopologyGroupInfo();
                primaryTopologyGroupInfo.groupMaterialIndex = *(int *)(*(int *)(*(int *)(getPrimaryTopologyPtr()) + 4) + i * 12 + 0);
                primaryTopologyGroupInfo.groupTriFirst      = *(int *)(*(int *)(*(int *)(getPrimaryTopologyPtr()) + 4) + i * 12 + 4);
                primaryTopologyGroupInfo.groupTriCount      = *(int *)(*(int *)(*(int *)(getPrimaryTopologyPtr()) + 4) + i * 12 + 8);
                primaryTopologyGroupInfos.Add(primaryTopologyGroupInfo);
            }

            meshInfo.primaryTopologyGroupInfos = primaryTopologyGroupInfos;

            int numIndices16 = getNumIndices16();
            int numIndices   = getNumIndices();

            List <int> indices = new List <int>();

            if (numIndices16 > 0)
            {
                for (int i = 0; i < numIndices16; i++)
                {
                    indices.Add((int)*(ushort *)(*(int *)(*(int *)(getPrimaryTopologyPtr()) + 28) + i * 2));
                }
            }
            else if (numIndices > 0)
            {
                for (int i = 0; i < numIndices; i++)
                {
                    indices.Add(*(int *)(*(int *)(*(int *)(getPrimaryTopologyPtr()) + 16) + i * 4));
                }
            }

            if (indices.Count > 0)
            {
                List <int[]> triangles = new List <int[]>();
                foreach (PrimaryTopologyGroupInfo info in primaryTopologyGroupInfos)
                {
                    for (int iTriangle = info.groupTriFirst; iTriangle < info.groupTriFirst + info.groupTriCount; iTriangle++)
                    {
                        int index0 = iTriangle * 3;
                        int index1 = index0 + 1;
                        int index2 = index0 + 2;

                        int[] triangle = new int[4];
                        triangle[0] = indices[index0];
                        triangle[1] = indices[index1];
                        triangle[2] = indices[index2];
                        triangle[3] = info.groupMaterialIndex;

                        triangles.Add(triangle);
                    }
                }
                meshInfo.triangles = triangles;
            }

            return(meshInfo);
        }
Exemple #4
0
        unsafe private void writeVertices(GrannyMeshInfo meshInfo)
        {
            int vertexCount = meshInfo.vertices.Count;

            setNumVertices(vertexCount);

            int vertexSize = meshInfo.bytesPerVertex;

            int oldVerticesPtr = *(int *)getVerticesPtr();

            *(int *)(getVerticesPtr()) = (int)Marshal.AllocHGlobal(vertexCount * vertexSize);
            int newVerticesPtr = *(int *)getVerticesPtr();

            List <GrannyVertexInfo> vertexInfos = meshInfo.vertices;

            for (int i = 0; i < vertexCount; i++)
            {
                MemoryUtil.MemCpy((void *)(newVerticesPtr + i * vertexSize), (void *)oldVerticesPtr, (uint)vertexSize);

                GrannyVertexInfo currentVertex = vertexInfos[i];

                GrannyMeshVertexStructInfo structInfo = meshInfo.getVertexStructInfoByName("Position");
                if (structInfo != null)
                {
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.position[0];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.position[1];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = currentVertex.position[2];
                }

                structInfo = meshInfo.getVertexStructInfoByName("BoneWeights");
                if (structInfo != null)
                {
                    for (int j = 0; j < structInfo.count; j++)
                    {
                        if (j < currentVertex.boneWeights.Length)
                        {
                            *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * j)) = (byte)currentVertex.boneWeights[j];
                        }
                        else
                        {
                            *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * j)) = (byte)0;
                        }
                    }
                }

                structInfo = meshInfo.getVertexStructInfoByName("BoneIndices");
                if (structInfo != null)
                {
                    for (int j = 0; j < structInfo.count; j++)
                    {
                        if (j < currentVertex.boneIndices.Length)
                        {
                            *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * j)) = (byte)currentVertex.boneIndices[j];
                        }
                        else
                        {
                            *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * j)) = (byte)0;
                        }
                    }
                }

                structInfo = meshInfo.getVertexStructInfoByName("Normal");
                if (structInfo != null)
                {
                    // granny_real32
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.normal[0];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.normal[1];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = currentVertex.normal[2];
                }

                structInfo = meshInfo.getVertexStructInfoByName("Tangent");
                if (structInfo != null && currentVertex.tangent != null)
                {
                    // granny_real32
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.tangent[0];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.tangent[1];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = currentVertex.tangent[2];
                }

                structInfo = meshInfo.getVertexStructInfoByName("Binormal");
                if (structInfo != null && currentVertex.binormal != null)
                {
                    // granny_real32
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.binormal[0];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.binormal[1];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = currentVertex.binormal[2];
                }

                structInfo = meshInfo.getVertexStructInfoByName("TextureCoordinates0");
                if (structInfo != null)
                {
                    // granny_real32
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.uv[0];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.uv[1];
                }

                structInfo = meshInfo.getVertexStructInfoByName("TextureCoordinates1");
                if (structInfo != null)
                {
                    // granny_real32
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.uv2[0];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.uv2[1];
                }

                structInfo = meshInfo.getVertexStructInfoByName("TextureCoordinates2");
                if (structInfo != null)
                {
                    // granny_real32
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.uv3[0];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.uv3[1];
                }
            }
        }
Exemple #5
0
        unsafe private void writeVertices(GrannyMeshInfo meshInfo, bool isLeaderFormat, bool isSceneFormat)
        {
            int vertexCount = meshInfo.vertices.Count;

            setNumVertices(vertexCount);

            int vertexSize = meshInfo.bytesPerVertex;

            int oldVerticesPtr = *(int *)getVerticesPtr();

            *(int *)(getVerticesPtr()) = (int)Marshal.AllocHGlobal(vertexCount * vertexSize);
            int newVerticesPtr = *(int *)getVerticesPtr();

            List <GrannyVertexInfo> vertexInfos = meshInfo.vertices;

            for (int i = 0; i < vertexCount; i++)
            {
                MemoryUtil.MemCpy((void *)(newVerticesPtr + i * vertexSize), (void *)oldVerticesPtr, (uint)vertexSize);

                GrannyVertexInfo currentVertex = vertexInfos[i];

                GrannyMeshVertexStructInfo structInfo = meshInfo.getVertexStructInfoByName("Position");
                if (structInfo != null)
                {
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.position[0];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.position[1];
                    *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = currentVertex.position[2];
                }

                if (!isSceneFormat)
                {
                    structInfo = meshInfo.getVertexStructInfoByName("BoneWeights");
                    if (structInfo != null)
                    {
                        *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = (byte)currentVertex.boneWeights[0];
                        *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = (byte)currentVertex.boneWeights[1];
                        *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = (byte)currentVertex.boneWeights[2];
                        *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 3)) = (byte)currentVertex.boneWeights[3];
                    }

                    structInfo = meshInfo.getVertexStructInfoByName("BoneIndices");
                    if (structInfo != null)
                    {
                        *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = (byte)currentVertex.boneIndices[0];
                        *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = (byte)currentVertex.boneIndices[1];
                        *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = (byte)currentVertex.boneIndices[2];
                        *(byte *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 3)) = (byte)currentVertex.boneIndices[3];
                    }
                }

                if (isLeaderFormat || isSceneFormat)
                {
                    structInfo = meshInfo.getVertexStructInfoByName("Normal");
                    if (structInfo != null)
                    {
                        // granny_real16
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = NumberUtils.floatToHalf(currentVertex.normal[0]);
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = NumberUtils.floatToHalf(currentVertex.normal[1]);
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = NumberUtils.floatToHalf(currentVertex.normal[2]);
                    }

                    structInfo = meshInfo.getVertexStructInfoByName("Binormal");
                    if (structInfo != null && currentVertex.binormal != null)
                    {
                        // granny_real16
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = NumberUtils.floatToHalf(currentVertex.binormal[0]);
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = NumberUtils.floatToHalf(currentVertex.binormal[1]);
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = NumberUtils.floatToHalf(currentVertex.binormal[2]);
                    }

                    structInfo = meshInfo.getVertexStructInfoByName("Tangent");
                    if (structInfo != null && currentVertex.tangent != null)
                    {
                        // granny_real16
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = NumberUtils.floatToHalf(currentVertex.tangent[0]);
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = NumberUtils.floatToHalf(currentVertex.tangent[1]);
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = NumberUtils.floatToHalf(currentVertex.tangent[2]);
                    }
                }
                else
                {
                    structInfo = meshInfo.getVertexStructInfoByName("Normal");
                    if (structInfo != null)
                    {
                        // granny_real32
                        *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.normal[0];
                        *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.normal[1];
                        *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 2)) = currentVertex.normal[2];
                    }
                }

                if (isLeaderFormat || isSceneFormat)
                {
                    structInfo = meshInfo.getVertexStructInfoByName("TextureCoordinates0");
                    if (structInfo != null)
                    {
                        // granny_real16
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = NumberUtils.floatToHalf(currentVertex.uv[0]);
                        *(ushort *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = NumberUtils.floatToHalf(currentVertex.uv[1]);
                    }
                }
                else
                {
                    structInfo = meshInfo.getVertexStructInfoByName("TextureCoordinates0");
                    if (structInfo != null)
                    {
                        // granny_real32
                        *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 0)) = currentVertex.uv[0];
                        *(float *)(newVerticesPtr + (i * vertexSize) + structInfo.offset + (structInfo.length * 1)) = currentVertex.uv[1];
                    }
                }
            }
        }
Exemple #6
0
        private static WriteModelToCN6Response WriteModelToCN6(IGrannyFile grannyFile, bool isBatch, IGrannyModel model, string filterMeshName)
        {
            List <string> textureMaps = new List <string>();

            string        fileExtension  = ".cn6";
            string        outputFilename = "";
            string        numberFormat   = "f8";
            List <string> decalMeshNames = new List <string>();

            IGrannySkeleton skeleton = model.Skeleton;

            string decalMeshName = "";

            if (filterMeshName != null)
            {
                decalMeshName = "_DCL_" + GetSafeFilename(filterMeshName);
            }

            if (grannyFile.Models.Count > 1)
            {
                string modelFilename = "__" + model.Name + decalMeshName + fileExtension;
                outputFilename = grannyFile.Filename.Replace(".gr2", modelFilename);
                outputFilename = outputFilename.Replace(".GR2", modelFilename);
            }
            else
            {
                outputFilename = grannyFile.Filename.Replace(".gr2", fileExtension);
                outputFilename = outputFilename.Replace(".GR2", fileExtension);
            }

            if (isBatch)
            {
                outputFilename = outputFilename.Replace(fileExtension, "_batch" + fileExtension);
            }

            string directory = Path.GetDirectoryName(outputFilename);
            string filename  = Path.GetFileName(outputFilename);

            outputFilename = directory + "\\" + GetSafeFilename(filename);

            StreamWriter outputWriter = new StreamWriter(new FileStream(outputFilename, FileMode.Create));

            // Lookup so we can identify the meshes belonging the current model in the list of file meshes
            Dictionary <int, int> meshBindingToMesh = new Dictionary <int, int>();
            HashSet <string>      distinctMeshNames = new HashSet <string>();

            for (int i = 0; i < model.MeshBindings.Count; i++)
            {
                for (int j = 0; j < grannyFile.Meshes.Count; j++)
                {
                    GrannyMeshWrapper modelMesh = new GrannyMeshWrapper(model.MeshBindings[i]);
                    IGrannyMesh       fileMesh  = grannyFile.Meshes[j];
                    if (modelMesh.meshEqual(fileMesh))
                    {
                        meshBindingToMesh.Add(i, j);
                    }
                }
                distinctMeshNames.Add(model.MeshBindings[i].Name);
            }

            // Used to give meshes distinct names where we have multiple meshes with the same name in our source gr2
            Dictionary <string, int> meshNameCount = new Dictionary <string, int>();

            foreach (string meshName in distinctMeshNames)
            {
                meshNameCount.Add(meshName, 0);
            }

            List <GrannyMeshInfo> grannyMeshInfos = new List <GrannyMeshInfo>();

            for (int i = 0; i < model.MeshBindings.Count; i++)
            {
                GrannyMeshWrapper meshWrapper = new GrannyMeshWrapper(model.MeshBindings[i]);
                grannyMeshInfos.Add(meshWrapper.getMeshInfo());
            }

            BiLookup <int, string> boneLookup = new BiLookup <int, string>();

            for (int i = 0; i < skeleton.Bones.Count; i++)
            {
                boneLookup.Add(i, skeleton.Bones[i].Name);
            }

            Dictionary <string, double[]> boneNameToPositionMap = new Dictionary <string, double[]>();

            foreach (IGrannyBone bone in skeleton.Bones)
            {
                if (!boneNameToPositionMap.ContainsKey(bone.Name))
                {
                    double[] bonePosition = NB2Exporter.getBoneWorldPosition(bone);
                    boneNameToPositionMap.Add(bone.Name, bonePosition);
                }
            }

            string headerLine = "// CivNexus6 CN6 - Exported from Nexus Buddy " + NexusBuddyApplicationForm.getVersionString();

            outputWriter.WriteLine(headerLine);
            outputWriter.WriteLine("skeleton");

            // Write Bones
            for (int boneIndex = 0; boneIndex < skeleton.Bones.Count; boneIndex++)
            {
                IGrannyBone      bone              = skeleton.Bones[boneIndex];
                string           boneName          = bone.Name;
                IGrannyTransform transform         = bone.LocalTransform;
                float[]          orientation       = transform.Orientation;
                float[]          position          = transform.Position;
                float[]          invWorldTransform = bone.InverseWorldTransform;

                StringBuilder boneStringBuilder = new StringBuilder(boneIndex + " \"" + boneName + "\" " + bone.ParentIndex + " " + position[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + position[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + position[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                                                    orientation[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[3].ToString(numberFormat, CultureInfo.InvariantCulture));

                foreach (float j in invWorldTransform)
                {
                    boneStringBuilder.Append(" " + j.ToString(numberFormat, CultureInfo.InvariantCulture));
                }

                outputWriter.WriteLine(boneStringBuilder);
            }


            List <IndieMaterial> modelMaterials = new List <IndieMaterial>();

            foreach (IGrannyMesh mesh in model.MeshBindings)
            {
                IGrannyMaterial material = mesh.MaterialBindings[0];
                foreach (ListViewItem materialListItem in NexusBuddyApplicationForm.form.materialList.Items)
                {
                    IndieMaterial         shader   = (IndieMaterial)materialListItem.Tag;
                    GrannyMaterialWrapper matWrap1 = new GrannyMaterialWrapper(shader.GetMaterial());
                    GrannyMaterialWrapper matWrap2 = new GrannyMaterialWrapper(material);
                    if (matWrap1.getName().Equals(matWrap2.getName()) && !modelMaterials.Contains(shader))
                    {
                        modelMaterials.Add(shader);
                    }
                }
            }

            int meshCount = 0;

            for (int mi = 0; mi < grannyMeshInfos.Count; mi++)
            {
                IGrannyMesh       mesh        = model.MeshBindings[mi];
                string            meshName    = model.MeshBindings[mi].Name;
                GrannyMeshWrapper meshWrapper = new GrannyMeshWrapper(mesh);
                GrannyMeshInfo    meshInfo    = meshWrapper.getMeshInfo();

                bool isFlatMesh = true;
                foreach (GrannyVertexInfo vertexInfo in meshInfo.vertices)
                {
                    float zPos   = vertexInfo.position[2];
                    bool  isZero = NumberUtils.almostEquals(zPos, 0.0f, 4);
                    if (!isZero)
                    {
                        isFlatMesh = false;
                        break;
                    }
                }

                if (filterMeshName == null)
                {
                    if (isFlatMesh)
                    {
                        decalMeshNames.Add(meshName);
                    }
                    else
                    {
                        meshCount++;
                    }
                }
                else
                {
                    meshCount = 1;
                }
            }

            if (meshCount == 0)
            {
                outputWriter.Close();
                File.Delete(outputFilename);
                return(new WriteModelToCN6Response(decalMeshNames, textureMaps));
            }

            // Write Meshes
            outputWriter.WriteLine("meshes:" + meshCount);

            for (int mi = 0; mi < grannyMeshInfos.Count; mi++)
            {
                GrannyMeshInfo grannyMeshInfo = grannyMeshInfos[mi];
                string         meshName       = model.MeshBindings[mi].Name;

                if ((filterMeshName == null && !decalMeshNames.Contains(meshName)) || meshName.Equals(filterMeshName))
                {
                    meshNameCount[meshName]++;
                    if (meshNameCount[meshName] > 1)
                    {
                        meshName += meshNameCount[meshName];
                    }

                    outputWriter.WriteLine("mesh:\"" + meshName + "\"");

                    // Write Materials
                    outputWriter.WriteLine("materials");
                    foreach (IGrannyMaterial material in model.MeshBindings[mi].MaterialBindings)
                    {
                        IndieMaterial shader = NexusBuddyApplicationForm.GetIndieMaterialFromMaterial(material);

                        string baseMap;

                        if (shader.GetType() == typeof(IndieLeaderGlassShader))
                        {
                            baseMap = "Leader_cornea";
                        }
                        else if (shader.GetType() == typeof(IndieBuildingShader))
                        {
                            baseMap = shader.Diffuse;
                        }
                        else if (shader.GetType().Name.StartsWith("IndieLeaderFur"))
                        {
                            baseMap = shader.Fur_BaseMap;
                        }
                        else if (shader.GetType().Name.StartsWith("IndieLeader"))
                        {
                            baseMap = shader.DiffuseMap;
                        }
                        else if (shader.GetType() == typeof(IndieLandmarkStencilShader))
                        {
                            baseMap = shader.BaseTextureMap;
                        }
                        else
                        {
                            baseMap = shader.BaseTextureMap;
                        }

                        if (!String.IsNullOrEmpty(baseMap))
                        {
                            outputWriter.WriteLine("\"" + baseMap + "\"");
                            textureMaps.Add(baseMap);
                        }
                        else
                        {
                            outputWriter.WriteLine("\"" + material.Name + "\"");
                        }
                    }

                    // Write Vertices
                    outputWriter.WriteLine("vertices");
                    for (int vi = 0; vi < grannyMeshInfo.vertices.Count; vi++)
                    {
                        GrannyVertexInfo vertex = grannyMeshInfo.vertices[vi];

                        string[] boneNames   = new string[8];
                        float[]  boneWeights = new float[8];
                        int[]    boneIds     = new int[8];

                        for (int z = 0; z < 8; z++)
                        {
                            if (z > 3)
                            {
                                //boneNames[z] = grannyMeshInfo.boneBindings[vertex.boneIndices[z]];
                                boneWeights[z] = 0f;
                                boneIds[z]     = 0;
                            }
                            else
                            {
                                boneNames[z]   = grannyMeshInfo.boneBindings[vertex.boneIndices[z]];
                                boneWeights[z] = (float)vertex.boneWeights[z] / 255;
                                boneIds[z]     = NB2Exporter.getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneNames[z], boneWeights[z], vertex.position);
                            }
                        }

                        float[] tangents = new float[3];
                        if (vertex.tangent == null)
                        {
                            tangents[0] = vertex.normal[0];
                            tangents[1] = vertex.normal[1];
                            tangents[2] = vertex.normal[2];
                        }
                        else
                        {
                            tangents[0] = vertex.tangent[0];
                            tangents[1] = vertex.tangent[1];
                            tangents[2] = vertex.tangent[2];
                        }

                        float[] binormals = new float[3];
                        if (vertex.binormal == null)
                        {
                            binormals[0] = vertex.normal[0];
                            binormals[1] = vertex.normal[1];
                            binormals[2] = vertex.normal[2];
                        }
                        else
                        {
                            binormals[0] = vertex.binormal[0];
                            binormals[1] = vertex.binormal[1];
                            binormals[2] = vertex.binormal[2];
                        }

                        outputWriter.WriteLine(vertex.position[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.position[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.position[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                               vertex.normal[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.normal[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.normal[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                               tangents[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + tangents[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + tangents[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                               binormals[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + binormals[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + binormals[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                               vertex.uv[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.uv[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                               0.00000000f.ToString(numberFormat, CultureInfo.InvariantCulture) + " " + 0.00000000f.ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                               0.00000000f.ToString(numberFormat, CultureInfo.InvariantCulture) + " " + 0.00000000f.ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                               boneIds[0] + " " + boneIds[1] + " " + boneIds[2] + " " + boneIds[3] + " 0 0 0 0 " +
                                               vertex.boneWeights[0] + " " + vertex.boneWeights[1] + " " + vertex.boneWeights[2] + " " + vertex.boneWeights[3] + " 0 0 0 0 "
                                               );
                    }

                    // Write Triangles
                    outputWriter.WriteLine("triangles");
                    for (int ti = 0; ti < grannyMeshInfo.triangles.Count; ti++)
                    {
                        int[] triangle = grannyMeshInfo.triangles[ti];
                        outputWriter.WriteLine(triangle[0] + " " + triangle[1] + " " + triangle[2] + " 0");
                    }
                }
            }

            outputWriter.WriteLine("end");

            outputWriter.Close();

            WriteModelToCN6Response response = new WriteModelToCN6Response(decalMeshNames, textureMaps);

            return(response);
        }
        public static void exportNB2Model(IGrannyFile grannyFile, int modelId)
        {
            string fileExtension  = ".nb2";
            string outputFilename = "";
            string numberFormat   = "f6";

            if (grannyFile.Models.Count > 1)
            {
                string modelFilename = "__" + grannyFile.Models[modelId].Name + fileExtension;
                outputFilename = grannyFile.Filename.Replace(".gr2", modelFilename);
                outputFilename = outputFilename.Replace(".GR2", modelFilename);
            }
            else
            {
                outputFilename = grannyFile.Filename.Replace(".gr2", fileExtension);
                outputFilename = outputFilename.Replace(".GR2", fileExtension);
            }

            StreamWriter outputWriter = new StreamWriter(new FileStream(outputFilename.ToLower(), FileMode.Create));

            IGrannyModel    model    = grannyFile.Models[modelId];
            IGrannySkeleton skeleton = model.Skeleton;

            // Lookup so we can identify the meshes belonging the current model in the list of file meshes
            Dictionary <int, int> meshBindingToMesh = new Dictionary <int, int>();
            HashSet <string>      distinctMeshNames = new HashSet <string>();

            for (int i = 0; i < model.MeshBindings.Count; i++)
            {
                for (int j = 0; j < grannyFile.Meshes.Count; j++)
                {
                    GrannyMeshWrapper modelMesh = new GrannyMeshWrapper(model.MeshBindings[i]);
                    IGrannyMesh       fileMesh  = grannyFile.Meshes[j];
                    if (modelMesh.meshEqual(fileMesh))
                    {
                        meshBindingToMesh.Add(i, j);
                    }
                }
                distinctMeshNames.Add(model.MeshBindings[i].Name);
            }

            // Used to give meshes distinct names where we have multiple meshes with the same name in our source gr2
            Dictionary <string, int> meshNameCount = new Dictionary <string, int>();

            foreach (string meshName in distinctMeshNames)
            {
                meshNameCount.Add(meshName, 0);
            }

            List <GrannyMeshInfo> grannyMeshInfos = new List <GrannyMeshInfo>();

            for (int i = 0; i < model.MeshBindings.Count; i++)
            {
                GrannyMeshWrapper meshWrapper = new GrannyMeshWrapper(model.MeshBindings[i]);
                grannyMeshInfos.Add(meshWrapper.getMeshInfo());
            }

            BiLookup <int, string> boneLookup = new BiLookup <int, string>();

            for (int i = 0; i < skeleton.Bones.Count; i++)
            {
                boneLookup.Add(i, skeleton.Bones[i].Name);
            }

            Dictionary <string, double[]> boneNameToPositionMap = new Dictionary <string, double[]>();

            double[] bonePosition;
            foreach (IGrannyBone bone in skeleton.Bones)
            {
                try {
                    bonePosition = getBoneWorldPosition(bone);
                    boneNameToPositionMap.Add(bone.Name, bonePosition);
                } catch (ArgumentException)
                {
                }
            }

            outputWriter.WriteLine("// Nexus Buddy NB2 - Exported from Nexus Buddy 2");
            outputWriter.WriteLine("Frames: 30");
            outputWriter.WriteLine("Frame: 1");

            List <IndieMaterial> modelMaterials = new List <IndieMaterial>();

            foreach (IGrannyMesh mesh in model.MeshBindings)
            {
                IGrannyMaterial material = mesh.MaterialBindings[0];
                foreach (ListViewItem materialListItem in NexusBuddyApplicationForm.form.materialList.Items)
                {
                    IndieMaterial         shader   = (IndieMaterial)materialListItem.Tag;
                    GrannyMaterialWrapper matWrap1 = new GrannyMaterialWrapper(shader.GetMaterial());
                    GrannyMaterialWrapper matWrap2 = new GrannyMaterialWrapper(material);
                    if (matWrap1.getName().Equals(matWrap2.getName()) && !modelMaterials.Contains(shader))
                    {
                        modelMaterials.Add(shader);
                    }
                }
            }

            // Write Meshes
            outputWriter.WriteLine("Meshes: " + model.MeshBindings.Count);
            for (int mi = 0; mi < grannyMeshInfos.Count; mi++)
            {
                GrannyMeshInfo grannyMeshInfo = grannyMeshInfos[mi];
                string         meshName       = model.MeshBindings[mi].Name;

                meshNameCount[meshName]++;
                if (meshNameCount[meshName] > 1)
                {
                    meshName += meshNameCount[meshName];
                }

                var materialBindingName = model.MeshBindings[mi].MaterialBindings[0].Name;
                var materialIndex       = 0;
                foreach (IndieMaterial material in modelMaterials)
                {
                    if (materialBindingName.Equals(material.GetMaterial().Name))
                    {
                        break;
                    }
                    materialIndex++;
                }

                outputWriter.WriteLine("\"" + meshName + "\" 0 " + materialIndex);

                // Write Vertices
                outputWriter.WriteLine(grannyMeshInfo.vertices.Count);
                for (int vi = 0; vi < grannyMeshInfo.vertices.Count; vi++)
                {
                    GrannyVertexInfo vertex = grannyMeshInfo.vertices[vi];

                    string boneName0   = grannyMeshInfo.boneBindings[vertex.boneIndices[0]];
                    float  boneWeight0 = (float)vertex.boneWeights[0] / 255;
                    int    boneId0     = getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName0, boneWeight0, vertex.position);

                    string boneName1   = grannyMeshInfo.boneBindings[vertex.boneIndices[1]];
                    float  boneWeight1 = (float)vertex.boneWeights[1] / 255;
                    int    boneId1     = getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName1, boneWeight1, vertex.position);

                    string boneName2   = grannyMeshInfo.boneBindings[vertex.boneIndices[2]];
                    float  boneWeight2 = (float)vertex.boneWeights[2] / 255;
                    int    boneId2     = getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName2, boneWeight2, vertex.position);

                    string boneName3   = grannyMeshInfo.boneBindings[vertex.boneIndices[3]];
                    float  boneWeight3 = (float)vertex.boneWeights[3] / 255;
                    int    boneId3     = getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName3, boneWeight3, vertex.position);


                    outputWriter.WriteLine("0 " + vertex.position[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.position[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.position[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                           vertex.uv[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.uv[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " "
                                           + boneId0 + " " + boneWeight0.ToString(numberFormat, CultureInfo.InvariantCulture) + " " + boneId1 + " " + boneWeight1.ToString(numberFormat, CultureInfo.InvariantCulture) + " "
                                           + boneId2 + " " + boneWeight2.ToString(numberFormat, CultureInfo.InvariantCulture) + " " + boneId3 + " " + boneWeight3.ToString(numberFormat, CultureInfo.InvariantCulture)
                                           );
                }

                // Write Normals
                outputWriter.WriteLine(grannyMeshInfo.vertices.Count);
                for (int ni = 0; ni < grannyMeshInfo.vertices.Count; ni++)
                {
                    GrannyVertexInfo vertex = grannyMeshInfo.vertices[ni];

                    outputWriter.WriteLine(vertex.normal[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.normal[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.normal[2].ToString(numberFormat, CultureInfo.InvariantCulture));
                }

                // Write Triangles
                outputWriter.WriteLine(grannyMeshInfo.triangles.Count);
                for (int ti = 0; ti < grannyMeshInfo.triangles.Count; ti++)
                {
                    int[] triangle = grannyMeshInfo.triangles[ti];
                    outputWriter.WriteLine("0 " + triangle[0] + " " + triangle[1] + " " + triangle[2] + " " + triangle[0] + " " + triangle[1] + " " + triangle[2] + " 1");
                }
            }

            // Write Materials
            outputWriter.WriteLine("Materials: " + modelMaterials.Count);
            for (int i = 0; i < modelMaterials.Count; i++)
            {
                outputWriter.WriteLine("\"" + modelMaterials[i].GetMaterial().Name + "\"");
                outputWriter.WriteLine("0.200000 0.200000 0.200000 1.000000");
                outputWriter.WriteLine("0.800000 0.800000 0.800000 1.000000");
                outputWriter.WriteLine("0.000000 0.000000 0.000000 1.000000");
                outputWriter.WriteLine("0.000000 0.000000 0.000000 1.000000");
                outputWriter.WriteLine("0.000000");
                outputWriter.WriteLine("1.000000");
                string        map1 = "ColorMap_" + i;
                string        map2 = "AlphaMap_" + i;
                string        baseMap;
                string        srefmap;
                IndieMaterial shader = modelMaterials[i];
                if (shader.GetType() == typeof(IndieBuildingShader))
                {
                    baseMap = shader.Diffuse;
                    srefmap = shader.BuildingSREF;
                }
                else if (shader.GetType() == typeof(IndieLandmarkStencilShader))
                {
                    baseMap = shader.BaseTextureMap;
                    srefmap = shader.SpecTextureMap;
                }
                else
                {
                    baseMap = shader.BaseTextureMap;
                    srefmap = shader.SREFMap;
                }

                if (!String.IsNullOrEmpty(baseMap))
                {
                    map1 = baseMap;
                }

                if (!String.IsNullOrEmpty(srefmap))
                {
                    map2 = srefmap;
                }
                outputWriter.WriteLine("\"" + map1 + "\"");
                outputWriter.WriteLine("\"" + map2 + "\"");
            }

            // Write Bones
            outputWriter.WriteLine("Bones: " + skeleton.Bones.Count);
            for (int bi = 0; bi < skeleton.Bones.Count; bi++)
            {
                IGrannyBone bone     = skeleton.Bones[bi];
                string      boneName = bone.Name;
                outputWriter.WriteLine("\"" + boneName + "\"");

                if (bone.ParentIndex == -1)
                {
                    outputWriter.WriteLine("\"\"");
                }
                else
                {
                    string parentBoneName = skeleton.Bones[bone.ParentIndex].Name;
                    outputWriter.WriteLine("\"" + parentBoneName + "\"");
                }

                IGrannyTransform transform   = bone.LocalTransform;
                float[]          orientation = transform.Orientation;
                float[]          position    = transform.Position;

                //Matrix3D boneWorldMatrix = getBoneWorldMatrix(bone);

                //ETransformFlags transformFlags = transform.Flags;
                //bool hasPosition = transformFlags.HasFlag(ETransformFlags.GrannyHasPosition);
                //bool hasOrientation = transformFlags.HasFlag(ETransformFlags.GrannyHasOrientation);

                // bone: flags, posx, posy, posz, quatx, quaty, quatz, quatw

                outputWriter.WriteLine("0 " + position[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + position[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + position[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                       orientation[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[3].ToString(numberFormat, CultureInfo.InvariantCulture));

                // number of position keys
                outputWriter.WriteLine("0");
                // number of rotation keys
                outputWriter.WriteLine("0");
            }

            outputWriter.Close();
        }
Exemple #8
0
        private static List <GrannyModelInfo> loadModelInfos(string filename, int vertexFormat)
        {
            string currentLine = "";
            string numberRegex = "([-+]?[0-9]+\\.?[0-9]*) ";

            StreamReader streamReader = new StreamReader(filename);

            bool endOfFile = false;

            List <GrannyModelInfo> modelInfos = new List <GrannyModelInfo>();


            while (!endOfFile)
            {
                while (!currentLine.StartsWith("skeleton"))
                {
                    if (currentLine.Equals("end"))
                    {
                        endOfFile = true;
                        break;
                    }
                    currentLine = streamReader.ReadLine();
                }

                if (endOfFile)
                {
                    break;
                }

                GrannyModelInfo modelInfo = new GrannyModelInfo();

                GrannySkeletonInfo    skeletonInfo  = new GrannySkeletonInfo();
                List <GrannyBoneInfo> skeletonBones = new List <GrannyBoneInfo>();

                while (!currentLine.StartsWith("meshes"))
                {
                    currentLine = streamReader.ReadLine();
                    if (!currentLine.StartsWith("meshes"))
                    {
                        string regexString = "([0-9]+) \"(.+)\" ";
                        for (int i = 0; i < 24; i++)
                        {
                            regexString = regexString + numberRegex;
                        }

                        Regex           regex = new Regex(regexString.Trim());
                        MatchCollection mc    = regex.Matches(currentLine);
                        foreach (Match m in mc)
                        {
                            GrannyBoneInfo      boneInfo      = new GrannyBoneInfo();
                            GrannyTransformInfo transformInfo = new GrannyTransformInfo();

                            //int boneindex = NumberUtils.parseInt(m.Groups[1].Value.Trim());
                            string boneName    = m.Groups[2].Value;
                            int    parentIndex = NumberUtils.parseInt(m.Groups[3].Value.Trim());

                            float[] position = new float[3];
                            position[0] = NumberUtils.parseFloat(m.Groups[4].Value.Trim());
                            position[1] = NumberUtils.parseFloat(m.Groups[5].Value.Trim());
                            position[2] = NumberUtils.parseFloat(m.Groups[6].Value.Trim());

                            float[] orientation = new float[4];
                            orientation[0] = NumberUtils.parseFloat(m.Groups[7].Value.Trim());
                            orientation[1] = NumberUtils.parseFloat(m.Groups[8].Value.Trim());
                            orientation[2] = NumberUtils.parseFloat(m.Groups[9].Value.Trim());
                            orientation[3] = NumberUtils.parseFloat(m.Groups[10].Value.Trim());

                            float[] scaleShear = new float[9];
                            scaleShear[0] = 1.0f;
                            scaleShear[1] = 0.0f;
                            scaleShear[2] = 0.0f;
                            scaleShear[3] = 0.0f;
                            scaleShear[4] = 1.0f;
                            scaleShear[5] = 0.0f;
                            scaleShear[6] = 0.0f;
                            scaleShear[7] = 0.0f;
                            scaleShear[8] = 1.0f;

                            float[] invWorld = new float[16];

                            for (int j = 0; j < 16; j++)
                            {
                                invWorld[j] = NumberUtils.parseFloat(m.Groups[j + 11].Value.Trim());
                            }


                            bool hasPosition    = true;
                            bool hasOrientation = true;
                            int  flags          = 0;

                            if (NumberUtils.almostEquals(position[0], 0.0f, 4) && NumberUtils.almostEquals(position[1], 0.0f, 4) && NumberUtils.almostEquals(position[2], 0.0f, 4))
                            {
                                hasPosition = false;
                            }

                            if (NumberUtils.almostEquals(orientation[0], 0.0f, 5) && NumberUtils.almostEquals(orientation[1], 0.0f, 5) &&
                                NumberUtils.almostEquals(orientation[2], 0.0f, 5) && NumberUtils.almostEquals(orientation[3], 1.0f, 5))
                            {
                                hasOrientation = false;
                            }

                            if (hasPosition)
                            {
                                flags = flags + 1;
                            }

                            if (hasOrientation)
                            {
                                flags = flags + 2;
                            }

                            transformInfo.flags       = flags;
                            transformInfo.position    = position;
                            transformInfo.orientation = orientation;
                            transformInfo.scaleShear  = scaleShear;

                            boneInfo.name                  = boneName;
                            boneInfo.parentIndex           = parentIndex;
                            boneInfo.localTransform        = transformInfo;
                            boneInfo.inverseWorldTransform = invWorld;
                            boneInfo.LODError              = 0;

                            skeletonBones.Add(boneInfo);
                        }
                    }
                }

                skeletonInfo.bones = skeletonBones;

                // Read Meshes
                int numMeshes = NumberUtils.parseInt(currentLine.Replace("meshes:", ""));
                List <GrannyMeshInfo> meshInfos = new List <GrannyMeshInfo>();
                for (int meshId = 0; meshId < numMeshes; meshId++)
                {
                    string meshName = "";
                    while (!currentLine.StartsWith("mesh:"))
                    {
                        currentLine = streamReader.ReadLine();
                    }

                    string          regexString = "\"(.+)\"";
                    Regex           regex       = new Regex(regexString);
                    MatchCollection mc          = regex.Matches(currentLine);

                    foreach (Match m in mc)
                    {
                        meshName = m.Groups[1].Value.Replace("#M", "");
                    }

                    // Read Materials
                    List <string> materialNames = new List <string>();
                    while (!currentLine.StartsWith("vertices"))
                    {
                        currentLine = streamReader.ReadLine();
                        if (!currentLine.StartsWith("materials") && !currentLine.StartsWith("vertices"))
                        {
                            mc = regex.Matches(currentLine);

                            foreach (Match m in mc)
                            {
                                string materialName = m.Groups[1].Value;
                                materialNames.Add(materialName);
                            }
                        }
                    }

                    // Read Vertices
                    int unweightedVertexCount = 0;

                    List <GrannyVertexInfo> vertexInfos = new List <GrannyVertexInfo>();
                    while (!currentLine.StartsWith("triangles"))
                    {
                        currentLine = streamReader.ReadLine();
                        if (!currentLine.StartsWith("vertices") && !currentLine.StartsWith("triangles"))
                        {
                            regexString = "";
                            for (int i = 0; i < 34; i++)
                            {
                                regexString = regexString + numberRegex;
                            }

                            regex = new Regex(regexString.Trim());
                            mc    = regex.Matches(currentLine);
                            foreach (Match m in mc)
                            {
                                GrannyVertexInfo vertexInfo = new GrannyVertexInfo();

                                float[] position = new float[3];
                                position[0] = NumberUtils.parseFloat(m.Groups[1].Value.Trim());
                                position[1] = NumberUtils.parseFloat(m.Groups[2].Value.Trim());
                                position[2] = NumberUtils.parseFloat(m.Groups[3].Value.Trim());

                                float[] normal = new float[3];
                                normal[0] = NumberUtils.parseFloat(m.Groups[4].Value.Trim());
                                normal[1] = NumberUtils.parseFloat(m.Groups[5].Value.Trim());
                                normal[2] = NumberUtils.parseFloat(m.Groups[6].Value.Trim());

                                float[] tangent = new float[3];
                                tangent[0] = NumberUtils.parseFloat(m.Groups[7].Value.Trim());
                                tangent[1] = NumberUtils.parseFloat(m.Groups[8].Value.Trim());
                                tangent[2] = NumberUtils.parseFloat(m.Groups[9].Value.Trim());

                                float[] binormal = new float[3];
                                binormal[0] = NumberUtils.parseFloat(m.Groups[10].Value.Trim());
                                binormal[1] = NumberUtils.parseFloat(m.Groups[11].Value.Trim());
                                binormal[2] = NumberUtils.parseFloat(m.Groups[12].Value.Trim());

                                float[] uv = new float[2];
                                uv[0] = NumberUtils.parseFloat(m.Groups[13].Value.Trim());
                                uv[1] = NumberUtils.parseFloat(m.Groups[14].Value.Trim());

                                float[] uv2 = new float[2];
                                uv2[0] = NumberUtils.parseFloat(m.Groups[15].Value.Trim());
                                uv2[1] = NumberUtils.parseFloat(m.Groups[16].Value.Trim());

                                float[] uv3 = new float[2];
                                uv3[0] = NumberUtils.parseFloat(m.Groups[17].Value.Trim());
                                uv3[1] = NumberUtils.parseFloat(m.Groups[18].Value.Trim());

                                int[] boneIndices = new int[8];
                                for (int j = 0; j < 8; j++)
                                {
                                    boneIndices[j] = NumberUtils.parseInt(m.Groups[j + 19].Value.Trim());
                                }

                                int[] boneWeights = new int[8];
                                for (int j = 0; j < 8; j++)
                                {
                                    boneWeights[j] = NumberUtils.parseInt(m.Groups[j + 27].Value.Trim());
                                }

                                // Assign unweighted vertices to root bone and record count
                                if (boneWeights[0] == -1)
                                {
                                    for (int j = 0; j < 8; j++)
                                    {
                                        boneIndices[j] = 0;
                                    }

                                    boneWeights[0] = 255;

                                    for (int j = 1; j < 8; j++)
                                    {
                                        boneWeights[j] = 0;
                                    }

                                    unweightedVertexCount++;
                                }

                                vertexInfo.position = position;
                                vertexInfo.normal   = normal;
                                vertexInfo.tangent  = tangent;
                                vertexInfo.binormal = binormal;

                                vertexInfo.uv  = uv;
                                vertexInfo.uv2 = uv2;
                                vertexInfo.uv3 = uv3;

                                vertexInfo.boneIndices = boneIndices;
                                vertexInfo.boneWeights = boneWeights;

                                vertexInfos.Add(vertexInfo);
                            }
                        }
                    }

                    if (unweightedVertexCount > 0 && vertexFormat == 0)
                    {
                        MessageBox.Show(unweightedVertexCount + " unweighted vertices have been assigned to root bone.", "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    }

                    // Read Triangles
                    List <int[]> triangles = new List <int[]>();
                    while (!currentLine.StartsWith("mesh") && !currentLine.StartsWith("end") && !currentLine.StartsWith("skeleton"))
                    {
                        currentLine = streamReader.ReadLine();
                        if (!currentLine.StartsWith("mesh") && !currentLine.StartsWith("end"))
                        {
                            regexString = "";
                            for (int i = 0; i < 4; i++)
                            {
                                regexString = regexString + "([-+]?[0-9]+\\.?[0-9]*) ";
                            }

                            regex = new Regex(regexString.Trim());
                            mc    = regex.Matches(currentLine);


                            foreach (Match m in mc)
                            {
                                int[] triangle = new int[4];
                                triangle[0] = NumberUtils.parseInt(m.Groups[1].Value.Trim());
                                triangle[1] = NumberUtils.parseInt(m.Groups[2].Value.Trim());
                                triangle[2] = NumberUtils.parseInt(m.Groups[3].Value.Trim());
                                triangle[3] = NumberUtils.parseInt(m.Groups[4].Value.Trim());

                                triangles.Add(triangle);
                            }
                        }
                    }

                    List <PrimaryTopologyGroupInfo> groupInfos = new List <PrimaryTopologyGroupInfo>();

                    int maxMaterialIndex = 0;
                    int groupIndexStart  = 0;
                    int triIndex;
                    for (triIndex = 0; triIndex < triangles.Count; triIndex++)
                    {
                        int[] triangle         = triangles[triIndex];
                        int   triMaterialIndex = triangle[3];

                        if (triMaterialIndex > maxMaterialIndex)
                        {
                            groupInfos.Add(new PrimaryTopologyGroupInfo(maxMaterialIndex, groupIndexStart, triIndex - groupIndexStart));
                            maxMaterialIndex = triMaterialIndex;
                            groupIndexStart  = triIndex;
                        }
                    }

                    groupInfos.Add(new PrimaryTopologyGroupInfo(maxMaterialIndex, groupIndexStart, triIndex - groupIndexStart));

                    GrannyMeshInfo meshInfo = new GrannyMeshInfo();
                    meshInfo.name      = meshName;
                    meshInfo.vertices  = vertexInfos;
                    meshInfo.triangles = triangles;
                    meshInfo.primaryTopologyGroupInfos = groupInfos;
                    meshInfo.materialBindingNames      = materialNames;

                    meshInfos.Add(meshInfo);
                }

                modelInfo.skeleton     = skeletonInfo;
                modelInfo.meshBindings = meshInfos;
                modelInfos.Add(modelInfo);
            }

            streamReader.Close();

            return(modelInfos);
        }
        public static void exportNB2Model(IGrannyFile grannyFile, int modelId)
        {
            string fileExtension  = ".nb2";
            string outputFilename = "";
            string numberFormat   = "f6";

            if (grannyFile.Models.Count > 1)
            {
                outputFilename = grannyFile.Filename.Replace(".fgx", "_model" + modelId + fileExtension);
                outputFilename = outputFilename.Replace(".FGX", "_model" + modelId + fileExtension);
            }
            else
            {
                outputFilename = grannyFile.Filename.Replace(".fgx", fileExtension);
                outputFilename = outputFilename.Replace(".FGX", fileExtension);
            }

            StreamWriter outputWriter = new StreamWriter(new FileStream(outputFilename, FileMode.Create));

            IGrannyModel          model           = grannyFile.Models[modelId];
            IGrannySkeleton       skeleton        = model.Skeleton;
            GrannySkeletonWrapper skeletonWrapper = new GrannySkeletonWrapper(skeleton);

            skeletonWrapper.readSkeletonInfo();

            // Lookup so we can identify the meshes belonging the current model in the list of file meshes
            Dictionary <int, int> meshBindingToMesh = new Dictionary <int, int>();
            HashSet <string>      distinctMeshNames = new HashSet <string>();

            for (int i = 0; i < model.MeshBindings.Count; i++)
            {
                for (int j = 0; j < grannyFile.Meshes.Count; j++)
                {
                    GrannyMeshWrapper modelMesh = new GrannyMeshWrapper(model.MeshBindings[i]);
                    IGrannyMesh       fileMesh  = grannyFile.Meshes[j];
                    if (modelMesh.meshEqual(fileMesh))
                    {
                        meshBindingToMesh.Add(i, j);
                    }
                }
                distinctMeshNames.Add(model.MeshBindings[i].Name);
            }

            // Used to give meshes distinct names where we have multiple meshes with the same name in our source gr2
            Dictionary <string, int> meshNameCount = new Dictionary <string, int>();

            foreach (string meshName in distinctMeshNames)
            {
                meshNameCount.Add(meshName, 0);
            }

            List <GrannyMeshInfo> grannyMeshInfos = new List <GrannyMeshInfo>();

            for (int i = 0; i < model.MeshBindings.Count; i++)
            {
                GrannyMeshWrapper meshWrapper = new GrannyMeshWrapper(model.MeshBindings[i]);
                grannyMeshInfos.Add(meshWrapper.getMeshInfo());
            }

            BiLookup <int, string> boneLookup = new BiLookup <int, string>();

            for (int i = 0; i < skeleton.Bones.Count; i++)
            {
                boneLookup.Add(i, skeleton.Bones[i].Name);
            }

            Dictionary <string, double[]> boneNameToPositionMap = new Dictionary <string, double[]>();

            foreach (IGrannyBone bone in skeleton.Bones)
            {
                double[] bonePosition = getBoneWorldPosition(bone);
                boneNameToPositionMap.Add(bone.Name, bonePosition);
            }

            outputWriter.WriteLine("// Nexus Buddy NB2 - Exported from Nexus Buddy 2");
            outputWriter.WriteLine("Frames: 30");
            outputWriter.WriteLine("Frame: 1");

            // Write Meshes
            outputWriter.WriteLine("Meshes: " + model.MeshBindings.Count);
            for (int mi = 0; mi < grannyMeshInfos.Count; mi++)
            {
                GrannyMeshInfo grannyMeshInfo = grannyMeshInfos[mi];
                string         meshName       = model.MeshBindings[mi].Name;

                meshNameCount[meshName]++;
                if (meshNameCount[meshName] > 1)
                {
                    meshName += meshNameCount[meshName];
                }
                outputWriter.WriteLine("\"" + meshName + "\" 0 0");

                // Write Vertices
                outputWriter.WriteLine(grannyMeshInfo.vertices.Count);
                for (int vi = 0; vi < grannyMeshInfo.vertices.Count; vi++)
                {
                    GrannyVertexInfo vertex = grannyMeshInfo.vertices[vi];

                    string boneName0   = grannyMeshInfo.boneBindings[vertex.boneIndices[0]];
                    float  boneWeight0 = (float)vertex.boneWeights[0] / 255;
                    int    boneId0     = getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName0, boneWeight0, vertex.position);

                    string boneName1   = grannyMeshInfo.boneBindings[vertex.boneIndices[1]];
                    float  boneWeight1 = (float)vertex.boneWeights[1] / 255;
                    int    boneId1     = getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName1, boneWeight1, vertex.position);

                    string boneName2   = grannyMeshInfo.boneBindings[vertex.boneIndices[2]];
                    float  boneWeight2 = (float)vertex.boneWeights[2] / 255;
                    int    boneId2     = getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName2, boneWeight2, vertex.position);

                    string boneName3   = grannyMeshInfo.boneBindings[vertex.boneIndices[3]];
                    float  boneWeight3 = (float)vertex.boneWeights[3] / 255;
                    int    boneId3     = getBoneIdForBoneName(boneLookup, boneNameToPositionMap, boneName3, boneWeight3, vertex.position);


                    outputWriter.WriteLine("0 " + vertex.position[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.position[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.position[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                           vertex.uv[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.uv[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " "
                                           + boneId0 + " " + boneWeight0.ToString(numberFormat, CultureInfo.InvariantCulture) + " " + boneId1 + " " + boneWeight1.ToString(numberFormat, CultureInfo.InvariantCulture) + " "
                                           + boneId2 + " " + boneWeight2.ToString(numberFormat, CultureInfo.InvariantCulture) + " " + boneId3 + " " + boneWeight3.ToString(numberFormat, CultureInfo.InvariantCulture)
                                           );
                }

                // Write Normals
                outputWriter.WriteLine(grannyMeshInfo.vertices.Count);
                for (int ni = 0; ni < grannyMeshInfo.vertices.Count; ni++)
                {
                    GrannyVertexInfo vertex = grannyMeshInfo.vertices[ni];

                    outputWriter.WriteLine(vertex.normal[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.normal[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + vertex.normal[2].ToString(numberFormat, CultureInfo.InvariantCulture));
                }

                // Write Triangles
                outputWriter.WriteLine(grannyMeshInfo.triangles.Count);
                for (int ti = 0; ti < grannyMeshInfo.triangles.Count; ti++)
                {
                    int[] triangle = grannyMeshInfo.triangles[ti];
                    outputWriter.WriteLine("0 " + triangle[0] + " " + triangle[1] + " " + triangle[2] + " " + triangle[0] + " " + triangle[1] + " " + triangle[2] + " 1");
                }
            }

            // Write Material
            outputWriter.WriteLine("Materials: 1");
            outputWriter.WriteLine("\"Material_0\"");
            outputWriter.WriteLine("0.200000 0.200000 0.200000 1.000000");
            outputWriter.WriteLine("0.800000 0.800000 0.800000 1.000000");
            outputWriter.WriteLine("0.000000 0.000000 0.000000 1.000000");
            outputWriter.WriteLine("0.000000 0.000000 0.000000 1.000000");
            outputWriter.WriteLine("0.000000");
            outputWriter.WriteLine("1.000000");
            outputWriter.WriteLine("\"Material_0\"");
            outputWriter.WriteLine("\"\"");

            // Write Bones
            outputWriter.WriteLine("Bones: " + skeleton.Bones.Count);
            for (int bi = 0; bi < skeleton.Bones.Count; bi++)
            {
                IGrannyBone bone     = skeleton.Bones[bi];
                string      boneName = bone.Name;
                outputWriter.WriteLine("\"" + boneName + "\"");

                if (bone.ParentIndex == -1)
                {
                    outputWriter.WriteLine("\"\"");
                }
                else
                {
                    string parentBoneName = skeleton.Bones[bone.ParentIndex].Name;
                    outputWriter.WriteLine("\"" + parentBoneName + "\"");
                }

                IGrannyTransform transform   = bone.LocalTransform;
                float[]          orientation = transform.Orientation;
                float[]          position    = transform.Position;

                outputWriter.WriteLine("0 " + position[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + position[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + position[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " +
                                       orientation[0].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[1].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[2].ToString(numberFormat, CultureInfo.InvariantCulture) + " " + orientation[3].ToString(numberFormat, CultureInfo.InvariantCulture));

                // number of position keys
                outputWriter.WriteLine("0");
                // number of rotation keys
                outputWriter.WriteLine("0");
            }

            outputWriter.Close();
        }