private void SelectTexture(TextureBase texbase, bool mipchange) { Texture tex = texbase as Texture; YtdFile ytd = null; string errstr = string.Empty; if ((tex == null) && (texbase != null)) { tex = TryGetTexture(texbase, out ytd, ref errstr); } if (tex != null) { currentTex = tex; int mip = 0; if (mipchange) { mip = SelTextureMipTrackBar.Value; if (mip >= tex.Levels) { mip = tex.Levels - 1; } } else { SelTextureMipTrackBar.Maximum = tex.Levels - 1; } DisplayTexture(tex, mip); //try get owner drawable to get the name for the dictionary textbox... object owner = null; if (Selection.Drawable != null) { owner = Selection.Drawable.Owner; } YdrFile ydr = owner as YdrFile; YddFile ydd = owner as YddFile; YftFile yft = owner as YftFile; SelTextureNameTextBox.Text = tex.Name; SelTextureDictionaryTextBox.Text = (ytd != null) ? ytd.Name : (ydr != null) ? ydr.Name : (ydd != null) ? ydd.Name : (yft != null) ? yft.Name : string.Empty; SaveTextureButton.Enabled = true; } else { SelDrawableTexturePictureBox.Image = null; SelTextureNameTextBox.Text = errstr; SelTextureDictionaryTextBox.Text = string.Empty; SelTextureMipTrackBar.Value = 0; SelTextureMipTrackBar.Maximum = 0; SelTextureDimensionsLabel.Text = "-"; SaveTextureButton.Enabled = false; currentTex = null; } }
public bool ContainsYtd(YtdFile ytd) { foreach (var f in YtdFiles) { if (f == ytd) { return(true); } } return(false); }
public void LoadYtd(YtdFile ytd) { Ytd = ytd; FileName = ytd?.Name; if (string.IsNullOrEmpty(FileName)) { FileName = ytd?.RpfFileEntry?.Name; } LoadTexDict(ytd.TextureDict, FileName); }
public YtdFile AddYtdFile(string filename) { YtdFile ytd = new YtdFile(); ytd.RpfFileEntry = new RpfResourceFileEntry(); ytd.RpfFileEntry.Name = Path.GetFileName(filename); ytd.FilePath = GetFullFilePath(filename); ytd.Name = ytd.RpfFileEntry.Name; if (!AddYtdFile(ytd)) { return(null); } return(ytd); }
public void RemoveYtdFile(YtdFile ytd) { if (ytd == null) { return; } var relpath = GetRelativePath(ytd.FilePath); if (string.IsNullOrEmpty(relpath)) { relpath = ytd.Name; } YtdFiles.Remove(ytd); YtdFilenames.Remove(relpath); HasChanged = true; }
public bool AddYtdFile(YtdFile ytd) { string relpath = GetRelativePath(ytd.FilePath); if (string.IsNullOrEmpty(relpath)) { relpath = ytd.Name; } if (YtdFilenames.Contains(relpath)) { return(false); } YtdFilenames.Add(relpath); YtdFiles.Add(ytd); return(true); }
private Texture TryGetTexture(TextureBase texbase, out YtdFile ytd, ref string errstr) { //need to load from txd. var arch = Selection.Archetype; uint texhash = texbase.NameHash; uint txdHash = (arch != null) ? arch.TextureDict.Hash : 0; var tex = TryGetTextureFromYtd(texhash, txdHash, out ytd); if (tex == null) { //search parent ytds... uint ptxdhash = WorldForm.GameFileCache.TryGetParentYtdHash(txdHash); while ((ptxdhash != 0) && (tex == null)) { tex = TryGetTextureFromYtd(texhash, ptxdhash, out ytd); if (tex == null) { ptxdhash = WorldForm.GameFileCache.TryGetParentYtdHash(ptxdhash); } else { } } if (tex == null) { ytd = WorldForm.GameFileCache.TryGetTextureDictForTexture(texhash); if (ytd != null) { int tries = 0; while (!ytd.Loaded && (tries < 500)) //wait upto ~5 sec { System.Threading.Thread.Sleep(10); tries++; } if (ytd.Loaded) { tex = ytd.TextureDict.Lookup(texhash); } } if (tex == null) { ytd = null; errstr = "<Couldn't find texture!>"; } } } return(tex); }
private Texture TryGetTextureFromYtd(uint texHash, uint txdHash, out YtdFile ytd) { if (txdHash != 0) { ytd = WorldForm.GameFileCache.GetYtd(txdHash); if (ytd != null) { int tries = 0; while (!ytd.Loaded && (tries < 500)) //wait upto ~5 sec { System.Threading.Thread.Sleep(10); tries++; } if (ytd.Loaded) { return(ytd.TextureDict.Lookup(texHash)); } } } ytd = null; return(null); }
private void SelectTexture(TextureBase texbase, bool mipchange) { Texture tex = texbase as Texture; YtdFile ytd = null; string errstr = string.Empty; if ((tex == null) && (texbase != null)) { //need to load from txd. var arch = Selection.Archetype; uint texhash = texbase.NameHash; uint txdHash = (arch != null) ? arch.TextureDict.Hash : 0; tex = TryGetTextureFromYtd(texhash, txdHash, out ytd); if (tex == null) { //search parent ytds... uint ptxdhash = WorldForm.GameFileCache.TryGetParentYtdHash(txdHash); while ((ptxdhash != 0) && (tex == null)) { tex = TryGetTextureFromYtd(texhash, ptxdhash, out ytd); if (tex == null) { ptxdhash = WorldForm.GameFileCache.TryGetParentYtdHash(ptxdhash); } else { } } if (tex == null) { ytd = WorldForm.GameFileCache.TryGetTextureDictForTexture(texhash); if (ytd != null) { int tries = 0; while (!ytd.Loaded && (tries < 500)) //wait upto ~5 sec { System.Threading.Thread.Sleep(10); tries++; } if (ytd.Loaded) { tex = ytd.TextureDict.Lookup(texhash); } } if (tex == null) { ytd = null; errstr = "<Couldn't find texture!>"; } } } } if (tex != null) { int mip = 0; if (mipchange) { mip = SelTextureMipTrackBar.Value; if (mip >= tex.Levels) { mip = tex.Levels - 1; } } else { SelTextureMipTrackBar.Maximum = tex.Levels - 1; } DisplayTexture(tex, mip); //try get owner drawable to get the name for the dictionary textbox... object owner = null; if (Selection.Drawable != null) { owner = Selection.Drawable.Owner; } YdrFile ydr = owner as YdrFile; YddFile ydd = owner as YddFile; YftFile yft = owner as YftFile; SelTextureNameTextBox.Text = tex.Name; SelTextureDictionaryTextBox.Text = (ytd != null) ? ytd.Name : (ydr != null) ? ydr.Name : (ydd != null) ? ydd.Name : (yft != null) ? yft.Name : string.Empty; } else { SelDrawableTexturePictureBox.Image = null; SelTextureNameTextBox.Text = errstr; SelTextureDictionaryTextBox.Text = string.Empty; SelTextureMipTrackBar.Value = 0; SelTextureMipTrackBar.Maximum = 0; SelTextureDimensionsLabel.Text = "-"; } }
private void SelectFile(RpfEntry entry, int offset, int length) { SelectedEntry = entry; SelectedOffset = offset; SelectedLength = length; RpfFileEntry rfe = entry as RpfFileEntry; if (rfe == null) { RpfDirectoryEntry rde = entry as RpfDirectoryEntry; if (rde != null) { FileInfoLabel.Text = rde.Path + " (Directory)"; DataTextBox.Text = "[Please select a data file]"; } else { FileInfoLabel.Text = "[Nothing selected]"; DataTextBox.Text = "[Please select a data file]"; } ShowTextures(null); return; } Cursor = Cursors.WaitCursor; string typestr = "Resource"; if (rfe is RpfBinaryFileEntry) { typestr = "Binary"; } byte[] data = rfe.File.ExtractFile(rfe); int datalen = (data != null) ? data.Length : 0; FileInfoLabel.Text = rfe.Path + " (" + typestr + " file) - " + TextUtil.GetBytesReadable(datalen); if (ShowLargeFileContentsCheckBox.Checked || (datalen < 524287)) //512K { DisplayFileContentsText(rfe, data, length, offset); } else { DataTextBox.Text = "[Filesize >512KB. Select the Show large files option to view its contents]"; } bool istexdict = false; if (rfe.NameLower.EndsWith(".ymap")) { YmapFile ymap = new YmapFile(rfe); ymap.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ymap; } else if (rfe.NameLower.EndsWith(".ytyp")) { YtypFile ytyp = new YtypFile(); ytyp.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ytyp; } else if (rfe.NameLower.EndsWith(".ymf")) { YmfFile ymf = new YmfFile(); ymf.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ymf; } else if (rfe.NameLower.EndsWith(".ymt")) { YmtFile ymt = new YmtFile(); ymt.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ymt; } else if (rfe.NameLower.EndsWith(".ybn")) { YbnFile ybn = new YbnFile(); ybn.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ybn; } else if (rfe.NameLower.EndsWith(".fxc")) { FxcFile fxc = new FxcFile(); fxc.Load(data, rfe); DetailsPropertyGrid.SelectedObject = fxc; } else if (rfe.NameLower.EndsWith(".yft")) { YftFile yft = new YftFile(); yft.Load(data, rfe); DetailsPropertyGrid.SelectedObject = yft; if ((yft.Fragment != null) && (yft.Fragment.Drawable != null) && (yft.Fragment.Drawable.ShaderGroup != null) && (yft.Fragment.Drawable.ShaderGroup.TextureDictionary != null)) { ShowTextures(yft.Fragment.Drawable.ShaderGroup.TextureDictionary); istexdict = true; } } else if (rfe.NameLower.EndsWith(".ydr")) { YdrFile ydr = new YdrFile(); ydr.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ydr; if ((ydr.Drawable != null) && (ydr.Drawable.ShaderGroup != null) && (ydr.Drawable.ShaderGroup.TextureDictionary != null)) { ShowTextures(ydr.Drawable.ShaderGroup.TextureDictionary); istexdict = true; } } else if (rfe.NameLower.EndsWith(".ydd")) { YddFile ydd = new YddFile(); ydd.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ydd; //todo: show embedded texdicts in ydd's? is this possible? } else if (rfe.NameLower.EndsWith(".ytd")) { YtdFile ytd = new YtdFile(); ytd.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ytd; ShowTextures(ytd.TextureDict); istexdict = true; } else if (rfe.NameLower.EndsWith(".ycd")) { YcdFile ycd = new YcdFile(); ycd.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ycd; } else if (rfe.NameLower.EndsWith(".ynd")) { YndFile ynd = new YndFile(); ynd.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ynd; } else if (rfe.NameLower.EndsWith(".ynv")) { YnvFile ynv = new YnvFile(); ynv.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ynv; } else if (rfe.NameLower.EndsWith("_cache_y.dat")) { CacheDatFile cdf = new CacheDatFile(); cdf.Load(data, rfe); DetailsPropertyGrid.SelectedObject = cdf; } else if (rfe.NameLower.EndsWith(".rel")) { RelFile rel = new RelFile(rfe); rel.Load(data, rfe); DetailsPropertyGrid.SelectedObject = rel; } else if (rfe.NameLower.EndsWith(".gxt2")) { Gxt2File gxt2 = new Gxt2File(); gxt2.Load(data, rfe); DetailsPropertyGrid.SelectedObject = gxt2; } else if (rfe.NameLower.EndsWith(".pso")) { JPsoFile pso = new JPsoFile(); pso.Load(data, rfe); DetailsPropertyGrid.SelectedObject = pso; } else { DetailsPropertyGrid.SelectedObject = null; } if (!istexdict) { ShowTextures(null); } Cursor = Cursors.Default; }
static void ExtractFilesInRPF(RpfFile rpf, string directoryOffset) { try { using (BinaryReader br = new BinaryReader(File.OpenRead(rpf.GetPhysicalFilePath()))) { foreach (RpfEntry entry in rpf.AllEntries) { if (!entry.NameLower.EndsWith(".rpf")) //don't try to extract rpf's, they will be done separately.. { if (entry is RpfBinaryFileEntry) { RpfBinaryFileEntry binentry = entry as RpfBinaryFileEntry; byte[] data = rpf.ExtractFileBinary(binentry, br); if (data == null) { if (binentry.FileSize == 0) { Console.WriteLine("Invalid binary file size!"); } else { Console.WriteLine("data is null!"); } } else if (data.Length == 0) { Console.WriteLine("{0} : Decompressed output was empty.", entry.Path); } else { Console.WriteLine("binary meme -> " + entry.NameLower); File.WriteAllBytes(directoryOffset + entry.NameLower, data); } } else if (entry is RpfResourceFileEntry) { RpfResourceFileEntry resentry = entry as RpfResourceFileEntry; byte[] data = rpf.ExtractFileResource(resentry, br); data = ResourceBuilder.Compress(data); //not completely ideal to recompress it... data = ResourceBuilder.AddResourceHeader(resentry, data); if (data == null) { if (resentry.FileSize == 0) { Console.WriteLine("{0} : Resource FileSize is 0.", entry.Path); } else { Console.WriteLine("{0} : {1}", entry.Path); } } else if (data.Length == 0) { Console.WriteLine("{0} : Decompressed output was empty.", entry.Path); } else { Console.WriteLine("Potential meme -> " + entry.NameLower); foreach (KeyValuePair <string, string[]> extentionMap in extensions) { foreach (string extention in extentionMap.Value) { if (entry.NameLower.EndsWith(extention)) { Console.WriteLine("Resource meme -> " + entry.NameLower); if (extention.Equals(".ytd")) { RpfFileEntry rpfent = entry as RpfFileEntry; byte[] ytddata = rpfent.File.ExtractFile(rpfent); bool needsResized = ytddata.Length > 5242880; // 5MB YtdFile ytd = new YtdFile(); ytd.Load(ytddata, rpfent); Dictionary <uint, Texture> Dicts = new Dictionary <uint, Texture>(); bool somethingResized = false; foreach (KeyValuePair <uint, Texture> texture in ytd.TextureDict.Dict) { if (texture.Value.Width > 1440 || needsResized && texture.Value.Width > 550) // Only resize if it is greater than 1440p or 550p if vehicle is oversized { byte[] dds = DDSIO.GetDDSFile(texture.Value); string fileName = $"{texture.Value.Name}.dds"; fileName = String.Concat(fileName.Where(c => !Char.IsWhiteSpace(c))); File.WriteAllBytes("./NConvert/" + fileName, dds); Process p = new Process(); p.StartInfo.FileName = @"./NConvert/nconvert.exe"; p.StartInfo.Arguments = @"-out dds -resize 50% 50% -overwrite ./NConvert/" + fileName; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.Start(); //Wait for the process to end. p.WaitForExit(); // Move file back File.Move("./NConvert/" + fileName, directoryOffset + fileName); byte[] resizedData = File.ReadAllBytes(directoryOffset + fileName); Texture resizedTex = DDSIO.GetTexture(resizedData); resizedTex.Name = texture.Value.Name; Console.WriteLine(resizedData.Length.ToString()); Dicts.Add(texture.Key, resizedTex); // Yeet the file, we are done with it File.Delete(directoryOffset + fileName); somethingResized = true; } else { Dicts.Add(texture.Key, texture.Value); } } // No point rebuilding the ytd when nothing was resized if (!somethingResized) { break; } TextureDictionary dic = new TextureDictionary(); dic.Textures = new ResourcePointerList64 <Texture>(); dic.TextureNameHashes = new ResourceSimpleList64_uint(); dic.Textures.data_items = Dicts.Values.ToArray(); dic.TextureNameHashes.data_items = Dicts.Keys.ToArray(); dic.BuildDict(); ytd.TextureDict = dic; byte[] resizedYtdData = ytd.Save(); File.WriteAllBytes(directoryOffset + entry.NameLower, resizedYtdData); Console.WriteLine("Done some ytd resize memes -> " + entry.NameLower); break; } File.WriteAllBytes(directoryOffset + entry.NameLower, data); break; } } } if (entry.NameLower.EndsWith(".ytd")) { latestModelName = entry.NameLower.Remove(entry.NameLower.Length - 4); } } } } else { // Write file first RpfBinaryFileEntry binentry = entry as RpfBinaryFileEntry; byte[] data = rpf.ExtractFileBinary(binentry, br); File.WriteAllBytes(directoryOffset + entry.NameLower, data); RpfFile subRPF = new RpfFile(directoryOffset + entry.NameLower, directoryOffset + entry.NameLower); if (subRPF.ScanStructure(null, null)) { //recursive memes ExtractFilesInRPF(subRPF, directoryOffset); } //yeet File.Delete(directoryOffset + entry.NameLower); } } } } catch (Exception e) { Console.WriteLine("Exception memes!"); Console.WriteLine(e.Message); } }
private void ExtractButton_Click(object sender, EventArgs e) { if (InProgress) { return; } if (!KeysLoaded) { MessageBox.Show("Please scan a GTA 5 exe dump for keys first, or include key files in this app's folder!"); return; } if (!Directory.Exists(FolderTextBox.Text)) { MessageBox.Show("Folder doesn't exist: " + FolderTextBox.Text); return; } if (!Directory.Exists(OutputFolderTextBox.Text)) { MessageBox.Show("Folder doesn't exist: " + OutputFolderTextBox.Text); return; } //if (Directory.GetFiles(OutputFolderTextBox.Text, "*.ysc", SearchOption.AllDirectories).Length > 0) //{ // if (MessageBox.Show("Output folder already contains .ysc files. Are you sure you want to continue?", "Output folder already contains .ysc files", MessageBoxButtons.OKCancel) != DialogResult.OK) // { // return; // } //} InProgress = true; AbortOperation = false; string searchpath = FolderTextBox.Text; string outputpath = OutputFolderTextBox.Text; string replpath = searchpath + "\\"; bool bytd = YtdChecBox.Checked; bool bydr = YdrCheckBox.Checked; bool bydd = YddCheckBox.Checked; bool byft = YftCheckBox.Checked; Task.Run(() => { UpdateExtractStatus("Keys loaded."); RpfManager rpfman = new RpfManager(); rpfman.Init(searchpath, UpdateExtractStatus, UpdateExtractStatus); UpdateExtractStatus("Beginning texture extraction..."); StringBuilder errsb = new StringBuilder(); foreach (RpfFile rpf in rpfman.AllRpfs) { foreach (RpfEntry entry in rpf.AllEntries) { if (AbortOperation) { UpdateExtractStatus("Operation aborted"); InProgress = false; return; } try { if (bytd && entry.NameLower.EndsWith(".ytd")) { UpdateExtractStatus(entry.Path); YtdFile ytd = rpfman.GetFile <YtdFile>(entry); if (ytd == null) { throw new Exception("Couldn't load file."); } if (ytd.TextureDict == null) { throw new Exception("Couldn't load texture dictionary."); } if (ytd.TextureDict.Textures == null) { throw new Exception("Couldn't load texture dictionary texture array."); } if (ytd.TextureDict.Textures.data_items == null) { throw new Exception("Texture dictionary had no entries..."); } foreach (var tex in ytd.TextureDict.Textures.data_items) { SaveTexture(tex, entry, outputpath); } } else if (bydr && entry.NameLower.EndsWith(".ydr")) { UpdateExtractStatus(entry.Path); YdrFile ydr = rpfman.GetFile <YdrFile>(entry); if (ydr == null) { throw new Exception("Couldn't load file."); } if (ydr.Drawable == null) { throw new Exception("Couldn't load drawable."); } if (ydr.Drawable.ShaderGroup != null) { var ydrtd = ydr.Drawable.ShaderGroup.TextureDictionary; if ((ydrtd != null) && (ydrtd.Textures != null) && (ydrtd.Textures.data_items != null)) { foreach (var tex in ydrtd.Textures.data_items) { SaveTexture(tex, entry, outputpath); } } } } else if (bydd && entry.NameLower.EndsWith(".ydd")) { UpdateExtractStatus(entry.Path); YddFile ydd = rpfman.GetFile <YddFile>(entry); if (ydd == null) { throw new Exception("Couldn't load file."); } //if (ydd.DrawableDict == null) throw new Exception("Couldn't load drawable dictionary."); //if (ydd.DrawableDict.Drawables == null) throw new Exception("Drawable dictionary had no items..."); //if (ydd.DrawableDict.Drawables.data_items == null) throw new Exception("Drawable dictionary had no items..."); if ((ydd.Dict == null) || (ydd.Dict.Count == 0)) { throw new Exception("Drawable dictionary had no items..."); } foreach (var drawable in ydd.Dict.Values) { if (drawable.ShaderGroup != null) { var ydrtd = drawable.ShaderGroup.TextureDictionary; if ((ydrtd != null) && (ydrtd.Textures != null) && (ydrtd.Textures.data_items != null)) { foreach (var tex in ydrtd.Textures.data_items) { SaveTexture(tex, entry, outputpath); } } } } } else if (byft && entry.NameLower.EndsWith(".yft")) { UpdateExtractStatus(entry.Path); YftFile yft = rpfman.GetFile <YftFile>(entry); if (yft == null) { throw new Exception("Couldn't load file."); } if (yft.Fragment == null) { throw new Exception("Couldn't load fragment."); } if (yft.Fragment.Drawable != null) { if (yft.Fragment.Drawable.ShaderGroup != null) { var ydrtd = yft.Fragment.Drawable.ShaderGroup.TextureDictionary; if ((ydrtd != null) && (ydrtd.Textures != null) && (ydrtd.Textures.data_items != null)) { foreach (var tex in ydrtd.Textures.data_items) { SaveTexture(tex, entry, outputpath); } } } } } } catch (Exception ex) { string err = entry.Name + ": " + ex.Message; UpdateExtractStatus(err); errsb.AppendLine(err); } } } File.WriteAllText(outputpath + "\\_errors.txt", errsb.ToString()); UpdateExtractStatus("Complete."); InProgress = false; }); }
public Exporter(string name, ResourcePointerList64 <DrawableModel> models, GameFileCache Cache) { using (StreamWriter FBXwriter = new StreamWriter("FBX/" + name + ".fbx")) { var timestamp = DateTime.Now; int BaseId = 10000; StringBuilder fbx = new StringBuilder(); StringBuilder ob = new StringBuilder(); //Objects builder StringBuilder cb = new StringBuilder(); //Connections builder StringBuilder mb = new StringBuilder(); //Materials builder to get texture count in advance StringBuilder cb2 = new StringBuilder(); //and keep connections ordered cb.Append("\n}\n"); //Objects end cb.Append("\nConnections: {"); List <DrawableGeometry> Geoms = new List <DrawableGeometry>(); List <ShaderFX> Shaders = new List <ShaderFX>(); List <Texture> Textures = new List <Texture>(); //Models for (int mi = 0; mi < models.data_items.Length; mi++) { var model = models.data_items[mi]; //SubMesh & Materials foreach (var geom in model.Geometries.data_items) { if ((geom.Shader != null) && (geom.Shader.ParametersList != null) && (geom.Shader.ParametersList.Hashes != null)) { Geoms.Add(geom); Shaders.Add(geom.Shader); var gname = "Geom" + Geoms.Count; //创建节点 ob.AppendFormat("\n\tModel: 1{0}, \"Model::{1}\", \"Mesh\" {{", BaseId + Geoms.Count, gname); ob.Append("\n\t\tVersion: 232"); ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",1"); ob.Append("\n\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); ob.Append("\n\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0"); ob.AppendFormat("\n\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",{0},{1},{2}", 0, 0, 0); ob.AppendFormat("\n\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",{0},{1},{2}", 0, 0, 0);//handedness is switched in quat ob.AppendFormat("\n\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", 1, 1, 1); ob.Append("\n\t\t}"); ob.Append("\n\t\tShading: T"); ob.Append("\n\t\tCulling: \"CullingOff\"\n\t}"); //把节点挂在根节点上 cb.AppendFormat("\n\n\t;Model::{0}, Model::RootNode", gname); cb.AppendFormat("\n\tC: \"OO\",1{0},0", BaseId + Geoms.Count); //把几何体挂在节点上 cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", gname); cb2.AppendFormat("\n\tC: \"OO\",3{0},1{1}", BaseId + Geoms.Count, BaseId + Geoms.Count); //把材质挂在节点上 cb2.AppendFormat("\n\n\t;Material::, Model::{0}", gname); cb2.AppendFormat("\n\tC: \"OO\",6{0},1{1}", BaseId + Shaders.Count, BaseId + Geoms.Count); var pl = geom.Shader.ParametersList; var h = pl.Hashes; var p = pl.Parameters; for (int ip = 0; ip < h.Length; ip++) { var hash = pl.Hashes[ip]; var parm = pl.Parameters[ip]; var tex = parm.Data as TextureBase; if (tex != null) { var t = tex as Texture; if (t == null) { YtdFile file = Cache.TryGetTextureDictForTexture(tex.NameHash); if (file != null) { t = file.TextureDict.Lookup(tex.NameHash); } } var tstr = tex.Name.Trim(); if (t != null) { Textures.Add(t); cb2.AppendFormat("\n\n\t;Texture::, Material::{0}", geom.Shader.Name); cb2.AppendFormat("\n\tC: \"OP\",7{0},6{1}, ", BaseId + Textures.Count, BaseId + Shaders.Count); switch (hash.ToString().Trim()) { case "DiffuseSampler": cb2.Append("\"DiffuseColor\""); break; case "BumpSampler": cb2.Append("\"NormalMap\""); break; case "SpecSampler": cb2.Append("\"SpecularColor\""); break; case "DetailSampler": break; } } } } } } } fbx.Append("; FBX 7.1.0 project file"); fbx.Append("\nFBXHeaderExtension: {\n\tFBXHeaderVersion: 1003\n\tFBXVersion: 7100\n\tCreationTimeStamp: {\n\t\tVersion: 1000"); fbx.Append("\n\t\tYear: " + timestamp.Year); fbx.Append("\n\t\tMonth: " + timestamp.Month); fbx.Append("\n\t\tDay: " + timestamp.Day); fbx.Append("\n\t\tHour: " + timestamp.Hour); fbx.Append("\n\t\tMinute: " + timestamp.Minute); fbx.Append("\n\t\tSecond: " + timestamp.Second); fbx.Append("\n\t\tMillisecond: " + timestamp.Millisecond); fbx.Append("\n\t}\n\tCreator: \"Unity Studio by Chipicao\"\n}\n"); fbx.Append("\nGlobalSettings: {"); fbx.Append("\n\tVersion: 1000"); fbx.Append("\n\tProperties70: {"); fbx.Append("\n\t\tP: \"UpAxis\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"UpAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"FrontAxis\", \"int\", \"Integer\", \"\",2"); fbx.Append("\n\t\tP: \"FrontAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"CoordAxis\", \"int\", \"Integer\", \"\",0"); fbx.Append("\n\t\tP: \"CoordAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"OriginalUpAxis\", \"int\", \"Integer\", \"\",1"); fbx.Append("\n\t\tP: \"OriginalUpAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.AppendFormat("\n\t\tP: \"UnitScaleFactor\", \"double\", \"Number\", \"\",1"); fbx.Append("\n\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",1.0"); fbx.Append("\n\t}\n}\n"); fbx.Append("\nDocuments: {"); fbx.Append("\n\tCount: 1"); fbx.Append("\n\tDocument: 1234567890, \"\", \"Scene\" {"); fbx.Append("\n\t\tProperties70: {"); fbx.Append("\n\t\t\tP: \"SourceObject\", \"object\", \"\", \"\""); fbx.Append("\n\t\t\tP: \"ActiveAnimStackName\", \"KString\", \"\", \"\", \"\""); fbx.Append("\n\t\t}"); fbx.Append("\n\t\tRootNode: 0"); fbx.Append("\n\t}\n}\n"); fbx.Append("\nReferences: {\n}\n"); fbx.Append("\nDefinitions: {"); fbx.Append("\n\tVersion: 100"); // fbx.AppendFormat("\n\tCount: {0}", 1 + 2 * GameObjects.Count + Materials.Count + 2 * Textures.Count + ((bool)Properties.Settings.Default["exportDeformers"] ? Skins.Count + DeformerCount + Skins.Count + 1 : 0)); fbx.Append("\n\tObjectType: \"GlobalSettings\" {"); fbx.Append("\n\t\tCount: 1"); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Model\" {"); fbx.AppendFormat("\n\t\tCount: {0}", 1); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Geometry\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Geoms.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Material\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Shaders.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Texture\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Textures.Count); fbx.Append("\n\t}"); fbx.Append("\n}\n"); fbx.Append("\nObjects: {"); FBXwriter.Write(fbx); fbx.Clear(); for (int i = 0; i < Shaders.Count; i++) { ShaderFX Shader = Shaders[i]; mb.AppendFormat("\n\tMaterial: 6{0}, \"Material::{1}\", \"\" {{", BaseId + i + 1, Shader.Name); mb.Append("\n\t\tVersion: 102"); mb.Append("\n\t\tShadingModel: \"phong\""); mb.Append("\n\t\tMultiLayer: 0"); mb.Append("\n\t\tProperties70: {"); mb.Append("\n\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"phong\""); //mb.Append("\n\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",0"); mb.Append("\n\t\t}"); mb.Append("\n\t}"); } for (int i = 0; i < Geoms.Count; i++) { MeshFBX(Geoms[i], BaseId + i + 1, ob); //write data 8MB at a time if (ob.Length > (8 * 0x100000)) { FBXwriter.Write(ob); ob.Clear(); } } for (int i = 0; i < Textures.Count; i++) { Texture t = Textures[i]; //TODO check texture type and set path accordingly; eg. CubeMap, Texture3D string texFilename = Path.GetFullPath("FBX/" + t.Name + ".png"); byte[] bytes = DDSIO.GetPixels(t, 0); FileStream stream = new FileStream(texFilename, FileMode.Create); PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Interlace = PngInterlaceOption.On; encoder.Frames.Add(BitmapFrame.Create(BitmapSource.Create(t.Width, t.Height, 96, 96, PixelFormats.Bgra32, null, bytes, t.Width * 4))); encoder.Save(stream); stream.Close(); // File.WriteAllBytes(texFilename, DDSIO.GetDDSFile(t)); ob.AppendFormat("\n\tTexture: 7{0}, \"Texture::{1}\", \"\" {{", BaseId + i + 1, t.Name); ob.Append("\n\t\tType: \"TextureVideoClip\""); ob.Append("\n\t\tVersion: 202"); ob.AppendFormat("\n\t\tTextureName: \"Texture::{0}\"", t.Name); ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\t\tP: \"UVSet\", \"KString\", \"\", \"\", \"UVChannel_0\""); ob.Append("\n\t\t\tP: \"UseMaterial\", \"bool\", \"\", \"\",1"); ob.Append("\n\t\t}"); ob.AppendFormat("\n\t\tMedia: \"Video::{0}\"", t.Name); ob.AppendFormat("\n\t\tFileName: \"{0}\"", texFilename); ob.AppendFormat("\n\t\tRelativeFilename: \"{0}\"", texFilename); ob.Append("\n\t}"); } ob.Append(mb); mb.Clear(); cb.Append(cb2); cb2.Clear(); FBXwriter.Write(ob); ob.Clear(); cb.Append("\n}");//Connections end FBXwriter.Write(cb); cb.Clear(); } }