Ejemplo n.º 1
0
        } //OnImportAsset

        public void ReadWithoutAssetImportContext(string filePath)
        {
            Fmdl fmdl = new Fmdl(Path.GetFileNameWithoutExtension(filePath));
            fmdl.Read(filePath);

            int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0;
            int materialCount = fmdl.fmdlMaterialInstances.Length;
            int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0;
            int meshCount = fmdl.fmdlMeshInfos.Length;
            int meshGroupCount = fmdl.fmdlMeshGroups.Length;

            GameObject mainObject = new GameObject(fmdl.name);
            FoxModel foxModel = mainObject.AddComponent<FoxModel>();
            foxModel.meshGroups = new FoxMeshGroup[meshGroupCount];
            foxModel.meshDefinitions = new FoxMeshDefinition[meshCount];
            Transform[] bones = new Transform[boneCount];
            Texture[] textures = new Texture[textureCount];
            Material[] materials = new Material[materialCount];
            Mesh[] meshes = new Mesh[meshCount];

            Transform rootBone = new GameObject().transform;
            rootBone.name = "[Root]";
            rootBone.parent = mainObject.transform;

            Read(fmdl, mainObject, foxModel, bones, textures, materials, meshes, rootBone);
        } //ReadWithoutAssetImportContext
Ejemplo n.º 2
0
    public static void FMDLWrite(string path)
    {
        FileStream stream = new FileStream(path, FileMode.Create);

        GameObject selectedGameObject = Selection.activeGameObject;
        Fmdl       fmdl = new Fmdl(selectedGameObject.name);

        fmdl.Write(selectedGameObject, stream);

        stream.Close();
    }
Ejemplo n.º 3
0
    public override void OnImportAsset(AssetImportContext ctx)
    {
        FileStream stream = new FileStream(ctx.assetPath, FileMode.Open);

        Fmdl       fmdl  = new Fmdl(Path.GetFileNameWithoutExtension(ctx.assetPath));
        UnityModel model = new UnityModel();

        fmdl.Read(stream);
        GameObject fmdlGameObject = model.GetDataFromFmdl(fmdl);

        ctx.AddObjectToAsset(ctx.assetPath, fmdlGameObject);
        ctx.SetMainObject(fmdlGameObject);
        stream.Close();
    }
Ejemplo n.º 4
0
        public static void ExportFMDLOption()
        {
            if (Selection.activeGameObject != null)
            {
                string windowPath = EditorUtility.SaveFilePanel("Export To FMDL", "", Selection.activeGameObject.name, "fmdl");

                if (!string.IsNullOrWhiteSpace(windowPath))
                {
                    Fmdl fmdl = new Fmdl(Selection.activeGameObject.name);
                    fmdl.Write(Selection.activeGameObject, windowPath);
                    Debug.Log("Fmdl Exported to: " + windowPath);
                } //if
                else
                    Debug.Log("No path selected.");
            }
            else
                Debug.Log("No objects selected.");
        } //ExportFMDLOption
Ejemplo n.º 5
0
        } //LoadTextureDXT

        private void ReadWithAssetImportContext(AssetImportContext ctx, string filePath)
        {
            Fmdl fmdl = new Fmdl(Path.GetFileNameWithoutExtension(filePath));
            fmdl.Read(filePath);

            int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0;
            int materialCount = fmdl.fmdlMaterialInstances.Length;
            int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0;
            int meshCount = fmdl.fmdlMeshInfos.Length;
            int meshGroupCount = fmdl.fmdlMeshGroups.Length;

            GameObject mainObject = new GameObject(fmdl.name);
            FoxModel foxModel = mainObject.AddComponent<FoxModel>();
            foxModel.meshGroups = new FoxMeshGroup[meshGroupCount];
            foxModel.meshDefinitions = new FoxMeshDefinition[meshCount];
            Transform[] bones = new Transform[boneCount];
            Texture[] textures = new Texture[textureCount];
            Material[] materials = new Material[materialCount];
            Mesh[] meshes = new Mesh[meshCount];

            Transform rootBone = new GameObject().transform;
            rootBone.name = "[Root]";
            rootBone.parent = mainObject.transform;

            Read(fmdl, mainObject, foxModel, bones, textures, materials, meshes, rootBone);

            ctx.AddObjectToAsset("mainObject", mainObject);
            ctx.SetMainObject(mainObject);

            for (int i = 0; i < textureCount; i++)
                ctx.AddObjectToAsset($"Texture {i}", textures[i]);

            for (int i = 0; i < materialCount; i++)
                ctx.AddObjectToAsset($"Material {i}", materials[i]);

            for (int i = 0; i < meshCount; i++)
                ctx.AddObjectToAsset($"Mesh {i}", meshes[i]);
        } //ReadWithAssetImportContext
