private static ToolResult CopyUsedTexturesObj(string objFile, string outputDirectory, string textureDirectory) { bool success = false; string message = ""; ObjData objData = ObjParser.TryParseObj(objFile); if (objData != null) { objData.UpdateMtlData(); MtlData mtlData = objData.Mtl; if (mtlData != null) { success = ObjModifier.CopyUsedTextures(mtlData, outputDirectory, textureDirectory); message = MessageBoxConstants.GetMessageExecutionGeneric(success); } else { message = MessageBoxConstants.MessageErrorCopyTextures + MessageBoxConstants.MessageMtlNotFound; } } else { message = MessageBoxConstants.GetMessageExecutionErrorParse(objFile); } return(new ToolResult(message, success)); }
private void LineReaded(string[] t) { switch (t[0]) { case "mtllib": LoadMtlLib(t[1]); break; case "v": AddVector3(Positions, t); break; case "vn": AddVector3(Normals, t); break; case "vt": AddVector3(TexCoords, t); break; case "o": CurrentName = t[1]; break; case "g": CurrentName = t[1]; break; case "usemtl": NewMesh("").Material = MtlData == null ? null : MtlData.Get(t[1]); break; // usemtl mat0 case "s": NewSubMesh(0).Name = CurrentName; break; // s 1 case "f": GetCurrentSubMesh().AddFace(t); break; // f 1/1/1 2/2/2 3/3/3 //Account for blender line output case "l": break; default: throw new FormatException(); } }
/// <summary> /// Delete every unused material the obj file /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="mtlData">Data parsed from the mtl file</param> public static bool DeleteUnusedMaterials(ObjData objData, MtlData mtlData) { if (mtlData == null) { return(false); } // Dictionary that associate every material to a list of groups Dictionary <string, List <int> > dictMaterialGroups = ObjUtils.GetDictMaterialGroups(objData); // Dictionary that associate every material of the mtl file to their index Dictionary <string, int> dictMaterialIndex = MtlUtils.GetDictMaterialIndex(mtlData); List <MaterialMtl> newMaterialsList = new List <MaterialMtl>(); foreach (KeyValuePair <string, List <int> > keyValue in dictMaterialGroups) { if (dictMaterialIndex.TryGetValue(keyValue.Key, out int index)) // We get the index of the material { MaterialMtl materialMtl = mtlData.MaterialsList[index]; newMaterialsList.Add(materialMtl); } } // Every material that wasnt used in a group was not added to the list mtlData.MaterialsList = newMaterialsList; return(true); }
/// <summary> /// Rename every material from the obj and mtl to make them unique after the merge /// </summary> /// <param name="objData"></param> /// <param name="mtlData"></param> /// <param name="indexMaterial"></param> private static void SetUniqueMaterialsNames(ObjData objData, MtlData mtlData, IntWrapper indexMaterial) { // Dictionary that associate every material to a list of groups Dictionary <string, List <int> > dictMaterialGroups = ObjUtils.GetDictMaterialGroups(objData); if (mtlData == null) // Need to rename the Materials in obj only { foreach (KeyValuePair <string, List <int> > keyValue in dictMaterialGroups) { SetUniqueMaterialsName(objData, keyValue.Value, indexMaterial); indexMaterial.Value++; } } else // Need to rename the Materials in both obj and mtl { // Dictionary that associate every material of the mtl file to their index Dictionary <string, int> dictMaterialIndex = MtlUtils.GetDictMaterialIndex(mtlData); foreach (KeyValuePair <string, List <int> > keyValue in dictMaterialGroups) { SetUniqueMaterialsName(objData, keyValue.Value, indexMaterial); if (dictMaterialIndex.TryGetValue(keyValue.Key, out int index)) // We get the index of the material { MaterialMtl materialMtl = mtlData.MaterialsList[index]; if (materialMtl.NewMtl != null) { materialMtl.NewMtl = GenericUtils.MergeIndexStr(indexMaterial.Value, materialMtl.NewMtl); } } indexMaterial.Value++; } } }
private static ToolResult ConvertObjToSmd(string objFile, string smdOutput, bool useTextureName) { bool success = false; string message = ""; ObjData objData = ObjParser.TryParseObj(objFile); if (objData != null) { objData.UpdateMtlData(); MtlData mtlData = objData.Mtl; if (mtlData == null) { // No MTL means the SMD will use a default material name for all objects useTextureName = false; } success = SmdExporter.WriteSmd(objData, mtlData, smdOutput, useTextureName); message = MessageBoxConstants.GetMessageExecutionCreation(success, smdOutput); } else { message = MessageBoxConstants.GetMessageExecutionErrorParse(objFile); } return(new ToolResult(message, success)); }
private static ToolResult DeleteUnusedMaterialsObj(string objFile, string objOutput) { bool success = false; string message = ""; ObjData objData = ObjParser.TryParseObj(objFile); if (objData != null) { objData.UpdateMtlData(); MtlData mtlData = objData.Mtl; if (mtlData != null) { ObjModifier.DeleteUnusedMaterials(objData, mtlData); success = ObjExporter.WriteObj(objData, mtlData, objOutput, makeMtl: true, useExistingMtl: true); message = MessageBoxConstants.GetMessageExecutionCreation(success, objOutput); } else { message = MessageBoxConstants.MessageErrorDeleteUnusedMaterials + MessageBoxConstants.MessageMtlNotFound; } } else { message = MessageBoxConstants.GetMessageExecutionErrorParse(objFile); } return(new ToolResult(message, success)); }
/// <summary> /// Try to delete all groups that use textures from a given list (compare the textures) /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="mtlData">Data parsed from the mtl file</param> /// <param name="listFileName">List of textures that should be matched</param> /// <returns>true if successful, false if error</returns> public static bool TryDeleteMatchingGroups(ObjData objData, MtlData mtlData, List <string> listFileName) { try { return(DeleteMatchingGroups(objData, mtlData, listFileName)); } catch { return(false); } }
public ObjMaterial(ShaderProgram program, MtlData aMtlData) { Name = aMtlData.Name; Transparency = (float)aMtlData.d; Ambient = aMtlData.Ka; Diffuse = aMtlData.Kd; Specular = aMtlData.Ks; SpecularCoefficient = (float)aMtlData.Ns; Illumination = (IlluminationMode)aMtlData.illum; Program = program; }
/// <summary> /// Iterate through the mtl to update every texture associated to each material in the obj /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="mtlData">Data parsed from the mtl file</param> public static void UpdateUsedTexture(ObjData objData, MtlData mtlData) { if (mtlData != null) { Dictionary <string, string> dictMaterialTexture = MtlUtils.GetDictMaterialTexture(mtlData); foreach (ObjectObj objectObj in objData.ObjectsList) { if (objectObj.MaterialName != null) { objectObj.TextureName = MtlUtils.GetTextureFromMaterial(dictMaterialTexture, objectObj.MaterialName); } } } }
/// <summary> /// Return a Hash List of all Textures used in the mtl /// </summary> /// <param name="mtlData"></param> /// <returns></returns> public static HashSet <string> GetListTextures(MtlData mtlData) { HashSet <string> textureList = new HashSet <string>(); foreach (MaterialMtl materialMtl in mtlData.MaterialsList) { if (materialMtl.NewMtl != null && materialMtl.MapKd != null) { textureList.Add(materialMtl.MapKd); } } return(textureList); }
/// <summary> /// Return a dictionary with each Material associated to a Texture /// </summary> /// <param name="mtlData"></param> /// <returns></returns> public static Dictionary <string, string> GetDictMaterialTexture(MtlData mtlData) { Dictionary <string, string> dict = new Dictionary <string, string>(); foreach (MaterialMtl materialMtl in mtlData.MaterialsList) { if (materialMtl.NewMtl != null && materialMtl.MapKd != null) { dict.Add(materialMtl.NewMtl, materialMtl.MapKd); } } return(dict); }
/// <summary> /// Merge together every materials in the array /// </summary> /// <param name="mtlData">Data parsed from the mtl file</param> /// <param name="textureName">Path to the texture file</param> /// <param name="materials">List of materials index</param> /// <returns></returns> private static MaterialMtl MergeMaterials(MtlData mtlData, string textureName, List <int> materials) { if (materials.Count >= 1) // Should always be the case { string relativeTexture = System.IO.Path.GetFileName(textureName); MaterialMtl materialMtl = new MaterialMtl(mtlData.MaterialsList[materials[0]]) { NewMtl = relativeTexture // The material name will be the same as the texture file }; return(materialMtl); } return(null); }
/// <summary> /// Sort materials alphabetically /// </summary> /// <param name="mtlData">Data parsed from the mtl file</param> public static bool SortMaterials(MtlData mtlData) { if (mtlData == null) { return(false); } foreach (MaterialMtl materialMtl in mtlData.MaterialsList) { if (materialMtl.NewMtl == null) // if a NewMtl is null, sorting would throw an exception { return(false); } } mtlData.MaterialsList.Sort((p, q) => p.NewMtl.CompareTo((q.NewMtl))); return(true); }
/// <summary> /// Return a dictionary with each Material associated to their indexes in the materials list /// </summary> /// <param name="mtlData"></param> /// <returns></returns> public static Dictionary <string, int> GetDictMaterialIndex(MtlData mtlData) { var dict = new Dictionary <string, int>(); int i = 0; foreach (MaterialMtl materialMtl in mtlData.MaterialsList) { if (materialMtl.NewMtl != null) { if (!dict.ContainsKey(materialMtl.NewMtl)) // The material wasn't added yet { dict.Add(materialMtl.NewMtl, i); } } i++; } return(dict); }
/// <summary> /// Parse the given mtl file /// </summary> /// <param name="file">File to parse</param> /// <returns></returns> public static MtlData ParseMtl(string file) { string[] lines = GenericUtils.RemoveBlankSpaces(FileUtilsShared.ReadFile(file)); // Read the file and remove blankspaces if (lines != null) { // Store all the other data to parse List <Tuple <string, string> > listKeysValues = GetListKeysValues(lines); MtlData mtlData = new MtlData(file); lines = null; // To let the garbage collector free the file from memory int i = 0; int length = listKeysValues.Count; while (i < length) { Tuple <string, string> keyValue = listKeysValues[i]; if (keyValue != null) // Never null unless error or final line { if (MtlUtils.IsNewMtl(keyValue.Item1)) { int materialStart = i; int materialEnd = GetIndexEnd(listKeysValues, length, materialStart); if (materialEnd != -1) { mtlData.MaterialsList.Add(MaterialData(listKeysValues, materialStart, materialEnd)); i = materialEnd; // Set to next material continue; } } } i++; } return(mtlData); } return(null); }
/// <summary> /// Create the mtl file with the given data /// </summary> /// <param name="mtlData">Data parsed from the mtl file</param> /// <param name="mtlFilename">Output path</param> /// <returns></returns> public static bool WriteMtl(MtlData mtlData, string mtlFilename) { try { using (StreamWriter mtl = new StreamWriter(mtlFilename)) { mtl.WriteLine(GenericUtils.GetCreditsFile()); // newmtl, Ns, Ka, Kd, Ks, Ni, d, illum, map_Kd, map_Ka, map_Ks, map_d foreach (MaterialMtl material in mtlData.MaterialsList) { mtl.WriteLine(MtlUtils.GetNewNewMtl(material.NewMtl)); mtl.WriteLine(MtlUtils.GetNewNs(material.Ns)); if (material.Ka != null) { mtl.WriteLine(MtlUtils.GetNewKa(material.Ka.ToString())); } else { mtl.WriteLine(MtlUtils.GetNewKa()); } if (material.Kd != null) { mtl.WriteLine(MtlUtils.GetNewKd(material.Kd.ToString())); } else { mtl.WriteLine(MtlUtils.GetNewKd()); } if (material.Ks != null) { mtl.WriteLine(MtlUtils.GetNewKs(material.Ks.ToString())); } else { mtl.WriteLine(MtlUtils.GetNewKs()); } if (material.Ke != null) { mtl.WriteLine(MtlUtils.GetNewKe(material.Ke.ToString())); } else { mtl.WriteLine(MtlUtils.GetNewKe()); } mtl.WriteLine(MtlUtils.GetNewNi(material.Ni)); mtl.WriteLine(MtlUtils.GetNewD(material.D)); mtl.WriteLine(MtlUtils.GetNewIllum(material.Illum)); if (material.MapKd != null) { mtl.WriteLine(MtlUtils.GetNewMapKd(material.MapKd)); } if (material.MapKa != null) { mtl.WriteLine(MtlUtils.GetNewMapKa(material.MapKa)); } if (material.MapKs != null) { mtl.WriteLine(MtlUtils.GetNewMapKs(material.MapKs)); } if (material.MapD != null) { mtl.WriteLine(MtlUtils.GetNewMapD(material.MapD)); } mtl.WriteLine(); // Empty line } } } catch { return(false); } return(true); }
/// <summary> /// Create the obj and mtl files with the given data /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="mtlData">Data parsed from the mtl file</param> /// <param name="objFilename">Output path</param> /// <param name="makeMtl">Create a mtl file</param> /// <param name="useExistingMtl">Use the mtlData to create the mtl file</param> /// <returns></returns> public static bool WriteObj(ObjData objData, MtlData mtlData, string objFilename, bool makeMtl, bool useExistingMtl) { // objFilename has the .obj extension string directory = System.IO.Path.GetDirectoryName(objFilename); string noExtension = System.IO.Path.GetFileNameWithoutExtension(objFilename); string mtlRelative = string.Format("{0}.mtl", noExtension); string mtlFilename = System.IO.Path.Combine(directory, mtlRelative); List <string> mtlLines = new List <string>(); // To store the lines to append to the mtl file try { using (StreamWriter obj = new StreamWriter(objFilename)) { // mtllib, o, v, vt, g, usemtl, s, f obj.WriteLine(GenericUtils.GetCreditsFile()); if (makeMtl) { obj.WriteLine(ObjUtils.GetNewMtlLib(mtlRelative)); } LocalIndexesObj indexesObj = new LocalIndexesObj(); foreach (ObjectObj objectObj in objData.ObjectsList) { if (objectObj.ObjectName != null) { obj.WriteLine(ObjUtils.GetNewObject(objectObj.ObjectName)); // o } foreach (Point p in objectObj.VerticesList) { obj.WriteLine(ObjUtils.GetNewCoord(p.ToString())); // v } foreach (UVCoordinates uv in objectObj.UVsList) { obj.WriteLine(ObjUtils.GetNewTexCoord(uv.ToString())); // vt } foreach (Vector v in objectObj.NormalsList) { obj.WriteLine(ObjUtils.GetNewVertNormal(v.ToString())); // vn } if (objectObj.GroupName != null) { obj.WriteLine(ObjUtils.GetNewGroup(objectObj.GroupName)); // g } if (objectObj.MaterialName != null) { obj.WriteLine(ObjUtils.GetNewUseMtl(objectObj.MaterialName)); // usemtl // Store lines in the mtl array to append to the file later mtlLines.Add(MtlUtils.GetMtlData(objectObj.MaterialName, objectObj.TextureName)); } if (objectObj.Smooth == -1) { obj.WriteLine(ObjUtils.GetNewSmoothGroup()); // s } else { obj.WriteLine(ObjUtils.GetNewSmoothGroup(objectObj.Smooth)); // s } foreach (VertIndexesObj vertIndexes in objectObj.VertIndexesList) { obj.WriteLine(ObjUtils.GetNewF(GetDataF(vertIndexes, indexesObj))); // f } indexesObj.vIndex += objectObj.VerticesList.Count; indexesObj.vtIndex += objectObj.UVsList.Count; indexesObj.vnIndex += objectObj.NormalsList.Count; } } } catch { return(false); } if (makeMtl) // If we dont delete materials { if (useExistingMtl && mtlData != null) // Use the parsed mtl { return(MtlExporter.WriteMtl(mtlData, mtlFilename)); } else // Create a mtl from the data obtained in the obj { return(MtlExporter.WriteMtl(mtlLines, mtlFilename)); } } return(true); }
/// <summary> /// Return the join of the TextureMaterial and MaterialGroup dictionaries /// </summary> /// <param name="objData"></param> /// <returns></returns> public static Dictionary <string, List <int> > GetDictTextureGroups(ObjData objData, MtlData mtlData, Dictionary <string, List <int> > dictTextureMaterials, Dictionary <string, List <int> > dictMaterialGroups) { Dictionary <string, List <int> > dictTextureGroups = new Dictionary <string, List <int> >(); foreach (KeyValuePair <string, List <int> > textureMaterial in dictTextureMaterials) { List <int> groupIdList = new List <int>(); foreach (int materialId in textureMaterial.Value) { string materialName = mtlData.MaterialsList[materialId].NewMtl; if (dictMaterialGroups.TryGetValue(materialName, out List <int> groups)) { if (groups != null) { foreach (int groupId in groups) { groupIdList.Add(groupId); } } } } dictTextureGroups.Add(textureMaterial.Key, groupIdList); // The texture is associated a list of group } return(dictTextureGroups); }
/// <summary> /// Create the smd file with the given data /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="mtlData">Data parsed from the mtl file</param> /// <param name="smdFilename">Output path</param> /// <returns></returns> public static bool WriteSmd(ObjData objData, MtlData mtlData, string smdFilename, bool useTextureName) { if (useTextureName) { ObjModifier.UpdateUsedTexture(objData, mtlData); } try { using (StreamWriter smd = new StreamWriter(smdFilename)) { // version 1 smd.WriteLine(SmdUtils.GetNewHeader()); // nodes smd.WriteLine(SmdUtils.GetNewNodes()); smd.WriteLine(SmdUtils.GetNewBone()); smd.WriteLine(SmdUtils.GetNewEnd()); // skeleton smd.WriteLine(SmdUtils.GetNewSkeleton()); smd.WriteLine(SmdUtils.GetNewTime()); smd.WriteLine(SmdUtils.GetNewPosition()); smd.WriteLine(SmdUtils.GetNewEnd()); // triangles smd.WriteLine(SmdUtils.GetNewTriangles()); foreach (ObjectObj objectObj in objData.ObjectsList) { string smdMaterial = GetSmdMaterial(objectObj.MaterialName, objectObj.TextureName, useTextureName); int coordLength = objectObj.VerticesList.Count; int uvLength = objectObj.UVsList.Count; int normalLength = objectObj.NormalsList.Count; foreach (VertIndexesObj vertIndexes in objectObj.VertIndexesList) { smd.WriteLine(smdMaterial); foreach (VertIndexObj vertIndex in vertIndexes.VertIndexList) { string coordStr = DefaultCoord; string uvStr = DefaultUV; string normalStr = DefaultCoord; if (vertIndex.V != null) { if (vertIndex.V < coordLength) // Should always be the case { // Source Engine use 'z' for the up-down axis coordStr = objectObj.VerticesList[(int)vertIndex.V].ToSmd(); } } if (vertIndex.Vt != null) { if (vertIndex.Vt < uvLength) // Should always be the case { uvStr = objectObj.UVsList[(int)vertIndex.Vt].ToString(); } } if (vertIndex.Vn != null) { if (vertIndex.Vn < normalLength) // Should always be the case { // Source Engine use 'z' for the up-down axis normalStr = objectObj.NormalsList[(int)vertIndex.Vn].ToSmd(); } } smd.WriteLine(SmdUtils.GetNewTriangle(0, coordStr, normalStr, uvStr)); } } } smd.WriteLine(SmdUtils.GetNewEnd()); } } catch { return(false); } return(true); }
/// <summary> /// Return a tuple with a dictionary of each Texture associated to the indexes of their Materials /// and a list of Materials without any texture /// </summary> /// <param name="mtlData"></param> /// <returns></returns> public static Tuple <Dictionary <string, List <int> >, List <int> > GetTupleDictTextureMaterials(MtlData mtlData) { Dictionary <string, List <int> > dict = new Dictionary <string, List <int> >(); List <int> untexturedMaterials = new List <int>(); int i = 0; foreach (MaterialMtl materialMtl in mtlData.MaterialsList) { if (materialMtl.NewMtl != null) { if (materialMtl.MapKd != null) { if (dict.TryGetValue(materialMtl.MapKd, out List <int> materials)) { materials.Add(i); // If the keyvalue already exists, we add the new index } else { dict.Add(materialMtl.MapKd, new List <int>() { i }); // Otherwise, we create the new keyvalue } } else // Material without any texture { untexturedMaterials.Add(i); } } i++; } return(new Tuple <Dictionary <string, List <int> >, List <int> >(dict, untexturedMaterials)); }
private static ToolResult ModifyObj(string objFile, string objOutput, ObjOptions objOptions, Dictionary <string, string> inputs) { bool success = false; bool warn = false; StringBuilder sb = new StringBuilder(); ObjData objData = ObjParser.TryParseObj(objFile); if (objData != null) { objData.UpdateMtlData(); MtlData mtlData = objData.Mtl; if (objOptions.HasFlag(ObjOptions.BlackList)) { // Delete Blacklisted Objects first if (mtlData != null) { if (!ObjModifier.TryDeleteMatchingGroups(objData, mtlData, texturesList)) { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorDeleteBlackList + MessageBoxConstants.MessageErrorExecution); } } else { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorDeleteBlackList + MessageBoxConstants.MessageMtlNotFound); } } ObjModifier.CalculateNormal(objData); if (objOptions.HasFlag(ObjOptions.UniformScale)) { if (inputs.TryGetValue(DictConstants.ScaleValue, out string scaleStr)) { if (Double.TryParse(scaleStr, out double scaleValue)) { ObjModifier.UniformScale(objData, scaleValue); // Scale Model } else { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorScale + MessageBoxConstants.MessageInvalidScaleValue); } } } if (objOptions.HasFlag(ObjOptions.NonUniformScale)) { bool isScaleValueX = false; bool isScaleValueY = false; bool isScaleValueZ = false; double scaleValueX = 0.0; double scaleValueY = 0.0; double scaleValueZ = 0.0; if (inputs.TryGetValue(DictConstants.ScaleValueX, out string scaleStr)) { isScaleValueX = Double.TryParse(scaleStr, out scaleValueX); } if (inputs.TryGetValue(DictConstants.ScaleValueY, out scaleStr)) { isScaleValueY = Double.TryParse(scaleStr, out scaleValueY); } if (inputs.TryGetValue(DictConstants.ScaleValueZ, out scaleStr)) { isScaleValueZ = Double.TryParse(scaleStr, out scaleValueZ); } if (isScaleValueX && isScaleValueY && isScaleValueZ) { // Scale Model ObjModifier.NonUniformScale(objData, scaleValueX, scaleValueY, scaleValueZ); } else { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorScale + MessageBoxConstants.MessageInvalidScaleValues); } } if (objOptions.HasFlag(ObjOptions.Rotate)) { bool isRotateValueX = false; bool isRotateValueY = false; bool isRotateValueZ = false; double rotateValueX = 0.0; double rotateValueY = 0.0; double rotateValueZ = 0.0; if (inputs.TryGetValue(DictConstants.RotateValueX, out string rotationStr)) { isRotateValueX = Double.TryParse(rotationStr, out rotateValueX); } if (inputs.TryGetValue(DictConstants.RotateValueY, out rotationStr)) { isRotateValueY = Double.TryParse(rotationStr, out rotateValueY); } if (inputs.TryGetValue(DictConstants.RotateValueZ, out rotationStr)) { isRotateValueZ = Double.TryParse(rotationStr, out rotateValueZ); } if (isRotateValueX && isRotateValueY && isRotateValueZ) { // Rotate Model ObjModifier.RotateModel(objData, rotateValueX, rotateValueY, rotateValueZ); } else { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorRotate + MessageBoxConstants.MessageInvalidRotateValues); } } if (objOptions.HasFlag(ObjOptions.ReverseVertex)) { // Reverse Vertex Order ObjModifier.ReverseVertexOrder(objData); } if (objOptions.HasFlag(ObjOptions.Merge)) { if (mtlData != null) { // Merge groups and materials ObjModifier.MergeGroups(objData, mtlData); } else { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorMergeGroups + MessageBoxConstants.MessageMtlNotFound); } } if (objOptions.HasFlag(ObjOptions.Sort)) { // Sort groups if (!ObjModifier.SortGroups(objData)) { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorSortGroups + MessageBoxConstants.MessageInvalidGroupName); } if (mtlData != null) { // Sort materials if (!ObjModifier.SortMaterials(mtlData)) { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorSortMaterials + MessageBoxConstants.MessageInvalidMaterialName); } } else { warn = true; sb.AppendLine(MessageBoxConstants.MessageErrorSortMaterials + MessageBoxConstants.MessageMtlNotFound); } } success = ObjExporter.WriteObj(objData, mtlData, objOutput, makeMtl: true, useExistingMtl: true); sb.Append(MessageBoxConstants.GetMessageExecutionCreation(success, objOutput)); } else { sb.Append(MessageBoxConstants.GetMessageExecutionErrorParse(objFile)); } return(new ToolResult(sb.ToString(), success, warn)); }
/// <summary> /// Delete all groups that use textures from a given list (compare the textures) /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="mtlData">Data parsed from the mtl file</param> /// <param name="listFileName">List of textures that should be matched</param> public static bool DeleteMatchingGroups(ObjData objData, MtlData mtlData, List <string> listFileName) { if (mtlData == null) { return(false); } List <BitmapStoreData> imgList = BitmapStoreData.GetListBitmapStoreData(listFileName); var tupleTextureMaterials = MtlUtils.GetTupleDictTextureMaterials(mtlData); // Dictionary that associate every texture to a list of materials Dictionary <string, List <int> > dictTextureMaterials = tupleTextureMaterials.Item1; // List of materials without any texture List <int> untexturedMaterials = tupleTextureMaterials.Item2; // Dictionary that associate every material to a list of groups Dictionary <string, List <int> > dictMaterialGroups = ObjUtils.GetDictMaterialGroups(objData); // Dictionary that associate every texture to a list of groups Dictionary <string, List <int> > dictTextureGroups = ObjUtils.GetDictTextureGroups(objData, mtlData, dictTextureMaterials, dictMaterialGroups); List <ObjectObj> newObjectsList = new List <ObjectObj>(); List <MaterialMtl> newMaterialsList = new List <MaterialMtl>(); string srcDir = System.IO.Path.GetDirectoryName(mtlData.FilePath); foreach (KeyValuePair <string, List <int> > keyValue in dictTextureGroups) { List <int> groups = keyValue.Value; if (groups != null) { if (groups.Count >= 1) // Should always be the case { string texturePath = keyValue.Key; if (!System.IO.Path.IsPathRooted(texturePath)) // Not an absolute path { texturePath = System.IO.Path.Combine(srcDir, texturePath); } System.Drawing.Bitmap img = ImageUtilsShared.CreateBitmap(texturePath); if (img != null) { BitmapStoreData bmpData = new BitmapStoreData(img); if (bmpData.BData != null) { if (!ImageUtilsShared.SamePictures(imgList, bmpData)) // Not the same image { // We can keep all these groups and materials foreach (int groupId in groups) { ObjectObj objectObj = objData.ObjectsList[groupId]; newObjectsList.Add(objectObj); // Insert the object in the list } if (dictTextureMaterials.TryGetValue(keyValue.Key, out List <int> materials)) { if (materials != null) { foreach (int materialId in materials) { MaterialMtl materialMtl = mtlData.MaterialsList[materialId]; newMaterialsList.Add(materialMtl); // Insert the material in the list } } } } bmpData.UnlockBits(); } } } } } foreach (int materialId in untexturedMaterials) // The untextured materials { MaterialMtl materialMtl = mtlData.MaterialsList[materialId]; newMaterialsList.Add(materialMtl); // Insert material in the list if (dictMaterialGroups.TryGetValue(materialMtl.NewMtl, out List <int> groups)) { if (groups != null) { foreach (int groupId in groups) { ObjectObj objectObj = objData.ObjectsList[groupId]; newObjectsList.Add(objectObj); // Insert the object in the list } } } } BitmapStoreData.BitmapDataUnlock(imgList); objData.ObjectsList = newObjectsList; mtlData.MaterialsList = newMaterialsList; return(true); }
/// <summary> /// Merge together groups that share a texture /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="mtlData">Data parsed from the mtl file</param> public static bool MergeGroups(ObjData objData, MtlData mtlData) { if (mtlData == null) { return(false); } var tupleTextureMaterials = MtlUtils.GetTupleDictTextureMaterials(mtlData); // Dictionary that associate every texture to a list of materials Dictionary <string, List <int> > dictTextureMaterials = tupleTextureMaterials.Item1; // List of materials without any texture List <int> untexturedMaterials = tupleTextureMaterials.Item2; // Dictionary that associate every material to a list of groups Dictionary <string, List <int> > dictMaterialGroups = ObjUtils.GetDictMaterialGroups(objData); // Dictionary that associate every texture to a list of groups Dictionary <string, List <int> > dictTextureGroups = ObjUtils.GetDictTextureGroups(objData, mtlData, dictTextureMaterials, dictMaterialGroups); List <ObjectObj> newObjectsList = new List <ObjectObj>(); List <MaterialMtl> newMaterialsList = new List <MaterialMtl>(); foreach (KeyValuePair <string, List <int> > keyValue in dictTextureGroups) // Textured groups { // Merge the groups ObjectObj objectObj = MergeObjects(objData, keyValue.Key, keyValue.Value); newObjectsList.Add(objectObj); if (dictTextureMaterials.TryGetValue(keyValue.Key, out List <int> materials)) { if (materials != null) { // Merge the materials MaterialMtl materialMtl = MergeMaterials(mtlData, keyValue.Key, materials); newMaterialsList.Add(materialMtl); } } } foreach (int materialId in untexturedMaterials) // The untextured materials { MaterialMtl materialMtl = mtlData.MaterialsList[materialId]; newMaterialsList.Add(materialMtl); // Insert material in the list if (dictMaterialGroups.TryGetValue(materialMtl.NewMtl, out List <int> groups)) { if (groups != null) { foreach (int groupId in groups) { ObjectObj objectObj = objData.ObjectsList[groupId]; newObjectsList.Add(objectObj); // Insert the object in the list } } } } objData.ObjectsList = newObjectsList; mtlData.MaterialsList = newMaterialsList; return(true); }
/// <summary> /// Copy every texture used by the obj file /// </summary> /// <param name="mtlData">Data parsed from the mtl file</param> /// <param name="outputFolder">Where the textures will be copied</param> /// <param name="srcDir">Where the textures are located</param> /// <returns>True if successful</returns> public static bool CopyUsedTextures(MtlData mtlData, string outputFolder, string srcDir) { if (mtlData == null) { // No Mtl to read texture data return(false); } bool relative = false; if (srcDir == null) { // If a textureDirectory was not specified, the textures are found relative to the mtl file srcDir = System.IO.Path.GetDirectoryName(mtlData.FilePath); relative = true; } if (!System.IO.Directory.Exists(srcDir)) { // The source directory doesn't exist return(false); } if (!System.IO.Directory.Exists(outputFolder)) { if (!FileUtilsShared.TryCreateDirectory(outputFolder)) { // Impossible to create the destination directory return(false); } } HashSet <string> texturesList = MtlUtils.GetListTextures(mtlData); foreach (string texture in texturesList) { string srcFile; string destFile = System.IO.Path.Combine(outputFolder, System.IO.Path.GetFileName(texture)); if (relative) // The path to the texture is inside the material { if (System.IO.Path.IsPathRooted(texture)) // Absolute path to the picture { srcFile = texture; } else // Relative to the mtl { srcFile = System.IO.Path.Combine(srcDir, texture); } } else // We find the texture in a given folder { srcFile = System.IO.Path.Combine(srcDir, System.IO.Path.GetFileName(texture)); } if (!destFile.Equals(srcFile)) // Destination file is not the Source file { if (System.IO.File.Exists(srcFile)) { if (System.IO.File.Exists(destFile)) // The destination file already exists, we need to delete it { if (!FileUtilsShared.TryDeleteFile(destFile)) { continue; // Impossible to delete the file, we go to the next texture } } FileUtilsShared.TryCopyFile(srcFile, destFile); } } } return(true); }