/// <summary> /// Gets the version of the selected item. /// </summary> /// <param name="selectedCategory">The category which contains the selected item </param> /// <param name="item">The selected items data</param> /// <param name="isSecondary">Use secondary item data</param> /// <returns>The version of the selected item</returns> public static Tuple <string, string> GetVersion(string selectedCategory, ItemData item, bool isSecondary) { if (int.Parse(item.ItemCategory) < 22 || selectedCategory.Equals(Strings.Pets) || selectedCategory.Equals(Strings.Mounts) || selectedCategory.Equals(Strings.Minions) || selectedCategory.Equals(Strings.Monster) || selectedCategory.Equals(Strings.DemiHuman)) { var slotID = Info.slotID[selectedCategory]; var type = Helper.GetCategoryType(selectedCategory); string itemID, body, variant; if (isSecondary) { itemID = item.SecondaryModelID; body = item.SecondaryModelBody; variant = item.SecondaryModelVariant; } else { itemID = item.PrimaryModelID; body = item.PrimaryModelBody; variant = item.PrimaryModelVariant; } int offset = 0; if (type.Equals("monster")) { offset = Helper.GetDataOffset(FFCRC.GetHash(string.Format(Strings.MonsterIMCFolder, itemID, body)), FFCRC.GetHash(string.Format(Strings.MonsterIMCFile, body)), Strings.ItemsDat); } else if (type.Equals("food") || type.Equals("weapon")) { offset = Helper.GetDataOffset(FFCRC.GetHash(string.Format(Strings.WeapIMCFolder, itemID, body)), FFCRC.GetHash(string.Format(Strings.WeapIMCFile, body)), Strings.ItemsDat); } else if (type.Equals("equipment")) { offset = Helper.GetDataOffset(FFCRC.GetHash(string.Format(Strings.EquipIMCFolder, itemID)), FFCRC.GetHash(string.Format(Strings.EquipIMCFile, itemID)), Strings.ItemsDat); } else if (type.Equals("accessory")) { offset = Helper.GetDataOffset(FFCRC.GetHash(string.Format(Strings.AccIMCFolder, itemID)), FFCRC.GetHash(string.Format(Strings.AccIMCFile, itemID)), Strings.ItemsDat); } else { offset = Helper.GetDataOffset(FFCRC.GetHash("chara/" + type + "/" + type.Substring(0, 1) + itemID), FFCRC.GetHash(type.Substring(0, 1) + itemID + ".imc"), Strings.ItemsDat); } if (offset != 0) { return(FindVersion(offset, slotID, variant, type)); } else { return(new Tuple <string, string>("0001", "0000")); } } else { return(new Tuple <string, string>("0001", "0000")); } }
/// <summary> /// Parses the MTRL file for items that contains types /// </summary> /// <param name="item">currently selected item</param> /// <param name="race">currently selected race</param> /// <param name="part">currently selected part</param> /// <param name="type">currently selected type</param> /// <param name="IMCVersion">version of the selected item</param> /// <param name="selectedCategory">The category of the item</param> /// <returns>A tuple containing the MTRLInfo and Observable Collection containing texture map names</returns> public static Tuple <MTRLData, ObservableCollection <ComboBoxInfo> > GetMTRLDatafromType(ItemData item, ComboBoxInfo race, string part, string type, string IMCVersion, string selectedCategory) { string MTRLFolder, MTRLFile; string MTRLPath = ""; bool isUncompressed = true; int offset = 0; if (item.ItemName.Equals(Strings.Face)) { MTRLFolder = String.Format(Strings.FaceMtrlFolder, race.ID, part.PadLeft(4, '0')); MTRLFile = String.Format(Strings.FaceMtrlFile, race.ID, part.PadLeft(4, '0'), Info.FaceTypes[type]); offset = Helper.GetItemOffset(FFCRC.GetHash(MTRLFolder), FFCRC.GetHash(MTRLFile)); MTRLPath = MTRLFolder + "/" + MTRLFile; isUncompressed = true; } else if (item.ItemName.Equals(Strings.Hair)) { MTRLFolder = String.Format(Strings.HairMtrlFolder, race.ID, part.PadLeft(4, '0')); isUncompressed = true; if (type.Equals(Strings.Accessory)) { MTRLFile = String.Format(Strings.HairMtrlFile, race.ID, part.PadLeft(4, '0'), Info.HairTypes[type], "b"); } else { MTRLFile = String.Format(Strings.HairMtrlFile, race.ID, part.PadLeft(4, '0'), Info.HairTypes[type], "a"); } MTRLPath = MTRLFolder + "/" + MTRLFile; offset = Helper.GetItemOffset(FFCRC.GetHash(MTRLFolder), FFCRC.GetHash(MTRLFile)); } else if (selectedCategory.Equals(Strings.Mounts)) { isUncompressed = false; if (item.PrimaryMTRLFolder.Contains("demihuman")) { MTRLFile = String.Format(Strings.DemiMtrlFile, item.PrimaryModelID.PadLeft(4, '0'), item.PrimaryModelBody.PadLeft(4, '0'), type); } else { MTRLFile = String.Format(Strings.MonsterMtrlFile, item.PrimaryModelID.PadLeft(4, '0'), item.PrimaryModelBody.PadLeft(4, '0'), part); } MTRLPath = item.PrimaryMTRLFolder + IMCVersion + "/" + MTRLFile; offset = Helper.GetItemOffset(FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion), FFCRC.GetHash(MTRLFile)); } var mtrlInfo = GetMTRLInfo(offset, isUncompressed); mtrlInfo.MTRLPath = MTRLPath; mtrlInfo.MTRLOffset = offset; return(new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, mtrlInfo.TextureMaps)); }
/// <summary> /// Gets the MTRL offset of decal files /// </summary> /// <param name="decalType">Type of decal</param> /// <param name="decalNum">The decal number</param> /// <returns>The mtrl offset of the decal file</returns> public static int GetDecalOffset(string decalType, string decalNum) { string decalFolder, decalFile; if (decalType.Equals(Strings.Face_Paint)) { decalFolder = Strings.FacePaintFolder; decalFile = String.Format(Strings.FacePaintFile, decalNum); } else { decalFolder = Strings.EquipDecalFolder; decalFile = String.Format(Strings.EquipDecalFile, decalNum.PadLeft(3, '0')); } return(Helper.GetItemOffset(FFCRC.GetHash(decalFolder), FFCRC.GetHash(decalFile))); }
/// <summary> /// Sets the data for the part combo box /// </summary> private void BodyComboBoxChanged() { is3DLoaded = false; bool isDemiHuman = false; if (CompositeVM != null && !disposing) { disposing = true; CompositeVM.Dispose(); } if (selectedItem.PrimaryMTRLFolder != null && selectedItem.PrimaryMTRLFolder.Contains("demihuman")) { isDemiHuman = true; } List <ComboBoxInfo> cbi = new List <ComboBoxInfo>(); string type = Helper.GetCategoryType(selectedCategory); string MDLFolder = ""; string MDLFile = ""; string[] abrParts = null; if (type.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = string.Format(Strings.BodyMDLFolder, SelectedRace.ID, SelectedBody.ID.PadLeft(4, '0')); MDLFile = string.Format(Strings.BodyMDLFile, SelectedRace.ID, SelectedBody.ID.PadLeft(4, '0'), "{0}"); abrParts = new string[5] { "met", "glv", "dwn", "sho", "top" }; } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = string.Format(Strings.FaceMDLFolder, SelectedRace.ID, SelectedBody.ID.PadLeft(4, '0')); MDLFile = string.Format(Strings.FaceMDLFile, SelectedRace.ID, SelectedBody.ID.PadLeft(4, '0'), "{0}"); abrParts = new string[3] { "fac", "iri", "etc" }; } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = string.Format(Strings.HairMDLFolder, SelectedRace.ID, SelectedBody.ID.PadLeft(4, '0')); MDLFile = string.Format(Strings.HairMDLFile, SelectedRace.ID, SelectedBody.ID.PadLeft(4, '0'), "{0}"); abrParts = new string[2] { "hir", "acc" }; } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = string.Format(Strings.TailMDLFolder, SelectedRace.ID, SelectedBody.ID.PadLeft(4, '0')); MDLFile = string.Format(Strings.TailMDLFile, SelectedRace.ID, SelectedBody.ID.PadLeft(4, '0'), "{0}"); abrParts = new string[1] { "til" }; } var fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(MDLFolder)); foreach (string abrPart in abrParts) { var file = String.Format(MDLFile, abrPart); if (fileHashList.Contains(FFCRC.GetHash(file))) { if (selectedItem.ItemName.Equals(Strings.Body)) { cbi.Add(new ComboBoxInfo() { Name = Info.slotAbr.FirstOrDefault(x => x.Value == abrPart).Key, ID = abrPart, IsNum = false }); } else if (selectedItem.ItemName.Equals(Strings.Face)) { cbi.Add(new ComboBoxInfo() { Name = Info.FaceTypes.FirstOrDefault(x => x.Value == abrPart).Key, ID = abrPart, IsNum = false }); } else if (selectedItem.ItemName.Equals(Strings.Hair)) { cbi.Add(new ComboBoxInfo() { Name = Info.HairTypes.FirstOrDefault(x => x.Value == abrPart).Key, ID = abrPart, IsNum = false }); } else if (selectedItem.ItemName.Equals(Strings.Tail)) { cbi.Add(new ComboBoxInfo() { Name = Strings.Tail, ID = abrPart, IsNum = false }); } } } } else if (isDemiHuman) { MDLFolder = string.Format(Strings.DemiMDLFolder, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); MDLFile = string.Format(Strings.DemiMDLFile, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody, "{0}"); abrParts = new string[5] { "met", "glv", "dwn", "sho", "top" }; var fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(MDLFolder)); foreach (string abrPart in abrParts) { var file = String.Format(MDLFile, abrPart); if (fileHashList.Contains(FFCRC.GetHash(file))) { cbi.Add(new ComboBoxInfo() { Name = Info.slotAbr.FirstOrDefault(x => x.Value == abrPart).Key, ID = abrPart, IsNum = false }); } } } else if (type.Equals("weapon")) { if (selectedItem.SecondaryModelID != null) { cbi.Add(new ComboBoxInfo() { Name = "Primary", ID = "Primary", IsNum = false }); cbi.Add(new ComboBoxInfo() { Name = "Secondary", ID = "Secondary", IsNum = false }); } else { cbi.Add(new ComboBoxInfo() { Name = "Primary", ID = "Primary", IsNum = false }); } } else if (type.Equals("monster")) { cbi.Add(new ComboBoxInfo() { Name = "1", ID = "1", IsNum = false }); } else { cbi.Add(new ComboBoxInfo() { Name = "-", ID = "-", IsNum = false }); } PartComboBox = new ObservableCollection <ComboBoxInfo>(cbi); PartIndex = 0; if (cbi.Count <= 1) { PartEnabled = false; } else { PartEnabled = true; } }
/// <summary> /// Sets the data for the body combo box /// </summary> private void RaceComboBoxChanged() { is3DLoaded = false; if (CompositeVM != null && !disposing) { disposing = true; CompositeVM.Dispose(); } List <ComboBoxInfo> cbi = new List <ComboBoxInfo>(); string categoryType = Helper.GetCategoryType(selectedCategory); string MDLFolder = ""; if (categoryType.Equals("weapon")) { cbi.Add(new ComboBoxInfo() { Name = selectedItem.PrimaryModelBody, ID = selectedItem.PrimaryModelBody, IsNum = false }); } else if (categoryType.Equals("food")) { cbi.Add(new ComboBoxInfo() { Name = selectedItem.PrimaryModelBody, ID = selectedItem.PrimaryModelBody, IsNum = false }); } else if (categoryType.Equals("accessory")) { cbi.Add(new ComboBoxInfo() { Name = "-", ID = "-", IsNum = false }); } else if (categoryType.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = string.Format(Strings.BodyMDLFolder, SelectedRace.ID, "{0}"); } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = string.Format(Strings.FaceMDLFolder, SelectedRace.ID, "{0}"); } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = string.Format(Strings.HairMDLFolder, SelectedRace.ID, "{0}"); } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = string.Format(Strings.TailMDLFolder, SelectedRace.ID, "{0}"); } } else if (categoryType.Equals("monster")) { cbi.Add(new ComboBoxInfo() { Name = selectedItem.PrimaryModelBody, ID = selectedItem.PrimaryModelBody, IsNum = false }); } else { cbi.Add(new ComboBoxInfo() { Name = "-", ID = "-", IsNum = false }); } if (categoryType.Equals("character")) { for (int i = 0; i < 50; i++) { string folder = String.Format(MDLFolder, i.ToString().PadLeft(4, '0')); if (Helper.FolderExists(FFCRC.GetHash(folder))) { cbi.Add(new ComboBoxInfo() { Name = i.ToString(), ID = i.ToString(), IsNum = true }); if (selectedItem.ItemName.Equals(Strings.Body)) { break; } } } } BodyComboBox = new ObservableCollection <ComboBoxInfo>(cbi); BodyIndex = 0; if (cbi.Count <= 1) { BodyEnabled = false; } else { BodyEnabled = true; } }
/// <summary> /// View Model for model view. /// </summary> /// <param name="item">the currently selcted item.</param> /// <param name="category">The category of the item.</param> public ModelViewModel(ItemData item, string category) { selectedItem = item; selectedCategory = category; try { string categoryType = Helper.GetCategoryType(selectedCategory); List <ComboBoxInfo> cbi = new List <ComboBoxInfo>(); string MDLFolder = ""; string MDLFile = ""; if (categoryType.Equals("weapon") || categoryType.Equals("food")) { MDLFolder = ""; cbi.Add(new ComboBoxInfo() { Name = Strings.All, ID = Strings.All, IsNum = false }); } else if (categoryType.Equals("accessory")) { MDLFolder = string.Format(Strings.AccMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.AccMDLFile, "{0}", selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else if (categoryType.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = Strings.BodyMDLFolder; } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = Strings.FaceMDLFolder; } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = Strings.HairMDLFolder; } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = Strings.TailMDLFolder; } } else if (categoryType.Equals("monster")) { cbi.Add(new ComboBoxInfo() { Name = Strings.All, ID = Strings.All, IsNum = false }); } else { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.EquipMDLFile, "{0}", selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } var fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(MDLFolder)); if (!categoryType.Equals("weapon") && !categoryType.Equals("monster")) { foreach (string raceID in Info.IDRace.Keys) { if (categoryType.Equals("character")) { for (int i = 0; i < 3; i++) { var mdlFolder = String.Format(MDLFolder, raceID, i.ToString().PadLeft(4, '0')); if (Helper.FolderExists(FFCRC.GetHash(mdlFolder))) { cbi.Add(new ComboBoxInfo() { Name = Info.IDRace[raceID], ID = raceID, IsNum = false }); break; } } } else { var mdlFile = String.Format(MDLFile, raceID); var fileHash = FFCRC.GetHash(mdlFile); if (fileHashList.Contains(fileHash)) { cbi.Add(new ComboBoxInfo() { Name = Info.IDRace[raceID], ID = raceID, IsNum = false }); } } } } RaceComboBox = new ObservableCollection <ComboBoxInfo>(cbi); RaceIndex = 0; if (cbi.Count <= 1) { RaceEnabled = false; } else { RaceEnabled = true; } } catch (Exception ex) { MessageBox.Show("[Main] tab 3D Error \n" + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }
public ModListModel ParseEntry(JsonEntry entry) { ModListModel mlm = new ModListModel(); string race, map, part, type; if (entry.fullPath.Contains("mt_")) { Debug.WriteLine(entry.fullPath); } if (entry.fullPath.Contains("weapon") || entry.fullPath.Contains("accessory") || entry.fullPath.Contains("decal") || entry.fullPath.Contains("vfx") || entry.fullPath.Contains("ui/")) { race = Strings.All; } else if (entry.fullPath.Contains("monster") || entry.fullPath.Contains("demihuman")) { race = Strings.Monster; } else { race = entry.fullPath.Substring(entry.fullPath.LastIndexOf('/')); if (entry.fullPath.Contains("mt_") && entry.fullPath.Contains("_acc_")) { race = race.Substring(race.IndexOf("_") + 2, 4); } else if ((entry.fullPath.Contains("_fac_") || entry.fullPath.Contains("_etc_") || entry.fullPath.Contains("_acc_")) && Properties.Settings.Default.DX_Ver.Equals(Strings.DX11)) { race = race.Substring(race.LastIndexOf("--c") + 3, 4); } else if (entry.fullPath.Contains("_fac_") || entry.fullPath.Contains("_etc_") || entry.fullPath.Contains("_acc_")) { race = race.Substring(race.LastIndexOf("/c") + 2, 4); } else if (entry.fullPath.Contains("_c_")) { race = race.Substring(race.IndexOf("_c") + 2, 4); } else { if (entry.fullPath.Contains(".mdl") && entry.fullPath.Contains("_fac")) { race = race.Substring(race.IndexOf('c') + 1, 4); } else { race = race.Substring(race.LastIndexOf('c') + 1, 4); } } if (entry.fullPath.Contains("mt_")) { Debug.WriteLine(race + "\n"); } race = Info.IDRace[race]; } mlm.Race = race; if (entry.fullPath.Contains("_d.")) { map = Strings.Diffuse; } else if (entry.fullPath.Contains("_n.")) { map = Strings.Normal; } else if (entry.fullPath.Contains("_s.")) { map = Strings.Specular; } else if (entry.fullPath.Contains("material")) { map = Strings.ColorSet; } else if (entry.fullPath.Contains("model")) { map = "3D"; } else if (entry.fullPath.Contains("ui/")) { map = "UI"; } else { map = Strings.Mask; } mlm.Map = map; if (entry.fullPath.Contains("_b_")) { part = "b"; } else if (entry.fullPath.Contains("_c_")) { part = "c"; } else if (entry.fullPath.Contains("_d_")) { part = "d"; } else if (entry.fullPath.Contains("decal")) { part = entry.fullPath.Substring(entry.fullPath.LastIndexOf('_') + 1, entry.fullPath.LastIndexOf('.') - (entry.fullPath.LastIndexOf('_') + 1)); } else { part = "a"; } mlm.Part = part; if (entry.fullPath.Contains("_iri_")) { type = "Iris"; } else if (entry.fullPath.Contains("_etc_")) { type = "Etc."; } else if (entry.fullPath.Contains("_fac_")) { type = "Face"; } else if (entry.fullPath.Contains("_hir_")) { type = "Hair"; } else if (entry.fullPath.Contains("_acc_")) { type = "Accessory"; } else if (entry.fullPath.Contains("demihuman")) { type = entry.fullPath.Substring(entry.fullPath.LastIndexOf('_') - 3, 3); type = (Info.slotAbr).FirstOrDefault(x => x.Value == type).Key; } else { type = "-"; } mlm.Type = type; if (entry.fullPath.Contains("material")) { var info = MTRL.GetMTRLInfo(entry.modOffset, false); using (var bitmap = TEX.ColorSetToBitmap(info.ColorData)) mlm.BMP = TexHelper.CreateBitmapSource(bitmap); mlm.BMP.Freeze(); } else if (entry.fullPath.Contains("model")) { mlm.BMP = new BitmapImage(new Uri("pack://application:,,,/FFXIV TexTools 2;component/Resources/3DModel.png")); } else { TEXData texData; if (entry.fullPath.Contains("vfx")) { texData = TEX.GetVFX(entry.modOffset, entry.datFile); } else { if (entry.fullPath.Contains("icon")) { texData = TEX.GetTex(entry.modOffset, entry.datFile); } else { texData = TEX.GetTex(entry.modOffset, entry.datFile); } } var scale = 1; if (texData.Width >= 4096 || texData.Height >= 4096) { scale = 16; } else if (texData.Width >= 2048 || texData.Height >= 2048) { scale = 8; } else if (texData.Width >= 1024 || texData.Height >= 1024) { scale = 4; } var nWidth = texData.Width / scale; var nHeight = texData.Height / scale; var resizedImage = TexHelper.CreateResizedImage(texData.BMPSouceNoAlpha, nWidth, nHeight); mlm.BMP = (BitmapSource)resizedImage; mlm.BMP.Freeze(); } var offset = Helper.GetDataOffset(FFCRC.GetHash(entry.fullPath.Substring(0, entry.fullPath.LastIndexOf("/"))), FFCRC.GetHash(Path.GetFileName(entry.fullPath)), entry.datFile); if (offset == entry.modOffset) { mlm.ActiveBorder = Brushes.Green; mlm.Active = Brushes.Transparent; mlm.ActiveOpacity = 1; } else if (offset == entry.originalOffset) { mlm.ActiveBorder = Brushes.Red; mlm.Active = Brushes.Gray; mlm.ActiveOpacity = 0.5f; } else { mlm.ActiveBorder = Brushes.Red; mlm.Active = Brushes.Red; mlm.ActiveOpacity = 1; } mlm.Entry = entry; return(mlm); }
/// <summary> /// Parses the MDL file to obtain model information /// </summary> /// <param name="selectedItem">The currently selected item</param> /// <param name="selectedRace">The currently selected race</param> /// <param name="selectedBody">The currently selected body</param> /// <param name="selectedPart">The currently selected part</param> /// <param name="selectedCategory">The items category </param> public MDL(ItemData selectedItem, string selectedCategory, string selectedRace, string selectedBody, string selectedPart) { string itemType = Helper.GetCategoryType(selectedCategory); string MDLFolder = ""; if (itemType.Equals("weapon") || itemType.Equals("food")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); } else { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); } } else if (itemType.Equals("accessory")) { MDLFolder = string.Format(Strings.AccMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.AccMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else if (itemType.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = string.Format(Strings.BodyMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.BodyMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = string.Format(Strings.FaceMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.FaceMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = string.Format(Strings.HairMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.HairMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = string.Format(Strings.TailMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.TailMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } } else if (itemType.Equals("monster")) { bool isDemiHuman = false; if (selectedItem.PrimaryMTRLFolder != null) { isDemiHuman = selectedItem.PrimaryMTRLFolder.Contains("demihuman"); } if (isDemiHuman) { MDLFolder = string.Format(Strings.DemiMDLFolder, selectedItem.PrimaryModelID.PadLeft(4, '0'), selectedItem.PrimaryModelBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.DemiMDLFile, selectedItem.PrimaryModelID.PadLeft(4, '0'), selectedItem.PrimaryModelBody, selectedPart); } else { MDLFolder = string.Format(Strings.MonsterMDLFolder, selectedItem.PrimaryModelID.PadLeft(4, '0'), selectedItem.PrimaryModelBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.MonsterMDLFile, selectedItem.PrimaryModelID.PadLeft(4, '0'), selectedItem.PrimaryModelBody.PadLeft(4, '0')); } } else { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.PrimaryModelID); if (selectedPart.Equals("-")) { MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else { MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, selectedPart); } } fullPath = MDLFolder + "/" + MDLFile; int offset = Helper.GetDataOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile), Strings.ItemsDat); if (offset == 0) { if (itemType.Equals("weapon")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.SecondaryModelID); MDLFile = string.Format(Strings.EquipMDLFile, "0101", selectedItem.SecondaryModelID, Info.slotAbr[Strings.Hands]); offset = Helper.GetDataOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile), Strings.ItemsDat); } } } int datNum = ((offset / 8) & 0x000f) / 2; var MDLDatData = Helper.GetType3DecompressedData(offset, datNum, Strings.ItemsDat); using (BinaryReader br = new BinaryReader(new MemoryStream(MDLDatData.Item1))) { // The size of the header + (size of the mesh information block (136 bytes) * the meshes) + padding br.BaseStream.Seek(64 + 136 * MDLDatData.Item2 + 4, SeekOrigin.Begin); var modelStringCount = br.ReadInt32(); var stringBlockSize = br.ReadInt32(); var stringBlock = br.ReadBytes(stringBlockSize); var unknown = br.ReadBytes(4); var totalMeshCount = br.ReadInt16(); var attributeStringCount = br.ReadInt16(); var meshPartsCount = br.ReadInt16(); var materialStringCount = br.ReadInt16(); var boneStringCount = br.ReadInt16(); var boneListCount = br.ReadInt16(); //Has something to do with amount of extra vertex data. var unknown1 = br.ReadInt16(); //Has something to do with amount of extra vertex data. var unknown2 = br.ReadInt16(); var unknown3 = br.ReadInt16(); // Seems to always be 1027 var unknown4 = br.ReadInt16(); var unknown5 = br.ReadInt16(); var unknown6 = br.ReadInt16(); br.ReadBytes(10); var unknown7 = br.ReadInt16(); br.ReadBytes(16); using (BinaryReader br1 = new BinaryReader(new MemoryStream(stringBlock))) { br1.BaseStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < attributeStringCount; i++) { byte a; List <byte> atrName = new List <byte>(); while ((a = br1.ReadByte()) != 0) { atrName.Add(a); } string atr = Encoding.ASCII.GetString(atrName.ToArray()); atr = atr.Replace("\0", ""); modelData.Attributes.Add(atr); atrStrings.Add(atr); } for (int i = 0; i < boneStringCount; i++) { byte b; List <byte> boneName = new List <byte>(); while ((b = br1.ReadByte()) != 0) { boneName.Add(b); } string bone = Encoding.ASCII.GetString(boneName.ToArray()); bone = bone.Replace("\0", ""); modelData.Bones.Add(bone); boneStrings.Add(bone); } for (int i = 0; i < materialStringCount; i++) { byte b; List <byte> name = new List <byte>(); while ((b = br1.ReadByte()) != 0) { name.Add(b); } string material = Encoding.ASCII.GetString(name.ToArray()); material = material.Replace("\0", ""); modelData.Materials.Add(material); materialStrings.Add(material); } } byte[] unknown5Bytes = br.ReadBytes(32 * unknown5); for (int i = 0; i < 3; i++) { LevelOfDetail LoD = new LevelOfDetail(); LoD.MeshOffset = br.ReadInt16(); LoD.MeshCount = br.ReadInt16(); br.ReadBytes(40); LoD.VertexDataSize = br.ReadInt32(); LoD.IndexDataSize = br.ReadInt32(); LoD.VertexOffset = br.ReadInt32(); LoD.IndexOffset = br.ReadInt32(); modelData.LoD.Add(LoD); } var savePos = br.BaseStream.Position; var lodStructPos = 68; for (int i = 0; i < modelData.LoD.Count; i++) { List <MeshDataInfo> meshInfoList = new List <MeshDataInfo>(); for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { modelData.LoD[i].MeshList.Add(new Mesh()); meshInfoList.Clear(); br.BaseStream.Seek((j * 136) + lodStructPos, SeekOrigin.Begin); var dataBlockNum = br.ReadByte(); while (dataBlockNum != 255) { MeshDataInfo meshInfo = new MeshDataInfo() { VertexDataBlock = dataBlockNum, Offset = br.ReadByte(), DataType = br.ReadByte(), UseType = br.ReadByte() }; meshInfoList.Add(meshInfo); br.ReadBytes(4); dataBlockNum = br.ReadByte(); } modelData.LoD[i].MeshList[j].MeshDataInfoList = meshInfoList.ToArray(); } lodStructPos += 136 * modelData.LoD[i].MeshCount; } br.BaseStream.Seek(savePos, SeekOrigin.Begin); for (int x = 0; x < modelData.LoD.Count; x++) { for (int i = 0; i < modelData.LoD[x].MeshCount; i++) { MeshInfo meshInfo = new MeshInfo() { VertexCount = br.ReadInt32(), IndexCount = br.ReadInt32(), MaterialNum = br.ReadInt16(), MeshPartOffset = br.ReadInt16(), MeshPartCount = br.ReadInt16(), BoneListIndex = br.ReadInt16(), IndexDataOffset = br.ReadInt32() }; modelData.LoD[x].MeshList[i].MaterialId = meshInfo.MaterialNum; var typeChar = materialStrings[meshInfo.MaterialNum][4].ToString() + materialStrings[meshInfo.MaterialNum][9].ToString(); modelData.LoD[x].MeshList[i].BoneListIndex = meshInfo.BoneListIndex; if (typeChar.Equals("cb")) { modelData.LoD[x].MeshList[i].IsBody = true; } for (int j = 0; j < 3; j++) { meshInfo.VertexDataOffsets.Add(br.ReadInt32()); } for (int k = 0; k < 3; k++) { meshInfo.VertexSizes.Add(br.ReadByte()); } meshInfo.VertexDataBlockCount = br.ReadByte(); modelData.LoD[x].MeshList[i].MeshInfo = meshInfo; } } byte[] attributeOffsetBytes = br.ReadBytes(attributeStringCount * 4); br.ReadBytes(unknown6 * 20); for (int i = 0; i < modelData.LoD.Count; i++) { foreach (var mesh in modelData.LoD[i].MeshList) { for (int j = 0; j < mesh.MeshInfo.MeshPartCount; j++) { MeshPart meshPart = new MeshPart() { IndexOffset = br.ReadInt32(), IndexCount = br.ReadInt32(), Attributes = br.ReadInt32(), BoneOffset = br.ReadInt16(), BoneCount = br.ReadInt16() }; mesh.MeshPartList.Add(meshPart); } } } br.ReadBytes(unknown7 * 12); br.ReadBytes(materialStringCount * 4); List <int> boneIncrements = new List <int>(); // Loop through the increments and save their data. for (int i = 0; i < boneStringCount; i++) { int increment = br.ReadInt32(); boneIncrements.Add(increment); } for (int i = 0; i < boneListCount; i++) { Bones bones = new Bones(); for (int j = 0; j < 64; j++) { bones.BoneData.Add(br.ReadInt16()); } bones.BoneCount = br.ReadInt32(); modelData.BoneSet.Add(bones); } //br.ReadBytes(unknown1 * 16); Dictionary <int, int> indexMin = new Dictionary <int, int>(); Dictionary <int, List <int> > extraIndices = new Dictionary <int, List <int> >(); Dictionary <int, List <int> > extraIndices2 = new Dictionary <int, List <int> >(); var indexCounts = new List <List <ExtraIndex> >(); // One for each LoD level. indexCounts.Add(new List <ExtraIndex>()); indexCounts.Add(new List <ExtraIndex>()); indexCounts.Add(new List <ExtraIndex>()); var pCounts = new int[3]; if (unknown1 > 0) { for (int i = 0; i < unknown1; i++) { //not sure br.ReadBytes(4); //LoD[0] Extra Data Index var p1 = br.ReadUInt16(); //LoD[1] Extra Data Index var p2 = br.ReadUInt16(); //LoD[2] Extra Data Index var p3 = br.ReadUInt16(); //LoD[0] Extra Data Part Count var p1n = br.ReadUInt16(); pCounts[0] += p1n; //LoD[1] Extra Data Part Count var p2n = br.ReadUInt16(); pCounts[1] += p2n; //LoD[2] Extra Data Part Count var p3n = br.ReadUInt16(); pCounts[2] += p3n; } } Dictionary <int, int> indexLoc = new Dictionary <int, int>(); if (unknown1 > 0) { for (int i = 0; i < modelData.LoD[LoDViewLevel].MeshCount; i++) { var ido = modelData.LoD[LoDViewLevel].MeshList[i].MeshInfo.IndexDataOffset; if (!indexLoc.ContainsKey(ido)) { indexLoc.Add(ido, i); } } } var totalMaskCounts = new int[3]; Dictionary <int, int> totalExtraCounts = new Dictionary <int, int>(); if (unknown2 > 0) { for (int x = 0; x < pCounts.Length; x++) { for (int i = 0; i < pCounts[x]; i++) { //Index Offset Start var m1 = br.ReadInt32(); //index count var mCount = br.ReadInt32(); //index offset in unk3 var mOffset = br.ReadInt32(); var iLoc = 0; if (indexLoc.ContainsKey(m1)) { iLoc = indexLoc[m1]; } indexCounts[x].Add(new ExtraIndex() { IndexLocation = iLoc, IndexCount = mCount }); totalMaskCounts[x] += mCount; } } } if (unknown3 > 0) { //var unk3Remainder = (unknown3 * 4) - (totalLoD0MaskCount * 4); var c = 0; for (int l = 0; l < indexCounts.Count; l++) { foreach (var ic in indexCounts[l]) { HashSet <int> mIndexList = new HashSet <int>(); for (int i = 0; i < ic.IndexCount; i++) { //index its replacing? attatched to? var oIndex = br.ReadUInt16(); //extra index following last equipment index var mIndex = br.ReadUInt16(); if (l == LoDViewLevel) { mIndexList.Add(mIndex); if (extraIndices.ContainsKey(ic.IndexLocation)) { extraIndices[ic.IndexLocation].Add(mIndex); extraIndices2[ic.IndexLocation].Add(oIndex); } else { extraIndices.Add(ic.IndexLocation, new List <int>() { mIndex }); extraIndices2.Add(ic.IndexLocation, new List <int>() { oIndex }); } } } if (l == LoDViewLevel) { if (totalExtraCounts.ContainsKey(ic.IndexLocation)) { totalExtraCounts[ic.IndexLocation] += mIndexList.Count; } else { totalExtraCounts.Add(ic.IndexLocation, mIndexList.Count); } } c++; } } //the rest of unk3 //br.ReadBytes(unk3Remainder); foreach (var ei in extraIndices) { indexMin.Add(ei.Key, ei.Value.Min()); } extraIndexData.indexCounts = indexCounts[LoDViewLevel]; extraIndexData.indexMin = indexMin; extraIndexData.totalExtraCounts = totalExtraCounts; extraIndexData.extraIndices = extraIndices; extraIndexData.extraIndices2 = extraIndices2; modelData.ExtraData = extraIndexData; } //br.ReadBytes(unknown3 * 4); var boneIndexSize = br.ReadInt32(); for (int i = 0; i < boneIndexSize / 2; i++) { modelData.BoneIndicies.Add(br.ReadUInt16()); } int padding = br.ReadByte(); br.ReadBytes(padding); for (int i = 0; i < 4; i++) { ModelMaterial.BoundingBox boundingBox = new ModelMaterial.BoundingBox(); for (int j = 0; j < 4; j++) { boundingBox.PointA.Add(br.ReadSingle()); } for (int k = 0; k < 4; k++) { boundingBox.PointB.Add(br.ReadSingle()); } modelData.BoundingBoxes.Add(boundingBox); } //float4x4 for (int i = 0; i < boneStringCount; i++) { string boneName = boneStrings[i]; Vector4 transform1 = new Vector4(); Vector4 transform2 = new Vector4(); transform1.X = br.ReadSingle(); transform1.Y = br.ReadSingle(); transform1.Z = br.ReadSingle(); transform1.W = br.ReadSingle(); transform2.X = br.ReadSingle(); transform2.Y = br.ReadSingle(); transform2.Z = br.ReadSingle(); transform2.W = br.ReadSingle(); boneTransforms.Add(transform1.X); boneTransforms.Add(transform1.Y); boneTransforms.Add(transform1.Z); boneTransforms.Add(transform1.W); boneTransforms.Add(transform2.X); boneTransforms.Add(transform2.Y); boneTransforms.Add(transform2.Z); boneTransforms.Add(transform2.W); } for (int i = 0; i < 3; i++) { for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { Mesh mesh = modelData.LoD[i].MeshList[j]; for (int k = 0; k < mesh.MeshInfo.VertexDataBlockCount; k++) { br.BaseStream.Seek(modelData.LoD[i].VertexOffset + mesh.MeshInfo.VertexDataOffsets[k], SeekOrigin.Begin); mesh.MeshVertexData.Add(br.ReadBytes(mesh.MeshInfo.VertexSizes[k] * mesh.MeshInfo.VertexCount)); } br.BaseStream.Seek(modelData.LoD[i].IndexOffset + (mesh.MeshInfo.IndexDataOffset * 2), SeekOrigin.Begin); mesh.IndexData = br.ReadBytes(2 * mesh.MeshInfo.IndexCount); } } int vertex = 0, coordinates = 0, normals = 0, tangents = 0, colors = 0, blendWeights = 0, blendIndices = 0; for (int i = 0; i < modelData.LoD[LoDViewLevel].MeshCount; i++) { objBytes.Clear(); var vertexList = new Vector3Collection(); var texCoordList = new Vector2Collection(); var texCoordList2 = new Vector2Collection(); var normalList = new Vector3Collection(); var tangentList = new Vector3Collection(); var colorsList = new Color4Collection(); var indexList = new IntCollection(); var blendWeightList = new List <float>(); var blendWeightList2 = new List <float[]>(); var blendIndicesList = new List <int>(); var blendIndicesList2 = new List <int[]>(); var weightCounts = new List <int>(); var extraVerts = new HashSet <Vector3>(); Dictionary <int, Vector3> extraVertDict = new Dictionary <int, Vector3>(); Mesh mesh = modelData.LoD[LoDViewLevel].MeshList[i]; MeshDataInfo[] meshDataInfoList = mesh.MeshDataInfoList; int c = 0; foreach (var meshDataInfo in meshDataInfoList) { if (meshDataInfo.UseType == 0) { vertex = c; } else if (meshDataInfo.UseType == 1) { blendWeights = c; } else if (meshDataInfo.UseType == 2) { blendIndices = c; } else if (meshDataInfo.UseType == 3) { normals = c; } else if (meshDataInfo.UseType == 4) { coordinates = c; } else if (meshDataInfo.UseType == 6) { tangents = c; } else if (meshDataInfo.UseType == 7) { colors = c; } c++; } /* * ----------------- * Vertex * ----------------- */ // Only actually read the buffers if they have data in them. if (mesh.MeshVertexData.Count > 0) { using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[vertex].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[vertex].VertexDataBlock] + meshDataInfoList[vertex].Offset, SeekOrigin.Begin); Vector3 vVector = new Vector3(); if (meshDataInfoList[vertex].DataType == 13 || meshDataInfoList[vertex].DataType == 14) { System.Half h1 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h2 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h3 = System.Half.ToHalf(br1.ReadUInt16()); float x = HalfHelper.HalfToSingle(h1); float y = HalfHelper.HalfToSingle(h2); float z = HalfHelper.HalfToSingle(h3); vVector = new Vector3(x, y, z); objBytes.Add("v " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); } else if (meshDataInfoList[vertex].DataType == 2) { var x = BitConverter.ToSingle(br1.ReadBytes(4), 0); var y = BitConverter.ToSingle(br1.ReadBytes(4), 0); var z = BitConverter.ToSingle(br1.ReadBytes(4), 0); vVector = new Vector3(x, y, z); objBytes.Add("v " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); } vertexList.Add(vVector); } } /* * ----------------- * Blend Weight * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[blendWeights].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[blendWeights].VertexDataBlock] + meshDataInfoList[blendWeights].Offset, SeekOrigin.Begin); float x = br1.ReadByte() / 255.0f; float y = br1.ReadByte() / 255.0f; float z = br1.ReadByte() / 255.0f; float w = br1.ReadByte() / 255.0f; int count = 0; if (x != 0) { blendWeightList.Add(x); count++; if (y != 0) { blendWeightList.Add(y); count++; if (z != 0) { blendWeightList.Add(z); count++; if (w != 0) { blendWeightList.Add(w); count++; } } } } if (count == 1) { blendWeightList2.Add(new float[] { x }); } else if (count == 2) { blendWeightList2.Add(new float[] { x, y }); } else if (count == 3) { blendWeightList2.Add(new float[] { x, y, z }); } else if (count == 4) { blendWeightList2.Add(new float[] { x, y, z, w }); } weightCounts.Add(count); } } /* * ----------------- * Blend Index * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[blendIndices].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[blendIndices].VertexDataBlock] + meshDataInfoList[blendIndices].Offset, SeekOrigin.Begin); int x = br1.ReadByte(); int y = br1.ReadByte(); int z = br1.ReadByte(); int w = br1.ReadByte(); if (weightCounts[j] == 1) { blendIndicesList.Add(x); blendIndicesList2.Add(new int[] { x }); } else if (weightCounts[j] == 2) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList2.Add(new int[] { x, y }); } else if (weightCounts[j] == 3) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList.Add(z); blendIndicesList2.Add(new int[] { x, y, z }); } else if (weightCounts[j] == 4) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList.Add(z); blendIndicesList.Add(w); blendIndicesList2.Add(new int[] { x, y, z, w }); } } } /* * ----------------- * Texture Coordinates * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[coordinates].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[coordinates].VertexDataBlock] + meshDataInfoList[coordinates].Offset, SeekOrigin.Begin); float x = 0; float y = 0; float z = 0; float w = 0; if (meshDataInfoList[coordinates].DataType == 13 || meshDataInfoList[coordinates].DataType == 14) { var sx = br1.ReadUInt16(); var sy = br1.ReadUInt16(); var sz = br1.ReadUInt16(); var sw = br1.ReadUInt16(); var h1 = new SharpDX.Half(sx); var h2 = new SharpDX.Half(sy); var h3 = new SharpDX.Half(sz); var h4 = new SharpDX.Half(sw); x = h1; y = h2; z = h3; w = h4; } else if (meshDataInfoList[coordinates].DataType == 1) { x = br1.ReadSingle(); y = br1.ReadSingle(); } else { x = br1.ReadSingle(); y = br1.ReadSingle(); z = br1.ReadSingle(); w = br1.ReadSingle(); } var ox = x - Math.Truncate(x); var oy = y - Math.Truncate(y); objBytes.Add("vt " + ox.ToString("N5") + " " + (1 - y).ToString("N5") + " "); texCoordList.Add(new Vector2(x, y)); texCoordList2.Add(new Vector2(z, w)); } } /* * ----------------- * Normals * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[normals].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[normals].VertexDataBlock] + meshDataInfoList[normals].Offset, SeekOrigin.Begin); float x = 0; float y = 0; float z = 0; float w = 0; if (meshDataInfoList[normals].DataType == 13 || meshDataInfoList[normals].DataType == 14) { System.Half h1 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h2 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h3 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h4 = System.Half.ToHalf(br1.ReadUInt16()); x = HalfHelper.HalfToSingle(h1); y = HalfHelper.HalfToSingle(h2); z = HalfHelper.HalfToSingle(h3); w = HalfHelper.HalfToSingle(h4); } else { x = br1.ReadSingle(); y = br1.ReadSingle(); z = br1.ReadSingle(); } var nv = new Vector3(x, y, z); objBytes.Add("vn " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); normalList.Add(nv); } } /* * ----------------- * Tangents * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[tangents].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[tangents].VertexDataBlock] + meshDataInfoList[tangents].Offset, SeekOrigin.Begin); int x = br1.ReadByte(); int y = br1.ReadByte(); int z = br1.ReadByte(); int w = br1.ReadByte(); var x1 = x * 2 / 255f - 1f; var y1 = y * 2 / 255f - 1f; var z1 = z * 2 / 255f - 1f; var w1 = w * 2 / 255f - 1f; var nv = new Vector3(x1, y1, z1); tangentList.Add(nv); } } /* * ----------------- * Vertex Color * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[colors].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[colors].VertexDataBlock] + meshDataInfoList[colors].Offset, SeekOrigin.Begin); int a = br1.ReadByte(); int r = br1.ReadByte(); int g = br1.ReadByte(); int b = br1.ReadByte(); colorsList.Add(new Color4(r, g, b, a)); } } } /* * ----------------- * Index * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.IndexData))) { for (int j = 0; j < mesh.MeshInfo.IndexCount; j += 3) { int i1 = br1.ReadUInt16(); int i2 = br1.ReadUInt16(); int i3 = br1.ReadUInt16(); objBytes.Add("f " + (i1 + 1) + "/" + (i1 + 1) + "/" + (i1 + 1) + " " + (i2 + 1) + "/" + (i2 + 1) + "/" + (i2 + 1) + " " + (i3 + 1) + "/" + (i3 + 1) + "/" + (i3 + 1) + " "); indexList.Add(i1); indexList.Add(i2); indexList.Add(i3); } } ModelMeshData modelMeshData = new ModelMeshData() { Vertices = vertexList, Normals = normalList, TextureCoordinates = texCoordList, TextureCoordinates2 = texCoordList2, BiTangents = tangentList, Indices = indexList, VertexColors = colorsList, OBJFileData = objBytes.ToArray(), BoneStrings = boneStrings, AttributeStrings = atrStrings, BoneIndices = modelData.BoneIndicies, BoneTransforms = boneTransforms, BlendWeights = blendWeightList, BlendIndices = blendIndicesList, WeightCounts = weightCounts, MeshPartList = mesh.MeshPartList, BlendIndicesArrayList = blendIndicesList2, BlendWeightsArrayList = blendWeightList2, MaterialNum = mesh.MeshInfo.MaterialNum, MeshPartCount = mesh.MeshInfo.MeshPartCount, MeshPartOffset = mesh.MeshInfo.MeshPartOffset }; if (extraIndices2.ContainsKey(i)) { foreach (var id in extraIndices2[i]) { if (!extraVertDict.ContainsKey(id)) { if (modelMeshData.Indices.Count >= id) { var v = 0; try { v = modelMeshData.Indices[id]; } catch { v = 0; } extraVertDict.Add(id, modelMeshData.Vertices[v]); } else { //new Thread(() => MessageBox.Show("There was an error reading the models extra data.\n\n" + // "Mesh " + i + " Index " + id + "\n\n" + // "This is likely caused by parts of a mesh being deleted and may cause crashes in-game.\n\n" + // "Consider using Advanced Import to Fix or Disable Hiding for the above mesh.", // "Extra Data Warning" + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Warning)).Start(); new Thread(() => MessageBox.Show(string.Format(Dialogs.MDLExtraDataWarning, i, id), Dialogs.ExtraDataWarning + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Warning)).Start(); break; } } } } mesh.extraVertDict = extraVertDict; meshList.Add(modelMeshData); } } }
/// <summary> /// Parses the MDL file to obtain model information /// </summary> /// <param name="selectedItem">The currently selected item</param> /// <param name="selectedRace">The currently selected race</param> /// <param name="selectedBody">The currently selected body</param> /// <param name="selectedPart">The currently selected part</param> /// <param name="selectedCategory">The items category </param> public MDL(ItemData selectedItem, string selectedCategory, string selectedRace, string selectedBody, string selectedPart) { string itemType = Helper.GetCategoryType(selectedCategory); string MDLFolder = ""; if (itemType.Equals("weapon") || itemType.Equals("food")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); } else { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); } } else if (itemType.Equals("accessory")) { MDLFolder = string.Format(Strings.AccMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.AccMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else if (itemType.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = string.Format(Strings.BodyMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.BodyMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = string.Format(Strings.FaceMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.FaceMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = string.Format(Strings.HairMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.HairMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = string.Format(Strings.TailMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.TailMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } } else if (itemType.Equals("monster")) { bool isDemiHuman = false; if (selectedItem.PrimaryMTRLFolder != null) { isDemiHuman = selectedItem.PrimaryMTRLFolder.Contains("demihuman"); } string ID = ""; string body = ""; if (selectedCategory.Equals(Strings.Pets)) { int part = 1; if (selectedItem.ItemName.Equals(Strings.Selene) || selectedItem.ItemName.Equals(Strings.Bishop_Autoturret)) { part = 2; } ID = Info.petID[selectedItem.ItemName]; body = part.ToString().PadLeft(4, '0'); } else { ID = selectedItem.PrimaryModelID.PadLeft(4, '0'); body = selectedItem.PrimaryModelBody; } if (isDemiHuman) { MDLFolder = string.Format(Strings.DemiMDLFolder, ID, body); MDLFile = string.Format(Strings.DemiMDLFile, ID, body, selectedPart); } else { MDLFolder = string.Format(Strings.MonsterMDLFolder, ID, body); MDLFile = string.Format(Strings.MonsterMDLFile, ID, body); } } else { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.PrimaryModelID); if (selectedPart.Equals("-")) { MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else { MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, selectedPart); } } fullPath = MDLFolder + "/" + MDLFile; int offset = Helper.GetDataOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile), Strings.ItemsDat); if (offset == 0) { if (itemType.Equals("weapon")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.SecondaryModelID); MDLFile = string.Format(Strings.EquipMDLFile, "0101", selectedItem.SecondaryModelID, Info.slotAbr[Strings.Hands]); offset = Helper.GetDataOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile), Strings.ItemsDat); } } } int datNum = ((offset / 8) & 0x000f) / 2; var MDLDatData = Helper.GetType3DecompressedData(offset, datNum, Strings.ItemsDat); using (BinaryReader br = new BinaryReader(new MemoryStream(MDLDatData.Item1))) { // The size of the header + (size of the mesh information block (136 bytes) * the number of meshes) + padding br.BaseStream.Seek(64 + 136 * MDLDatData.Item2 + 4, SeekOrigin.Begin); var modelStringCount = br.ReadInt32(); var stringBlockSize = br.ReadInt32(); var stringBlock = br.ReadBytes(stringBlockSize); var unknown = br.ReadBytes(4); var totalMeshCount = br.ReadInt16(); var attributeStringCount = br.ReadInt16(); var meshPartsCount = br.ReadInt16(); var materialStringCount = br.ReadInt16(); var boneStringCount = br.ReadInt16(); var boneListCount = br.ReadInt16(); var unknown1 = br.ReadInt16(); var unknown2 = br.ReadInt16(); var unknown3 = br.ReadInt16(); var unknown4 = br.ReadInt16(); var unknown5 = br.ReadInt16(); var unknown6 = br.ReadInt16(); br.ReadBytes(10); var unknown7 = br.ReadInt16(); br.ReadBytes(16); using (BinaryReader br1 = new BinaryReader(new MemoryStream(stringBlock))) { br1.BaseStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < attributeStringCount; i++) { while (br1.ReadByte() != 0) { //extract each atribute string here } } for (int i = 0; i < boneStringCount; i++) { byte b; List <byte> boneName = new List <byte>(); while ((b = br1.ReadByte()) != 0) { boneName.Add(b); } string bone = Encoding.ASCII.GetString(boneName.ToArray()); bone = bone.Replace("\0", ""); boneStrings.Add(bone); } for (int i = 0; i < materialStringCount; i++) { byte b; List <byte> name = new List <byte>(); while ((b = br1.ReadByte()) != 0) { name.Add(b); } string material = Encoding.ASCII.GetString(name.ToArray()); material = material.Replace("\0", ""); materialStrings.Add(material); } } br.ReadBytes(32 * unknown5); for (int i = 0; i < 3; i++) { LevelOfDetail LoD = new LevelOfDetail(); LoD.MeshOffset = br.ReadInt16(); LoD.MeshCount = br.ReadInt16(); br.ReadBytes(40); LoD.VertexDataSize = br.ReadInt32(); LoD.IndexDataSize = br.ReadInt32(); LoD.VertexOffset = br.ReadInt32(); LoD.IndexOffset = br.ReadInt32(); modelData.LoD.Add(LoD); } var savePos = br.BaseStream.Position; for (int i = 0; i < modelData.LoD.Count; i++) { List <MeshDataInfo> meshInfoList = new List <MeshDataInfo>(); for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { modelData.LoD[i].MeshList.Add(new Mesh()); meshInfoList.Clear(); br.BaseStream.Seek((i * 136) + 68, SeekOrigin.Begin); var dataBlockNum = br.ReadByte(); while (dataBlockNum != 255) { MeshDataInfo meshInfo = new MeshDataInfo() { VertexDataBlock = dataBlockNum, Offset = br.ReadByte(), DataType = br.ReadByte(), UseType = br.ReadByte() }; meshInfoList.Add(meshInfo); br.ReadBytes(4); dataBlockNum = br.ReadByte(); } modelData.LoD[i].MeshList[j].MeshDataInfoList = meshInfoList.ToArray(); } } br.BaseStream.Seek(savePos, SeekOrigin.Begin); for (int x = 0; x < modelData.LoD.Count; x++) { for (int i = 0; i < modelData.LoD[x].MeshCount; i++) { MeshInfo meshInfo = new MeshInfo() { VertexCount = br.ReadInt32(), IndexCount = br.ReadInt32(), MaterialNum = br.ReadInt16(), MeshPartOffset = br.ReadInt16(), MeshPartCount = br.ReadInt16(), BoneListIndex = br.ReadInt16(), IndexDataOffset = br.ReadInt32() }; for (int j = 0; j < 3; j++) { meshInfo.VertexDataOffsets.Add(br.ReadInt32()); } for (int k = 0; k < 3; k++) { meshInfo.VertexSizes.Add(br.ReadByte()); } meshInfo.VertexDataBlockCount = br.ReadByte(); modelData.LoD[x].MeshList[i].MeshInfo = meshInfo; } } br.ReadBytes(attributeStringCount * 4); br.ReadBytes(unknown6 * 20); for (int i = 0; i < modelData.LoD.Count; i++) { foreach (var mesh in modelData.LoD[i].MeshList) { for (int j = 0; j < mesh.MeshInfo.MeshPartCount; j++) { MeshPart meshPart = new MeshPart() { IndexOffset = br.ReadInt32(), IndexCount = br.ReadInt32(), Attributes = br.ReadInt32(), BoneOffset = br.ReadInt16(), BoneCount = br.ReadInt16() }; mesh.MeshPartList.Add(meshPart); } } } br.ReadBytes(unknown7 * 12); br.ReadBytes(materialStringCount * 4); br.ReadBytes(boneStringCount * 4); for (int i = 0; i < boneListCount; i++) { Bones bones = new Bones(); for (int j = 0; j < 64; j++) { bones.BoneData.Add(br.ReadInt16()); } bones.BoneCount = br.ReadInt32(); modelData.BoneSet.Add(bones); } //br.ReadBytes(unknown1 * 16); Dictionary <int, int> indexMin = new Dictionary <int, int>(); Dictionary <int, List <int> > extraIndices = new Dictionary <int, List <int> >(); List <ExtraIndex> indexCounts = new List <ExtraIndex>(); var pCount = 0; var pCount1 = 0; var pCount2 = 0; if (unknown1 > 0) { for (int i = 0; i < unknown1; i++) { //not sure br.ReadBytes(4); //LoD[0] Extra Data Index var p1 = br.ReadUInt16(); //LoD[1] Extra Data Index var p2 = br.ReadUInt16(); //LoD[2] Extra Data Index var p3 = br.ReadUInt16(); //LoD[0] Extra Data Part Count var p1n = br.ReadUInt16(); pCount += p1n; //LoD[1] Extra Data Part Count var p2n = br.ReadUInt16(); pCount1 += p2n; //LoD[2] Extra Data Part Count var p3n = br.ReadUInt16(); pCount2 += p3n; } } Dictionary <int, int> indexLoc = new Dictionary <int, int>(); if (unknown1 > 0) { for (int i = 0; i < modelData.LoD[0].MeshCount; i++) { var ido = modelData.LoD[0].MeshList[i].MeshInfo.IndexDataOffset; indexLoc.Add(ido, i); } } List <int> maskCounts = new List <int>(); Dictionary <int, int> totalExtraCounts = new Dictionary <int, int>(); if (unknown2 > 0) { for (int i = 0; i < pCount; i++) { //Index Offset Start var m1 = br.ReadInt32(); var iLoc = 0; if (indexLoc.ContainsKey(m1)) { iLoc = indexLoc[m1]; } //index count var mCount = br.ReadInt32(); //index offset in unk3 var mOffset = br.ReadInt32(); indexCounts.Add(new ExtraIndex() { IndexLocation = iLoc, IndexCount = mCount }); maskCounts.Add(mCount); } br.ReadBytes((pCount1 + pCount2) * 12); } int totalLoD0MaskCount = 0; if (unknown2 > 0) { for (int i = 0; i < pCount; i++) { totalLoD0MaskCount += maskCounts[i]; } } if (unknown3 > 0) { var unk3Remainder = (unknown3 * 4) - (totalLoD0MaskCount * 4); foreach (var ic in indexCounts) { HashSet <int> mIndexList = new HashSet <int>(); for (int i = 0; i < ic.IndexCount; i++) { //index its replacing? attatched to? br.ReadBytes(2); //extra index following last equipment index var mIndex = br.ReadInt16(); mIndexList.Add(mIndex); if (extraIndices.ContainsKey(ic.IndexLocation)) { extraIndices[ic.IndexLocation].Add(mIndex); } else { extraIndices.Add(ic.IndexLocation, new List <int>() { mIndex }); } } if (totalExtraCounts.ContainsKey(ic.IndexLocation)) { totalExtraCounts[ic.IndexLocation] += mIndexList.Count; } else { totalExtraCounts.Add(ic.IndexLocation, mIndexList.Count); } } //the rest of unk3 br.ReadBytes(unk3Remainder); } if (unknown3 > 0) { foreach (var ei in extraIndices) { indexMin.Add(ei.Key, ei.Value.Min()); } extraIndexData.indexCounts = indexCounts; extraIndexData.indexMin = indexMin; extraIndexData.totalExtraCounts = totalExtraCounts; extraIndexData.extraIndices = extraIndices; modelData.ExtraData = extraIndexData; } //br.ReadBytes(unknown3 * 4); var boneIndexSize = br.ReadInt32(); for (int i = 0; i < boneIndexSize / 2; i++) { modelData.BoneIndicies.Add(br.ReadInt16()); } int padding = br.ReadByte(); br.ReadBytes(padding); for (int i = 0; i < 4; i++) { ModelMaterial.BoundingBox boundingBox = new ModelMaterial.BoundingBox(); for (int j = 0; j < 4; j++) { boundingBox.PointA.Add(br.ReadSingle()); } for (int k = 0; k < 4; k++) { boundingBox.PointB.Add(br.ReadSingle()); } modelData.BoundingBoxes.Add(boundingBox); } //float4x4 for (int i = 0; i < boneStringCount; i++) { boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); } for (int i = 0; i < 3; i++) { for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { Mesh mesh = modelData.LoD[i].MeshList[j]; for (int k = 0; k < mesh.MeshInfo.VertexDataBlockCount; k++) { br.BaseStream.Seek(modelData.LoD[i].VertexOffset + mesh.MeshInfo.VertexDataOffsets[k], SeekOrigin.Begin); mesh.MeshVertexData.Add(br.ReadBytes(mesh.MeshInfo.VertexSizes[k] * mesh.MeshInfo.VertexCount)); } br.BaseStream.Seek(modelData.LoD[i].IndexOffset + (mesh.MeshInfo.IndexDataOffset * 2), SeekOrigin.Begin); mesh.IndexData = br.ReadBytes(2 * mesh.MeshInfo.IndexCount); } } int vertex = 0, coordinates = 0, normals = 0, tangents = 0, colors = 0, blendWeights = 0, blendIndices = 0; for (int i = 0; i < modelData.LoD[0].MeshCount; i++) { objBytes.Clear(); var vertexList = new Vector3Collection(); var texCoordList = new Vector2Collection(); var texCoordList2 = new Vector2Collection(); var normalList = new Vector3Collection(); var tangentList = new Vector3Collection(); var colorsList = new Color4Collection(); var indexList = new IntCollection(); var blendWeightList = new List <float>(); var blendWeightList2 = new List <float[]>(); var blendIndicesList = new List <int>(); var blendIndicesList2 = new List <int[]>(); var weightCounts = new List <int>(); Mesh mesh = modelData.LoD[0].MeshList[i]; MeshDataInfo[] meshDataInfoList = mesh.MeshDataInfoList; int c = 0; foreach (var meshDataInfo in meshDataInfoList) { if (meshDataInfo.UseType == 0) { vertex = c; } else if (meshDataInfo.UseType == 1) { blendWeights = c; } else if (meshDataInfo.UseType == 2) { blendIndices = c; } else if (meshDataInfo.UseType == 3) { normals = c; } else if (meshDataInfo.UseType == 4) { coordinates = c; } else if (meshDataInfo.UseType == 6) { tangents = c; } else if (meshDataInfo.UseType == 7) { colors = c; } c++; } /* * ----------------- * Vertex * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[vertex].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[vertex].VertexDataBlock] + meshDataInfoList[vertex].Offset, SeekOrigin.Begin); Vector3 vVector = new Vector3(); if (meshDataInfoList[vertex].DataType == 13 || meshDataInfoList[vertex].DataType == 14) { System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h3 = System.Half.ToHalf((ushort)br1.ReadInt16()); float x = HalfHelper.HalfToSingle(h1); float y = HalfHelper.HalfToSingle(h2); float z = HalfHelper.HalfToSingle(h3); vVector = new Vector3(x, y, z); objBytes.Add("v " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); } else if (meshDataInfoList[vertex].DataType == 2) { var x = BitConverter.ToSingle(br1.ReadBytes(4), 0); var y = BitConverter.ToSingle(br1.ReadBytes(4), 0); var z = BitConverter.ToSingle(br1.ReadBytes(4), 0); vVector = new Vector3(x, y, z); objBytes.Add("v " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); } vertexList.Add(vVector); } } /* * ----------------- * Blend Weight * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[blendWeights].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[blendWeights].VertexDataBlock] + meshDataInfoList[blendWeights].Offset, SeekOrigin.Begin); float x = br1.ReadByte() / 255.0f; float y = br1.ReadByte() / 255.0f; float z = br1.ReadByte() / 255.0f; float w = br1.ReadByte() / 255.0f; int count = 0; if (x != 0) { blendWeightList.Add(x); count++; if (y != 0) { blendWeightList.Add(y); count++; if (z != 0) { blendWeightList.Add(z); count++; if (w != 0) { blendWeightList.Add(w); count++; } } } } if (count == 1) { blendWeightList2.Add(new float[] { x }); } else if (count == 2) { blendWeightList2.Add(new float[] { x, y }); } else if (count == 3) { blendWeightList2.Add(new float[] { x, y, z }); } else if (count == 4) { blendWeightList2.Add(new float[] { x, y, z, w }); } weightCounts.Add(count); } } /* * ----------------- * Blend Index * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[blendIndices].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[blendIndices].VertexDataBlock] + meshDataInfoList[blendIndices].Offset, SeekOrigin.Begin); int x = br1.ReadByte(); int y = br1.ReadByte(); int z = br1.ReadByte(); int w = br1.ReadByte(); if (weightCounts[j] == 1) { blendIndicesList.Add(x); blendIndicesList2.Add(new int[] { x }); } else if (weightCounts[j] == 2) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList2.Add(new int[] { x, y }); } else if (weightCounts[j] == 3) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList.Add(z); blendIndicesList2.Add(new int[] { x, y, z }); } else if (weightCounts[j] == 4) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList.Add(z); blendIndicesList.Add(w); blendIndicesList2.Add(new int[] { x, y, z, w }); } } } /* * ----------------- * Texture Coordinates * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[coordinates].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[coordinates].VertexDataBlock] + meshDataInfoList[coordinates].Offset, SeekOrigin.Begin); float x = 0; float y = 0; float z = 0; float w = 0; if (meshDataInfoList[coordinates].DataType == 13 || meshDataInfoList[coordinates].DataType == 14) { var sx = (ushort)br1.ReadInt16(); var sy = (ushort)br1.ReadInt16(); var sz = (ushort)br1.ReadInt16(); var sw = (ushort)br1.ReadInt16(); var h1 = new SharpDX.Half(sx); var h2 = new SharpDX.Half(sy); var h3 = new SharpDX.Half(sz); var h4 = new SharpDX.Half(sw); x = h1; y = h2; z = h3; w = h4; } else if (meshDataInfoList[coordinates].DataType == 1) { x = br1.ReadSingle(); y = br1.ReadSingle(); } else { x = br1.ReadSingle(); y = br1.ReadSingle(); z = br1.ReadSingle(); w = br1.ReadSingle(); } var ox = x - Math.Truncate(x); var oy = y - Math.Truncate(y); objBytes.Add("vt " + ox.ToString("N5") + " " + (1 - y).ToString("N5") + " "); texCoordList.Add(new Vector2(x, y)); texCoordList2.Add(new Vector2(z, w)); } } /* * ----------------- * Normals * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[normals].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[normals].VertexDataBlock] + meshDataInfoList[normals].Offset, SeekOrigin.Begin); float x = 0; float y = 0; float z = 0; float w = 0; if (meshDataInfoList[normals].DataType == 13 || meshDataInfoList[normals].DataType == 14) { System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h3 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h4 = System.Half.ToHalf((ushort)br1.ReadInt16()); x = HalfHelper.HalfToSingle(h1); y = HalfHelper.HalfToSingle(h2); z = HalfHelper.HalfToSingle(h3); w = HalfHelper.HalfToSingle(h4); } else { x = br1.ReadSingle(); y = br1.ReadSingle(); z = br1.ReadSingle(); } var nv = new Vector3(x, y, z); objBytes.Add("vn " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); normalList.Add(nv); } } /* * ----------------- * Tangents * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[tangents].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[tangents].VertexDataBlock] + meshDataInfoList[tangents].Offset, SeekOrigin.Begin); int x = br1.ReadByte(); int y = br1.ReadByte(); int z = br1.ReadByte(); int w = br1.ReadByte(); var x1 = x * 2 / 255f - 1f; var y1 = y * 2 / 255f - 1f; var z1 = z * 2 / 255f - 1f; var w1 = w * 2 / 255f - 1f; var nv = new Vector3(x1, y1, z1); tangentList.Add(nv); } } /* * ----------------- * Vertex Color * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[colors].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[colors].VertexDataBlock] + meshDataInfoList[colors].Offset, SeekOrigin.Begin); int a = br1.ReadByte(); int r = br1.ReadByte(); int g = br1.ReadByte(); int b = br1.ReadByte(); colorsList.Add(new Color4(r, g, b, a)); } } /* * ----------------- * Index * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.IndexData))) { for (int j = 0; j < mesh.MeshInfo.IndexCount; j += 3) { int i1 = br1.ReadInt16(); int i2 = br1.ReadInt16(); int i3 = br1.ReadInt16(); objBytes.Add("f " + (i1 + 1) + "/" + (i1 + 1) + "/" + (i1 + 1) + " " + (i2 + 1) + "/" + (i2 + 1) + "/" + (i2 + 1) + " " + (i3 + 1) + "/" + (i3 + 1) + "/" + (i3 + 1) + " "); indexList.Add(i1); indexList.Add(i2); indexList.Add(i3); } } ModelMeshData modelMeshData = new ModelMeshData() { Vertices = vertexList, Normals = normalList, TextureCoordinates = texCoordList, TextureCoordinates2 = texCoordList2, BiTangents = tangentList, Indices = indexList, VertexColors = colorsList, OBJFileData = objBytes.ToArray(), BoneStrings = boneStrings, BoneIndices = modelData.BoneIndicies, BoneTransforms = boneTransforms, BlendWeights = blendWeightList, BlendIndices = blendIndicesList, WeightCounts = weightCounts, MeshPartList = mesh.MeshPartList, BlendIndicesArrayList = blendIndicesList2, BlendWeightsArrayList = blendWeightList2, MaterialNum = mesh.MeshInfo.MaterialNum, MeshPartCount = mesh.MeshInfo.MeshPartCount, MeshPartOffset = mesh.MeshInfo.MeshPartOffset }; meshList.Add(modelMeshData); } } }
/// <summary> /// Gets the texture data and displays it for the currently selected item given a specified race, part, type(if applicable), and map /// </summary> private void MapComboBoxChanged() { if (saveClone != null) { //saveClone.UnlockBits(cloneLock); saveClone.Dispose(); } Bitmap colorBmp = null; int offset = 0; bool isVFX = false; bool isUI = false; if (selectedMap.Name.Equals(Strings.Normal)) { fullPath = mtrlData.NormalPath; offset = mtrlData.NormalOffset; FullPathString = fullPath; } else if (selectedMap.Name.Equals(Strings.Specular)) { fullPath = mtrlData.SpecularPath; offset = mtrlData.SpecularOffset; FullPathString = fullPath; } else if (selectedMap.Name.Equals(Strings.Diffuse)) { fullPath = mtrlData.DiffusePath; offset = mtrlData.DiffuseOffset; FullPathString = fullPath; } else if (selectedMap.Name.Equals(Strings.Mask) || selectedMap.Name.Equals(Strings.Skin)) { if (selectedItem.ItemName.Equals(Strings.Face_Paint) || selectedItem.ItemName.Equals(Strings.Equipment_Decals)) { string part; if (selectedItem.ItemName.Equals(Strings.Equipment_Decals)) { if (!SelectedPart.Name.Contains("stigma")) { part = selectedPart.Name.PadLeft(3, '0'); } else { part = SelectedPart.Name; } } else { part = selectedPart.Name; } fullPath = String.Format(mtrlData.MaskPath, part); offset = MTRL.GetDecalOffset(selectedItem.ItemName, selectedPart.Name); } else { fullPath = mtrlData.MaskPath; offset = mtrlData.MaskOffset; } FullPathString = fullPath; } else if (selectedMap.Name.Equals(Strings.ColorSet)) { colorBmp = TEX.TextureToBitmap(mtrlData.ColorData, 9312, 4, 16); fullPath = mtrlData.MTRLPath; FullPathString = fullPath; } else if (SelectedMap.Name.Contains("Icon")) { if (SelectedMap.Name.Contains("HQ")) { fullPath = mtrlData.UIHQPath; offset = mtrlData.UIHQOffset; } else { fullPath = mtrlData.UIPath; offset = mtrlData.UIOffset; } FullPathString = fullPath; isUI = true; } else if (selectedItem.ItemCategory.Equals(Strings.Maps)) { if (selectedMap.Name.Contains("HighRes Map")) { fullPath = string.Format(mtrlData.UIPath, "_m"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } else if (selectedMap.Name.Contains("LowRes Map")) { fullPath = string.Format(mtrlData.UIPath, "_s"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } else if (selectedMap.Name.Contains("PoI")) { fullPath = string.Format(mtrlData.UIPath, "d"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } else if (selectedMap.Name.Contains("HighRes Mask")) { fullPath = string.Format(mtrlData.UIPath, "m_m"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } else if (selectedMap.Name.Contains("LowRes Mask")) { fullPath = string.Format(mtrlData.UIPath, "m_s"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } FullPathString = fullPath; isUI = true; } else if (selectedItem.ItemCategory.Equals("HUD") || selectedItem.ItemCategory.Equals("LoadingImage")) { fullPath = mtrlData.UIPath; offset = mtrlData.UIOffset; FullPathString = fullPath; isUI = true; } else { fullPath = SelectedMap.ID; var VFXFolder = fullPath.Substring(0, fullPath.LastIndexOf("/")); var VFXFile = fullPath.Substring(fullPath.LastIndexOf("/") + 1); offset = Helper.GetDataOffset(FFCRC.GetHash(VFXFolder), FFCRC.GetHash(VFXFile), Strings.ItemsDat); FullPathString = fullPath; isVFX = true; } string line; JsonEntry modEntry = null; bool inModList = false; try { using (StreamReader sr = new StreamReader(Properties.Settings.Default.Modlist_Directory)) { while ((line = sr.ReadLine()) != null) { modEntry = JsonConvert.DeserializeObject <JsonEntry>(line); if (modEntry.fullPath.Equals(fullPath)) { inModList = true; break; } } } } catch (Exception ex) { MessageBox.Show("[TVM] Error Accessing .modlist File \n" + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } if (inModList) { var currOffset = Helper.GetDataOffset(FFCRC.GetHash(modEntry.fullPath.Substring(0, modEntry.fullPath.LastIndexOf("/"))), FFCRC.GetHash(Path.GetFileName(modEntry.fullPath)), modEntry.datFile); if (currOffset == modEntry.modOffset) { ActiveToggle = "Disable"; } else if (currOffset == modEntry.originalOffset) { ActiveToggle = "Enable"; } else { ActiveToggle = "Error"; } ActiveEnabled = true; } else { ActiveEnabled = false; ActiveToggle = "Enable/Disable"; } if (offset == 0) { TextureType = "Type: 16.16.16.16f ABGR\nMipMaps: None"; TextureDimensions = "(4 x 16)"; alphaBitmap = Imaging.CreateBitmapSourceFromHBitmap(colorBmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); alphaBitmap.Freeze(); var removeAlphaBitmap = SetAlpha(colorBmp, 255); noAlphaBitmap = Imaging.CreateBitmapSourceFromHBitmap(removeAlphaBitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); noAlphaBitmap.Freeze(); colorBmp.Dispose(); removeAlphaBitmap.Dispose(); } else { if (!isVFX) { if (!isUI) { texData = TEX.GetTex(offset, Strings.ItemsDat); } else { texData = TEX.GetTex(offset, Strings.UIDat); } } else { texData = TEX.GetVFX(offset, Strings.ItemsDat); } string mipMaps = "Yes (" + texData.MipCount + ")"; if (texData.MipCount < 1) { mipMaps = "None"; } TextureType = "Type: " + texData.TypeString + "\nMipMaps: " + mipMaps; TextureDimensions = "(" + texData.Width + " x " + texData.Height + ")"; var clonerect = new Rectangle(0, 0, texData.Width, texData.Height); saveClone = texData.BMP.Clone(new Rectangle(0, 0, texData.Width, texData.Height), PixelFormat.Format32bppArgb); alphaBitmap = Imaging.CreateBitmapSourceFromHBitmap(texData.BMP.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); alphaBitmap.Freeze(); if (!isUI) { var removeAlphaBitmap = SetAlpha(texData.BMP, 255); noAlphaBitmap = Imaging.CreateBitmapSourceFromHBitmap(removeAlphaBitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); noAlphaBitmap.Freeze(); removeAlphaBitmap.Dispose(); } } try { ImageEffect = new ColorChannels() { Channel = new System.Windows.Media.Media3D.Point4D(1.0f, 1.0f, 1.0f, 0.0f) }; } catch (Exception ex) { Debug.WriteLine(ex.StackTrace); } if (!isUI) { ImageSource = noAlphaBitmap; SetColorChannelFilter(imageEffect); ChannelsEnabled = true; } else { ImageSource = alphaBitmap; SetColorChannelFilter(imageEffect); ChannelsEnabled = true; } SaveEnabled = true; texData.Dispose(); string dxPath = Path.GetFileNameWithoutExtension(fullPath); string savePath = Properties.Settings.Default.Save_Directory + "/" + selectedCategory + "/" + selectedItem.ItemName + "/" + dxPath + ".dds"; if (selectedCategory.Equals("UI")) { savePath = Properties.Settings.Default.Save_Directory + "/" + selectedCategory + "/" + selectedItem.ItemCategory + "/" + dxPath + ".dds"; } if (File.Exists(savePath)) { ImportEnabled = true; } else { ImportEnabled = false; } string folderPath = Properties.Settings.Default.Save_Directory + "/" + selectedCategory + "/" + selectedItem.ItemName; if (selectedCategory.Equals("UI")) { folderPath = Properties.Settings.Default.Save_Directory + "/" + selectedCategory + "/" + selectedItem.ItemCategory; } if (Directory.Exists(folderPath)) { OpenEnabled = true; } else { OpenEnabled = false; } }
/// <summary> /// Gets the races that have an mtrl file for the given item /// </summary> /// <remarks> /// Goes through a list of all races to see if an mtrl file exists within the items material folder /// </remarks> /// <param name="item">Selected item to check</param> /// <param name="selectedCategory">The category of the selected item</param> /// <param name="IMCVersion">The items version from its imc file</param> /// <returns>ObservableCollection of ComboBoxInfo classes containing race and race ID</returns> public static ObservableCollection <ComboBoxInfo> GetMTRLRaces(ItemData item, string selectedCategory, string IMCVersion) { ObservableCollection <ComboBoxInfo> cbiList; Dictionary <int, string> racesDict = new Dictionary <int, string>(); string MTRLFolder; if (item.ItemName.Equals(Strings.Body)) { foreach (string race in Info.IDRace.Keys) { MTRLFolder = String.Format(Strings.BodyMtrlFolder, race, "0001"); racesDict.Add(FFCRC.GetHash(MTRLFolder), race); } cbiList = new ObservableCollection <ComboBoxInfo>(Helper.FolderExistsListRace(racesDict)); } else if (item.ItemName.Equals(Strings.Face)) { foreach (string race in Info.IDRace.Keys) { MTRLFolder = String.Format(Strings.FaceMtrlFolder, race, "0001"); racesDict.Add(FFCRC.GetHash(MTRLFolder), race); } cbiList = new ObservableCollection <ComboBoxInfo>(Helper.FolderExistsListRace(racesDict)); } else if (item.ItemName.Equals(Strings.Hair)) { foreach (string race in Info.IDRace.Keys) { MTRLFolder = String.Format(Strings.HairMtrlFolder, race, "0001"); racesDict.Add(FFCRC.GetHash(MTRLFolder), race); } cbiList = new ObservableCollection <ComboBoxInfo>(Helper.FolderExistsListRace(racesDict)); } else if (item.ItemName.Equals(Strings.Tail)) { foreach (string race in Info.IDRace.Keys) { MTRLFolder = String.Format(Strings.TailMtrlFolder, race, "0001"); racesDict.Add(FFCRC.GetHash(MTRLFolder), race); } cbiList = new ObservableCollection <ComboBoxInfo>(Helper.FolderExistsListRace(racesDict)); } else if (item.ItemName.Equals(Strings.Face_Paint) || item.ItemName.Equals(Strings.Equipment_Decals) || item.ItemCategory.Equals("9901")) { cbiList = new ObservableCollection <ComboBoxInfo>(); ComboBoxInfo cbi = new ComboBoxInfo() { Name = Strings.All, ID = "0", IsNum = true }; cbiList.Add(cbi); } else if (selectedCategory.Equals(Strings.Pets) || selectedCategory.Equals(Strings.Mounts) || selectedCategory.Equals(Strings.Minions)) { cbiList = new ObservableCollection <ComboBoxInfo>(); ComboBoxInfo cbi = new ComboBoxInfo() { Name = Strings.Monster, ID = "0", IsNum = true }; cbiList.Add(cbi); } else { string type = Helper.GetCategoryType(selectedCategory); ObservableCollection <ComboBoxInfo> cbiInfo = new ObservableCollection <ComboBoxInfo>(); var fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion)); if (type.Equals("weapon") || type.Equals("accessory") || type.Equals("food")) { cbiInfo.Add(new ComboBoxInfo() { Name = Strings.All, ID = Strings.All, IsNum = false }); } else { foreach (string raceID in Info.raceID.Values) { Console.WriteLine(selectedCategory); var MTRLFile = String.Format(Strings.EquipMtrlFile, raceID, item.PrimaryModelID, Info.slotAbr[selectedCategory], "a"); var fileHash = FFCRC.GetHash(MTRLFile); if (fileHashList.Contains(fileHash)) { cbiInfo.Add(new ComboBoxInfo() { Name = Info.IDRace[raceID], ID = raceID, IsNum = false }); } } } cbiList = cbiInfo; } return(cbiList); }
/// <summary> /// Parses the data of the items MTRL file /// </summary> /// <param name="item">currently selected item</param> /// <param name="raceID">currently selected race</param> /// <param name="selectedCategory">the category of the item</param> /// <param name="part">currently selected part</param> /// <param name="IMCVersion">version of selected item</param> /// <param name="type">the items type</param> /// <returns>A tuple containing the MTRLInfo and Observable Collection containing texture map names</returns> public static Tuple <MTRLData, ObservableCollection <ComboBoxInfo> > GetMTRLData(ItemData item, string raceID, string selectedCategory, string part, string IMCVersion, string type, string modelID, string VFXVersion) { string MTRLFolder = ""; string MTRLFile = ""; int offset; ObservableCollection <ComboBoxInfo> cbiList; Tuple <MTRLData, ObservableCollection <ComboBoxInfo> > info; MTRLData mtrlInfo = null; if (item.ItemName.Equals(Strings.Face)) { MTRLFolder = String.Format(Strings.FaceMtrlFolder, raceID, part.PadLeft(4, '0')); var fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(MTRLFolder)); cbiList = new ObservableCollection <ComboBoxInfo>(); if (fileHashList.Contains(FFCRC.GetHash(String.Format(Strings.FaceMtrlFile, raceID, part.PadLeft(4, '0'), "fac")))) { cbiList.Add(new ComboBoxInfo() { Name = Strings.Face, ID = "", IsNum = false }); } if (fileHashList.Contains(FFCRC.GetHash(String.Format(Strings.FaceMtrlFile, raceID, part.PadLeft(4, '0'), "iri")))) { cbiList.Add(new ComboBoxInfo() { Name = Strings.Iris, ID = "", IsNum = false }); } if (fileHashList.Contains(FFCRC.GetHash(String.Format(Strings.FaceMtrlFile, raceID, part.PadLeft(4, '0'), "etc")))) { cbiList.Add(new ComboBoxInfo() { Name = Strings.Etc, ID = "", IsNum = false }); } info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, cbiList); } else if (item.ItemName.Equals(Strings.Body)) { MTRLFolder = String.Format(Strings.BodyMtrlFolder, raceID, part.PadLeft(4, '0')); MTRLFile = String.Format(Strings.BodyMtrlFile, raceID, part.PadLeft(4, '0')); if (Helper.FileExists(FFCRC.GetHash(MTRLFile), FFCRC.GetHash(MTRLFolder))) { offset = Helper.GetItemOffset(FFCRC.GetHash(MTRLFolder), FFCRC.GetHash(MTRLFile)); mtrlInfo = GetMTRLInfo(offset, true); info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, mtrlInfo.TextureMaps); } else { return(null); } } else if (item.ItemName.Equals(Strings.Hair)) { MTRLFolder = String.Format(Strings.HairMtrlFolder, raceID, part.PadLeft(4, '0')); var fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(MTRLFolder)); cbiList = new ObservableCollection <ComboBoxInfo>(); if (fileHashList.Contains(FFCRC.GetHash(String.Format(Strings.HairMtrlFile, raceID, part.PadLeft(4, '0'), "hir", "a")))) { cbiList.Add(new ComboBoxInfo() { Name = Strings.Hair, ID = "", IsNum = false }); } if (fileHashList.Contains(FFCRC.GetHash(String.Format(Strings.HairMtrlFile, raceID, part.PadLeft(4, '0'), "acc", "b")))) { cbiList.Add(new ComboBoxInfo() { Name = Strings.Accessory, ID = "", IsNum = false }); } info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, cbiList); } else if (item.ItemName.Equals(Strings.Face_Paint) || item.ItemName.Equals(Strings.Equipment_Decals)) { string texPath = "chara/common/texture/"; if (item.ItemName.Equals(Strings.Face_Paint)) { texPath = texPath + "decal_face/_decal_{0}.tex"; } else { texPath = texPath + "decal_equip/-decal_{0}.tex"; } cbiList = new ObservableCollection <ComboBoxInfo> { new ComboBoxInfo() { Name = Strings.Mask, ID = "", IsNum = false } } ; mtrlInfo = new MTRLData() { MaskPath = texPath }; info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, cbiList); } else if (item.ItemName.Equals(Strings.Tail)) { MTRLFolder = String.Format(Strings.TailMtrlFolder, raceID, part.PadLeft(4, '0')); MTRLFile = string.Format(Strings.TailMtrlFile, raceID, part.PadLeft(4, '0')); if (Helper.FileExists(FFCRC.GetHash(MTRLFile), FFCRC.GetHash(MTRLFolder))) { offset = Helper.GetItemOffset(FFCRC.GetHash(MTRLFolder), FFCRC.GetHash(MTRLFile)); mtrlInfo = GetMTRLInfo(offset, true); info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, mtrlInfo.TextureMaps); } else { return(null); } } else if (selectedCategory.Equals(Strings.Pets)) { int p = 1; if (item.ItemName.Equals(Strings.Selene) || item.ItemName.Equals(Strings.Bishop_Autoturret)) { p = 2; } MTRLFolder = String.Format(Strings.MonsterMtrlFolder, Info.petID[item.ItemName], p.ToString().PadLeft(4, '0')) + part.PadLeft(4, '0'); MTRLFile = String.Format(Strings.MonsterMtrlFile, Info.petID[item.ItemName], p.ToString().PadLeft(4, '0'), "a"); if (Helper.FileExists(FFCRC.GetHash(MTRLFile), FFCRC.GetHash(MTRLFolder))) { offset = Helper.GetItemOffset(FFCRC.GetHash(MTRLFolder), FFCRC.GetHash(MTRLFile)); mtrlInfo = GetMTRLInfo(offset, false); mtrlInfo.MTRLPath = MTRLFolder + "/" + MTRLFile; mtrlInfo.MTRLOffset = offset; info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, mtrlInfo.TextureMaps); } else { return(null); } } else if (selectedCategory.Equals(Strings.Mounts)) { if (item.PrimaryMTRLFolder.Contains("demihuman")) { SortedSet <ComboBoxInfo> typeSet = new SortedSet <ComboBoxInfo>(); var fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion)); foreach (string abr in Info.slotAbr.Values) { MTRLFile = String.Format(Strings.DemiMtrlFile, item.PrimaryModelID.PadLeft(4, '0'), item.PrimaryModelBody.PadLeft(4, '0'), abr); if (fileHashList.Contains(FFCRC.GetHash(MTRLFile))) { typeSet.Add(new ComboBoxInfo() { Name = Info.slotAbr.FirstOrDefault(x => x.Value == abr).Key, ID = "", IsNum = false }); } } info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, new ObservableCollection <ComboBoxInfo>(typeSet.ToList())); } else { MTRLFile = String.Format(Strings.MonsterMtrlFile, item.PrimaryModelID.PadLeft(4, '0'), item.PrimaryModelBody.PadLeft(4, '0'), part); if (Helper.FileExists(FFCRC.GetHash(MTRLFile), FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion))) { offset = Helper.GetItemOffset(FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion), FFCRC.GetHash(MTRLFile)); mtrlInfo = GetMTRLInfo(offset, false); mtrlInfo.MTRLPath = item.PrimaryMTRLFolder + IMCVersion + "/" + MTRLFile; mtrlInfo.MTRLOffset = offset; info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, mtrlInfo.TextureMaps); } else { return(null); } } } else if (selectedCategory.Equals(Strings.Minions)) { MTRLFile = String.Format(Strings.MonsterMtrlFile, item.PrimaryModelID.PadLeft(4, '0'), item.PrimaryModelBody.PadLeft(4, '0'), part); if (Helper.FileExists(FFCRC.GetHash(MTRLFile), FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion))) { offset = Helper.GetItemOffset(FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion), FFCRC.GetHash(MTRLFile)); mtrlInfo = GetMTRLInfo(offset, false); mtrlInfo.MTRLPath = item.PrimaryMTRLFolder + IMCVersion + "/" + MTRLFile; mtrlInfo.MTRLOffset = offset; info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, mtrlInfo.TextureMaps); } else { return(null); } } else { var categoryType = Helper.GetCategoryType(selectedCategory); string imcVersion = IMCVersion; MTRLFolder = item.PrimaryMTRLFolder; if (categoryType.Equals("weapon")) { if (!modelID.Equals("")) { MTRLFile = String.Format(Strings.WeapMtrlFile, modelID, item.PrimaryModelBody, part); MTRLFolder = item.PrimaryMTRLFolder.Substring(0, 14) + modelID + item.PrimaryMTRLFolder.Substring(18); } else { MTRLFile = String.Format(Strings.WeapMtrlFile, item.PrimaryModelID, item.PrimaryModelBody, part); } if (part.Equals("s") || type.Equals("Secondary")) { MTRLFolder = item.SecondaryMTRLFolder; imcVersion = IMC.GetVersion(selectedCategory, item, true).Item1; MTRLFile = String.Format(Strings.WeapMtrlFile, item.SecondaryModelID, item.SecondaryModelBody, "a"); } } else if (categoryType.Equals("accessory")) { MTRLFile = String.Format(Strings.AccMtrlFile, item.PrimaryModelID, Info.slotAbr[selectedCategory], part); } else if (categoryType.Equals("food")) { MTRLFile = String.Format(Strings.WeapMtrlFile, item.PrimaryModelID, item.PrimaryModelBody, "a"); } else { MTRLFile = String.Format(Strings.EquipMtrlFile, raceID, item.PrimaryModelID, Info.slotAbr[selectedCategory], part); } string VFXFolder = ""; string VFXFile = ""; ObservableCollection <ComboBoxInfo> cbi = new ObservableCollection <ComboBoxInfo>(); if (Helper.FileExists(FFCRC.GetHash(MTRLFile), FFCRC.GetHash(MTRLFolder + imcVersion))) { offset = Helper.GetItemOffset(FFCRC.GetHash(MTRLFolder + imcVersion), FFCRC.GetHash(MTRLFile)); mtrlInfo = GetMTRLInfo(offset, false); mtrlInfo.MTRLPath = MTRLFolder + imcVersion + "/" + MTRLFile; mtrlInfo.MTRLOffset = offset; foreach (var texMap in mtrlInfo.TextureMaps) { cbi.Add(texMap); } } else { return(null); } if (!VFXVersion.Equals("0000")) { if (categoryType.Equals("equipment")) { VFXFolder = string.Format(Strings.EquipVFXFolder, item.PrimaryModelID); VFXFile = string.Format(Strings.EquipVFXFile, VFXVersion); } else if (categoryType.Equals("weapon")) { VFXFolder = string.Format(Strings.WeapVFXFolder, item.PrimaryModelID, item.PrimaryModelBody); VFXFile = string.Format(Strings.WeapVFXFile, VFXVersion); } if (Helper.FileExists(FFCRC.GetHash(VFXFile), FFCRC.GetHash(VFXFolder))) { offset = Helper.GetItemOffset(FFCRC.GetHash(VFXFolder), FFCRC.GetHash(VFXFile)); var vfxData = GetVFXData(offset); foreach (var vfx in vfxData.VFXPaths) { cbi.Add(new ComboBoxInfo() { Name = Path.GetFileNameWithoutExtension(vfx), ID = vfx, IsNum = false }); } } } info = new Tuple <MTRLData, ObservableCollection <ComboBoxInfo> >(mtrlInfo, cbi); } return(info); }
/// <summary> /// Gets the parts for the selected item /// </summary> /// <param name="item">currently selected item</param> /// <param name="raceID">currently selected race</param> /// <param name="IMCVersion">version of selected item</param> /// <param name="selectedCategory">The category of the selected item</param> /// <returns></returns> public static ObservableCollection <ComboBoxInfo> GetMTRLParts(ItemData item, string raceID, string IMCVersion, string selectedCategory) { Dictionary <int, int> MTRLDict = new Dictionary <int, int>(); List <ComboBoxInfo> cbiList; List <int> fileHashList; string MTRLFolder; if (item.ItemName.Equals(Strings.Body)) { for (int i = 1; i < 251; i++) { MTRLFolder = String.Format(Strings.BodyMtrlFolder, raceID, i.ToString().PadLeft(4, '0')); MTRLDict.Add(FFCRC.GetHash(MTRLFolder), i); } cbiList = new List <ComboBoxInfo>(Helper.FolderExistsList(MTRLDict)); } else if (item.ItemName.Equals(Strings.Face)) { for (int i = 1; i < 251; i++) { MTRLFolder = String.Format(Strings.FaceMtrlFolder, raceID, i.ToString().PadLeft(4, '0')); MTRLDict.Add(FFCRC.GetHash(MTRLFolder), i); } cbiList = new List <ComboBoxInfo>(Helper.FolderExistsList(MTRLDict)); } else if (item.ItemName.Equals(Strings.Hair)) { for (int i = 1; i < 251; i++) { MTRLFolder = String.Format(Strings.HairMtrlFolder, raceID, i.ToString().PadLeft(4, '0')); MTRLDict.Add(FFCRC.GetHash(MTRLFolder), i); } cbiList = new List <ComboBoxInfo>(Helper.FolderExistsList(MTRLDict)); } else if (item.ItemName.Equals(Strings.Tail)) { for (int i = 1; i < 251; i++) { MTRLFolder = String.Format(Strings.TailMtrlFolder, raceID, i.ToString().PadLeft(4, '0')); MTRLDict.Add(FFCRC.GetHash(MTRLFolder), i); } cbiList = new List <ComboBoxInfo>(Helper.FolderExistsList(MTRLDict)); } else if (item.ItemName.Equals(Strings.Face_Paint)) { fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(Strings.FacePaintFolder)); cbiList = new List <ComboBoxInfo>(); for (int i = 1; i < 100; i++) { MTRLFolder = String.Format(Strings.FacePaintFile, i); if (fileHashList.Contains(FFCRC.GetHash(MTRLFolder))) { cbiList.Add(new ComboBoxInfo() { Name = i.ToString(), ID = i.ToString(), IsNum = true }); } } } else if (item.ItemName.Equals(Strings.Equipment_Decals)) { fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(Strings.EquipDecalFolder)); cbiList = new List <ComboBoxInfo>(); for (int i = 1; i < 300; i++) { MTRLFolder = String.Format(Strings.EquipDecalFile, i.ToString().PadLeft(3, '0')); if (fileHashList.Contains(FFCRC.GetHash(MTRLFolder))) { cbiList.Add(new ComboBoxInfo() { Name = i.ToString(), ID = i.ToString(), IsNum = true }); } } } else if (selectedCategory.Equals(Strings.Pets)) { int part = 1; if (item.ItemName.Equals(Strings.Selene) || item.ItemName.Equals(Strings.Bishop_Autoturret)) { part = 2; } for (int i = 1; i < 20; i++) { MTRLFolder = String.Format(Strings.MonsterMtrlFolder, Info.petID[item.ItemName], part.ToString().PadLeft(4, '0')) + i.ToString().PadLeft(4, '0'); MTRLDict.Add(FFCRC.GetHash(MTRLFolder), i); } cbiList = new List <ComboBoxInfo>(Helper.FolderExistsList(MTRLDict)); } else if (selectedCategory.Equals(Strings.Mounts)) { cbiList = new List <ComboBoxInfo>(); if (item.PrimaryMTRLFolder.Contains("demihuman")) { cbiList.Add(new ComboBoxInfo() { Name = "a", ID = "a", IsNum = false }); } else { Dictionary <string, int> mountMTRLDict = new Dictionary <string, int>(); string[] parts = { "a", "b", "c", "d", "e" }; fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion)); foreach (string c in parts) { MTRLFolder = String.Format(Strings.MonsterMtrlFile, item.PrimaryModelID.PadLeft(4, '0'), item.PrimaryModelBody.PadLeft(4, '0'), c); if (fileHashList.Contains(FFCRC.GetHash(MTRLFolder))) { cbiList.Add(new ComboBoxInfo() { Name = c, ID = c, IsNum = false }); } } } } else if (selectedCategory.Equals(Strings.Minions)) { Dictionary <string, int> minionMTRLDict = new Dictionary <string, int>(); string[] parts = { "a", "b", "c", "d", "e" }; cbiList = new List <ComboBoxInfo>(); fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion)); foreach (string c in parts) { MTRLFolder = String.Format(Strings.MonsterMtrlFile, item.PrimaryModelID.PadLeft(4, '0'), item.PrimaryModelBody.PadLeft(4, '0'), c); if (fileHashList.Contains(FFCRC.GetHash(MTRLFolder))) { cbiList.Add(new ComboBoxInfo() { Name = c, ID = c, IsNum = false }); } } } else { string type = Helper.GetCategoryType(selectedCategory); string[] parts = { "a", "b", "c", "d", "e" }; cbiList = new List <ComboBoxInfo>(); fileHashList = Helper.GetAllFilesInFolder(FFCRC.GetHash(item.PrimaryMTRLFolder + IMCVersion)); foreach (string part in parts) { if (type.Equals("weapon") || type.Equals("food")) { MTRLFolder = String.Format(Strings.WeapMtrlFile, item.PrimaryModelID, item.PrimaryModelBody, part); } else if (type.Equals("accessory")) { MTRLFolder = String.Format(Strings.AccMtrlFile, item.PrimaryModelID, Info.slotAbr[selectedCategory], part); } else { MTRLFolder = String.Format(Strings.EquipMtrlFile, raceID, item.PrimaryModelID, Info.slotAbr[selectedCategory], part); } if (fileHashList.Contains(FFCRC.GetHash(MTRLFolder))) { cbiList.Add(new ComboBoxInfo() { Name = part, ID = part, IsNum = false }); } } if (item.SecondaryModelID != null) { cbiList.Add(new ComboBoxInfo() { Name = "s", ID = "s", IsNum = false }); } cbiList.Sort(); } return(new ObservableCollection <ComboBoxInfo>(cbiList)); }
/// <summary> /// Creates a list of minions contained in companion_(num)_(language).exd /// </summary> /// <returns>List<Items> Items:Item data associated with Minion</returns> public static List <ItemData> MakeMinionsList() { string minionFile = String.Format(Strings.MinionFile, Strings.Language); byte[] minionsBytes = Helper.GetDecompressedEXDData(Helper.GetEXDOffset(FFCRC.GetHash(Strings.ExdFolder), FFCRC.GetHash(minionFile))); byte[] modelChara = Helper.GetDecompressedEXDData(Helper.GetEXDOffset(FFCRC.GetHash(Strings.ExdFolder), FFCRC.GetHash(Strings.ModelCharaFile))); List <ItemData> minionsDict = new List <ItemData>(); using (BinaryReader br = new BinaryReader(new MemoryStream(minionsBytes))) { using (BinaryReader br1 = new BinaryReader(new MemoryStream(modelChara))) { br.ReadBytes(8); int offsetTableSize = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0); br1.ReadBytes(8); int offsetTableSize1 = BitConverter.ToInt32(br1.ReadBytes(4).Reverse().ToArray(), 0); for (int i = 0; i < offsetTableSize; i += 8) { br.BaseStream.Seek(i + 32, SeekOrigin.Begin); int index = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0); int tableOffset = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0); br.BaseStream.Seek(tableOffset, SeekOrigin.Begin); br.ReadBytes(13); int firstText = br.ReadByte(); if (firstText >= 2) { ItemData item = new ItemData(); br.ReadBytes(8); uint modelIndex = BitConverter.ToUInt16(br.ReadBytes(2).Reverse().ToArray(), 0); br.ReadBytes(30); byte[] minionNameBytes = br.ReadBytes(firstText - 1); item.ItemName = Helper.ToTitleCase((Encoding.UTF8.GetString(minionNameBytes)).Replace("\0", "")); item.ItemCategory = Strings.Minion_Category; for (int j = 0; j < offsetTableSize1; j += 8) { br1.BaseStream.Seek(j + 32, SeekOrigin.Begin); uint index1 = BitConverter.ToUInt32(br1.ReadBytes(4).Reverse().ToArray(), 0); if (index1 == modelIndex) { int tableOffset1 = BitConverter.ToInt32(br1.ReadBytes(4).Reverse().ToArray(), 0); br1.BaseStream.Seek(tableOffset1, SeekOrigin.Begin); br1.ReadBytes(6); item.PrimaryModelID = (BitConverter.ToInt16(br1.ReadBytes(2).Reverse().ToArray(), 0)).ToString().PadLeft(4, '0'); br1.ReadBytes(3); item.PrimaryModelBody = (br1.ReadByte()).ToString().PadLeft(4, '0'); item.PrimaryModelVariant = (br1.ReadByte()).ToString(); item.PrimaryMTRLFolder = string.Format(Strings.MonsterMtrlFolder, item.PrimaryModelID, item.PrimaryModelBody); if (!item.PrimaryModelID.Equals("0000")) { minionsDict.Add(item); } break; } } } } } } return(minionsDict); }
/// <summary> /// Creates a list of Items contained in item_(num)_(language).exd /// </summary> /// <returns>Dictionary<string, Items> String:Item Name Items:Item data associated with Item</returns> public static List <ItemData> MakeItemsList() { List <ItemData> itemsDict = new List <ItemData>(); List <int> itemOffsetList = new List <int>(); var smallClothesMTRL = "chara/equipment/e0000/material/v"; //smallclothes are not in the item list, so they are added manualy ItemData item = new ItemData() { ItemName = "SmallClothes Body", ItemCategory = "4", PrimaryModelID = "0000", PrimaryModelVariant = "1", PrimaryMTRLFolder = smallClothesMTRL }; itemsDict.Add(item); item = new ItemData() { ItemName = "SmallClothes Legs", ItemCategory = "7", PrimaryModelID = "0000", PrimaryModelVariant = "1", PrimaryMTRLFolder = smallClothesMTRL }; itemsDict.Add(item); item = new ItemData() { ItemName = "SmallClothes Feet", ItemCategory = "8", PrimaryModelID = "0000", PrimaryModelVariant = "1", PrimaryMTRLFolder = smallClothesMTRL }; itemsDict.Add(item); //searches item files which increase in increments of 500 in 0a0000 index until one does not exist for (int i = 0; ; i += 500) { string itemExd = String.Format(Strings.itemFile, i, Strings.Language); int offset = Helper.GetEXDOffset(FFCRC.GetHash(Strings.ExdFolder), FFCRC.GetHash(itemExd)); if (offset != 0) { itemOffsetList.Add(offset); } else { break; } } foreach (int offset in itemOffsetList) { using (BinaryReader br = new BinaryReader(new MemoryStream(Helper.GetDecompressedEXDData(offset)))) { br.ReadBytes(8); int offsetTableSize = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0); for (int i = 0; i < offsetTableSize; i += 8) { br.BaseStream.Seek(i + 32, SeekOrigin.Begin); int index = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0); int tableOffset = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0); br.BaseStream.Seek(tableOffset, SeekOrigin.Begin); int entrySize = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0); br.ReadBytes(16); int lastText = BitConverter.ToInt16(br.ReadBytes(2).Reverse().ToArray(), 0); br.ReadBytes(3); if (lastText > 10) { item = new ItemData(); bool hasSecondary = false; br.ReadBytes(7); byte[] textureDetails = br.ReadBytes(4).ToArray(); int itemCheck = textureDetails[3]; if (itemCheck != 0) { int weaponCheck = textureDetails[1]; if (weaponCheck == 0) { item.PrimaryModelVariant = textureDetails[3].ToString().PadLeft(2, '0'); } else { item.PrimaryModelVariant = weaponCheck.ToString().PadLeft(2, '0'); item.PrimaryModelBody = textureDetails[3].ToString().PadLeft(4, '0'); } item.PrimaryModelID = BitConverter.ToInt16(br.ReadBytes(2).Reverse().ToArray(), 0).ToString().PadLeft(4, '0'); br.ReadBytes(2); textureDetails = br.ReadBytes(4).ToArray(); int secondaryCheck = textureDetails[3]; if (secondaryCheck != 0) { hasSecondary = true; weaponCheck = textureDetails[1]; if (weaponCheck == 0) { item.SecondaryModelVariant = textureDetails[3].ToString().PadLeft(2, '0'); } else { item.SecondaryModelVariant = weaponCheck.ToString().PadLeft(2, '0'); item.SecondaryModelBody = textureDetails[3].ToString().PadLeft(4, '0'); } item.SecondaryModelID = BitConverter.ToInt16(br.ReadBytes(2).Reverse().ToArray(), 0).ToString().PadLeft(4, '0'); br.ReadBytes(2); } if (!hasSecondary) { br.ReadBytes(110); } else { br.ReadBytes(106); } byte[] slotBytes = br.ReadBytes(4).ToArray(); item.ItemCategory = slotBytes[0].ToString(); br.ReadBytes(lastText); item.ItemName = Encoding.UTF8.GetString(br.ReadBytes(entrySize - (lastText + 152))).Replace("\0", ""); if (item.ItemCategory.Equals("0") || item.ItemCategory.Equals("1") || item.ItemCategory.Equals("2") || item.ItemCategory.Equals("13") || item.ItemCategory.Equals("14")) { item.PrimaryMTRLFolder = String.Format(Strings.WeapMtrlFolder, item.PrimaryModelID, item.PrimaryModelBody); if (hasSecondary) { item.SecondaryMTRLFolder = String.Format(Strings.WeapMtrlFolder, item.SecondaryModelID, item.SecondaryModelBody); } } else if (item.ItemCategory.Equals("9") || item.ItemCategory.Equals("10") || item.ItemCategory.Equals("11") || item.ItemCategory.Equals("12")) { item.PrimaryMTRLFolder = String.Format(Strings.AccMtrlFolder, item.PrimaryModelID); } else { item.PrimaryMTRLFolder = String.Format(Strings.EquipMtrlFolder, item.PrimaryModelID); } try { itemsDict.Add(item); } catch (Exception e) { Debug.WriteLine("EXD_MakeItemListError " + e); } } } } } } return(itemsDict); }
/// <summary> /// Gets the MTRL data of the given mesh /// </summary> /// <param name="mesh">The mesh to obtain the data from</param> /// <returns>The MTRLData of the given mesh</returns> public MTRLData MTRL3D(int mesh) { MTRLData mtrlData = null; bool isDemiHuman = false; if (selectedItem.PrimaryMTRLFolder != null) { isDemiHuman = selectedItem.PrimaryMTRLFolder.Contains("demihuman"); } var itemVersion = IMC.GetVersion(selectedCategory, selectedItem, false).Item1; var itemType = Helper.GetCategoryType(selectedCategory); try { if (selectedItem.ItemName.Equals(Strings.Face) || selectedItem.ItemName.Equals(Strings.Hair) || isDemiHuman) { string slotAbr; if (isDemiHuman) { slotAbr = Info.slotAbr[SelectedPart.Name]; } else if (selectedCategory.Equals(Strings.Character)) { var race = materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("c") + 1, 4); if (materialStrings[mesh].Contains("h00")) { var hairNum = materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("h00") + 1, 4); var mtrlFolder = string.Format(Strings.HairMtrlFolder, race, hairNum); slotAbr = materialStrings[mesh].Substring(materialStrings[mesh].LastIndexOf("_") - 3, 3); slotAbr = Info.HairTypes.FirstOrDefault(x => x.Value == slotAbr).Key; var hairInfo = MTRL.GetMTRLDatafromType(selectedItem, SelectedRace, hairNum, slotAbr, itemVersion, selectedCategory); return(hairInfo.Item1); } else if (materialStrings[mesh].Contains("f00")) { var faceNum = materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("f00") + 1, 4); var mtrlFolder = string.Format(Strings.FaceMtrlFolder, race, faceNum); slotAbr = materialStrings[mesh].Substring(materialStrings[mesh].LastIndexOf("_") - 3, 3); slotAbr = Info.FaceTypes.FirstOrDefault(x => x.Value == slotAbr).Key; var faceInfo = MTRL.GetMTRLDatafromType(selectedItem, SelectedRace, faceNum, slotAbr, itemVersion, selectedCategory); return(faceInfo.Item1); } else { slotAbr = selectedPart.Name; } } else { slotAbr = selectedPart.Name; } var info = MTRL.GetMTRLDatafromType(selectedItem, SelectedRace, selectedPart.Name, slotAbr, itemVersion, selectedCategory); mtrlData = info.Item1; } else { Tuple <MTRLData, ObservableCollection <ComboBoxInfo> > info; if (itemType.Equals("character") || itemType.Equals("equipment")) { try { if (materialStrings[mesh].Contains("b00") || materialStrings[mesh].Contains("t00") || materialStrings[mesh].Contains("h00")) { if (materialStrings[mesh].Contains("mt_c")) { var mtrlFolder = ""; var race = materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("c") + 1, 4); if (materialStrings[mesh].Contains("b00")) { mtrlFolder = string.Format(Strings.BodyMtrlFolder, race, materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("b00") + 1, 4)); } else if (materialStrings[mesh].Contains("t00")) { mtrlFolder = string.Format(Strings.TailMtrlFolder, race, materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("t00") + 1, 4)); } else if (materialStrings[mesh].Contains("h00")) { mtrlFolder = string.Format(Strings.HairMtrlFolder, race, materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("h00") + 1, 4)); } var mtrlFile = materialStrings[mesh].Substring(1); return(MTRL.GetMTRLInfo(Helper.GetItemOffset(FFCRC.GetHash(mtrlFolder), FFCRC.GetHash(mtrlFile)), true)); } } } catch (Exception ex) { Debug.WriteLine(ex.Message); Debug.WriteLine(ex.StackTrace); } } else { info = MTRL.GetMTRLData(selectedItem, SelectedRace.ID, selectedCategory, SelectedPart.Name, itemVersion, "", "", "0000"); } if (SelectedPart.Name.Equals("Secondary")) { info = MTRL.GetMTRLData(selectedItem, SelectedRace.ID, selectedCategory, SelectedPart.Name, itemVersion, "Secondary", "", "0000"); } else { string part = "a"; string itemID = selectedItem.PrimaryModelID; if (materialStrings.Count > 1) { try { part = materialStrings[mesh].Substring(materialStrings[mesh].LastIndexOf("_") + 1, 1); itemID = materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("_") + 2, 4); } catch (Exception ex) { Debug.WriteLine(ex.Message); Debug.WriteLine(ex.StackTrace); } } if (selectedCategory.Equals(Strings.Pets)) { part = "1"; } info = MTRL.GetMTRLData(selectedItem, SelectedRace.ID, selectedCategory, part, itemVersion, "", itemID, "0000"); } if (info != null) { mtrlData = info.Item1; } else { var combo = new ComboBoxInfo() { Name = "Default", ID = materialStrings[mesh].Substring(materialStrings[mesh].IndexOf("c") + 1, 4), IsNum = false }; if (SelectedPart.Name.Equals("-")) { info = MTRL.GetMTRLData(selectedItem, combo.ID, selectedCategory, "a", itemVersion, "", "", "0000"); } else { info = MTRL.GetMTRLData(selectedItem, combo.ID, selectedCategory, SelectedPart.Name, itemVersion, "", "", "0000"); } mtrlData = info.Item1; } } } catch (Exception ex) { Debug.WriteLine(ex.Message); Debug.WriteLine(ex.StackTrace); return(null); } return(mtrlData); }
public void SaveAllDDS() { foreach (var m in MapComboBox) { int offset = 0; if (m.Name.Equals(Strings.Normal)) { fullPath = mtrlData.NormalPath; offset = mtrlData.NormalOffset; } else if (m.Name.Equals(Strings.Specular)) { fullPath = mtrlData.SpecularPath; offset = mtrlData.SpecularOffset; } else if (m.Name.Equals(Strings.Diffuse)) { fullPath = mtrlData.DiffusePath; offset = mtrlData.DiffuseOffset; } else if (m.Name.Equals(Strings.Mask) || m.Name.Equals(Strings.Skin)) { if (selectedItem.ItemName.Equals(Strings.Face_Paint) || selectedItem.ItemName.Equals(Strings.Equipment_Decals)) { string part; if (selectedItem.ItemName.Equals(Strings.Equipment_Decals)) { if (!SelectedPart.Name.Contains("stigma")) { part = selectedPart.Name.PadLeft(3, '0'); } else { part = SelectedPart.Name; } } else { part = selectedPart.Name; } fullPath = String.Format(mtrlData.MaskPath, part); offset = MTRL.GetDecalOffset(selectedItem.ItemName, selectedPart.Name); } else { fullPath = mtrlData.MaskPath; offset = mtrlData.MaskOffset; } } else if (m.Name.Equals(Strings.ColorSet)) { fullPath = mtrlData.MTRLPath; } else if (m.Name.Contains("Icon")) { if (m.Name.Contains("HQ")) { fullPath = mtrlData.UIHQPath; offset = mtrlData.UIHQOffset; } else { fullPath = mtrlData.UIPath; offset = mtrlData.UIOffset; } } else if (selectedItem.ItemCategory.Equals(Strings.Maps)) { if (selectedMap.Name.Contains("HighRes Map")) { fullPath = string.Format(mtrlData.UIPath, "_m"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } else if (selectedMap.Name.Contains("LowRes Map")) { fullPath = string.Format(mtrlData.UIPath, "_s"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } else if (selectedMap.Name.Contains("PoI")) { fullPath = string.Format(mtrlData.UIPath, "d"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } else if (selectedMap.Name.Contains("HighRes Mask")) { fullPath = string.Format(mtrlData.UIPath, "m_m"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } else if (selectedMap.Name.Contains("LowRes Mask")) { fullPath = string.Format(mtrlData.UIPath, "m_s"); offset = mtrlData.UIOffset = int.Parse(selectedMap.ID); } } else if (selectedItem.ItemCategory.Equals("HUD")) { fullPath = mtrlData.UIPath; offset = mtrlData.UIOffset; } else { fullPath = SelectedMap.ID; var VFXFolder = fullPath.Substring(0, fullPath.LastIndexOf("/")); var VFXFile = fullPath.Substring(fullPath.LastIndexOf("/") + 1); offset = Helper.GetDataOffset(FFCRC.GetHash(VFXFolder), FFCRC.GetHash(VFXFile), Strings.ItemsDat); } if (offset != 0) { if (m.ID.Contains("vfx")) { texData = TEX.GetVFX(offset, Strings.ItemsDat); } else { if (selectedCategory.Equals("UI")) { texData = TEX.GetTex(offset, Strings.UIDat); } else { texData = TEX.GetTex(offset, Strings.ItemsDat); } } } SaveTex.SaveDDS(selectedCategory, selectedItem.ItemName, fullPath, m.Name, mtrlData, texData, selectedItem.ItemCategory); } }
/// <summary> /// Gets the data from the MTRL file /// </summary> /// <param name="offset">MTRL file offset</param> /// <param name="isUncompressed">DX compression</param> /// <returns>Data from MTRL file</returns> public static MTRLData GetMTRLInfo(int offset, bool isUncompressed) { int datNum = ((offset / 8) & 0x000f) / 2; MTRLData mtrlInfo = new MTRLData(); using (BinaryReader br = new BinaryReader(new MemoryStream(Helper.GetType2DecompressedData(offset, datNum)))) { br.BaseStream.Seek(6, SeekOrigin.Begin); short colorDataSize = br.ReadInt16(); short textureNameSize = br.ReadInt16(); br.ReadBytes(2); byte numOfTextures = br.ReadByte(); byte numOfMaps = br.ReadByte(); byte numOfColorSets = br.ReadByte(); byte unknown = br.ReadByte(); int headerEnd = 16 + ((numOfTextures + numOfMaps + numOfColorSets) * 4); int[] texPathOffsets = new int[numOfTextures + 1]; for (int i = 0; i < numOfTextures + 1; i++) { texPathOffsets[i] = br.ReadInt16(); br.ReadBytes(2); } br.ReadBytes((numOfMaps - 1) * 4); for (int i = 0; i < numOfTextures; i++) { br.BaseStream.Seek(headerEnd + texPathOffsets[i], SeekOrigin.Begin); string fullPath = Encoding.ASCII.GetString(br.ReadBytes(texPathOffsets[i + 1] - texPathOffsets[i])).Replace("\0", ""); string fileName = fullPath.Substring(fullPath.LastIndexOf("/") + 1); if (Properties.Settings.Default.DX_Ver.Equals("DX11") && isUncompressed) { if (textureNameSize > 50) { fileName = fileName.Insert(0, "--"); int mtrlOffset = Helper.GetItemOffset(FFCRC.GetHash(fullPath.Substring(0, fullPath.LastIndexOf("/"))), FFCRC.GetHash(fileName)); if (mtrlOffset == 0) { fileName = fileName.Substring(2); } } } int texHash = FFCRC.GetHash(fileName); string mapName = GetMapName(fileName); if (fileName.Contains("_s.tex")) { mtrlInfo.SpecularPath = fullPath.Substring(0, fullPath.LastIndexOf("/")) + "/" + fileName; mtrlInfo.TextureMaps.Add(new ComboBoxInfo() { Name = mapName, ID = "", IsNum = false }); mtrlInfo.SpecularOffset = Helper.GetItemOffset(FFCRC.GetHash(fullPath.Substring(0, fullPath.LastIndexOf("/"))), FFCRC.GetHash(fileName)); } else if (fileName.Contains("_d.tex")) { mtrlInfo.DiffusePath = fullPath.Substring(0, fullPath.LastIndexOf("/")) + "/" + fileName; mtrlInfo.TextureMaps.Add(new ComboBoxInfo() { Name = mapName, ID = "", IsNum = false }); mtrlInfo.DiffuseOffset = Helper.GetItemOffset(FFCRC.GetHash(fullPath.Substring(0, fullPath.LastIndexOf("/"))), FFCRC.GetHash(fileName)); } else if (fileName.Contains("_n.tex")) { mtrlInfo.NormalPath = fullPath.Substring(0, fullPath.LastIndexOf("/")) + "/" + fileName; mtrlInfo.TextureMaps.Add(new ComboBoxInfo() { Name = mapName, ID = "", IsNum = false }); mtrlInfo.NormalOffset = Helper.GetItemOffset(FFCRC.GetHash(fullPath.Substring(0, fullPath.LastIndexOf("/"))), FFCRC.GetHash(fileName)); } else if (fileName.Contains("_m.tex")) { mtrlInfo.MaskPath = fullPath.Substring(0, fullPath.LastIndexOf("/")) + "/" + fileName; mtrlInfo.TextureMaps.Add(new ComboBoxInfo() { Name = mapName, ID = "", IsNum = false }); mtrlInfo.MaskOffset = Helper.GetItemOffset(FFCRC.GetHash(fullPath.Substring(0, fullPath.LastIndexOf("/"))), FFCRC.GetHash(fileName)); } } if (numOfColorSets > 0 && colorDataSize > 0) { br.BaseStream.Seek((16 + (numOfTextures * 4) + (numOfMaps * 4) + (numOfColorSets * 4) + textureNameSize + 4), SeekOrigin.Begin); mtrlInfo.TextureMaps.Add(new ComboBoxInfo() { Name = Strings.ColorSet, ID = "", IsNum = false }); if (colorDataSize == 544) { mtrlInfo.ColorData = br.ReadBytes(colorDataSize - 32); mtrlInfo.ColorFlags = br.ReadBytes(32); } else { mtrlInfo.ColorData = br.ReadBytes(colorDataSize); } } } return(mtrlInfo); }
public ModListModel ParseEntry(JsonEntry entry) { ModListModel mlm = new ModListModel(); string race, map, part, type; if (entry.fullPath.Contains("weapon") || entry.fullPath.Contains("accessory") || entry.fullPath.Contains("decal") || entry.fullPath.Contains("vfx") || entry.fullPath.Contains("ui/")) { race = Strings.All; } else if (entry.fullPath.Contains("monster") || entry.fullPath.Contains("demihuman")) { race = Strings.Monster; } else { race = entry.fullPath.Substring(entry.fullPath.LastIndexOf('/')); if ((entry.fullPath.Contains("_fac_") || entry.fullPath.Contains("_etc_") || entry.fullPath.Contains("_acc_")) && Properties.Settings.Default.DX_Ver.Equals(Strings.DX11)) { race = race.Substring(race.LastIndexOf("--c") + 3, 4); } else if (entry.fullPath.Contains("_fac_") || entry.fullPath.Contains("_etc_") || entry.fullPath.Contains("_acc_")) { race = race.Substring(race.LastIndexOf("/c") + 2, 4); } else if (entry.fullPath.Contains("_c_")) { race = race.Substring(race.IndexOf("_c") + 2, 4); } else { race = race.Substring(race.LastIndexOf('c') + 1, 4); } race = Info.IDRace[race]; } mlm.Race = race; if (entry.fullPath.Contains("_d.")) { map = Strings.Diffuse; } else if (entry.fullPath.Contains("_n.")) { map = Strings.Normal; } else if (entry.fullPath.Contains("_s.")) { map = Strings.Specular; } else if (entry.fullPath.Contains("material")) { map = Strings.ColorSet; } else if (entry.fullPath.Contains("model")) { map = "3D"; } else if (entry.fullPath.Contains("ui/")) { map = "UI"; } else { map = Strings.Mask; } mlm.Map = map; if (entry.fullPath.Contains("_b_")) { part = "b"; } else if (entry.fullPath.Contains("_c_")) { part = "c"; } else if (entry.fullPath.Contains("_d_")) { part = "d"; } else if (entry.fullPath.Contains("decal")) { part = entry.fullPath.Substring(entry.fullPath.LastIndexOf('_') + 1, entry.fullPath.LastIndexOf('.') - (entry.fullPath.LastIndexOf('_') + 1)); } else { part = "a"; } mlm.Part = part; if (entry.fullPath.Contains("_iri_")) { type = "Iris"; } else if (entry.fullPath.Contains("_etc_")) { type = "Etc."; } else if (entry.fullPath.Contains("_fac_")) { type = "Face"; } else if (entry.fullPath.Contains("_hir_")) { type = "Hair"; } else if (entry.fullPath.Contains("_acc_")) { type = "Accessory"; } else if (entry.fullPath.Contains("demihuman")) { type = entry.fullPath.Substring(entry.fullPath.LastIndexOf('_') - 3, 3); type = (Info.slotAbr).FirstOrDefault(x => x.Value == type).Key; } else { type = "-"; } mlm.Type = type; if (entry.fullPath.Contains("material")) { var info = MTRL.GetMTRLInfo(entry.modOffset, false); var bitmap = TEX.TextureToBitmap(info.ColorData, 9312, 4, 16); mlm.BMP = Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } else if (entry.fullPath.Contains("model")) { mlm.BMP = new BitmapImage(new Uri("pack://application:,,,/FFXIV TexTools 2;component/Resources/3DModel.png")); } else { TEXData texData; if (entry.fullPath.Contains("vfx")) { texData = TEX.GetVFX(entry.modOffset, entry.datFile); } else { if (entry.fullPath.Contains("icon")) { texData = TEX.GetTex(entry.modOffset, entry.datFile); } else { texData = TEX.GetTex(entry.modOffset, entry.datFile); } } mlm.BMP = Imaging.CreateBitmapSourceFromHBitmap(texData.BMP.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } var offset = Helper.GetDataOffset(FFCRC.GetHash(entry.fullPath.Substring(0, entry.fullPath.LastIndexOf("/"))), FFCRC.GetHash(Path.GetFileName(entry.fullPath)), entry.datFile); if (offset == entry.modOffset) { mlm.ActiveBorder = Brushes.Green; mlm.Active = Brushes.Transparent; mlm.ActiveOpacity = 1; } else if (offset == entry.originalOffset) { mlm.ActiveBorder = Brushes.Red; mlm.Active = Brushes.Gray; mlm.ActiveOpacity = 0.5f; } else { mlm.ActiveBorder = Brushes.Red; mlm.Active = Brushes.Red; mlm.ActiveOpacity = 1; } mlm.Entry = entry; return(mlm); }
/// <summary> /// Gets the texture data and displays it for the currently selected item given a specified race, part, type(if applicable), and map /// </summary> private void MapComboBoxChanged() { Bitmap colorBmp = null; int offset = 0; bool isVFX = false; if (selectedMap.Name.Equals(Strings.Normal)) { fullPath = mtrlData.NormalPath; offset = mtrlData.NormalOffset; FullPathString = fullPath + " [" + FFCRC.GetHash(fullPath) + "]"; } else if (selectedMap.Name.Equals(Strings.Specular)) { fullPath = mtrlData.SpecularPath; offset = mtrlData.SpecularOffset; FullPathString = fullPath + " [" + FFCRC.GetHash(fullPath) + "]"; } else if (selectedMap.Name.Equals(Strings.Diffuse)) { fullPath = mtrlData.DiffusePath; offset = mtrlData.DiffuseOffset; FullPathString = fullPath + " [" + FFCRC.GetHash(fullPath) + "]"; } else if (selectedMap.Name.Equals(Strings.Mask) || selectedMap.Name.Equals(Strings.Skin)) { if (selectedItem.ItemName.Equals(Strings.Face_Paint) || selectedItem.ItemName.Equals(Strings.Equipment_Decals)) { string part; if (selectedItem.ItemName.Equals(Strings.Equipment_Decals)) { part = selectedPart.Name.PadLeft(3, '0'); } else { part = selectedPart.Name; } fullPath = String.Format(mtrlData.MaskPath, part); offset = MTRL.GetDecalOffset(selectedItem.ItemName, selectedPart.Name); FullPathString = fullPath + " [" + FFCRC.GetHash(fullPath) + "]"; } else { fullPath = mtrlData.MaskPath; offset = mtrlData.MaskOffset; FullPathString = fullPath + " [" + FFCRC.GetHash(fullPath) + "]"; } } else if (selectedMap.Name.Equals(Strings.ColorSet)) { colorBmp = TEX.TextureToBitmap(mtrlData.ColorData, 9312, 4, 16); fullPath = mtrlData.MTRLPath; FullPathString = fullPath + " [" + FFCRC.GetHash(fullPath) + "]"; } else { fullPath = SelectedMap.ID; var VFXFolder = fullPath.Substring(0, fullPath.LastIndexOf("/")); var VFXFile = fullPath.Substring(fullPath.LastIndexOf("/") + 1); offset = Helper.GetItemOffset(FFCRC.GetHash(VFXFolder), FFCRC.GetHash(VFXFile)); FullPathString = fullPath; isVFX = true; } if (Properties.Settings.Default.Mod_List == 0) { string line; JsonEntry modEntry = null; bool inModList = false; try { using (StreamReader sr = new StreamReader(Info.modListDir)) { while ((line = sr.ReadLine()) != null) { modEntry = JsonConvert.DeserializeObject <JsonEntry>(line); if (modEntry.fullPath.Equals(fullPath)) { inModList = true; break; } } } } catch (Exception ex) { MessageBox.Show("[Main] Error Accessing .modlist File \n" + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } if (inModList) { var currOffset = Helper.GetItemOffset(FFCRC.GetHash(modEntry.fullPath.Substring(0, modEntry.fullPath.LastIndexOf("/"))), FFCRC.GetHash(Path.GetFileName(modEntry.fullPath))); if (currOffset == modEntry.modOffset) { ActiveToggle = "Disable"; } else if (currOffset == modEntry.originalOffset) { ActiveToggle = "Enable"; } else { ActiveToggle = "Error"; } ActiveEnabled = true; } else { ActiveEnabled = false; ActiveToggle = "Enable/Disable"; } } else { ActiveEnabled = false; ActiveToggle = "Enable/Disable"; } if (offset == 0) { TextureType = "A16B16G16R16F"; textureType = "A16B16G16R16F"; TextureDimensions = "(4 x 16)"; textureDimensions = "(4 x 16)"; alphaBitmap = Imaging.CreateBitmapSourceFromHBitmap(colorBmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); var removeAlphaBitmap = SetAlpha(colorBmp, 255); noAlphaBitmap = Imaging.CreateBitmapSourceFromHBitmap(removeAlphaBitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); colorBmp.Dispose(); removeAlphaBitmap.Dispose(); } else { if (!isVFX) { texData = TEX.GetTex(offset); } else { texData = TEX.GetVFX(offset); } TextureType = texData.TypeString; TextureDimensions = "(" + texData.Width + " x " + texData.Height + ")"; alphaBitmap = Imaging.CreateBitmapSourceFromHBitmap(texData.BMP.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); var removeAlphaBitmap = SetAlpha(texData.BMP, 255); noAlphaBitmap = Imaging.CreateBitmapSourceFromHBitmap(removeAlphaBitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); removeAlphaBitmap.Dispose(); } try { ImageEffect = new ColorChannels() { Channel = new System.Windows.Media.Media3D.Point4D(1.0f, 1.0f, 1.0f, 0.0f) }; } catch (Exception ex) { Debug.WriteLine(ex.StackTrace); } ImageSource = noAlphaBitmap; SetColorChannelFilter(); SaveEnabled = true; texData.Dispose(); string dxPath = Path.GetFileNameWithoutExtension(fullPath); if (File.Exists(Properties.Settings.Default.Save_Directory + "/" + selectedCategory + "/" + selectedItem.ItemName + "/" + dxPath + ".dds")) { ImportEnabled = true; } else { ImportEnabled = false; } }
private void Bw_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; List <SearchItems> workList = new List <SearchItems>(); string[] eqSlots = new string[] { "met", "glv", "dwn", "sho", "top", }; string[] acSlots = new string[] { "ear", "nek", "rir", "wrs" }; string[] parts = new string[] { "a", "b", "c", "d" }; List <int> variantList = new List <int>(); List <int> bodyList = new List <int>(); Dictionary <int, List <string> > slotList = new Dictionary <int, List <string> >(); string folder = Strings.EquipMtrlFolder; string file = Strings.EquipMtrlFile; if (SelectedType.Name.Equals(Strings.Weapon)) { folder = Strings.WeapMtrlFolder; file = Strings.WeapMtrlFile; } else if (SelectedType.Name.Equals(Strings.Accessory)) { folder = Strings.AccMtrlFolder; file = Strings.AccMtrlFile; } else if (SelectedType.Name.Equals(Strings.Monster)) { folder = Strings.MonsterMtrlFolder; file = Strings.MonsterMtrlFile; } else if (SelectedType.Name.Equals("DemiHuman")) { folder = Strings.DemiMtrlFolder; file = Strings.DemiMtrlFile; } if (SelectedType.Name.Equals(Strings.Equipment) || SelectedType.Name.Equals(Strings.Accessory)) { for (int i = 0; i <= 200; i++) { var folderCheck = string.Format(folder, searchText.PadLeft(4, '0')) + i.ToString().PadLeft(4, '0'); if (Helper.FolderExists(FFCRC.GetHash(folderCheck), Strings.ItemsDat)) { variantList.Add(i); } worker.ReportProgress(i / 2); ProgressLabel = "Variant: " + i; } int var = 0; if (variantList.Count > 0) { foreach (int v in variantList) { slotList.Add(v, new List <string>()); var eFolder = string.Format(folder, searchText.PadLeft(4, '0')) + v.ToString().PadLeft(4, '0'); var files = Helper.GetAllFilesInFolder(FFCRC.GetHash(eFolder), Strings.ItemsDat); if (SelectedType.Name.Equals(Strings.Accessory)) { foreach (var s in acSlots) { foreach (var p in parts) { var aFile = string.Format(file, searchText.PadLeft(4, '0'), s, p); var fileHash = FFCRC.GetHash(aFile); if (files.Contains(fileHash)) { workList.Add(new SearchItems() { Race = Info.IDRace["0101"], RaceID = "0101", Slot = accSlotDict[s], SlotAbr = s, SlotID = Info.IDSlot[accSlotDict[s]], Body = "-", Variant = v.ToString(), Part = p }); } ProgressLabel = "Slot: " + s + "Part: " + p; } } } else { foreach (var r in Info.IDRace.Keys) { foreach (var s in eqSlots) { foreach (var p in parts) { var eFile = string.Format(file, r, searchText.PadLeft(4, '0'), s, p); var fileHash = FFCRC.GetHash(eFile); if (files.Contains(fileHash)) { if (!slotList[v].Contains(s)) { slotList[v].Add(s); workList.Add(new SearchItems() { Race = Info.IDRace[r], RaceID = r, Slot = equipSlotDict[s], SlotAbr = s, SlotID = Info.IDSlot[equipSlotDict[s]], Body = "-", Variant = v.ToString(), Part = p }); } } ProgressLabel = "Race: " + r + " Slot: " + s + "Part: " + p; } } } } int prog = (int)(((double)var / Info.IDRace.Count) * 100f); worker.ReportProgress(prog); var++; } } else { folder = Strings.EquipMDLFolder; file = Strings.EquipMDLFile; if (SelectedType.Name.Equals(Strings.Accessory)) { folder = Strings.AccMDLFolder; file = Strings.AccMDLFile; } var folderCheck = string.Format(folder, searchText.PadLeft(4, '0')); if (Helper.FolderExists(FFCRC.GetHash(folderCheck), Strings.ItemsDat)) { variantList.Add(1); } slotList.Add(1, new List <string>()); var files = Helper.GetAllFilesInFolder(FFCRC.GetHash(folderCheck), Strings.ItemsDat); if (SelectedType.Name.Equals(Strings.Accessory)) { foreach (var s in acSlots) { var aFile = string.Format(file, "0101", searchText.PadLeft(4, '0'), s); var fileHash = FFCRC.GetHash(aFile); if (files.Contains(fileHash)) { workList.Add(new SearchItems() { Race = Info.IDRace["0101"], RaceID = "0101", Slot = accSlotDict[s], SlotAbr = s, SlotID = Info.IDSlot[accSlotDict[s]], Body = "-", Variant = "1", Part = "a" }); } ProgressLabel = "Slot: " + s; } } else { foreach (var r in Info.IDRace.Keys) { foreach (var s in eqSlots) { var eFile = string.Format(file, r, searchText.PadLeft(4, '0'), s); var fileHash = FFCRC.GetHash(eFile); if (files.Contains(fileHash)) { workList.Add(new SearchItems() { Race = Info.IDRace[r], RaceID = r, Slot = equipSlotDict[s], SlotAbr = s, SlotID = Info.IDSlot[equipSlotDict[s]], Body = "-", Variant = "1", Part = "a" }); } ProgressLabel = "Race: " + r + " Slot: " + s; } } } } ProgressLabel = "Found: " + workList.Count; } else { if (!SelectedType.Name.Equals("DemiHuman")) { string slotName = Strings.Main_Hand; if (SelectedType.Name.Equals(Strings.Monster)) { slotName = Strings.Mounts; } for (int i = 0; i <= 50; i++) { var folderCheck = string.Format(folder, searchText.PadLeft(4, '0'), i.ToString().PadLeft(4, '0')) + "0001"; if (Helper.FolderExists(FFCRC.GetHash(folderCheck), Strings.ItemsDat)) { bodyList.Add(i); } ProgressLabel = "Body: " + i; worker.ReportProgress(i * 2); } for (int i = 0; i < bodyList.Count; i++) { for (int j = 0; j <= 20; j++) { var wmFolder = string.Format(folder, searchText.PadLeft(4, '0'), bodyList[i].ToString().PadLeft(4, '0')) + j.ToString().PadLeft(4, '0'); var files = Helper.GetAllFilesInFolder(FFCRC.GetHash(wmFolder), Strings.ItemsDat); foreach (var p in parts) { var wmFile = string.Format(file, searchText.PadLeft(4, '0'), bodyList[i].ToString().PadLeft(4, '0'), p); var fileHash = FFCRC.GetHash(wmFile); if (files.Contains(fileHash)) { workList.Add(new SearchItems() { Race = "-", Slot = slotName, SlotID = Info.IDSlot[slotName], Body = bodyList[i].ToString(), Variant = j.ToString(), Part = p }); } ProgressLabel = "Body: " + bodyList[i] + " Variant: " + j + " Part: " + p; } } int prog = (int)(((double)(i + 1) / bodyList.Count) * 100f); worker.ReportProgress(prog); } ProgressLabel = "Found: " + workList.Count; } else { string slotName = "DemiHuman"; for (int i = 0; i <= 100; i++) { var folderCheck = string.Format(folder, searchText.PadLeft(4, '0'), i.ToString().PadLeft(4, '0')) + "0001"; if (Helper.FolderExists(FFCRC.GetHash(folderCheck), Strings.ItemsDat)) { bodyList.Add(i); } ProgressLabel = "Equipment: " + i; worker.ReportProgress(i * 2); } for (int i = 0; i < bodyList.Count; i++) { for (int j = 0; j <= 20; j++) { var wmFolder = string.Format(folder, searchText.PadLeft(4, '0'), bodyList[i].ToString().PadLeft(4, '0')) + j.ToString().PadLeft(4, '0'); var files = Helper.GetAllFilesInFolder(FFCRC.GetHash(wmFolder), Strings.ItemsDat); foreach (var eq in eqSlots) { var wmFile = string.Format(file, searchText.PadLeft(4, '0'), bodyList[i].ToString().PadLeft(4, '0'), eq); var fileHash = FFCRC.GetHash(wmFile); if (files.Contains(fileHash)) { workList.Add(new SearchItems() { Race = "-", Slot = equipSlotDict[eq], SlotID = Info.IDSlot[equipSlotDict[eq]], Body = bodyList[i].ToString(), Variant = j.ToString(), Part = eq }); } ProgressLabel = "Body: " + bodyList[i] + " Variant: " + j; } } int prog = (int)(((double)(i + 1) / bodyList.Count) * 100f); worker.ReportProgress(prog); } ProgressLabel = "Found: " + workList.Count; } } e.Result = workList; }
/// <summary> /// Parses the MDL file to obtain model information /// </summary> /// <param name="selectedItem">The currently selected item</param> /// <param name="selectedRace">The currently selected race</param> /// <param name="selectedBody">The currently selected body</param> /// <param name="selectedPart">The currently selected part</param> /// <param name="selectedCategory">The items category </param> public MDL(ItemData selectedItem, string selectedCategory, string selectedRace, string selectedBody, string selectedPart) { string itemType = Helper.GetCategoryType(selectedCategory); string MDLFolder = ""; if (itemType.Equals("weapon") || itemType.Equals("food")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); } else { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); } } else if (itemType.Equals("accessory")) { MDLFolder = string.Format(Strings.AccMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.AccMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else if (itemType.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = string.Format(Strings.BodyMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.BodyMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = string.Format(Strings.FaceMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.FaceMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = string.Format(Strings.HairMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.HairMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = string.Format(Strings.TailMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.TailMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } } else if (itemType.Equals("monster")) { bool isDemiHuman = false; if (selectedItem.PrimaryMTRLFolder != null) { isDemiHuman = selectedItem.PrimaryMTRLFolder.Contains("demihuman"); } string ID = ""; string body = ""; if (selectedCategory.Equals(Strings.Pets)) { ID = Info.petID[selectedItem.ItemName]; body = "0001"; } else { ID = selectedItem.PrimaryModelID.PadLeft(4, '0'); body = selectedItem.PrimaryModelBody; } if (isDemiHuman) { MDLFolder = string.Format(Strings.DemiMDLFolder, ID, body); MDLFile = string.Format(Strings.DemiMDLFile, ID, body, selectedPart); } else { MDLFolder = string.Format(Strings.MonsterMDLFolder, ID, body); MDLFile = string.Format(Strings.MonsterMDLFile, ID, body); } } else { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } int offset = Helper.GetItemOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile)); int datNum = ((offset / 8) & 0x000f) / 2; offset = Helper.OffsetCorrection(datNum, offset); var MDLDatData = Helper.GetType3DecompressedData(offset, datNum); using (BinaryReader br = new BinaryReader(new MemoryStream(MDLDatData.Item1))) { ModelData modelData = new ModelData(); // The size of the header + (size of the mesh information block (136 bytes) * the number of meshes) + padding br.BaseStream.Seek(64 + 136 * MDLDatData.Item2 + 4, SeekOrigin.Begin); var modelStringCount = br.ReadInt32(); var stringBlockSize = br.ReadInt32(); var stringBlock = br.ReadBytes(stringBlockSize); var unknown = br.ReadBytes(4); var totalMeshCount = br.ReadInt16(); var attributeStringCount = br.ReadInt16(); var meshPartsCount = br.ReadInt16(); var materialStringCount = br.ReadInt16(); var boneStringCount = br.ReadInt16(); var boneListCount = br.ReadInt16(); var unknown1 = br.ReadInt16(); var unknown2 = br.ReadInt16(); var unknown3 = br.ReadInt16(); var unknown4 = br.ReadInt16(); var unknown5 = br.ReadInt16(); var unknown6 = br.ReadInt16(); br.ReadBytes(10); var unknown7 = br.ReadInt16(); br.ReadBytes(16); using (BinaryReader br1 = new BinaryReader(new MemoryStream(stringBlock))) { br1.BaseStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < attributeStringCount; i++) { while (br1.ReadByte() != 0) { //extract each atribute string here } } for (int i = 0; i < boneStringCount; i++) { while (br1.ReadByte() != 0) { //extact each bone string here } } for (int i = 0; i < materialStringCount; i++) { byte b; List <byte> name = new List <byte>(); while ((b = br1.ReadByte()) != 0) { name.Add(b); } string material = Encoding.ASCII.GetString(name.ToArray()); material = material.Replace("\0", ""); materialStrings.Add(material); } } br.ReadBytes(32 * unknown5); for (int i = 0; i < 3; i++) { LevelOfDetail LoD = new LevelOfDetail(); LoD.MeshOffset = br.ReadInt16(); LoD.MeshCount = br.ReadInt16(); br.ReadBytes(40); LoD.VertexDataSize = br.ReadInt32(); LoD.IndexDataSize = br.ReadInt32(); LoD.VertexOffset = br.ReadInt32(); LoD.IndexOffset = br.ReadInt32(); modelData.LoD.Add(LoD); } var savePos = br.BaseStream.Position; for (int i = 0; i < modelData.LoD.Count; i++) { List <MeshDataInfo> meshInfoList = new List <MeshDataInfo>(); for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { modelData.LoD[i].MeshList.Add(new Mesh()); meshInfoList.Clear(); br.BaseStream.Seek((i * 136) + 68, SeekOrigin.Begin); var dataBlockNum = br.ReadByte(); while (dataBlockNum != 255) { MeshDataInfo meshInfo = new MeshDataInfo() { VertexDataBlock = dataBlockNum, Offset = br.ReadByte(), DataType = br.ReadByte(), UseType = br.ReadByte() }; meshInfoList.Add(meshInfo); br.ReadBytes(4); dataBlockNum = br.ReadByte(); } modelData.LoD[i].MeshList[j].MeshDataInfoList = meshInfoList.ToArray(); } } br.BaseStream.Seek(savePos, SeekOrigin.Begin); for (int x = 0; x < modelData.LoD.Count; x++) { for (int i = 0; i < modelData.LoD[x].MeshCount; i++) { MeshInfo meshInfo = new MeshInfo() { VertexCount = br.ReadInt32(), IndexCount = br.ReadInt32(), MaterialNum = br.ReadInt16(), MeshPartOffset = br.ReadInt16(), MeshPartCount = br.ReadInt16(), BoneListIndex = br.ReadInt16(), IndexDataOffset = br.ReadInt32() }; for (int j = 0; j < 3; j++) { meshInfo.VertexDataOffsets.Add(br.ReadInt32()); } for (int k = 0; k < 3; k++) { meshInfo.VertexSizes.Add(br.ReadByte()); } meshInfo.VertexDataBlockCount = br.ReadByte(); modelData.LoD[x].MeshList[i].MeshInfo = meshInfo; } } br.ReadBytes(attributeStringCount * 4); br.ReadBytes(unknown6 * 20); for (int i = 0; i < modelData.LoD.Count; i++) { foreach (var mesh in modelData.LoD[i].MeshList) { for (int j = 0; j < mesh.MeshInfo.MeshPartCount; j++) { MeshPart meshPart = new MeshPart() { IndexOffset = br.ReadInt32(), IndexCount = br.ReadInt32(), Attributes = br.ReadInt32(), BoneOffset = br.ReadInt16(), BoneCount = br.ReadInt16() }; mesh.MeshPartList.Add(meshPart); } } } br.ReadBytes(unknown7 * 12); br.ReadBytes(materialStringCount * 4); br.ReadBytes(boneStringCount * 4); for (int i = 0; i < boneListCount; i++) { Bones bones = new Bones(); for (int j = 0; j < 64; j++) { bones.BoneData.Add(br.ReadInt16()); } bones.BoneCount = br.ReadInt32(); modelData.BoneSet.Add(bones); } br.ReadBytes(unknown1 * 16); br.ReadBytes(unknown2 * 12); br.ReadBytes(unknown3 * 4); var boneIndexSize = br.ReadInt32(); for (int i = 0; i < boneIndexSize / 2; i++) { modelData.BoneIndicies.Add(br.ReadInt16()); } int padding = br.ReadByte(); br.ReadBytes(padding); for (int i = 0; i < 4; i++) { ModelMaterial.BoundingBox boundingBox = new ModelMaterial.BoundingBox(); for (int j = 0; j < 4; j++) { boundingBox.PointA.Add(br.ReadSingle()); } for (int k = 0; k < 4; k++) { boundingBox.PointB.Add(br.ReadSingle()); } modelData.BoundingBoxes.Add(boundingBox); } for (int i = 0; i < 3; i++) { for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { Mesh mesh = modelData.LoD[i].MeshList[j]; for (int k = 0; k < mesh.MeshInfo.VertexDataBlockCount; k++) { br.BaseStream.Seek(modelData.LoD[i].VertexOffset + mesh.MeshInfo.VertexDataOffsets[k], SeekOrigin.Begin); mesh.MeshVertexData.Add(br.ReadBytes(mesh.MeshInfo.VertexSizes[k] * mesh.MeshInfo.VertexCount)); } br.BaseStream.Seek(modelData.LoD[i].IndexOffset + (mesh.MeshInfo.IndexDataOffset * 2), SeekOrigin.Begin); mesh.IndexData = br.ReadBytes(2 * mesh.MeshInfo.IndexCount); } } int vertex = 0, coordinates = 0, normals = 0, tangents = 0, colors = 0; for (int i = 0; i < modelData.LoD[0].MeshCount; i++) { objBytes.Clear(); var vertexList = new Vector3Collection(); var texCoordList = new Vector2Collection(); var normalList = new Vector3Collection(); var tangentList = new Vector3Collection(); var colorsList = new Color4Collection(); var indexList = new IntCollection(); Mesh mesh = modelData.LoD[0].MeshList[i]; MeshDataInfo[] meshDataInfoList = mesh.MeshDataInfoList; int c = 0; foreach (var meshDataInfo in meshDataInfoList) { if (meshDataInfo.UseType == 0) { vertex = c; } else if (meshDataInfo.UseType == 3) { normals = c; } else if (meshDataInfo.UseType == 4) { coordinates = c; } else if (meshDataInfo.UseType == 6) { tangents = c; } else if (meshDataInfo.UseType == 7) { colors = c; } c++; } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[vertex].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[vertex].VertexDataBlock] + meshDataInfoList[vertex].Offset, SeekOrigin.Begin); if (meshDataInfoList[vertex].DataType == 13 || meshDataInfoList[vertex].DataType == 14) { System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h3 = System.Half.ToHalf((ushort)br1.ReadInt16()); float x = HalfHelper.HalfToSingle(h1); float y = HalfHelper.HalfToSingle(h2); float z = HalfHelper.HalfToSingle(h3); objBytes.Add("v " + x.ToString() + " " + y.ToString() + " " + z.ToString() + " "); vertexList.Add(new Vector3(x, y, z)); } else if (meshDataInfoList[vertex].DataType == 2) { float x = br1.ReadSingle(); float y = br1.ReadSingle(); float z = br1.ReadSingle(); objBytes.Add("v " + x.ToString() + " " + y.ToString() + " " + z.ToString() + " "); vertexList.Add(new Vector3(x, y, z)); } } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[coordinates].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[coordinates].VertexDataBlock] + meshDataInfoList[coordinates].Offset, SeekOrigin.Begin); System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); float x = HalfHelper.HalfToSingle(h1); float y = HalfHelper.HalfToSingle(h2); objBytes.Add("vt " + x.ToString() + " " + (y * -1f).ToString() + " "); texCoordList.Add(new Vector2(x, y)); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[normals].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[normals].VertexDataBlock] + meshDataInfoList[normals].Offset, SeekOrigin.Begin); System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h3 = System.Half.ToHalf((ushort)br1.ReadInt16()); objBytes.Add("vn " + HalfHelper.HalfToSingle(h1).ToString() + " " + HalfHelper.HalfToSingle(h2).ToString() + " " + HalfHelper.HalfToSingle(h3).ToString() + " "); normalList.Add(new Vector3(HalfHelper.HalfToSingle(h1), HalfHelper.HalfToSingle(h2), HalfHelper.HalfToSingle(h3))); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[tangents].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[tangents].VertexDataBlock] + meshDataInfoList[tangents].Offset, SeekOrigin.Begin); float x = br1.ReadByte() / 255f; float y = br1.ReadByte() / 255f; float z = br1.ReadByte() / 255f; tangentList.Add(new Vector3(x, y, z)); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[colors].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[colors].VertexDataBlock] + meshDataInfoList[colors].Offset, SeekOrigin.Begin); int a = br1.ReadByte(); int r = br1.ReadByte(); int g = br1.ReadByte(); int b = br1.ReadByte(); colorsList.Add(new Color4(r, g, b, a)); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.IndexData))) { for (int j = 0; j < mesh.MeshInfo.IndexCount; j += 3) { int i1 = br1.ReadInt16(); int i2 = br1.ReadInt16(); int i3 = br1.ReadInt16(); objBytes.Add("f " + (i1 + 1) + "/" + (i1 + 1) + "/" + (i1 + 1) + " " + (i2 + 1) + "/" + (i2 + 1) + "/" + (i2 + 1) + " " + (i3 + 1) + "/" + (i3 + 1) + "/" + (i3 + 1) + " "); indexList.Add(i1); indexList.Add(i2); indexList.Add(i3); } } ModelMeshData modelMeshData = new ModelMeshData() { Vertices = vertexList, Normals = normalList, TextureCoordinates = texCoordList, Tangents = tangentList, Indices = indexList, VertexColors = colorsList, OBJFileData = objBytes.ToArray() }; meshList.Add(modelMeshData); } } }