Ejemplo n.º 6
0
        public void Import(Stream input, string path)
        {
            var prefabPath = Path.GetDirectoryName(path) + "/" + Path.GetFileNameWithoutExtension(path) + ".prefab";

            if (File.Exists(prefabPath))
            {
                return;
            }

            try
            {
                var reader = new Fmdl();
                reader.Read(input);

                Directory.CreateDirectory(Path.GetDirectoryName(Directory.GetParent(assetPath) + "/" + path));
                var createMeshCommand = new CreateMesh(() => reader.CreateAndSaveMesh(path));
                unityThreadDispacher.DispatchCommand(createMeshCommand);
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError(e);
                throw;
            }
        }
Ejemplo n.º 7
0
        } //ReadWithAssetImportContext

        private void Read(Fmdl fmdl, GameObject mainObject, FoxModel foxModel, Transform[] bones, Texture[] textures, Material[] materials, Mesh[] meshes, Transform rootBone)
        {
            bool isGZFormat = fmdl.version == 2.03f;
            int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0;
            int materialCount = fmdl.fmdlMaterialInstances.Length;
            int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0;
            int meshCount = fmdl.fmdlMeshInfos.Length;
            int meshGroupCount = fmdl.fmdlMeshGroups.Length;

            {
                Fmdl.FmdlBoundingBox fmdlBoundingBox = fmdl.fmdlBoundingBoxes[0];

                Bounds bounds = new Bounds();
                bounds.SetMinMax(new Vector3(-fmdlBoundingBox.min.x, fmdlBoundingBox.min.y, fmdlBoundingBox.min.z), new Vector3(-fmdlBoundingBox.max.x, fmdlBoundingBox.max.y, fmdlBoundingBox.max.z));
                BoxCollider boxCollider = rootBone.gameObject.AddComponent<BoxCollider>();
                boxCollider.center = rootBone.InverseTransformPoint(bounds.center);
                boxCollider.size = bounds.size;
            } //code block

            for (int i = 0; i < boneCount; i++)
            {
                bones[i] = new GameObject().transform;

                Fmdl.FmdlBone fmdlBone = fmdl.fmdlBones[i];
                Fmdl.FmdlBoundingBox fmdlBoundingBox = fmdl.fmdlBoundingBoxes[fmdlBone.boundingBoxIndex];

                //Get the name.
                if (isGZFormat)
                    bones[i].gameObject.name = fmdl.fmdlStrings[fmdlBone.nameIndex];
                else
                    bones[i].gameObject.name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlBone.nameIndex]);

                try
                {
                    UInt64.Parse(bones[i].gameObject.name, System.Globalization.NumberStyles.HexNumber);
                    bones[i].name = $"SKL_{(Int32.Parse(bones[i - 1].name.Substring(4, 3)) + 1).ToString("000")}_UNKNOWN ({bones[i].name})";
                } //try
                catch { }

                //Assign the parent.
                if (fmdlBone.parentIndex != -1)
                    bones[i].parent = bones[fmdlBone.parentIndex];
                else
                    bones[i].parent = rootBone.transform;

                bones[i].position = new Vector3(-fmdlBone.worldPosition.x, fmdlBone.worldPosition.y, fmdlBone.worldPosition.z);

                //Set up the bounding box.
                Bounds bounds = new Bounds();

                //The x min and max are swapped here on purpose! The max value will end up as the smallest value and the min value will end up as the largest value if they aren't swapped here!
                bounds.SetMinMax(new Vector3(-fmdlBoundingBox.max.x, fmdlBoundingBox.min.y, fmdlBoundingBox.min.z), new Vector3(-fmdlBoundingBox.min.x, fmdlBoundingBox.max.y, fmdlBoundingBox.max.z));
                BoxCollider boxCollider = bones[i].gameObject.AddComponent<BoxCollider>();
                boxCollider.center = bones[i].InverseTransformPoint(bounds.center);
                boxCollider.size = bounds.size;
            } //for

            for (int i = 0; i < textureCount; i++)
            {
                string name;

                Fmdl.FmdlTexture fmdlTexture = fmdl.fmdlTextures[i];

                //Get the name.
                if (isGZFormat)
                {
                    name = fmdl.fmdlStrings[fmdlTexture.pathIndex] + fmdl.fmdlStrings[fmdlTexture.nameIndex];
                    name = name.Substring(0, name.IndexOf(".")) + ".dds";
                } //if
                else
                    name = Hashing.TryGetPathName(fmdl.fmdlPathCode64s[fmdlTexture.pathIndex]) + ".dds";

                //Read the file.
                if (File.Exists($"{Globals.GetTexturePath()}\\{name}"))
                    textures[i] = LoadTextureDXT($"{Globals.GetTexturePath()}\\{name}");
                else
                {
                    Debug.LogWarning($"Could not find {Globals.GetTexturePath()}\\{name}");

                    Texture2D texture = new Texture2D(512, 512);

                    for (int j = 0; j < 512; j++)
                        for (int h = 0; h < 512; h++)
                        {
                            Color c = new Color(0.25f, 0.25f, 0.25f);

                            if (((j / 32) % 2 == 0 && (h / 32) % 2 != 0) || ((j / 32) % 2 != 0 && (h / 32) % 2 == 0))
                                c = new Color(0.5f, 0.5f, 0.5f);

                            texture.SetPixel(j, h, c);
                        } //for

                    texture.Apply();

                    textures[i] = texture;
                } //else
                
                textures[i].name = name;
            } //for

            for (int i = 0; i < materialCount; i++)
            {
                string shaderName;
                string materialName;

                Fmdl.FmdlMaterialInstance fmdlMaterialInstance = fmdl.fmdlMaterialInstances[i];

                //Get the shader and material name.
                if (isGZFormat)
                {
                    shaderName = fmdl.fmdlStrings[fmdl.fmdlMaterials[fmdlMaterialInstance.materialIndex].typeIndex];
                    materialName = fmdl.fmdlStrings[fmdlMaterialInstance.nameIndex];
                } //if
                else
                {
                    shaderName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdl.fmdlMaterials[fmdlMaterialInstance.materialIndex].typeIndex]);
                    materialName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialInstance.nameIndex]);
                } //else

                //Some ombs models have broken, unused, materials in them. Try catch here is necessary to handle them.
                try
                {
                    materials[i] = new Material(Shader.Find($"FoxShaders/{shaderName}"));
                } //try
                catch
                {
                    materials[i] = new Material(Shader.Find($"FoxShaders/fox3DDF_Blin_LNM"));
                    Debug.LogWarning($"Material {materialName} trying to use missing shader: {shaderName}! Defaulting to fox3DDF_Blin_LNM!");
                } //catch
                
                materials[i].name = materialName;

                //Link textures.
                for (int j = fmdlMaterialInstance.firstTextureIndex; j < fmdlMaterialInstance.firstTextureIndex + fmdlMaterialInstance.textureCount; j++)
                {
                    string textureType;

                    Fmdl.FmdlMaterialParameter fmdlMaterialParameter = fmdl.fmdlMaterialParameters[j];

                    if (isGZFormat)
                        textureType = fmdl.fmdlStrings[fmdlMaterialParameter.nameIndex];
                    else
                        textureType = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialParameter.nameIndex]);

                    materials[i].SetTexture($"_{textureType}", textures[fmdlMaterialParameter.referenceIndex]);
                    materials[i].SetTextureScale($"_{textureType}", new Vector2(1, -1)); //Have to flip textures here because Texture2D.LoadRawData is bugged an imports DDS files upside down.
                } //for

                //Set parameters.
                for (int j = fmdlMaterialInstance.firstParameterIndex; j < fmdlMaterialInstance.firstParameterIndex + fmdlMaterialInstance.parameterCount; j++)
                {
                    string parameterName;

                    Fmdl.FmdlMaterialParameter fmdlMaterialParameter = fmdl.fmdlMaterialParameters[j];

                    if (isGZFormat)
                        parameterName = fmdl.fmdlStrings[fmdlMaterialParameter.nameIndex];
                    else
                        parameterName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialParameter.nameIndex]);

                    materials[i].SetVector($"_{parameterName}", fmdl.fmdlMaterialParameterVectors[fmdlMaterialParameter.referenceIndex]);
                } //for
            } //for

            for (int i = 0; i < meshGroupCount; i++)
            {
                foxModel.meshGroups[i] = new FoxMeshGroup();
                string name;

                Fmdl.FmdlMeshGroup fmdlMeshGroup = fmdl.fmdlMeshGroups[i];

                if (isGZFormat)
                    name = fmdl.fmdlStrings[fmdlMeshGroup.nameIndex];
                else
                    name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMeshGroup.nameIndex]);

                foxModel.meshGroups[i].name = name;
                foxModel.meshGroups[i].parent = fmdlMeshGroup.parentIndex;

                if (fmdlMeshGroup.invisibilityFlag == 0)
                    foxModel.meshGroups[i].visible = true;
                else
                    foxModel.meshGroups[i].visible = false;
            } //for

            for (int i = 0; i < meshCount; i++)
            {
                meshes[i] = new Mesh();
                GameObject gameObject = new GameObject();
                gameObject.transform.parent = mainObject.transform;
                SkinnedMeshRenderer skinnedMeshRenderer = gameObject.AddComponent<SkinnedMeshRenderer>();
                foxModel.meshDefinitions[i] = new FoxMeshDefinition();

                Fmdl.FmdlMesh fmdlMesh = fmdl.fmdlMeshes[i];
                Fmdl.FmdlMeshInfo fmdlMeshInfo = fmdl.fmdlMeshInfos[i];
                Fmdl.FmdlBoneGroup fmdlBoneGroup = fmdl.fmdlBoneGroups != null ? fmdl.fmdlBoneGroups[fmdlMeshInfo.boneGroupIndex] : new Fmdl.FmdlBoneGroup();

                int vertexLength = fmdlMesh.vertices.Length;
                int faceLength = fmdlMesh.triangles.Length;
                string name;

                Vector3[] vertices = new Vector3[vertexLength];
                Vector3[] normals = new Vector3[vertexLength];
                Vector4[] tangents = fmdlMesh.tangents != null ? new Vector4[vertexLength] : new Vector4[0];
                Color[] colors = fmdlMesh.colors != null ? new Color[vertexLength] : new Color[0];
                BoneWeight[] boneWeights = fmdlMesh.boneWeights != null ? new BoneWeight[vertexLength] : new BoneWeight[0];
                Vector2[] uv = fmdlMesh.uv != null ? new Vector2[vertexLength] : new Vector2[0];
                Vector2[] uv2 = fmdlMesh.uv2 != null ? new Vector2[vertexLength] : new Vector2[0];
                Vector2[] uv3 = fmdlMesh.uv3 != null ? new Vector2[vertexLength] : new Vector2[0];
                Vector2[] uv4 = fmdlMesh.uv4 != null ? new Vector2[vertexLength] : new Vector2[0];
                int[] triangles = new int[faceLength];
                Matrix4x4[] bindPoses;

                List<Transform> usedBones = new List<Transform>(0);
                Transform[] usedBonesArray;

                for (int j = 0; j < vertexLength; j++)
                {
                    vertices[j] = new Vector3(-fmdlMesh.vertices[j].x, fmdlMesh.vertices[j].y, fmdlMesh.vertices[j].z);
                    normals[j] = new Vector3(-fmdlMesh.normals[j].x, fmdlMesh.normals[j].y, fmdlMesh.normals[j].z);
                    if (tangents.Length > 0)
                        tangents[j] = new Vector4(-fmdlMesh.tangents[j].x, fmdlMesh.tangents[j].y, fmdlMesh.tangents[j].z, fmdlMesh.tangents[j].w);
                    if (colors.Length > 0)
                        colors[j] = new Color(fmdlMesh.colors[j].x / 255f, fmdlMesh.colors[j].y / 255f, fmdlMesh.colors[j].z / 255f, fmdlMesh.colors[j].w / 255f);
                    if (boneWeights.Length > 0)
                    {
                        boneWeights[j].weight0 = fmdlMesh.boneWeights[j].x / 255f;
                        boneWeights[j].weight1 = fmdlMesh.boneWeights[j].y / 255f;
                        boneWeights[j].weight2 = fmdlMesh.boneWeights[j].z / 255f;
                        boneWeights[j].weight3 = fmdlMesh.boneWeights[j].w / 255f;
                        boneWeights[j].boneIndex0 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].x];
                        boneWeights[j].boneIndex1 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].y];
                        boneWeights[j].boneIndex2 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].z];
                        boneWeights[j].boneIndex3 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].w];
                    } //if
                    if (uv.Length > 0)
                        uv[j] = new Vector2(fmdlMesh.uv[j].x, 1 - fmdlMesh.uv[j].y);
                    if (uv2.Length > 0)
                        uv2[j] = new Vector2(fmdlMesh.uv2[j].x, 1 - fmdlMesh.uv2[j].y);
                    if (uv3.Length > 0)
                        uv3[j] = new Vector2(fmdlMesh.uv3[j].x, 1 - fmdlMesh.uv3[j].y);
                    if (uv4.Length > 0)
                        uv4[j] = new Vector2(fmdlMesh.uv4[j].x, 1 - fmdlMesh.uv4[j].y);
                } //for

                for (int j = 0; j < faceLength; j++)
                    triangles[j] = fmdlMesh.triangles[j];

                for (int j = 0; j < boneWeights.Length; j++)
                {
                    if (boneWeights[j].weight0 > 0f)
                    {
                        if (usedBones.Contains(bones[boneWeights[j].boneIndex0]))
                            boneWeights[j].boneIndex0 = usedBones.IndexOf(bones[boneWeights[j].boneIndex0]);
                        else
                        {
                            usedBones.Add(bones[boneWeights[j].boneIndex0]);
                            boneWeights[j].boneIndex0 = usedBones.IndexOf(bones[boneWeights[j].boneIndex0]);
                        } //else
                    } //if
                    else
                        boneWeights[j].boneIndex0 = 0;

                    if (boneWeights[j].weight1 > 0f)
                    {
                        if (usedBones.Contains(bones[boneWeights[j].boneIndex1]))
                            boneWeights[j].boneIndex1 = usedBones.IndexOf(bones[boneWeights[j].boneIndex1]);
                        else
                        {
                            usedBones.Add(bones[boneWeights[j].boneIndex1]);
                            boneWeights[j].boneIndex1 = usedBones.IndexOf(bones[boneWeights[j].boneIndex1]);
                        } //else
                    } //if
                    else
                        boneWeights[j].boneIndex1 = 0;

                    if (boneWeights[j].weight2 > 0f)
                    {
                        if (usedBones.Contains(bones[boneWeights[j].boneIndex2]))
                            boneWeights[j].boneIndex2 = usedBones.IndexOf(bones[boneWeights[j].boneIndex2]);
                        else
                        {
                            usedBones.Add(bones[boneWeights[j].boneIndex2]);
                            boneWeights[j].boneIndex2 = usedBones.IndexOf(bones[boneWeights[j].boneIndex2]);
                        } //else
                    } //if
                    else
                        boneWeights[j].boneIndex2 = 0;

                    if (boneWeights[j].weight3 > 0f)
                    {
                        if (usedBones.Contains(bones[boneWeights[j].boneIndex3]))
                            boneWeights[j].boneIndex3 = usedBones.IndexOf(bones[boneWeights[j].boneIndex3]);
                        else
                        {
                            usedBones.Add(bones[boneWeights[j].boneIndex3]);
                            boneWeights[j].boneIndex3 = usedBones.IndexOf(bones[boneWeights[j].boneIndex3]);
                        } //else
                    } //if
                    else
                        boneWeights[j].boneIndex3 = 0;
                } //for

                usedBonesArray = usedBones.ToArray();
                bindPoses = new Matrix4x4[usedBonesArray.Length];

                for (int j = 0; j < usedBonesArray.Length; j++)
                    bindPoses[j] = usedBones[j].worldToLocalMatrix * gameObject.transform.localToWorldMatrix;

                meshes[i].vertices = vertices;
                meshes[i].normals = normals;
                meshes[i].tangents = tangents;
                meshes[i].colors = colors;
                meshes[i].boneWeights = boneWeights;
                meshes[i].uv = uv;
                meshes[i].uv2 = uv2;
                meshes[i].uv3 = uv3;
                meshes[i].uv4 = uv4;
                meshes[i].triangles = triangles;
                meshes[i].bindposes = bindPoses;

                skinnedMeshRenderer.bones = usedBonesArray;
                skinnedMeshRenderer.sharedMaterial = materials[fmdlMeshInfo.materialInstanceIndex];
                skinnedMeshRenderer.sharedMesh = meshes[i];
                skinnedMeshRenderer.rootBone = mainObject.transform;

                foxModel.meshDefinitions[i].mesh = meshes[i];
                foxModel.meshDefinitions[i].meshGroup = Array.Find(fmdl.fmdlMeshGroupEntries, x => x.firstMeshIndex <= i && x.firstMeshIndex + x.meshCount > i).meshGroupIndex;
                foxModel.meshDefinitions[i].alpha = (FoxMeshDefinition.Alpha)fmdlMeshInfo.alphaEnum;
                foxModel.meshDefinitions[i].shadow = (FoxMeshDefinition.Shadow)fmdlMeshInfo.shadowEnum;

                if (isGZFormat)
                    name = fmdl.fmdlStrings[fmdl.fmdlMeshGroups[foxModel.meshDefinitions[i].meshGroup].nameIndex];
                else
                    name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdl.fmdlMeshGroups[foxModel.meshDefinitions[i].meshGroup].nameIndex]);

                gameObject.name = $"{i} - {name}";
            } //for
        } //Read
