/// <summary> /// Flatten all child materials into a one dimensional list /// </summary> /// <param name="material"></param> /// <returns></returns> public static IEnumerable <CryEngine_Core.Material> FlattenMaterials(CryEngine_Core.Material material) { if (material != null) { yield return(material); if (material.SubMaterials != null) { foreach (var subMaterial in material.SubMaterials.SelectMany(m => CryEngine.FlattenMaterials(m))) { yield return(subMaterial); } } } }
public CryEngine(String fileName, String dataDir) { this.InputFile = fileName; FileInfo inputFile = new FileInfo(fileName); List <FileInfo> inputFiles = new List <FileInfo> { inputFile }; // Validate file extension - handles .cgam / skinm if (!CryEngine._validExtensions.Contains(inputFile.Extension)) { Utils.Log(LogLevelEnum.Debug, "Warning: Unsupported file extension - please use a cga, cgf, chr or skin file"); throw new FileLoadException("Warning: Unsupported file extension - please use a cga, cgf, chr or skin file", fileName); } #region m-File Auto-Detection FileInfo mFile = new FileInfo(Path.ChangeExtension(fileName, String.Format("{0}m", inputFile.Extension))); if (mFile.Exists) { Utils.Log(LogLevelEnum.Debug, "Found mFile file {0}", mFile.Name); // Add to list of files to process inputFiles.Add(mFile); } #endregion this.Models = new List <CryEngine_Core.Model> { }; foreach (var file in inputFiles) { CryEngine_Core.Model model = CryEngine_Core.Model.FromFile(file.FullName); this.RootNode = this.RootNode ?? model.RootNode; this.Models.Add(model); } foreach (CryEngine_Core.ChunkMtlName mtlChunk in this.Models.SelectMany(a => a.ChunkMap.Values).Where(c => c.ChunkType == ChunkTypeEnum.MtlName)) { // Don't process child materials for now if (mtlChunk.MatType == MtlNameTypeEnum.Child) { continue; } String cleanName = mtlChunk.Name; FileInfo materialFile; if (mtlChunk.Name.Contains(@"/") || mtlChunk.Name.Contains(@"\")) { // The mtlname has a path. Most likely starts at the Objects directory. // string[] stringSeparators = new string[] { @"\", @"/" }; string[] result; // if objectdir is provided, check objectdir + mtlchunk.name if (dataDir != null) { materialFile = new FileInfo(Path.Combine(dataDir, mtlChunk.Name)); } else { // object dir not provided, but we have a path. Just grab the last part of the name and check the dir of the cga file result = mtlChunk.Name.Split(stringSeparators, StringSplitOptions.None); materialFile = new FileInfo(result[result.Length - 1]); } } else { var charsToClean = cleanName.ToCharArray().Intersect(Path.GetInvalidFileNameChars()).ToArray(); if (charsToClean.Length > 0) { foreach (Char character in charsToClean) { cleanName = cleanName.Replace(character.ToString(), ""); } } materialFile = new FileInfo(Path.Combine(Path.GetDirectoryName(fileName), cleanName)); } // First try relative to file being processed if (materialFile.Extension != "mtl") { materialFile = new FileInfo(Path.ChangeExtension(materialFile.FullName, "mtl")); } // Then try just the last part of the chunk, relative to the file being processed if (!materialFile.Exists) { materialFile = new FileInfo(Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileName(cleanName))); } if (materialFile.Extension != "mtl") { materialFile = new FileInfo(Path.ChangeExtension(materialFile.FullName, "mtl")); } // Then try relative to the ObjectDir if (!materialFile.Exists && dataDir != null) { materialFile = new FileInfo(Path.Combine(dataDir, cleanName)); } if (materialFile.Extension != "mtl") { materialFile = new FileInfo(Path.ChangeExtension(materialFile.FullName, "mtl")); } // Then try just the fileName.mtl if (!materialFile.Exists) { materialFile = new FileInfo(fileName); } if (materialFile.Extension != "mtl") { materialFile = new FileInfo(Path.ChangeExtension(materialFile.FullName, "mtl")); } // TODO: Try more paths CryEngine_Core.Material material = CryEngine_Core.Material.FromFile(materialFile); if (material != null) { // Utils.Log(LogLevelEnum.Debug, "Located material file {0}", materialFile.Name); //this.Materials = CryEngine.FlattenMaterials(material).Skip(1).ToArray(); this.Materials = CryEngine.FlattenMaterials(material).Where(m => m.Textures != null).ToArray(); Console.WriteLine("Flattened material {0}", material.Name); // Early return - we have the material map return; } else { // Utils.Log(LogLevelEnum.Debug, "Unable to locate material file {0}.mtl", mtlChunk.Name); } } // Utils.Log(LogLevelEnum.Debug, "Unable to locate any material file"); this.Materials = new CryEngine_Core.Material[] { }; }
public CryEngine(String fileName, String dataDir) { this.InputFile = fileName; FileInfo inputFile = new FileInfo(fileName); List <FileInfo> inputFiles = new List <FileInfo> { inputFile }; // Validate file extension - handles .cgam / skinm if (!CryEngine._validExtensions.Contains(inputFile.Extension)) { Utils.Log(LogLevelEnum.Debug, "Warning: Unsupported file extension - please use a cga, cgf, chr or skin file"); throw new FileLoadException("Warning: Unsupported file extension - please use a cga, cgf, chr or skin file", fileName); } #region m-File Auto-Detection FileInfo mFile = new FileInfo(Path.ChangeExtension(fileName, String.Format("{0}m", inputFile.Extension))); if (mFile.Exists) { Utils.Log(LogLevelEnum.Debug, "Found geometry file {0}", mFile.Name); // Add to list of files to process inputFiles.Add(mFile); } #endregion this.Models = new List <CryEngine_Core.Model> { }; foreach (var file in inputFiles) { // Each file (.cga and .cgam if applicable) will have its own RootNode. This can cause problems. .cga files with a .cgam files won't have geometry for the one root node. CryEngine_Core.Model model = CryEngine_Core.Model.FromFile(file.FullName); if (this.RootNode == null) { RootNode = model.RootNode; // This makes the assumption that we read the .cga file before the .cgam file. } //this.RootNode = this.RootNode ?? model.RootNode; this.Bones = this.Bones ?? model.Bones; this.Models.Add(model); } SkinningInfo = ConsolidateSkinningInfo(); // For eanch node with geometry info, populate that node's Mesh Chunk GeometryInfo with the geometry data. ConsolidateGeometryInfo(); #region Get material file name // Get the material file name foreach (CryEngine_Core.ChunkMtlName mtlChunk in this.Models.SelectMany(a => a.ChunkMap.Values).Where(c => c.ChunkType == ChunkTypeEnum.MtlName)) { // Don't process child or collision materials for now if (mtlChunk.MatType == MtlNameTypeEnum.Child || mtlChunk.MatType == MtlNameTypeEnum.Unknown1) { continue; } // The Replace part is for SC files that point to a _core material file that doesn't exist. String cleanName = mtlChunk.Name.Replace("_core", ""); FileInfo materialFile; if (mtlChunk.Name.Contains("default_body")) { // New MWO models for some crazy reason don't put the actual mtl file name in the mtlchunk. They just have /objects/mechs/default_body // have to assume that it's /objects/mechs/<mechname>/body/<mechname>_body.mtl. There is also a <mechname>.mtl that contains mtl // info for hitboxes, but not needed. // TODO: This isn't right. Fix it. var charsToClean = cleanName.ToCharArray().Intersect(Path.GetInvalidFileNameChars()).ToArray(); if (charsToClean.Length > 0) { foreach (Char character in charsToClean) { cleanName = cleanName.Replace(character.ToString(), ""); } } materialFile = new FileInfo(Path.Combine(Path.GetDirectoryName(fileName), cleanName)); } else if (mtlChunk.Name.Contains(@"/") || mtlChunk.Name.Contains(@"\")) { // The mtlname has a path. Most likely starts at the Objects directory. // string[] stringSeparators = new string[] { @"\", @"/" }; string[] result; // if objectdir is provided, check objectdir + mtlchunk.name if (dataDir != null) { materialFile = new FileInfo(Path.Combine(dataDir, mtlChunk.Name)); } else { // object dir not provided, but we have a path. Just grab the last part of the name and check the dir of the cga file result = mtlChunk.Name.Split(stringSeparators, StringSplitOptions.None); materialFile = new FileInfo(result[result.Length - 1]); } } else { var charsToClean = cleanName.ToCharArray().Intersect(Path.GetInvalidFileNameChars()).ToArray(); if (charsToClean.Length > 0) { foreach (Char character in charsToClean) { cleanName = cleanName.Replace(character.ToString(), ""); } } materialFile = new FileInfo(Path.Combine(Path.GetDirectoryName(fileName), cleanName)); } // First try relative to file being processed if (materialFile.Extension != ".mtl") { materialFile = new FileInfo(Path.ChangeExtension(materialFile.FullName, "mtl")); } // Then try just the last part of the chunk, relative to the file being processed if (!materialFile.Exists) { materialFile = new FileInfo(Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileName(cleanName))); } if (materialFile.Extension != ".mtl") { materialFile = new FileInfo(Path.ChangeExtension(materialFile.FullName, "mtl")); } // Then try relative to the ObjectDir if (!materialFile.Exists && dataDir != null) { materialFile = new FileInfo(Path.Combine(dataDir, cleanName)); } if (materialFile.Extension != ".mtl") { materialFile = new FileInfo(Path.ChangeExtension(materialFile.FullName, "mtl")); } // Then try just the fileName.mtl if (!materialFile.Exists) { materialFile = new FileInfo(fileName); } if (materialFile.Extension != ".mtl") { materialFile = new FileInfo(Path.ChangeExtension(materialFile.FullName, "mtl")); } // TODO: Try more paths // Populate CryEngine_Core.Material CryEngine_Core.Material material = CryEngine_Core.Material.FromFile(materialFile); if (material != null) { Utils.Log(LogLevelEnum.Debug, "Located material file {0}", materialFile.Name); this.Materials = CryEngine.FlattenMaterials(material).Where(m => m.Textures != null).ToArray(); if (this.Materials.Length == 1) { // only one material, so it's a material file with no submaterials. Check and set the name //Console.WriteLine("Single material found. setting name..."); this.Materials[0].Name = this.RootNode.Name; } // Early return - we have the material map return; } else { Utils.Log(LogLevelEnum.Debug, "Unable to locate material file {0}.mtl", mtlChunk.Name); } } #endregion Utils.Log(LogLevelEnum.Debug, "Unable to locate any material file"); this.Materials = new CryEngine_Core.Material[] { }; }