Ejemplo n.º 8
0
    public GameObject GetDataFromFmdl(Fmdl fmdl)
    {
        Globals.ReadTexturePath();

        meshes = new UnityMesh[fmdl.section0Block3Entries.Count];

        GameObject fmdlGameObject = new GameObject();

        fmdlGameObject.name = fmdl.name;
        GameObject[] subFmdlGameObjects = new GameObject[fmdl.objects.Count];
        Transform[]  bones;
        Matrix4x4[]  bindPoses;
        Bounds[]     bounds = new Bounds[fmdl.section0BlockDEntries.Count];

        fmdlGameObject.AddComponent <FoxModel>().definitions = new FoxMeshDefinition[fmdl.objects.Count];
        UnityMaterial[] materials = new UnityMaterial[fmdl.section0Block4Entries.Count];

        if (fmdl.bonesIndex != -1)
        {
            bones     = new Transform[fmdl.section0Block0Entries.Count];
            bindPoses = new Matrix4x4[fmdl.section0Block0Entries.Count];
        } //if
        else
        {
            bones     = new Transform[0];
            bindPoses = new Matrix4x4[0];
        } //else

        for (int i = 0; i < fmdl.section0Block4Entries.Count; i++)
        {
            materials[i].material = new Material(Shader.Find("FoxShaders/Base"));
            //materials[i].material = new Material(Shader.Find("Legacy Shaders/Transparent/Cutout/Bumped Diffuse"));
            //materials[i].material = new Material(Shader.Find("Standard"));

            if (fmdl.stringsIndex != -1)
            {
                materials[i].material.name = fmdl.strings[fmdl.section0Block4Entries[i].stringId];
                materials[i].materialName  = fmdl.strings[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].stringId];
                materials[i].materialType  = fmdl.strings[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].typeId];

                for (int j = fmdl.section0Block4Entries[i].firstTextureId; j < fmdl.section0Block4Entries[i].firstTextureId + fmdl.section0Block4Entries[i].numTextures; j++)
                {
                    string textureName = "";
                    int    extensionLocation;

                    textureName = fmdl.strings[fmdl.section0Block6Entries[fmdl.section0Block7Entries[j].referenceId].pathId] + fmdl.strings[fmdl.section0Block6Entries[fmdl.section0Block7Entries[j].referenceId].stringId];
                    //materials[i].textureType = fmdl.strings[fmdl.section0Block7Entries[fmdl.section0Block4Entries[i].firstTextureId].stringId];

                    extensionLocation = textureName.IndexOf('.');
                    textureName       = textureName.Substring(0, extensionLocation);

                    if (File.Exists(Globals.texturePath + "\\" + textureName + ".dds"))
                    {
                        Texture2D texture = LoadTextureDXT(Globals.texturePath + "\\" + textureName + ".dds");
                        texture.name = textureName + ".dds";

                        if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "Base_Tex_SRGB")
                        {
                            materials[i].material.mainTexture = texture;
                        }
                        else if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "NormalMap_Tex_NRM")
                        {
                            materials[i].material.SetTexture("_BumpMap", texture);
                        }
                        else if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "SpecularMap_Tex_LIN")
                        {
                            materials[i].material.SetTexture("_SRM", texture);
                        }
                        else if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "Layer_Tex_SRGB")
                        {
                            materials[i].material.SetTexture("_LayerTex", texture);
                        }
                        else if (fmdl.strings[fmdl.section0Block7Entries[j].stringId] == "LayerMask_Tex_LIN")
                        {
                            materials[i].material.SetTexture("_LayerMask", texture);
                        }
                        //_MainTex = Diffuse. _BumpMap = Normal Map. _Color = Main Colour. _SpecColor = Specular Map. _Shininess.
                    } //if
                    else
                    {
                        UnityEngine.Debug.Log("Could not find: " + Globals.texturePath + "\\" + textureName + ".dds");
                    } //else
                }     //for
            }         //if
            else
            {
                materials[i].material.name = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block4Entries[i].stringId]);
                materials[i].materialName  = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].stringId]);
                materials[i].materialType  = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].typeId]);

                if (fmdl.texturePathsIndex != -1)
                {
                    for (int j = fmdl.section0Block4Entries[i].firstTextureId; j < fmdl.section0Block4Entries[i].firstTextureId + fmdl.section0Block4Entries[i].numTextures; j++)
                    {
                        if (File.Exists(Globals.texturePath + "\\" + Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]) + ".dds"))
                        {
                            Texture2D texture = LoadTextureDXT(Globals.texturePath + "\\" + Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]) + ".dds");
                            texture.name = Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]) + ".dds";
                            //materials[i].textureType = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[fmdl.section0Block4Entries[i].firstTextureId].stringId]);

                            if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "Base_Tex_SRGB")
                            {
                                materials[i].material.mainTexture = texture;
                            }
                            else if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "NormalMap_Tex_NRM")
                            {
                                materials[i].material.SetTexture("_BumpMap", texture);
                            }
                            else if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "SpecularMap_Tex_LIN")
                            {
                                materials[i].material.SetTexture("_SRM", texture);
                            }
                            else if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "Layer_Tex_SRGB")
                            {
                                materials[i].material.SetTexture("_LayerTex", texture);
                            }
                            else if (Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]) == "LayerMask_Tex_LIN")
                            {
                                materials[i].material.SetTexture("_LayerMask", texture);
                            }
                        } //if
                        else
                        {
                            UnityEngine.Debug.Log("Could not find: " + Globals.texturePath + "\\" + Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]) + ".dds");
                        } //else
                    }     //for
                }         //if
            }             //else
        }                 //for

        for (int i = 0; i < bounds.Length; i++)
        {
            bounds[i].SetMinMax(new Vector3(fmdl.section0BlockDEntries[i].minZ, fmdl.section0BlockDEntries[i].minY, fmdl.section0BlockDEntries[i].minX), new Vector3(fmdl.section0BlockDEntries[i].maxZ, fmdl.section0BlockDEntries[i].maxY, fmdl.section0BlockDEntries[i].maxX));
        } //for

        Transform rootBone = new GameObject("[Root]").transform; //From what I can tell, the real name is "". But it looks kinda dumb having "" as its name; so using "[Root]" as a placeholder seems better.

        rootBone.parent = fmdlGameObject.transform;

        {
            BoxCollider collider = rootBone.gameObject.AddComponent <BoxCollider>();
            collider.center = rootBone.InverseTransformPoint(bounds[0].center); //Have to convert these to local positions. They're stored as world positions.
            collider.size   = bounds[0].size;
        } //code block

        for (int i = 0; i < bones.Length; i++)
        {
            bones[i]          = new GameObject().transform;
            bones[i].position = new Vector3(fmdl.section0Block0Entries[i].worldPositionZ, fmdl.section0Block0Entries[i].worldPositionY, fmdl.section0Block0Entries[i].worldPositionX);

            BoxCollider collider = bones[i].gameObject.AddComponent <BoxCollider>();
            collider.center = bones[i].InverseTransformPoint(bounds[fmdl.section0Block0Entries[i].boundingBoxId].center); //Have to convert these to local positions. They're stored as world positions.
            collider.size   = bounds[fmdl.section0Block0Entries[i].boundingBoxId].size;

            if (fmdl.stringsIndex != -1)
            {
                bones[i].name = fmdl.strings[fmdl.section0Block0Entries[i].stringId];
            }
            else
            {
                bones[i].name = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block0Entries[i].stringId]);
            }

            if (fmdl.section0Block0Entries[i].parentId != 0xFFFF)
            {
                bones[i].parent = bones[fmdl.section0Block0Entries[i].parentId];
            }
            else
            {
                bones[i].parent = rootBone;
            }
        } //for

        for (int i = 0; i < fmdl.objects.Count; i++)
        {
            int lod = 0; //Temporary solution. 0 loads the normal faces. 1 loads the first set of LOD faces. 2 loads the next set. Etc....

            meshes[i].vertices = new Vector3[fmdl.objects[i].vertices.Length];
            meshes[i].normals  = new Vector3[fmdl.objects[i].additionalVertexData.Length];
            meshes[i].tangents = new Vector4[fmdl.objects[i].additionalVertexData.Length];
            meshes[i].colour   = new Color[fmdl.objects[i].additionalVertexData.Length];
            meshes[i].uv       = new Vector2[fmdl.objects[i].additionalVertexData.Length];
            meshes[i].uv2      = new Vector2[fmdl.objects[i].additionalVertexData.Length];
            meshes[i].uv3      = new Vector2[fmdl.objects[i].additionalVertexData.Length];
            meshes[i].uv4      = new Vector2[fmdl.objects[i].additionalVertexData.Length];
            //meshes[i].faces = new int[fmdl.objects[i].faces.Length * 3];
            meshes[i].faces       = new int[fmdl.objects[i].lodFaces[lod].Length * 3];
            meshes[i].boneWeights = new BoneWeight[fmdl.objects[i].additionalVertexData.Length];

            //Position
            for (int j = 0; j < fmdl.objects[i].vertices.Length; j++)
            {
                meshes[i].vertices[j] = new Vector3(fmdl.objects[i].vertices[j].z, fmdl.objects[i].vertices[j].y, fmdl.objects[i].vertices[j].x);
            }

            //Normals, Bone Weights, Bone Group Ids and UVs
            for (int j = 0; j < fmdl.objects[i].additionalVertexData.Length; j++)
            {
                meshes[i].normals[j]  = new Vector3(fmdl.objects[i].additionalVertexData[j].normalZ, fmdl.objects[i].additionalVertexData[j].normalY, fmdl.objects[i].additionalVertexData[j].normalX);
                meshes[i].tangents[j] = new Vector4(fmdl.objects[i].additionalVertexData[j].tangentZ, fmdl.objects[i].additionalVertexData[j].tangentY, fmdl.objects[i].additionalVertexData[j].tangentX, fmdl.objects[i].additionalVertexData[j].tangentW);
                meshes[i].colour[j]   = new Color(fmdl.objects[i].additionalVertexData[j].colourR, fmdl.objects[i].additionalVertexData[j].colourG, fmdl.objects[i].additionalVertexData[j].colourB, fmdl.objects[i].additionalVertexData[j].colourA);

                if (fmdl.bonesIndex != -1)
                {
                    meshes[i].boneWeights[j].weight0    = fmdl.objects[i].additionalVertexData[j].boneWeightX;
                    meshes[i].boneWeights[j].weight1    = fmdl.objects[i].additionalVertexData[j].boneWeightY;
                    meshes[i].boneWeights[j].weight2    = fmdl.objects[i].additionalVertexData[j].boneWeightZ;
                    meshes[i].boneWeights[j].weight3    = fmdl.objects[i].additionalVertexData[j].boneWeightW;
                    meshes[i].boneWeights[j].boneIndex0 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup0Id];
                    meshes[i].boneWeights[j].boneIndex1 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup1Id];
                    meshes[i].boneWeights[j].boneIndex2 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup2Id];
                    meshes[i].boneWeights[j].boneIndex3 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup3Id];
                } //if

                meshes[i].uv[j]  = new Vector2(fmdl.objects[i].additionalVertexData[j].textureU, fmdl.objects[i].additionalVertexData[j].textureV);
                meshes[i].uv2[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU0, fmdl.objects[i].additionalVertexData[j].unknownV0);
                meshes[i].uv3[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU1, fmdl.objects[i].additionalVertexData[j].unknownV1);
                meshes[i].uv4[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU2, fmdl.objects[i].additionalVertexData[j].unknownV2);
            } //for

            //Faces

            /*for (int j = 0, h = 0; j < fmdl.objects[i].faces.Length; j++, h += 3)
             * {
             *  meshes[i].faces[h] = fmdl.objects[i].faces[j].vertex1Id;
             *  meshes[i].faces[h + 1] = fmdl.objects[i].faces[j].vertex2Id;
             *  meshes[i].faces[h + 2] = fmdl.objects[i].faces[j].vertex3Id;
             * } //for*/

            for (int j = 0, h = 0; j < fmdl.objects[i].lodFaces[lod].Length; j++, h += 3)
            {
                meshes[i].faces[h]     = fmdl.objects[i].lodFaces[lod][j].vertex1Id;
                meshes[i].faces[h + 1] = fmdl.objects[i].lodFaces[lod][j].vertex2Id;
                meshes[i].faces[h + 2] = fmdl.objects[i].lodFaces[lod][j].vertex3Id;
            } //for

            //Render the mesh in Unity.
            subFmdlGameObjects[i] = new GameObject();
            FoxMeshDefinition foxMeshDefinition = new FoxMeshDefinition();

            //Get the mesh name.
            for (int j = 0; j < fmdl.section0Block2Entries.Count; j++)
            {
                if (i >= fmdl.section0Block2Entries[j].firstObjectId && i < fmdl.section0Block2Entries[j].firstObjectId + fmdl.section0Block2Entries[j].numObjects)
                {
                    if (fmdl.stringsIndex != -1)
                    {
                        subFmdlGameObjects[i].name  = i + " - " + fmdl.strings[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId];
                        foxMeshDefinition.meshGroup = fmdl.strings[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId];
                    } //if
                    else
                    {
                        subFmdlGameObjects[i].name  = i + " - " + Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId]);
                        foxMeshDefinition.meshGroup = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId]);
                    } //else

                    break;
                } //if
            }     //for

            subFmdlGameObjects[i].transform.parent = fmdlGameObject.transform;
            SkinnedMeshRenderer meshRenderer = subFmdlGameObjects[i].AddComponent <SkinnedMeshRenderer>();

            meshRenderer.material          = materials[fmdl.section0Block3Entries[i].materialInstanceId].material;
            foxMeshDefinition.material     = materials[fmdl.section0Block3Entries[i].materialInstanceId].materialName;
            foxMeshDefinition.materialType = materials[fmdl.section0Block3Entries[i].materialInstanceId].materialType;

            Mesh mesh = new Mesh();
            foxMeshDefinition.mesh = mesh;

            mesh.vertices    = meshes[i].vertices;
            mesh.uv          = meshes[i].uv;
            mesh.uv2         = meshes[i].uv2;
            mesh.uv3         = meshes[i].uv3;
            mesh.uv4         = meshes[i].uv4;
            mesh.normals     = meshes[i].normals;
            mesh.tangents    = meshes[i].tangents;
            mesh.triangles   = meshes[i].faces;
            mesh.boneWeights = meshes[i].boneWeights;

            for (int j = 0; j < bones.Length; j++)
            {
                bindPoses[j] = bones[j].worldToLocalMatrix * subFmdlGameObjects[i].transform.localToWorldMatrix;
            } //for

            mesh.bindposes = bindPoses;

            meshRenderer.bones      = bones;
            meshRenderer.sharedMesh = mesh;

            fmdlGameObject.GetComponent <FoxModel>().definitions[i] = foxMeshDefinition;
            subFmdlGameObjects[i].AddComponent <MeshCollider>();
        } //for
        return(fmdlGameObject);
    }     //GetDataFromFmdl