// Save texture to disk private void ExportTexture(Unity_Studio.AssetPreloadData asset) { Unity_Studio.Texture2D m_Texture2D = new Unity_Studio.Texture2D(asset, false); m_Texture2D = new Unity_Studio.Texture2D(asset, true); Directory.CreateDirectory(ContentData.ContentPath()); Directory.CreateDirectory(ContentData.ContentPath() + gameType); Directory.CreateDirectory(ContentData.ContentPath() + gameType + "/ffg"); Directory.CreateDirectory(ContentData.ContentPath() + gameType + "/ffg/img"); // Default file name string fileCandidate = ContentData.ContentPath() + gameType + "/ffg/img/" + asset.Text; string fileName = fileCandidate + asset.extension; // This should apend a postfix to the name to avoid collisions, but as we import multiple times // This is broken while (File.Exists(fileName)) { return;// Fixme; } switch (m_Texture2D.m_TextureFormat) { #region DDS case 1: //Alpha8 case 2: //A4R4G4B4 case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure case 4: //G8R8A8B8 //confirmed on X360, iOS case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS case 10: //DXT1 case 12: //DXT5 case 13: //R4G4B4A4, iOS (only?) using (BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create))) { // We have to manually add a header because unity doesn't have it writer.Write(0x20534444); writer.Write(0x7C); writer.Write(m_Texture2D.dwFlags); writer.Write(m_Texture2D.m_Height); writer.Write(m_Texture2D.m_Width); writer.Write(m_Texture2D.dwPitchOrLinearSize); //should be main tex size without mips); writer.Write((int)0); //dwDepth not implemented writer.Write(m_Texture2D.dwMipMapCount); writer.Write(new byte[44]); //dwReserved1[11] writer.Write(m_Texture2D.dwSize); writer.Write(m_Texture2D.dwFlags2); writer.Write(m_Texture2D.dwFourCC); writer.Write(m_Texture2D.dwRGBBitCount); writer.Write(m_Texture2D.dwRBitMask); writer.Write(m_Texture2D.dwGBitMask); writer.Write(m_Texture2D.dwBBitMask); writer.Write(m_Texture2D.dwABitMask); writer.Write(m_Texture2D.dwCaps); writer.Write(m_Texture2D.dwCaps2); writer.Write(new byte[12]); //dwCaps3&4 & dwReserved2 // Write image data writer.Write(m_Texture2D.image_data); writer.Close(); } break; #endregion #region PVR case 30: //PVRTC_RGB2 case 31: //PVRTC_RGBA2 case 32: //PVRTC_RGB4 case 33: //PVRTC_RGBA4 case 34: //ETC_RGB4 using (BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create))) { // We have to manually add a header because unity doesn't have it writer.Write(m_Texture2D.pvrVersion); writer.Write(m_Texture2D.pvrFlags); writer.Write(m_Texture2D.pvrPixelFormat); writer.Write(m_Texture2D.pvrColourSpace); writer.Write(m_Texture2D.pvrChannelType); writer.Write(m_Texture2D.m_Height); writer.Write(m_Texture2D.m_Width); writer.Write(m_Texture2D.pvrDepth); writer.Write(m_Texture2D.pvrNumSurfaces); writer.Write(m_Texture2D.pvrNumFaces); writer.Write(m_Texture2D.dwMipMapCount); writer.Write(m_Texture2D.pvrMetaDataSize); // Write image data writer.Write(m_Texture2D.image_data); writer.Close(); } break; #endregion case 28: //DXT1 Crunched case 29: //DXT1 Crunched default: using (BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create))) { writer.Write(m_Texture2D.image_data); writer.Close(); } break; } }
private void WritePVR(string PVRfile, Texture2D m_Texture2D) { using (BinaryWriter writer = new BinaryWriter(File.Open(PVRfile, FileMode.Create))) { writer.Write(m_Texture2D.pvrVersion); writer.Write(m_Texture2D.pvrFlags); writer.Write(m_Texture2D.pvrPixelFormat); writer.Write(m_Texture2D.pvrColourSpace); writer.Write(m_Texture2D.pvrChannelType); writer.Write(m_Texture2D.m_Height); writer.Write(m_Texture2D.m_Width); writer.Write(m_Texture2D.pvrDepth); writer.Write(m_Texture2D.pvrNumSurfaces); writer.Write(m_Texture2D.pvrNumFaces); writer.Write(m_Texture2D.dwMipMapCount); writer.Write(m_Texture2D.pvrMetaDataSize); writer.Write(m_Texture2D.image_data); writer.Close(); } }
private void BuildAssetStrucutres() { #region first loop - read asset data & create list if (!dontLoadAssetsMenuItem.Checked) { assetListView.BeginUpdate(); progressBar1.Value = 0; progressBar1.Maximum = totalAssetCount; string fileIDfmt = "D" + assetsfileList.Count.ToString().Length.ToString(); foreach (var assetsFile in assetsfileList) { StatusStripUpdate("Building asset list from " + Path.GetFileName(assetsFile.filePath)); var a_Stream = assetsFile.a_Stream; var fileGen = assetsFile.fileGen; //var m_version = assetsFile.m_version; var version = assetsFile.version; string fileID = assetsfileList.IndexOf(assetsFile).ToString(fileIDfmt); //ListViewGroup assetGroup = new ListViewGroup(Path.GetFileName(assetsFile.filePath)); foreach (var asset in assetsFile.preloadTable.Values) { asset.uniqueID = fileID + asset.uniqueID; a_Stream.Position = asset.Offset; switch (asset.Type2) { case 1: //GameObject { GameObject m_GameObject = new GameObject(asset); assetsFile.GameObjectList.Add(asset.m_PathID, m_GameObject); totalTreeNodes++; break; } case 4: //Transform { Transform m_Transform = new Transform(asset); assetsFile.TransformList.Add(asset.m_PathID, m_Transform); break; } case 224: //RectTransform { RectTransform m_Rect = new RectTransform(asset); assetsFile.TransformList.Add(asset.m_PathID, m_Rect.m_Transform); break; } //case 21: //Material case 28: //Texture2D { Texture2D m_Texture2D = new Texture2D(asset, false); asset.Text = m_Texture2D.m_Name; asset.exportSize = 128 + m_Texture2D.image_data_size; #region Get Info Text asset.InfoText = "Width: " + m_Texture2D.m_Width.ToString() + "\nHeight: " + m_Texture2D.m_Height.ToString() + "\nFormat: "; switch (m_Texture2D.m_TextureFormat) { case 1: asset.InfoText += "Alpha8"; break; case 2: asset.InfoText += "ARGB 4.4.4.4"; break; case 3: asset.InfoText += "BGR 8.8.8"; break; case 4: asset.InfoText += "GRAB 8.8.8.8"; break; case 5: asset.InfoText += "BGRA 8.8.8.8"; break; case 7: asset.InfoText += "RGB 5.6.5"; break; case 10: asset.InfoText += "RGB DXT1"; break; case 12: asset.InfoText += "ARGB DXT5"; break; case 13: asset.InfoText += "RGBA 4.4.4.4"; break; case 30: asset.InfoText += "PVRTC_RGB2"; asset.exportSize -= 76; break; case 31: asset.InfoText += "PVRTC_RGBA2"; asset.exportSize -= 76; break; case 32: asset.InfoText += "PVRTC_RGB4"; asset.exportSize = 52; break; case 33: asset.InfoText += "PVRTC_RGBA4"; asset.exportSize -= 76; break; case 34: asset.InfoText += "ETC_RGB4"; asset.exportSize -= 76; break; default: asset.InfoText += "unknown"; asset.exportSize -= 128; break; } switch (m_Texture2D.m_FilterMode) { case 0: asset.InfoText += "\nFilter Mode: Point "; break; case 1: asset.InfoText += "\nFilter Mode: Bilinear "; break; case 2: asset.InfoText += "\nFilter Mode: Trilinear "; break; } asset.InfoText += "\nAnisotropic level: " + m_Texture2D.m_Aniso.ToString() + "\nMip map bias: " + m_Texture2D.m_MipBias.ToString(); switch (m_Texture2D.m_WrapMode) { case 0: asset.InfoText += "\nWrap mode: Repeat"; break; case 1: asset.InfoText += "\nWrap mode: Clamp"; break; } #endregion assetsFile.exportableAssets.Add(asset); break; } case 49: //TextAsset { TextAsset m_TextAsset = new TextAsset(asset, false); asset.Text = m_TextAsset.m_Name; asset.exportSize = m_TextAsset.exportSize; assetsFile.exportableAssets.Add(asset); break; } case 83: //AudioClip { AudioClip m_AudioClip = new AudioClip(asset, false); asset.Text = m_AudioClip.m_Name; asset.exportSize = (int)m_AudioClip.m_Size; assetsFile.exportableAssets.Add(asset); break; } case 48: //Shader case 89: //CubeMap case 128: //Font { asset.Text = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); assetsFile.exportableAssets.Add(asset); break; } case 129: //PlayerSettings { PlayerSettings plSet = new PlayerSettings(asset); productName = plSet.productName; base.Text = "Unity Studio - " + productName + " - " + assetsFile.m_Version + " - " + assetsFile.platformStr; break; } } if (asset.Text == "") { asset.Text = asset.TypeString + " #" + asset.uniqueID; } asset.SubItems.AddRange(new string[] { asset.TypeString, asset.exportSize.ToString() }); progressBar1.PerformStep(); } exportableAssets.AddRange(assetsFile.exportableAssets); //if (assetGroup.Items.Count > 0) { listView1.Groups.Add(assetGroup); } } if (base.Text == "Unity Studio" && assetsfileList.Count > 0) { base.Text = "Unity Studio - no productName - " + assetsfileList[0].m_Version + " - " + assetsfileList[0].platformStr; } visibleAssets = exportableAssets; assetListView.VirtualListSize = visibleAssets.Count; //will only work if ListView is visible resizeAssetListColumns(); assetListView.EndUpdate(); progressBar1.Value = 0; } #endregion #region second loop - build tree structure if (!dontBuildHierarchyMenuItem.Checked) { sceneTreeView.BeginUpdate(); progressBar1.Value = 0; progressBar1.Maximum = totalTreeNodes; foreach (var assetsFile in assetsfileList) { StatusStripUpdate("Building tree structure from " + Path.GetFileName(assetsFile.filePath)); GameObject fileNode = new GameObject(null); fileNode.Text = Path.GetFileName(assetsFile.filePath); fileNode.m_Name = "RootNode"; foreach (var m_GameObject in assetsFile.GameObjectList.Values) { var parentNode = fileNode; Transform m_Transform; if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) { Transform m_Father; if (assetsfileList.TryGetTransform(m_Transform.m_Father, out m_Father)) { //GameObject Parent; if (assetsfileList.TryGetGameObject(m_Father.m_GameObject, out parentNode)) { //parentNode = Parent; } } } parentNode.Nodes.Add(m_GameObject); progressBar1.PerformStep(); } if (fileNode.Nodes.Count == 0) { fileNode.Text += " (no children)"; } sceneTreeView.Nodes.Add(fileNode); } sceneTreeView.EndUpdate(); progressBar1.Value = 0; if (File.Exists(mainPath + "\\materials.json")) { string matLine = ""; using (StreamReader reader = File.OpenText(mainPath + "\\materials.json")) { matLine = reader.ReadToEnd(); } jsonMats = new JavaScriptSerializer().Deserialize<Dictionary<string, Dictionary<string, string>>>(matLine); //var jsonMats = new JavaScriptSerializer().DeserializeObject(matLine); } } #endregion #region build list of class strucutres if (buildClassStructuresMenuItem.Checked) { //group class structures by versionv foreach (var assetsFile in assetsfileList) { SortedDictionary<int, ClassStrStruct> curVer; if (AllClassStructures.TryGetValue(assetsFile.m_Version, out curVer)) { foreach (var uClass in assetsFile.ClassStructures) { curVer[uClass.Key] = uClass.Value; } } else { AllClassStructures.Add(assetsFile.m_Version, assetsFile.ClassStructures); } } classesListView.BeginUpdate(); foreach (var version in AllClassStructures) { ListViewGroup versionGroup = new ListViewGroup(version.Key); classesListView.Groups.Add(versionGroup); foreach (var uclass in version.Value) { uclass.Value.Group = versionGroup; classesListView.Items.Add(uclass.Value); } } classesListView.EndUpdate(); } #endregion StatusStripUpdate("Finished loading " + assetsfileList.Count.ToString() + " files with " + (assetListView.Items.Count + sceneTreeView.Nodes.Count).ToString() + " exportable assets."); progressBar1.Value = 0; treeSearch.Select(); TexEnv dsd = new TexEnv(); }
private int ExportAsset(AssetPreloadData asset, string exportPath) { int exportCount = 0; switch (asset.Type2) { #region Texture2D case 28: //Texture2D { Texture2D m_Texture2D = new Texture2D(asset, true); string texPath = exportPath + "\\" + asset.Text; if (uniqueNames.Checked) { texPath += " #" + asset.uniqueID; } if (m_Texture2D.m_TextureFormat < 30) { texPath += ".dds"; } else if (m_Texture2D.m_TextureFormat < 35) { texPath += ".pvr"; } else { texPath += "_" + m_Texture2D.m_Width.ToString() + "x" + m_Texture2D.m_Height.ToString() + "." + m_Texture2D.m_TextureFormat.ToString() + ".tex"; } if (File.Exists(texPath)) { StatusStripUpdate("Texture file " + Path.GetFileName(texPath) + " already exists"); } else { StatusStripUpdate("Exporting Texture2D: " + Path.GetFileName(texPath)); exportCount += 1; switch (m_Texture2D.m_TextureFormat) { case 1: //Alpha8 case 2: //A4R4G4B4 case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure case 4: //G8R8A8B8 //confirmed on X360, iOS case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS case 10: //DXT1 case 12: //DXT5 case 13: //R4G4B4A4, iOS (only?) WriteDDS(texPath, m_Texture2D); break; case 30: //PVRTC_RGB2 case 31: //PVRTC_RGBA2 case 32: //PVRTC_RGB4 case 33: //PVRTC_RGBA4 case 34: //ETC_RGB4 WritePVR(texPath, m_Texture2D); break; default: { using (BinaryWriter writer = new BinaryWriter(File.Open(texPath, FileMode.Create))) { writer.Write(m_Texture2D.image_data); writer.Close(); } break; } } } break; } #endregion #region AudioClip case 83: //AudioClip { AudioClip m_AudioClip = new AudioClip(asset, true); string audPath = exportPath + "\\" + asset.Text; if (uniqueNames.Checked) { audPath += " #" + asset.uniqueID; } audPath += m_AudioClip.extension; if (File.Exists(audPath)) { StatusStripUpdate("Audio file " + Path.GetFileName(audPath) + " already exists"); } else { StatusStripUpdate("Exporting AudioClip: " + Path.GetFileName(audPath)); exportCount += 1; using (BinaryWriter writer = new BinaryWriter(File.Open(audPath, FileMode.Create))) { writer.Write(m_AudioClip.m_AudioData); writer.Close(); } } break; } #endregion #region Shader & TextAsset case 48: //Shader case 49: //TextAsset { TextAsset m_TextAsset = new TextAsset(asset, true); string textAssetPath = exportPath + "\\" + asset.Text; if (uniqueNames.Checked) { textAssetPath += " #" + asset.uniqueID; } textAssetPath += m_TextAsset.extension; if (File.Exists(textAssetPath)) { StatusStripUpdate("TextAsset file " + Path.GetFileName(textAssetPath) + " already exists"); } else { StatusStripUpdate("Exporting TextAsset: " + Path.GetFileName(textAssetPath)); exportCount += 1; using (BinaryWriter writer = new BinaryWriter(File.Open(textAssetPath, FileMode.Create))) { writer.Write(m_TextAsset.m_Script); writer.Close(); } } break; } #endregion #region Font case 128: //Font { unityFont m_Font = new unityFont(asset); if (m_Font.m_FontData != null) { string fontPath = exportPath + "\\" + asset.Text; if (uniqueNames.Checked) { fontPath += " #" + asset.uniqueID; } fontPath += m_Font.extension; if (File.Exists(fontPath)) { StatusStripUpdate("Font file " + Path.GetFileName(fontPath) + " already exists"); } else { StatusStripUpdate("Exporting Font: " + Path.GetFileName(fontPath)); using (BinaryWriter writer = new BinaryWriter(File.Open(fontPath, FileMode.Create))) { writer.Write(m_Font.m_FontData); writer.Close(); } exportCount += 1; } } break; } #endregion /*default: { string assetPath = exportPath + "\\" + asset.Name + "." + asset.TypeString; byte[] assetData = new byte[asset.Size]; Stream.Read(assetData, 0, asset.Size); using (BinaryWriter writer = new BinaryWriter(File.Open(assetPath, FileMode.Create))) { writer.Write(assetData); writer.Close(); } exportCount += 1; break; }*/ } return exportCount; }
private void WriteDDS(string DDSfile, Texture2D m_Texture2D) { using (BinaryWriter writer = new BinaryWriter(File.Open(DDSfile, FileMode.Create))) { writer.Write(0x20534444); writer.Write(0x7C); writer.Write(m_Texture2D.dwFlags); writer.Write(m_Texture2D.m_Height); writer.Write(m_Texture2D.m_Width); writer.Write(m_Texture2D.dwPitchOrLinearSize); //should be main tex size without mips); writer.Write((int)0); //dwDepth not implemented writer.Write(m_Texture2D.dwMipMapCount); writer.Write(new byte[44]); //dwReserved1[11] writer.Write(m_Texture2D.dwSize); writer.Write(m_Texture2D.dwFlags2); writer.Write(m_Texture2D.dwFourCC); writer.Write(m_Texture2D.dwRGBBitCount); writer.Write(m_Texture2D.dwRBitMask); writer.Write(m_Texture2D.dwGBitMask); writer.Write(m_Texture2D.dwBBitMask); writer.Write(m_Texture2D.dwABitMask); writer.Write(m_Texture2D.dwCaps); writer.Write(m_Texture2D.dwCaps2); writer.Write(new byte[12]); //dwCaps3&4 & dwReserved2 writer.Write(m_Texture2D.image_data); writer.Close(); } }
private void PreviewAsset(AssetPreloadData asset) { switch (asset.Type2) { #region Texture2D case 28: //Texture2D { Texture2D m_Texture2D = new Texture2D(asset, true); if (m_Texture2D.m_TextureFormat < 30) { byte[] imageBuffer = new byte[128 + m_Texture2D.image_data_size]; imageBuffer[0] = 0x44; imageBuffer[1] = 0x44; imageBuffer[2] = 0x53; imageBuffer[3] = 0x20; imageBuffer[4] = 0x7c; BitConverter.GetBytes(m_Texture2D.dwFlags).CopyTo(imageBuffer, 8); BitConverter.GetBytes(m_Texture2D.m_Height).CopyTo(imageBuffer, 12); BitConverter.GetBytes(m_Texture2D.m_Width).CopyTo(imageBuffer, 16); BitConverter.GetBytes(m_Texture2D.dwPitchOrLinearSize).CopyTo(imageBuffer, 20); BitConverter.GetBytes(m_Texture2D.dwMipMapCount).CopyTo(imageBuffer, 28); BitConverter.GetBytes(m_Texture2D.dwSize).CopyTo(imageBuffer, 76); BitConverter.GetBytes(m_Texture2D.dwFlags2).CopyTo(imageBuffer, 80); BitConverter.GetBytes(m_Texture2D.dwFourCC).CopyTo(imageBuffer, 84); BitConverter.GetBytes(m_Texture2D.dwRGBBitCount).CopyTo(imageBuffer, 88); BitConverter.GetBytes(m_Texture2D.dwRBitMask).CopyTo(imageBuffer, 92); BitConverter.GetBytes(m_Texture2D.dwGBitMask).CopyTo(imageBuffer, 96); BitConverter.GetBytes(m_Texture2D.dwBBitMask).CopyTo(imageBuffer, 100); BitConverter.GetBytes(m_Texture2D.dwABitMask).CopyTo(imageBuffer, 104); BitConverter.GetBytes(m_Texture2D.dwCaps).CopyTo(imageBuffer, 108); BitConverter.GetBytes(m_Texture2D.dwCaps2).CopyTo(imageBuffer, 112); m_Texture2D.image_data.CopyTo(imageBuffer, 128); imageTexture = DDSDataToBMP(imageBuffer); imageTexture.RotateFlip(RotateFlipType.RotateNoneFlipY); previewPanel.BackgroundImage = imageTexture; previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; } else { StatusStripUpdate("Unsupported image for preview. Try to export."); } break; } #endregion #region AudioClip case 83: //AudioClip { AudioClip m_AudioClip = new AudioClip(asset, true); //MemoryStream memoryStream = new MemoryStream(m_AudioData, true); //System.Media.SoundPlayer soundPlayer = new System.Media.SoundPlayer(memoryStream); //soundPlayer.Play(); FMOD.RESULT result; FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO(); exinfo.cbsize = Marshal.SizeOf(exinfo); exinfo.length = (uint)m_AudioClip.m_Size; result = system.createSound(m_AudioClip.m_AudioData, (FMOD.MODE.OPENMEMORY | loopMode), ref exinfo, out sound); if (ERRCHECK(result)) { break; } result = sound.getLength(out FMODlenms, FMOD.TIMEUNIT.MS); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { break; } } result = system.playSound(sound, null, false, out channel); if (ERRCHECK(result)) { break; } timer.Start(); FMODstatusLabel.Text = "Playing"; FMODpanel.Visible = true; //result = channel.getChannelGroup(out channelGroup); //if (ERRCHECK(result)) { break; } result = channel.getFrequency(out FMODfrequency); ERRCHECK(result); FMODinfoLabel.Text = FMODfrequency.ToString() + " Hz"; break; } #endregion #region Shader & TextAsset case 48: case 49: { TextAsset m_TextAsset = new TextAsset(asset, true); string m_Script_Text = UnicodeEncoding.UTF8.GetString(m_TextAsset.m_Script); m_Script_Text = Regex.Replace(m_Script_Text, "(?<!\r)\n", "\r\n"); textPreviewBox.Text = m_Script_Text; textPreviewBox.Visible = true; break; } #endregion #region Font case 128: //Font { unityFont m_Font = new unityFont(asset); if (m_Font.extension != ".otf" && m_Font.m_FontData != null) { IntPtr data = Marshal.AllocCoTaskMem(m_Font.m_FontData.Length); Marshal.Copy(m_Font.m_FontData, 0, data, m_Font.m_FontData.Length); System.Drawing.Text.PrivateFontCollection pfc = new System.Drawing.Text.PrivateFontCollection(); // We HAVE to do this to register the font to the system (Weird .NET bug !) uint cFonts = 0; AddFontMemResourceEx(data, (uint)m_Font.m_FontData.Length, IntPtr.Zero, ref cFonts); pfc.AddMemoryFont(data, m_Font.m_FontData.Length); System.Runtime.InteropServices.Marshal.FreeCoTaskMem(data); //textPreviewBox.Font = new Font(pfc.Families[0], 16, FontStyle.Regular); //textPreviewBox.Text = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ\r\n1234567890.:,;'\"(!?)+-*/=\r\nThe quick brown fox jumps over the lazy dog. 1234567890"; fontPreviewBox.SelectionStart = 0; fontPreviewBox.SelectionLength = 80; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 16, FontStyle.Regular); fontPreviewBox.SelectionStart = 81; fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 12, FontStyle.Regular); fontPreviewBox.SelectionStart = 138; fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 18, FontStyle.Regular); fontPreviewBox.SelectionStart = 195; fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 24, FontStyle.Regular); fontPreviewBox.SelectionStart = 252; fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 36, FontStyle.Regular); fontPreviewBox.SelectionStart = 309; fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 48, FontStyle.Regular); fontPreviewBox.SelectionStart = 366; fontPreviewBox.SelectionLength = 56; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 60, FontStyle.Regular); fontPreviewBox.SelectionStart = 423; fontPreviewBox.SelectionLength = 55; fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 72, FontStyle.Regular); fontPreviewBox.Visible = true; } else { StatusStripUpdate("Unsupported font for preview. Try to export."); } break; } #endregion } }
public void WriteFBX(string FBXfile, bool allNodes) { var timestamp = DateTime.Now; using (StreamWriter FBXwriter = new StreamWriter(FBXfile)) { 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: {"); HashSet<GameObject> GameObjects = new HashSet<GameObject>(); HashSet<GameObject> LimbNodes = new HashSet<GameObject>(); HashSet<AssetPreloadData> Skins = new HashSet<AssetPreloadData>(); HashSet<AssetPreloadData> Meshes = new HashSet<AssetPreloadData>();//MeshFilters are not unique!! HashSet<AssetPreloadData> Materials = new HashSet<AssetPreloadData>(); HashSet<AssetPreloadData> Textures = new HashSet<AssetPreloadData>(); int DeformerCount = 0; /* uniqueIDs can begin with zero, so they are preceded by a number specific to their type this will also make it easier to debug FBX files 1: Model 2: NodeAttribute 3: Geometry 4: Deformer 5: CollectionExclusive 6: Material 7: Texture 8: Video 9: */ #region loop nodes and collect objects for export foreach (var assetsFile in assetsfileList) { foreach (var m_GameObject in assetsFile.GameObjectList.Values) { if (m_GameObject.Checked || allNodes) { GameObjects.Add(m_GameObject); AssetPreloadData MeshFilterPD; if (assetsfileList.TryGetPD(m_GameObject.m_MeshFilter, out MeshFilterPD)) { //MeshFilters are not unique! //MeshFilters.Add(MeshFilterPD); MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); AssetPreloadData MeshPD; if (assetsfileList.TryGetPD(m_MeshFilter.m_Mesh, out MeshPD)) { Meshes.Add(MeshPD); //write connections here and Mesh objects separately without having to backtrack through their MEshFilter to het the GameObject ID //also note that MeshFilters are not unique, they cannot be used for instancing geometry cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", m_GameObject.m_Name); cb2.AppendFormat("\n\tC: \"OO\",3{0},1{1}", MeshPD.uniqueID, m_GameObject.uniqueID); } } #region get Renderer AssetPreloadData RendererPD; if (assetsfileList.TryGetPD(m_GameObject.m_Renderer, out RendererPD)) { Renderer m_Renderer = new Renderer(RendererPD); foreach (var MaterialPPtr in m_Renderer.m_Materials) { AssetPreloadData MaterialPD; if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) { Materials.Add(MaterialPD); cb2.AppendFormat("\n\n\t;Material::, Model::{0}", m_GameObject.m_Name); cb2.AppendFormat("\n\tC: \"OO\",6{0},1{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); } } } #endregion #region get SkinnedMeshRenderer AssetPreloadData SkinnedMeshPD; if (assetsfileList.TryGetPD(m_GameObject.m_SkinnedMeshRenderer, out SkinnedMeshPD)) { Skins.Add(SkinnedMeshPD); SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) { AssetPreloadData MaterialPD; if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) { Materials.Add(MaterialPD); cb2.AppendFormat("\n\n\t;Material::, Model::{0}", m_GameObject.m_Name); cb2.AppendFormat("\n\tC: \"OO\",6{0},1{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); } } if ((bool)Properties.Settings.Default["exportDeformers"]) { DeformerCount += m_SkinnedMeshRenderer.m_Bones.Length; //collect skeleton dummies to make sure they are exported foreach (var bonePPtr in m_SkinnedMeshRenderer.m_Bones) { Transform b_Transform; if (assetsfileList.TryGetTransform(bonePPtr, out b_Transform)) { GameObject m_Bone; if (assetsfileList.TryGetGameObject(b_Transform.m_GameObject, out m_Bone)) { LimbNodes.Add(m_Bone); //also collect the root bone if (m_Bone.Parent.Level > 0) { LimbNodes.Add((GameObject)m_Bone.Parent); } //should I collect siblings? } #region collect children because m_SkinnedMeshRenderer.m_Bones doesn't contain terminations foreach (var ChildPPtr in b_Transform.m_Children) { Transform ChildTR; if (assetsfileList.TryGetTransform(ChildPPtr, out ChildTR)) { GameObject m_Child; if (assetsfileList.TryGetGameObject(ChildTR.m_GameObject, out m_Child)) { //check that the Model doesn't contain a Mesh, although this won't ensure it's part of the skeleton if (m_Child.m_MeshFilter == null && m_Child.m_SkinnedMeshRenderer == null) { LimbNodes.Add(m_Child); } } } } #endregion } } } } #endregion } } } //if ((bool)Properties.Settings.Default["convertDummies"]) { GameObjects.Except(LimbNodes); } //else { GameObjects.UnionWith(LimbNodes); LimbNodes.Clear(); } //add either way and use LimbNodes to test if a node is Null or LimbNode GameObjects.UnionWith(LimbNodes); #endregion #region write Materials, collect Texture objects StatusStripUpdate("Writing Materials"); foreach (var MaterialPD in Materials) { Material m_Material = new Material(MaterialPD); mb.AppendFormat("\n\tMaterial: 6{0}, \"Material::{1}\", \"\" {{", MaterialPD.uniqueID, m_Material.m_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\""); #region write material colors foreach (var m_Color in m_Material.m_Colors) { switch (m_Color.first) { case "_Color": case "gSurfaceColor": mb.AppendFormat("\n\t\t\tP: \"DiffuseColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); break; case "_SpecularColor"://then what is _SpecColor?? mb.AppendFormat("\n\t\t\tP: \"SpecularColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); break; case "_ReflectColor": mb.AppendFormat("\n\t\t\tP: \"AmbientColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); break; default: mb.AppendFormat("\n;\t\t\tP: \"{3}\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2], m_Color.first);//commented out break; } } #endregion #region write material parameters foreach (var m_Float in m_Material.m_Floats) { switch (m_Float.first) { case "_Shininess": mb.AppendFormat("\n\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",{0}", m_Float.second); mb.AppendFormat("\n\t\t\tP: \"Shininess\", \"Number\", \"\", \"A\",{0}", m_Float.second); break; default: mb.AppendFormat("\n;\t\t\tP: \"{0}\", \"Number\", \"\", \"A\",{1}", m_Float.first, m_Float.second); break; } } #endregion //mb.Append("\n\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",0"); mb.Append("\n\t\t}"); mb.Append("\n\t}"); #region write texture connections foreach (var m_TexEnv in m_Material.m_TexEnvs) { AssetPreloadData TexturePD; #region get Porsche material from json if (!assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD) && jsonMats != null) { Dictionary<string, string> matProp; if (jsonMats.TryGetValue(m_Material.m_Name, out matProp)) { string texName; if (matProp.TryGetValue(m_TexEnv.name, out texName)) { foreach (var asset in exportableAssets) { if (asset.Type2 == 28 && asset.Text == texName) { TexturePD = asset; break; } } } } } #endregion if (TexturePD != null && TexturePD.Type2 == 28) { Textures.Add(TexturePD); cb2.AppendFormat("\n\n\t;Texture::, Material::{0}", m_Material.m_Name); cb2.AppendFormat("\n\tC: \"OP\",7{0},6{1}, \"", TexturePD.uniqueID, MaterialPD.uniqueID); switch (m_TexEnv.name) { case "_MainTex": case "gDiffuseSampler": cb2.Append("DiffuseColor\""); break; case "_SpecularMap": case "gSpecularSampler": cb2.Append("SpecularColor\""); break; case "_NormalMap": case "_BumpMap": case "gNormalSampler": cb2.Append("NormalMap\""); break; default: cb2.AppendFormat("{0}\"", m_TexEnv.name); break; } } } #endregion } #endregion #region write generic FBX data after everything was collected 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\", \"\",{0}", Properties.Settings.Default["scaleFactor"]); fbx.Append("\n\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",1.0"); //fbx.Append("\n\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); //fbx.Append("\n\t\tP: \"DefaultCamera\", \"KString\", \"\", \"\", \"Producer Perspective\""); //fbx.Append("\n\t\tP: \"TimeMode\", \"enum\", \"\", \"\",6"); //fbx.Append("\n\t\tP: \"TimeProtocol\", \"enum\", \"\", \"\",2"); //fbx.Append("\n\t\tP: \"SnapOnFrameMode\", \"enum\", \"\", \"\",0"); //fbx.Append("\n\t\tP: \"TimeSpanStart\", \"KTime\", \"Time\", \"\",0"); //fbx.Append("\n\t\tP: \"TimeSpanStop\", \"KTime\", \"Time\", \"\",153953860000"); //fbx.Append("\n\t\tP: \"CustomFrameRate\", \"double\", \"Number\", \"\",-1"); //fbx.Append("\n\t\tP: \"TimeMarker\", \"Compound\", \"\", \"\""); //fbx.Append("\n\t\tP: \"CurrentTimeMarker\", \"int\", \"Integer\", \"\",-1"); 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}", GameObjects.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"NodeAttribute\" {"); fbx.AppendFormat("\n\t\tCount: {0}", GameObjects.Count - Meshes.Count - Skins.Count); fbx.Append("\n\t\tPropertyTemplate: \"FbxNull\" {"); fbx.Append("\n\t\t\tProperties70: {"); fbx.Append("\n\t\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",0.8,0.8,0.8"); fbx.Append("\n\t\t\t\tP: \"Size\", \"double\", \"Number\", \"\",100"); fbx.Append("\n\t\t\t\tP: \"Look\", \"enum\", \"\", \"\",1"); fbx.Append("\n\t\t\t}\n\t\t}\n\t}"); fbx.Append("\n\tObjectType: \"Geometry\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Meshes.Count + Skins.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Material\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Materials.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\tObjectType: \"Video\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Textures.Count); fbx.Append("\n\t}"); if ((bool)Properties.Settings.Default["exportDeformers"]) { fbx.Append("\n\tObjectType: \"CollectionExclusive\" {"); fbx.AppendFormat("\n\t\tCount: {0}", Skins.Count); fbx.Append("\n\t\tPropertyTemplate: \"FbxDisplayLayer\" {"); fbx.Append("\n\t\t\tProperties70: {"); fbx.Append("\n\t\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",0.8,0.8,0.8"); fbx.Append("\n\t\t\t\tP: \"Show\", \"bool\", \"\", \"\",1"); fbx.Append("\n\t\t\t\tP: \"Freeze\", \"bool\", \"\", \"\",0"); fbx.Append("\n\t\t\t\tP: \"LODBox\", \"bool\", \"\", \"\",0"); fbx.Append("\n\t\t\t}"); fbx.Append("\n\t\t}"); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Deformer\" {"); fbx.AppendFormat("\n\t\tCount: {0}", DeformerCount + Skins.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Pose\" {"); fbx.Append("\n\t\tCount: 1"); fbx.Append("\n\t}"); } fbx.Append("\n}\n"); fbx.Append("\nObjects: {"); FBXwriter.Write(fbx); fbx.Clear(); #endregion #region write Model nodes and connections StatusStripUpdate("Writing Nodes and hierarchy"); foreach (var m_GameObject in GameObjects) { if (m_GameObject.m_MeshFilter == null && m_GameObject.m_SkinnedMeshRenderer == null) { if ((bool)Properties.Settings.Default["exportDeformers"] && (bool)Properties.Settings.Default["convertDummies"] && LimbNodes.Contains(m_GameObject)) { ob.AppendFormat("\n\tNodeAttribute: 2{0}, \"NodeAttribute::\", \"LimbNode\" {{", m_GameObject.uniqueID); ob.Append("\n\t\tTypeFlags: \"Skeleton\""); ob.Append("\n\t}"); ob.AppendFormat("\n\tModel: 1{0}, \"Model::{1}\", \"LimbNode\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); } else { ob.AppendFormat("\n\tNodeAttribute: 2{0}, \"NodeAttribute::\", \"Null\" {{", m_GameObject.uniqueID); ob.Append("\n\t\tTypeFlags: \"Null\""); ob.Append("\n\t}"); ob.AppendFormat("\n\tModel: 1{0}, \"Model::{1}\", \"Null\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); } //connect NodeAttribute to Model cb.AppendFormat("\n\n\t;NodeAttribute::, Model::{0}", m_GameObject.m_Name); cb.AppendFormat("\n\tC: \"OO\",2{0},1{0}", m_GameObject.uniqueID); } else { ob.AppendFormat("\n\tModel: 1{0}, \"Model::{1}\", \"Mesh\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); } 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"); Transform m_Transform; if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) { float[] m_EulerRotation = QuatToEuler(new float[] { m_Transform.m_LocalRotation[0], -m_Transform.m_LocalRotation[1], -m_Transform.m_LocalRotation[2], m_Transform.m_LocalRotation[3] }); ob.AppendFormat("\n\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",{0},{1},{2}", -m_Transform.m_LocalPosition[0], m_Transform.m_LocalPosition[1], m_Transform.m_LocalPosition[2]); ob.AppendFormat("\n\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",{0},{1},{2}", m_EulerRotation[0], m_EulerRotation[1], m_EulerRotation[2]);//handedness is switched in quat ob.AppendFormat("\n\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", m_Transform.m_LocalScale[0], m_Transform.m_LocalScale[1], m_Transform.m_LocalScale[2]); } //mb.Append("\n\t\t\tP: \"UDP3DSMAX\", \"KString\", \"\", \"U\", \"MapChannel:1 = UVChannel_1&cr;&lf;MapChannel:2 = UVChannel_2&cr;&lf;\""); //mb.Append("\n\t\t\tP: \"MaxHandle\", \"int\", \"Integer\", \"UH\",24"); ob.Append("\n\t\t}"); ob.Append("\n\t\tShading: T"); ob.Append("\n\t\tCulling: \"CullingOff\"\n\t}"); //connect Model to parent GameObject parentObject = (GameObject)m_GameObject.Parent; if (GameObjects.Contains(parentObject)) { cb.AppendFormat("\n\n\t;Model::{0}, Model::{1}", m_GameObject.m_Name, parentObject.m_Name); cb.AppendFormat("\n\tC: \"OO\",1{0},1{1}", m_GameObject.uniqueID, parentObject.uniqueID); } else { cb.AppendFormat("\n\n\t;Model::{0}, Model::RootNode", m_GameObject.m_Name); cb.AppendFormat("\n\tC: \"OO\",1{0},0", m_GameObject.uniqueID); } } #endregion #region write non-skinnned Geometry StatusStripUpdate("Writing Geometry"); foreach (var MeshPD in Meshes) { Mesh m_Mesh = new Mesh(MeshPD); MeshFBX(m_Mesh, MeshPD.uniqueID, ob); //write data 8MB at a time if (ob.Length > (8 * 0x100000)) { FBXwriter.Write(ob); ob.Clear(); } } #endregion #region write Deformer objects and skinned Geometry StringBuilder pb = new StringBuilder(); //generate unique ID for BindPose pb.Append("\n\tPose: 5123456789, \"Pose::BIND_POSES\", \"BindPose\" {"); pb.Append("\n\t\tType: \"BindPose\""); pb.Append("\n\t\tVersion: 100"); pb.AppendFormat("\n\t\tNbPoseNodes: {0}", Skins.Count + LimbNodes.Count); foreach (var SkinnedMeshPD in Skins) { SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); GameObject m_GameObject; AssetPreloadData MeshPD; if (assetsfileList.TryGetGameObject(m_SkinnedMeshRenderer.m_GameObject, out m_GameObject) && assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out MeshPD)) { Mesh m_Mesh = new Mesh(MeshPD); MeshFBX(m_Mesh, MeshPD.uniqueID, ob); //write data 8MB at a time if (ob.Length > (8 * 0x100000)) { FBXwriter.Write(ob); ob.Clear(); } cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", m_GameObject.m_Name); cb2.AppendFormat("\n\tC: \"OO\",3{0},1{1}", MeshPD.uniqueID, m_GameObject.uniqueID); if ((bool)Properties.Settings.Default["exportDeformers"]) { //add BindPose node pb.Append("\n\t\tPoseNode: {"); pb.AppendFormat("\n\t\t\tNode: 1{0}", m_GameObject.uniqueID); //pb.Append("\n\t\t\tMatrix: *16 {"); //pb.Append("\n\t\t\t\ta: "); //pb.Append("\n\t\t\t} "); pb.Append("\n\t\t}"); ob.AppendFormat("\n\tCollectionExclusive: 5{0}, \"DisplayLayer::{1}\", \"DisplayLayer\" {{", SkinnedMeshPD.uniqueID, m_GameObject.m_Name); ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\t}"); ob.Append("\n\t}"); //connect Model to DisplayLayer cb2.AppendFormat("\n\n\t;Model::{0}, DisplayLayer::", m_GameObject.m_Name); cb2.AppendFormat("\n\tC: \"OO\",1{0},5{1}", m_GameObject.uniqueID, SkinnedMeshPD.uniqueID); //write Deformers if (m_Mesh.m_Skin.Length > 0 && m_Mesh.m_BindPose.Length >= m_SkinnedMeshRenderer.m_Bones.Length) { //write main Skin Deformer ob.AppendFormat("\n\tDeformer: 4{0}, \"Deformer::\", \"Skin\" {{", SkinnedMeshPD.uniqueID); ob.Append("\n\t\tVersion: 101"); ob.Append("\n\t\tLink_DeformAcuracy: 50"); ob.Append("\n\t}"); //Deformer end //connect Skin Deformer to Geometry cb2.Append("\n\n\t;Deformer::, Geometry::"); cb2.AppendFormat("\n\tC: \"OO\",4{0},3{1}", SkinnedMeshPD.uniqueID, MeshPD.uniqueID); for (int b = 0; b < m_SkinnedMeshRenderer.m_Bones.Length; b++) { Transform m_Transform; if (assetsfileList.TryGetTransform(m_SkinnedMeshRenderer.m_Bones[b], out m_Transform)) { GameObject m_Bone; if (assetsfileList.TryGetGameObject(m_Transform.m_GameObject, out m_Bone)) { int influences = 0, ibSplit = 0, wbSplit = 0; StringBuilder ib = new StringBuilder();//indices (vertex) StringBuilder wb = new StringBuilder();//weights for (int index = 0; index < m_Mesh.m_Skin.Length; index++) { if (m_Mesh.m_Skin[index][0].weight == 0 && (m_Mesh.m_Skin[index].All(x => x.weight == 0) || //if all weights (and indicces) are 0, bone0 has full control m_Mesh.m_Skin[index][1].weight > 0)) //this implies a second bone exists, so bone0 has control too (otherwise it wouldn't be the first in the series) { m_Mesh.m_Skin[index][0].weight = 1; } var influence = m_Mesh.m_Skin[index].Find(x => x.boneIndex == b && x.weight > 0); if (influence != null) { influences++; ib.AppendFormat("{0},", index); wb.AppendFormat("{0},", influence.weight); if (ib.Length - ibSplit > 2000) { ib.Append("\n"); ibSplit = ib.Length; } if (wb.Length - wbSplit > 2000) { wb.Append("\n"); wbSplit = wb.Length; } } /*float weight; if (m_Mesh.m_Skin[index].TryGetValue(b, out weight)) { if (weight > 0) { influences++; ib.AppendFormat("{0},", index); wb.AppendFormat("{0},", weight); } else if (m_Mesh.m_Skin[index].Keys.Count == 1)//m_Mesh.m_Skin[index].Values.All(x => x == 0) { influences++; ib.AppendFormat("{0},", index); wb.AppendFormat("{0},", 1); } if (ib.Length - ibSplit > 2000) { ib.Append("\n"); ibSplit = ib.Length; } if (wb.Length - wbSplit > 2000) { wb.Append("\n"); wbSplit = wb.Length; } }*/ } if (influences > 0) { ib.Length--;//remove last comma wb.Length--;//remove last comma } //SubDeformer objects need unique IDs because 2 or more deformers can be linked to the same bone ob.AppendFormat("\n\tDeformer: 4{0}{1}, \"SubDeformer::\", \"Cluster\" {{", b, SkinnedMeshPD.uniqueID); ob.Append("\n\t\tVersion: 100"); ob.Append("\n\t\tUserData: \"\", \"\""); ob.AppendFormat("\n\t\tIndexes: *{0} {{\n\t\t\ta: ", influences); ob.Append(ib); ob.Append("\n\t\t}"); ib.Clear(); ob.AppendFormat("\n\t\tWeights: *{0} {{\n\t\t\ta: ", influences); ob.Append(wb); ob.Append("\n\t\t}"); wb.Clear(); ob.Append("\n\t\tTransform: *16 {\n\t\t\ta: "); //ob.Append(string.Join(",", m_Mesh.m_BindPose[b])); var m = m_Mesh.m_BindPose[b]; ob.AppendFormat("{0},{1},{2},{3},", m[0, 0], -m[1, 0], -m[2, 0], m[3, 0]); ob.AppendFormat("{0},{1},{2},{3},", -m[0, 1], m[1, 1], m[2, 1], m[3, 1]); ob.AppendFormat("{0},{1},{2},{3},", -m[0, 2], m[1, 2], m[2, 2], m[3, 2]); ob.AppendFormat("{0},{1},{2},{3},", -m[0, 3], m[1, 3], m[2, 3], m[3, 3]); ob.Append("\n\t\t}"); ob.Append("\n\t}"); //SubDeformer end //connect SubDeformer to Skin Deformer cb2.Append("\n\n\t;SubDeformer::, Deformer::"); cb2.AppendFormat("\n\tC: \"OO\",4{0}{1},4{1}", b, SkinnedMeshPD.uniqueID); //connect dummy Model to SubDeformer cb2.AppendFormat("\n\n\t;Model::{0}, SubDeformer::", m_Bone.m_Name); cb2.AppendFormat("\n\tC: \"OO\",1{0},4{1}{2}", m_Bone.uniqueID, b, SkinnedMeshPD.uniqueID); } } } } else { bool stop = true; } } } } if ((bool)Properties.Settings.Default["exportDeformers"]) { foreach (var m_Bone in LimbNodes) { //add BindPose node pb.Append("\n\t\tPoseNode: {"); pb.AppendFormat("\n\t\t\tNode: 1{0}", m_Bone.uniqueID); //pb.Append("\n\t\t\tMatrix: *16 {"); //pb.Append("\n\t\t\t\ta: "); //pb.Append("\n\t\t\t} "); pb.Append("\n\t\t}"); } pb.Append("\n\t}"); //BindPose end ob.Append(pb); pb.Clear(); } #endregion ob.Append(mb); mb.Clear(); cb.Append(cb2); cb2.Clear(); #region write & extract Textures Directory.CreateDirectory(Path.GetDirectoryName(FBXfile) + "\\Texture2D"); foreach (var TexturePD in Textures) { Texture2D m_Texture2D = new Texture2D(TexturePD, true); #region extract texture string texPath = Path.GetDirectoryName(FBXfile) + "\\Texture2D\\" + TexturePD.Text; //TODO check texture type and set path accordingly; eg. CubeMap, Texture3D if (uniqueNames.Checked) { texPath += " #" + TexturePD.uniqueID; } if (m_Texture2D.m_TextureFormat < 30) { texPath += ".dds"; } else if (m_Texture2D.m_TextureFormat < 35) { texPath += ".pvr"; } else { texPath += "_" + m_Texture2D.m_Width.ToString() + "x" + m_Texture2D.m_Height.ToString() + "." + m_Texture2D.m_TextureFormat.ToString() + ".tex"; } if (File.Exists(texPath)) { StatusStripUpdate("Texture file " + Path.GetFileName(texPath) + " already exists"); } else { StatusStripUpdate("Exporting Texture2D: " + Path.GetFileName(texPath)); switch (m_Texture2D.m_TextureFormat) { case 1: //Alpha8 case 2: //A4R4G4B4 case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure case 4: //G8R8A8B8 //confirmed on X360, iOS case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS case 10: //DXT1 case 12: //DXT5 case 13: //R4G4B4A4, iOS (only?) WriteDDS(texPath, m_Texture2D); break; case 30: //PVRTC_RGB2 case 31: //PVRTC_RGBA2 case 32: //PVRTC_RGB4 case 33: //PVRTC_RGBA4 case 34: //ETC_RGB4 WritePVR(texPath, m_Texture2D); break; default: { using (BinaryWriter writer = new BinaryWriter(File.Open(texPath, FileMode.Create))) { writer.Write(m_Texture2D.image_data); writer.Close(); } break; } } } #endregion ob.AppendFormat("\n\tTexture: 7{0}, \"Texture::{1}\", \"\" {{", TexturePD.uniqueID, TexturePD.Text); ob.Append("\n\t\tType: \"TextureVideoClip\""); ob.Append("\n\t\tVersion: 202"); ob.AppendFormat("\n\t\tTextureName: \"Texture::{0}\"", TexturePD.Text); 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}\"", TexturePD.Text); ob.AppendFormat("\n\t\tFileName: \"{0}\"", texPath); ob.AppendFormat("\n\t\tRelativeFilename: \"Texture2D\\{0}\"", Path.GetFileName(texPath)); ob.Append("\n\t}"); ob.AppendFormat("\n\tVideo: 8{0}, \"Video::{1}\", \"Clip\" {{", TexturePD.uniqueID, TexturePD.Text); ob.Append("\n\t\tType: \"Clip\""); ob.Append("\n\t\tProperties70: {"); ob.AppendFormat("\n\t\t\tP: \"Path\", \"KString\", \"XRefUrl\", \"\", \"{0}\"", texPath); ob.Append("\n\t\t}"); ob.AppendFormat("\n\t\tFileName: \"{0}\"", texPath); ob.AppendFormat("\n\t\tRelativeFilename: \"Texture2D\\{0}\"", Path.GetFileName(texPath)); ob.Append("\n\t}"); //connect video to texture cb.AppendFormat("\n\n\t;Video::{0}, Texture::{0}", TexturePD.Text); cb.AppendFormat("\n\tC: \"OO\",8{0},7{1}", TexturePD.uniqueID, TexturePD.uniqueID); } #endregion FBXwriter.Write(ob); ob.Clear(); cb.Append("\n}");//Connections end FBXwriter.Write(cb); cb.Clear(); StatusStripUpdate("Finished exporting " + Path.GetFileName(FBXfile)); } }
private void BuildAssetStrucutres() { #region first loop - read asset data & create list if (!dontLoadAssetsMenuItem.Checked) { assetListView.BeginUpdate(); progressBar1.Value = 0; progressBar1.Maximum = totalAssetCount; string fileIDfmt = "D" + assetsfileList.Count.ToString().Length.ToString(); foreach (var assetsFile in assetsfileList) { StatusStripUpdate("Building asset list from " + Path.GetFileName(assetsFile.filePath)); string fileID = assetsfileList.IndexOf(assetsFile).ToString(fileIDfmt); //ListViewGroup assetGroup = new ListViewGroup(Path.GetFileName(assetsFile.filePath)); foreach (var asset in assetsFile.preloadTable.Values) { asset.uniqueID = fileID + asset.uniqueID; switch (asset.Type2) { case 1: //GameObject { GameObject m_GameObject = new GameObject(asset); assetsFile.GameObjectList.Add(asset.m_PathID, m_GameObject); totalTreeNodes++; break; } case 4: //Transform { Transform m_Transform = new Transform(asset); assetsFile.TransformList.Add(asset.m_PathID, m_Transform); break; } case 224: //RectTransform { RectTransform m_Rect = new RectTransform(asset); assetsFile.TransformList.Add(asset.m_PathID, m_Rect.m_Transform); break; } //case 21: //Material case 28: //Texture2D { Texture2D m_Texture2D = new Texture2D(asset, false); assetsFile.exportableAssets.Add(asset); break; } case 48: //Shader case 49: //TextAsset { TextAsset m_TextAsset = new TextAsset(asset, false); assetsFile.exportableAssets.Add(asset); break; } case 83: //AudioClip { AudioClip m_AudioClip = new AudioClip(asset, false); assetsFile.exportableAssets.Add(asset); break; } //case 89: //CubeMap case 128: //Font { unityFont m_Font = new unityFont(asset, false); assetsFile.exportableAssets.Add(asset); break; } case 129: //PlayerSettings { PlayerSettings plSet = new PlayerSettings(asset); productName = plSet.productName; base.Text = "Unity Studio - " + productName + " - " + assetsFile.m_Version + " - " + assetsFile.platformStr; break; } case 0: break; } progressBar1.PerformStep(); } exportableAssets.AddRange(assetsFile.exportableAssets); //if (assetGroup.Items.Count > 0) { listView1.Groups.Add(assetGroup); } } if (base.Text == "Unity Studio" && assetsfileList.Count > 0) { base.Text = "Unity Studio - no productName - " + assetsfileList[0].m_Version + " - " + assetsfileList[0].platformStr; } visibleAssets = exportableAssets; assetListView.VirtualListSize = visibleAssets.Count; //will only work if ListView is visible resizeAssetListColumns(); assetListView.EndUpdate(); progressBar1.Value = 0; } #endregion #region second loop - build tree structure if (!dontBuildHierarchyMenuItem.Checked) { sceneTreeView.BeginUpdate(); progressBar1.Value = 0; progressBar1.Maximum = totalTreeNodes; foreach (var assetsFile in assetsfileList) { StatusStripUpdate("Building tree structure from " + Path.GetFileName(assetsFile.filePath)); GameObject fileNode = new GameObject(null); fileNode.Text = Path.GetFileName(assetsFile.filePath); fileNode.m_Name = "RootNode"; foreach (var m_GameObject in assetsFile.GameObjectList.Values) { var parentNode = fileNode; Transform m_Transform; if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) { Transform m_Father; if (assetsfileList.TryGetTransform(m_Transform.m_Father, out m_Father)) { //GameObject Parent; if (assetsfileList.TryGetGameObject(m_Father.m_GameObject, out parentNode)) { //parentNode = Parent; } } } parentNode.Nodes.Add(m_GameObject); progressBar1.PerformStep(); } if (fileNode.Nodes.Count == 0) { fileNode.Text += " (no children)"; } sceneTreeView.Nodes.Add(fileNode); } sceneTreeView.EndUpdate(); progressBar1.Value = 0; if (File.Exists(mainPath + "\\materials.json")) { string matLine = ""; using (StreamReader reader = File.OpenText(mainPath + "\\materials.json")) { matLine = reader.ReadToEnd(); } jsonMats = new JavaScriptSerializer().Deserialize<Dictionary<string, Dictionary<string, string>>>(matLine); //var jsonMats = new JavaScriptSerializer().DeserializeObject(matLine); } } #endregion #region build list of class strucutres if (buildClassStructuresMenuItem.Checked) { //group class structures by versionv foreach (var assetsFile in assetsfileList) { SortedDictionary<int, ClassStrStruct> curVer; if (AllClassStructures.TryGetValue(assetsFile.m_Version, out curVer)) { foreach (var uClass in assetsFile.ClassStructures) { curVer[uClass.Key] = uClass.Value; } } else { AllClassStructures.Add(assetsFile.m_Version, assetsFile.ClassStructures); } } classesListView.BeginUpdate(); foreach (var version in AllClassStructures) { ListViewGroup versionGroup = new ListViewGroup(version.Key); classesListView.Groups.Add(versionGroup); foreach (var uclass in version.Value) { uclass.Value.Group = versionGroup; classesListView.Items.Add(uclass.Value); } } classesListView.EndUpdate(); } #endregion StatusStripUpdate("Finished loading " + assetsfileList.Count.ToString() + " files with " + (assetListView.Items.Count + sceneTreeView.Nodes.Count).ToString() + " exportable assets."); progressBar1.Value = 0; treeSearch.Select(); saveFolderDialog1.InitialDirectory = mainPath; }
private void ExportTexture (Texture2D m_Texture2D, string exportFilename) { switch (m_Texture2D.m_TextureFormat) { #region DDS case 1: //Alpha8 case 2: //A4R4G4B4 case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure case 4: //G8R8A8B8 //confirmed on X360, iOS case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS case 10: //DXT1 case 12: //DXT5 case 13: //R4G4B4A4, iOS (only?) using (BinaryWriter writer = new BinaryWriter(File.Open(exportFilename, FileMode.Create))) { writer.Write(0x20534444); writer.Write(0x7C); writer.Write(m_Texture2D.dwFlags); writer.Write(m_Texture2D.m_Height); writer.Write(m_Texture2D.m_Width); writer.Write(m_Texture2D.dwPitchOrLinearSize); //should be main tex size without mips); writer.Write((int)0); //dwDepth not implemented writer.Write(m_Texture2D.dwMipMapCount); writer.Write(new byte[44]); //dwReserved1[11] writer.Write(m_Texture2D.dwSize); writer.Write(m_Texture2D.dwFlags2); writer.Write(m_Texture2D.dwFourCC); writer.Write(m_Texture2D.dwRGBBitCount); writer.Write(m_Texture2D.dwRBitMask); writer.Write(m_Texture2D.dwGBitMask); writer.Write(m_Texture2D.dwBBitMask); writer.Write(m_Texture2D.dwABitMask); writer.Write(m_Texture2D.dwCaps); writer.Write(m_Texture2D.dwCaps2); writer.Write(new byte[12]); //dwCaps3&4 & dwReserved2 writer.Write(m_Texture2D.image_data); writer.Close(); } break; #endregion #region PVR case 30: //PVRTC_RGB2 case 31: //PVRTC_RGBA2 case 32: //PVRTC_RGB4 case 33: //PVRTC_RGBA4 case 34: //ETC_RGB4 using (BinaryWriter writer = new BinaryWriter(File.Open(exportFilename, FileMode.Create))) { writer.Write(m_Texture2D.pvrVersion); writer.Write(m_Texture2D.pvrFlags); writer.Write(m_Texture2D.pvrPixelFormat); writer.Write(m_Texture2D.pvrColourSpace); writer.Write(m_Texture2D.pvrChannelType); writer.Write(m_Texture2D.m_Height); writer.Write(m_Texture2D.m_Width); writer.Write(m_Texture2D.pvrDepth); writer.Write(m_Texture2D.pvrNumSurfaces); writer.Write(m_Texture2D.pvrNumFaces); writer.Write(m_Texture2D.dwMipMapCount); writer.Write(m_Texture2D.pvrMetaDataSize); writer.Write(m_Texture2D.image_data); writer.Close(); } break; #endregion case 28: //DXT1 Crunched case 29: //DXT1 Crunched default: using (BinaryWriter writer = new BinaryWriter(File.Open(exportFilename, FileMode.Create))) { writer.Write(m_Texture2D.image_data); writer.Close(); } break; } }
public void WriteFBX(string FBXfile, bool allNodes) { var timestamp = DateTime.Now; using (StreamWriter FBXwriter = new StreamWriter(FBXfile)) { StringBuilder fbx = new StringBuilder(); StringBuilder ob = new StringBuilder(); //Objects builder StringBuilder cb = new StringBuilder(); //Connections builder cb.Append("\n}\n");//Objects end cb.Append("\nConnections: {"); HashSet<AssetPreloadData> MeshList = new HashSet<AssetPreloadData>(); HashSet<AssetPreloadData> MaterialList = new HashSet<AssetPreloadData>(); HashSet<AssetPreloadData> TextureList = new HashSet<AssetPreloadData>(); int ModelCount = 0; int GeometryCount = 0; int MaterialCount = 0; int TextureCount = 0; //using m_PathID as unique ID would fail because it could be a negative number (Hearthstone syndrome) //consider using uint //no, do something smarter #region write generic FBX data 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\", \"\",{0}", Properties.Settings.Default["scaleFactor"]); fbx.Append("\n\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",1.0"); //sb.Append("\n\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); //sb.Append("\n\t\tP: \"DefaultCamera\", \"KString\", \"\", \"\", \"Producer Perspective\""); //sb.Append("\n\t\tP: \"TimeMode\", \"enum\", \"\", \"\",6"); //sb.Append("\n\t\tP: \"TimeProtocol\", \"enum\", \"\", \"\",2"); //sb.Append("\n\t\tP: \"SnapOnFrameMode\", \"enum\", \"\", \"\",0"); //sb.Append("\n\t\tP: \"TimeSpanStart\", \"KTime\", \"Time\", \"\",0"); //sb.Append("\n\t\tP: \"TimeSpanStop\", \"KTime\", \"Time\", \"\",153953860000"); //sb.Append("\n\t\tP: \"CustomFrameRate\", \"double\", \"Number\", \"\",-1"); //sb.Append("\n\t\tP: \"TimeMarker\", \"Compound\", \"\", \"\""); //sb.Append("\n\t\tP: \"CurrentTimeMarker\", \"int\", \"Integer\", \"\",-1"); 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 + srcModel.nodes.Count + FBXgeometryCount + srcModel.materials.Count + srcModel.usedTex.Count * 2); 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}", ModelCount); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Geometry\" {"); //fbx.AppendFormat("\n\t\tCount: {0}", GeometryCount); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Material\" {"); //fbx.AppendFormat("\n\t\tCount: {0}", MaterialCount); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Texture\" {"); //fbx.AppendFormat("\n\t\tCount: {0}", TextureCount); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Video\" {"); //fbx.AppendFormat("\n\t\tCount: {0}", TextureCount); fbx.Append("\n\t}"); fbx.Append("\n}\n"); fbx.Append("\nObjects: {"); FBXwriter.Write(fbx); fbx.Length = 0; #endregion #region write Models, collect Mesh & Material objects foreach (var assetsFile in assetsfileList) { foreach (var m_GameObject in assetsFile.GameObjectList) { if (m_GameObject.Checked || allNodes) { #region write Model and Transform ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\"", m_GameObject.uniqueID, m_GameObject.m_Name); if (m_GameObject.m_MeshFilter != null || m_GameObject.m_SkinnedMeshRenderer != null) { ob.Append(", \"Mesh\" {"); } else { ob.Append(", \"Null\" {"); } 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"); //connect model to parent GameObject parentObject = (GameObject)m_GameObject.Parent; if (parentObject.Checked || allNodes) { cb.AppendFormat("\n\tC: \"OO\",{0},{1}", m_GameObject.uniqueID, parentObject.uniqueID); //if parentObject is a file or folder node, it will have uniqueID 0 } else { cb.AppendFormat("\n\tC: \"OO\",{0},0", m_GameObject.uniqueID); }//connect to scene Transform m_Transform; if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) { float[] m_EulerRotation = QuatToEuler(new float[] { m_Transform.m_LocalRotation[0], -m_Transform.m_LocalRotation[1], -m_Transform.m_LocalRotation[2], m_Transform.m_LocalRotation[3] }); ob.AppendFormat("\n\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",{0},{1},{2}", -m_Transform.m_LocalPosition[0], m_Transform.m_LocalPosition[1], m_Transform.m_LocalPosition[2]); ob.AppendFormat("\n\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",{0},{1},{2}", m_EulerRotation[0], m_EulerRotation[1], m_EulerRotation[2]);//handedness is switched in quat ob.AppendFormat("\n\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", m_Transform.m_LocalScale[0], m_Transform.m_LocalScale[1], m_Transform.m_LocalScale[2]); } //mb.Append("\n\t\t\tP: \"UDP3DSMAX\", \"KString\", \"\", \"U\", \"MapChannel:1 = UVChannel_1&cr;&lf;MapChannel:2 = UVChannel_2&cr;&lf;\""); //mb.Append("\n\t\t\tP: \"MaxHandle\", \"int\", \"Integer\", \"UH\",24"); ob.Append("\n\t\t}"); ob.Append("\n\t\tShading: T"); ob.Append("\n\t\tCulling: \"CullingOff\"\n\t}"); #endregion #region get MeshFilter AssetPreloadData MeshFilterPD; if (assetsfileList.TryGetPD(m_GameObject.m_MeshFilter, out MeshFilterPD)) { MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); AssetPreloadData MeshPD; if (assetsfileList.TryGetPD(m_MeshFilter.m_Mesh, out MeshPD)) { MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); } } /*if (m_GameObject.m_MeshFilter != null && m_GameObject.m_MeshFilter.m_FileID >= 0) { var MeshFilterAF = assetsfileList[m_GameObject.m_MeshFilter.m_FileID]; AssetPreloadData MeshFilterPD; if (MeshFilterAF.preloadTable.TryGetValue(m_GameObject.m_MeshFilter.m_PathID, out MeshFilterPD)) { MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); if (m_MeshFilter.m_Mesh.m_FileID >= 0) { var MeshAF = assetsfileList[m_MeshFilter.m_Mesh.m_FileID]; AssetPreloadData MeshPD; if (MeshAF.preloadTable.TryGetValue(m_MeshFilter.m_Mesh.m_PathID, out MeshPD)) { MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); } } } }*/ #endregion #region get Renderer AssetPreloadData RendererPD; if (assetsfileList.TryGetPD(m_GameObject.m_Renderer, out RendererPD)) { Renderer m_Renderer = new Renderer(RendererPD); foreach (var MaterialPPtr in m_Renderer.m_Materials) { AssetPreloadData MaterialPD; if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) { MaterialList.Add(MaterialPD); cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); } } } /*if (m_GameObject.m_Renderer != null && m_GameObject.m_Renderer.m_FileID >= 0) { var RendererAF = assetsfileList[m_GameObject.m_Renderer.m_FileID]; AssetPreloadData RendererPD; if (RendererAF.preloadTable.TryGetValue(m_GameObject.m_Renderer.m_PathID, out RendererPD)) { Renderer m_Renderer = new Renderer(RendererPD); foreach (var MaterialPPtr in m_Renderer.m_Materials) { if (MaterialPPtr.m_FileID >= 0) { var MaterialAF = assetsfileList[MaterialPPtr.m_FileID]; AssetPreloadData MaterialPD; if (MaterialAF.preloadTable.TryGetValue(MaterialPPtr.m_PathID, out MaterialPD)) { MaterialList.Add(MaterialPD); cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); } } } } }*/ #endregion #region get SkinnedMeshRenderer AssetPreloadData SkinnedMeshPD; if (assetsfileList.TryGetPD(m_GameObject.m_SkinnedMeshRenderer, out SkinnedMeshPD)) { SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) { AssetPreloadData MaterialPD; if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) { MaterialList.Add(MaterialPD); cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); } } AssetPreloadData MeshPD; if (assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out MeshPD)) { MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); } } /*if (m_GameObject.m_SkinnedMeshRenderer != null && m_GameObject.m_SkinnedMeshRenderer.m_FileID >= 0) { var SkinnedMeshAF = assetsfileList[m_GameObject.m_SkinnedMeshRenderer.m_FileID]; AssetPreloadData SkinnedMeshPD; if (SkinnedMeshAF.preloadTable.TryGetValue(m_GameObject.m_SkinnedMeshRenderer.m_PathID, out SkinnedMeshPD)) { SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) { if (MaterialPPtr.m_FileID >= 0) { var MaterialAF = assetsfileList[MaterialPPtr.m_FileID]; AssetPreloadData MaterialPD; if (MaterialAF.preloadTable.TryGetValue(MaterialPPtr.m_PathID, out MaterialPD)) { MaterialList.Add(MaterialPD); cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); } } } if (m_SkinnedMeshRenderer.m_Mesh.m_FileID >= 0) { var MeshAF = assetsfileList[m_SkinnedMeshRenderer.m_Mesh.m_FileID]; AssetPreloadData MeshPD; if (MeshAF.preloadTable.TryGetValue(m_SkinnedMeshRenderer.m_Mesh.m_PathID, out MeshPD)) { MeshList.Add(MeshPD); cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); } } } }*/ #endregion //write data 8MB at a time if (ob.Length > (8 * 0x100000)) { FBXwriter.Write(ob); ob.Length = 0; } } } } #endregion #region write Geometry foreach (var MeshPD in MeshList) { Mesh m_Mesh = new Mesh(MeshPD); if (m_Mesh.m_VertexCount > 0)//general failsafe { StatusStripUpdate("Writing Geometry: " + m_Mesh.m_Name); ob.AppendFormat("\n\tGeometry: {0}, \"Geometry::\", \"Mesh\" {{", MeshPD.uniqueID); ob.Append("\n\t\tProperties70: {"); var randomColor = RandomColorGenerator(MeshPD.uniqueID); ob.AppendFormat("\n\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",{0},{1},{2}", ((float)randomColor[0] / 255), ((float)randomColor[1] / 255), ((float)randomColor[2] / 255)); ob.Append("\n\t\t}"); #region Vertices ob.AppendFormat("\n\t\tVertices: *{0} {{\n\t\t\ta: ", m_Mesh.m_VertexCount * 3); int c = 3;//vertex components //skip last value in half4 components if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) { c++; } //haha //split arrays in groups of 2040 chars uint f3Lines = m_Mesh.m_VertexCount / 40;//40 verts * 3 components * 17 max chars per float including comma uint remf3Verts = m_Mesh.m_VertexCount % 40; uint f2Lines = m_Mesh.m_VertexCount / 60;//60 UVs * 2 components * 17 max chars per float including comma uint remf2Verts = m_Mesh.m_VertexCount % 60; //this is fast but line length is not optimal for (int l = 0; l < f3Lines; l++) { for (int v = 0; v < 40; v++) { ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[(l * 40 + v) * c], m_Mesh.m_Vertices[(l * 40 + v) * c + 1], m_Mesh.m_Vertices[(l * 40 + v) * c + 2]); } ob.Append("\n"); } if (remf3Verts != 0) { for (int v = 0; v < remf3Verts; v++) { ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[(f3Lines * 40 + v) * c], m_Mesh.m_Vertices[(f3Lines * 40 + v) * c + 1], m_Mesh.m_Vertices[(f3Lines * 40 + v) * c + 2]); } } else { ob.Length--; }//remove last newline ob.Length--;//remove last comma ob.Append("\n\t\t}"); #endregion #region Indices //in order to test topology for triangles/quads we need to store submeshes and write each one as geometry, then link to Mesh Node ob.AppendFormat("\n\t\tPolygonVertexIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); int iLines = m_Mesh.m_Indices.Count / 180; int remTris = (m_Mesh.m_Indices.Count % 180) / 3; for (int l = 0; l < iLines; l++) { for (int f = 0; f < 60; f++) { ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[l * 180 + f * 3], m_Mesh.m_Indices[l * 180 + f * 3 + 2], (-m_Mesh.m_Indices[l * 180 + f * 3 + 1] - 1)); } ob.Append("\n"); } if (remTris != 0) { for (int f = 0; f < remTris; f++) { ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[iLines * 180 + f * 3], m_Mesh.m_Indices[iLines * 180 + f * 3 + 2], (-m_Mesh.m_Indices[iLines * 180 + f * 3 + 1] - 1)); } } else { ob.Length--; }//remove last newline ob.Length--;//remove last comma ob.Append("\n\t\t}"); ob.Append("\n\t\tGeometryVersion: 124"); #endregion #region Normals if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) { ob.Append("\n\t\tLayerElementNormal: 0 {"); ob.Append("\n\t\t\tVersion: 101"); ob.Append("\n\t\t\tName: \"\""); ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); ob.AppendFormat("\n\t\t\tNormals: *{0} {{\n\t\t\ta: ", (m_Mesh.m_VertexCount * 3)); if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) { c = 3; } else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) { c = 4; } for (int l = 0; l < f3Lines; l++) { for (int v = 0; v < 40; v++) { ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[(l * 40 + v) * c], m_Mesh.m_Normals[(l * 40 + v) * c + 1], m_Mesh.m_Normals[(l * 40 + v) * c + 2]); } ob.Append("\n"); } if (remf3Verts != 0) { for (int v = 0; v < remf3Verts; v++) { ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[(f3Lines * 40 + v) * c], m_Mesh.m_Normals[(f3Lines * 40 + v) * c + 1], m_Mesh.m_Normals[(f3Lines * 40 + v) * c + 2]); } } else { ob.Length--; }//remove last newline ob.Length--;//remove last comma ob.Append("\n\t\t\t}\n\t\t}"); } #endregion #region Colors if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) { ob.Append("\n\t\tLayerElementColor: 0 {"); ob.Append("\n\t\t\tVersion: 101"); ob.Append("\n\t\t\tName: \"\""); //ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); //ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); ob.Append("\n\t\t\tMappingInformationType: \"ByPolygonVertex\""); ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); ob.AppendFormat("\n\t\t\tColors: *{0} {{\n\t\t\ta: ", m_Mesh.m_Colors.Length); //ob.Append(string.Join(",", m_Mesh.m_Colors)); int cLines = m_Mesh.m_Colors.Length / 120; int remCols = m_Mesh.m_Colors.Length % 120; for (int l = 0; l < cLines; l++) { for (int i = 0; i < 120; i++) { ob.AppendFormat("{0},", m_Mesh.m_Colors[l * 120 + i]); } ob.Append("\n"); } if (remCols > 0) { for (int i = 0; i < remCols; i++) { ob.AppendFormat("{0},", m_Mesh.m_Colors[cLines * 120 + i]); } } else { ob.Length--; }//remove last newline ob.Length--;//remove last comma ob.Append("\n\t\t\t}"); ob.AppendFormat("\n\t\t\tColorIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); for (int l = 0; l < iLines; l++) { for (int f = 0; f < 60; f++) { ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[l * 180 + f * 3], m_Mesh.m_Indices[l * 180 + f * 3 + 2], m_Mesh.m_Indices[l * 180 + f * 3 + 1]); } ob.Append("\n"); } if (remTris != 0) { for (int f = 0; f < remTris; f++) { ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[iLines * 180 + f * 3], m_Mesh.m_Indices[iLines * 180 + f * 3 + 2], m_Mesh.m_Indices[iLines * 180 + f * 3 + 1]); } } else { ob.Length--; }//remove last newline ob.Length--;//remove last comma ob.Append("\n\t\t\t}\n\t\t}"); } #endregion #region UV //does FBX support UVW coordinates? if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) { ob.Append("\n\t\tLayerElementUV: 0 {"); ob.Append("\n\t\t\tVersion: 101"); ob.Append("\n\t\t\tName: \"UVChannel_1\""); ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV1.Length); for (int l = 0; l < f2Lines; l++) { for (int v = 0; v < 60; v++) { ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[l * 120 + v * 2], 1 - m_Mesh.m_UV1[l * 120 + v * 2 + 1]); } ob.Append("\n"); } if (remf2Verts != 0) { for (int v = 0; v < remf2Verts; v++) { ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV1[f2Lines * 120 + v * 2 + 1]); } } else { ob.Length--; }//remove last newline ob.Length--;//remove last comma ob.Append("\n\t\t\t}\n\t\t}"); } if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) { ob.Append("\n\t\tLayerElementUV: 1 {"); ob.Append("\n\t\t\tVersion: 101"); ob.Append("\n\t\t\tName: \"UVChannel_2\""); ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV2.Length); for (int l = 0; l < f2Lines; l++) { for (int v = 0; v < 60; v++) { ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[l * 120 + v * 2], 1 - m_Mesh.m_UV2[l * 120 + v * 2 + 1]); } ob.Append("\n"); } if (remf2Verts != 0) { for (int v = 0; v < remf2Verts; v++) { ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV2[f2Lines * 120 + v * 2 + 1]); } } else { ob.Length--; }//remove last newline ob.Length--;//remove last comma ob.Append("\n\t\t\t}\n\t\t}"); } #endregion #region Material ob.Append("\n\t\tLayerElementMaterial: 0 {"); ob.Append("\n\t\t\tVersion: 101"); ob.Append("\n\t\t\tName: \"\""); ob.Append("\n\t\t\tMappingInformationType: \""); if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("AllSame\""); } else { ob.Append("ByPolygon\""); } ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); ob.AppendFormat("\n\t\t\tMaterials: *{0} {{", m_Mesh.m_materialIDs.Count); ob.Append("\n\t\t\t\t"); if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("0"); } else { int idLines = m_Mesh.m_materialIDs.Count / 500; int remIds = m_Mesh.m_materialIDs.Count % 500; for (int l = 0; l < idLines; l++) { for (int i = 0; i < 500; i++) { ob.AppendFormat("{0},", m_Mesh.m_materialIDs[l * 500 + i]); } ob.Append("\n"); } if (remIds != 0) { for (int i = 0; i < remIds; i++) { ob.AppendFormat("{0},", m_Mesh.m_materialIDs[idLines * 500 + i]); } } else { ob.Length--; }//remove last newline ob.Length--;//remove last comma } ob.Append("\n\t\t\t}\n\t\t}"); #endregion #region Layers ob.Append("\n\t\tLayer: 0 {"); ob.Append("\n\t\t\tVersion: 100"); if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) { ob.Append("\n\t\t\tLayerElement: {"); ob.Append("\n\t\t\t\tType: \"LayerElementNormal\""); ob.Append("\n\t\t\t\tTypedIndex: 0"); ob.Append("\n\t\t\t}"); } ob.Append("\n\t\t\tLayerElement: {"); ob.Append("\n\t\t\t\tType: \"LayerElementMaterial\""); ob.Append("\n\t\t\t\tTypedIndex: 0"); ob.Append("\n\t\t\t}"); // /*ob.Append("\n\t\t\tLayerElement: {"); ob.Append("\n\t\t\t\tType: \"LayerElementTexture\""); ob.Append("\n\t\t\t\tTypedIndex: 0"); ob.Append("\n\t\t\t}"); ob.Append("\n\t\t\tLayerElement: {"); ob.Append("\n\t\t\t\tType: \"LayerElementBumpTextures\""); ob.Append("\n\t\t\t\tTypedIndex: 0"); ob.Append("\n\t\t\t}");*/ if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) { ob.Append("\n\t\t\tLayerElement: {"); ob.Append("\n\t\t\t\tType: \"LayerElementColor\""); ob.Append("\n\t\t\t\tTypedIndex: 0"); ob.Append("\n\t\t\t}"); } if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) { ob.Append("\n\t\t\tLayerElement: {"); ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); ob.Append("\n\t\t\t\tTypedIndex: 0"); ob.Append("\n\t\t\t}"); } ob.Append("\n\t\t}"); //Layer 0 end if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) { ob.Append("\n\t\tLayer: 1 {"); ob.Append("\n\t\t\tVersion: 100"); ob.Append("\n\t\t\tLayerElement: {"); ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); ob.Append("\n\t\t\t\tTypedIndex: 1"); ob.Append("\n\t\t\t}"); ob.Append("\n\t\t}"); //Layer 1 end } #endregion ob.Append("\n\t}"); //Geometry end //write data 8MB at a time if (ob.Length > (8 * 0x100000)) { FBXwriter.Write(ob); ob.Length = 0; } } } #endregion #region write Materials, collect Texture objects StatusStripUpdate("Writing Materials"); foreach (var MaterialPD in MaterialList) { Material m_Material = new Material(MaterialPD); ob.AppendFormat("\n\tMaterial: {0}, \"Material::{1}\", \"\" {{", MaterialPD.uniqueID, m_Material.m_Name); ob.Append("\n\t\tVersion: 102"); ob.Append("\n\t\tShadingModel: \"phong\""); ob.Append("\n\t\tMultiLayer: 0"); ob.Append("\n\t\tProperties70: {"); ob.Append("\n\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"phong\""); #region write material colors foreach (var m_Color in m_Material.m_Colors) { switch (m_Color.first) { case "_Color": case "gSurfaceColor": ob.AppendFormat("\n\t\t\tP: \"DiffuseColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); break; case "_SpecColor": ob.AppendFormat("\n\t\t\tP: \"SpecularColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); break; case "_ReflectColor": ob.AppendFormat("\n\t\t\tP: \"AmbientColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); break; default: ob.AppendFormat("\n;\t\t\tP: \"{3}\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2], m_Color.first);//commented out break; } } #endregion #region write material parameters foreach (var m_Float in m_Material.m_Floats) { switch (m_Float.first) { case "_Shininess": ob.AppendFormat("\n\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",{0}", m_Float.second); break; default: ob.AppendFormat("\n;\t\t\tP: \"{0}\", \"Number\", \"\", \"A\",{1}", m_Float.first, m_Float.second); break; } } #endregion //ob.Append("\n\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",0"); ob.Append("\n\t\t}"); ob.Append("\n\t}"); #region write texture connections foreach (var m_TexEnv in m_Material.m_TexEnvs) { AssetPreloadData TexturePD; if (assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD)) { } else if (jsonMats != null) { Dictionary<string, string> matProp; if (jsonMats.TryGetValue(m_Material.m_Name, out matProp)) { string texName; if (matProp.TryGetValue(m_TexEnv.name, out texName)) { foreach (var asset in exportableAssets) { if (asset.Type2 == 28 && asset.Text == texName) { TexturePD = asset; break; } } } } } if (TexturePD != null) { TextureList.Add(TexturePD); cb.AppendFormat("\n\tC: \"OP\",{0},{1}, \"", TexturePD.uniqueID, MaterialPD.uniqueID); switch (m_TexEnv.name) { case "_MainTex": case "gDiffuseSampler": cb.Append("DiffuseColor\""); break; case "_SpecularMap": case "gSpecularSampler": cb.Append("SpecularColor\""); break; case "_NormalMap": case "_BumpMap": case "gNormalSampler": cb.Append("NormalMap\""); break; default: cb.AppendFormat("{0}\"", m_TexEnv.name); break; } } } #endregion } #endregion #region write & extract Textures Directory.CreateDirectory(Path.GetDirectoryName(FBXfile) + "\\Texture2D"); foreach (var TexturePD in TextureList) { Texture2D m_Texture2D = new Texture2D(TexturePD, true); #region extract texture string texPath = Path.GetDirectoryName(FBXfile) + "\\Texture2D\\" + TexturePD.Text; //TODO check texture type and set path accordingly; eg. CubeMap, Texture3D if (uniqueNames.Checked) { texPath += " #" + TexturePD.uniqueID; } if (m_Texture2D.m_TextureFormat < 30) { texPath += ".dds"; } else if (m_Texture2D.m_TextureFormat < 35) { texPath += ".pvr"; } else { texPath += "_" + m_Texture2D.m_Width.ToString() + "x" + m_Texture2D.m_Height.ToString() + "." + m_Texture2D.m_TextureFormat.ToString() + ".tex"; } if (File.Exists(texPath)) { StatusStripUpdate("Texture file " + Path.GetFileName(texPath) + " already exists"); } else { StatusStripUpdate("Exporting Texture2D: " + Path.GetFileName(texPath)); switch (m_Texture2D.m_TextureFormat) { case 1: //Alpha8 case 2: //A4R4G4B4 case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure case 4: //G8R8A8B8 //confirmed on X360, iOS case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS case 10: //DXT1 case 12: //DXT5 case 13: //R4G4B4A4, iOS (only?) WriteDDS(texPath, m_Texture2D); break; case 30: //PVRTC_RGB2 case 31: //PVRTC_RGBA2 case 32: //PVRTC_RGB4 case 33: //PVRTC_RGBA4 case 34: //ETC_RGB4 WritePVR(texPath, m_Texture2D); break; default: { using (BinaryWriter writer = new BinaryWriter(File.Open(texPath, FileMode.Create))) { writer.Write(m_Texture2D.image_data); writer.Close(); } break; } } } #endregion ob.AppendFormat("\n\tTexture: {0}, \"Texture::{1}\", \"\" {{", TexturePD.uniqueID, TexturePD.Text); ob.Append("\n\t\tType: \"TextureVideoClip\""); ob.Append("\n\t\tVersion: 202"); ob.AppendFormat("\n\t\tTextureName: \"Texture::{0}\"", TexturePD.Text); 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}\"", TexturePD.Text); ob.AppendFormat("\n\t\tFileName: \"{0}\"", texPath); ob.AppendFormat("\n\t\tRelativeFilename: \"Texture2D\\{0}\"", Path.GetFileName(texPath)); ob.Append("\n\t}"); //Video ID is prefixed by 1 ob.AppendFormat("\n\tVideo: 1{0}, \"Video::{1}\", \"Clip\" {{", TexturePD.uniqueID, TexturePD.Text); ob.Append("\n\t\tType: \"Clip\""); ob.Append("\n\t\tProperties70: {"); ob.AppendFormat("\n\t\t\tP: \"Path\", \"KString\", \"XRefUrl\", \"\", \"{0}\"", texPath); ob.Append("\n\t\t}"); ob.AppendFormat("\n\t\tFileName: \"{0}\"", texPath); ob.AppendFormat("\n\t\tRelativeFilename: \"Texture2D\\{0}\"", Path.GetFileName(texPath)); ob.Append("\n\t}"); //connect video to texture cb.AppendFormat("\n\tC: \"OO\",1{0},{1}", TexturePD.uniqueID, TexturePD.uniqueID); } #endregion FBXwriter.Write(ob); ob.Clear(); cb.Append("\n}");//Connections end FBXwriter.Write(cb); cb.Clear(); StatusStripUpdate("Finished exporting " + Path.GetFileName(FBXfile)); } }
private void BuildAssetStrucutres() { #region first loop - read asset data & create list StatusStripUpdate("Building asset list..."); assetListView.BeginUpdate(); string fileIDfmt = "D" + assetsfileList.Count.ToString().Length.ToString(); foreach (var assetsFile in assetsfileList) { var a_Stream = assetsFile.a_Stream; var fileGen = assetsFile.fileGen; //var m_version = assetsFile.m_version; var version = assetsFile.version; string fileID = "1" + assetsfileList.IndexOf(assetsFile).ToString(fileIDfmt); //ListViewGroup assetGroup = new ListViewGroup(Path.GetFileName(assetsFile.filePath)); foreach (var asset in assetsFile.preloadTable.Values) { asset.uniqueID = fileID + asset.uniqueID; a_Stream.Position = asset.Offset; switch (asset.Type2) { case 1: //GameObject { GameObject m_GameObject = new GameObject(asset); //asset.Text = m_GameObject.m_Name; asset.specificIndex = assetsFile.GameObjectList.Count; assetsFile.GameObjectList.Add(m_GameObject); break; } case 4: //Transform { Transform m_Transform = new Transform(asset); asset.specificIndex = assetsFile.TransformList.Count; assetsFile.TransformList.Add(m_Transform); break; } case 224: //RectTransform { RectTransform m_Rect = new RectTransform(asset); asset.specificIndex = assetsFile.TransformList.Count; assetsFile.TransformList.Add(m_Rect.m_Transform); break; } //case 21: //Material case 28: //Texture2D { Texture2D m_Texture2D = new Texture2D(asset, false); asset.Text = m_Texture2D.m_Name; asset.exportSize = 128 + m_Texture2D.image_data_size; #region Get Info Text asset.InfoText = "Width: " + m_Texture2D.m_Width.ToString() + "\nHeight: " + m_Texture2D.m_Height.ToString() + "\nFormat: "; switch (m_Texture2D.m_TextureFormat) { case 1: asset.InfoText += "Alpha8"; break; case 2: asset.InfoText += "ARGB 4.4.4.4"; break; case 3: asset.InfoText += "BGR 8.8.8"; break; case 4: asset.InfoText += "GRAB 8.8.8.8"; break; case 5: asset.InfoText += "BGRA 8.8.8.8"; break; case 7: asset.InfoText += "RGB 5.6.5"; break; case 10: asset.InfoText += "RGB DXT1"; break; case 12: asset.InfoText += "ARGB DXT5"; break; case 13: asset.InfoText += "RGBA 4.4.4.4"; break; case 30: asset.InfoText += "PVRTC_RGB2"; asset.exportSize -= 76; break; case 31: asset.InfoText += "PVRTC_RGBA2"; asset.exportSize -= 76; break; case 32: asset.InfoText += "PVRTC_RGB4"; asset.exportSize = 52; break; case 33: asset.InfoText += "PVRTC_RGBA4"; asset.exportSize -= 76; break; case 34: asset.InfoText += "ETC_RGB4"; asset.exportSize -= 76; break; default: asset.InfoText += "unknown"; asset.exportSize -= 128; break; } switch (m_Texture2D.m_FilterMode) { case 0: asset.InfoText += "\nFilter Mode: Point "; break; case 1: asset.InfoText += "\nFilter Mode: Bilinear "; break; case 2: asset.InfoText += "\nFilter Mode: Trilinear "; break; } asset.InfoText += "\nAnisotropic level: " + m_Texture2D.m_Aniso.ToString() + "\nMip map bias: " + m_Texture2D.m_MipBias.ToString(); switch (m_Texture2D.m_WrapMode) { case 0: asset.InfoText += "\nWrap mode: Repeat"; break; case 1: asset.InfoText += "\nWrap mode: Clamp"; break; } #endregion assetsFile.exportableAssets.Add(asset); break; } case 49: //TextAsset { TextAsset m_TextAsset = new TextAsset(asset, false); asset.Text = m_TextAsset.m_Name; asset.exportSize = m_TextAsset.exportSize; assetsFile.exportableAssets.Add(asset); break; } case 83: //AudioClip { AudioClip m_AudioClip = new AudioClip(asset, false); asset.Text = m_AudioClip.m_Name; asset.exportSize = (int)m_AudioClip.m_Size; assetsFile.exportableAssets.Add(asset); break; } case 48: //Shader case 89: //CubeMap case 128: //Font { asset.Text = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); assetsFile.exportableAssets.Add(asset); break; } case 129: //PlayerSettings { PlayerSettings plSet = new PlayerSettings(asset); productName = plSet.productName; base.Text = "Unity Studio - " + productName + " - " + assetsFile.m_Version ; break; } } if (asset.Text == "") { asset.Text = asset.TypeString + " #" + asset.uniqueID; } asset.SubItems.AddRange(new string[] { asset.TypeString, asset.exportSize.ToString() }); } exportableAssets.AddRange(assetsFile.exportableAssets); //if (assetGroup.Items.Count > 0) { listView1.Groups.Add(assetGroup); } } visibleAssets = exportableAssets; assetListView.VirtualListSize = visibleAssets.Count; assetListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent); assetListView.AutoResizeColumn(2, ColumnHeaderAutoResizeStyle.ColumnContent); resizeNameColumn(); assetListView.EndUpdate(); #endregion #region second loop - build tree structure StatusStripUpdate("Building tree structure..."); sceneTreeView.BeginUpdate(); foreach (var assetsFile in assetsfileList) { GameObject fileNode = new GameObject(null); fileNode.Text = Path.GetFileName(assetsFile.filePath); foreach (var m_GameObject in assetsFile.GameObjectList) { var parentNode = fileNode; Transform m_Transform; if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) { Transform m_Father; if (assetsfileList.TryGetTransform(m_Transform.m_Father, out m_Father)) { //GameObject Parent; if (assetsfileList.TryGetGameObject(m_Father.m_GameObject, out parentNode)) { //parentNode = Parent; } } } parentNode.Nodes.Add(m_GameObject); } if (fileNode.Nodes.Count == 0) { fileNode.Text += " (no children)"; } sceneTreeView.Nodes.Add(fileNode); } sceneTreeView.EndUpdate(); #endregion if (File.Exists(mainPath + "\\materials.json")) { string matLine = ""; using (StreamReader reader = File.OpenText(mainPath + "\\materials.json")) { matLine = reader.ReadToEnd(); } jsonMats = new JavaScriptSerializer().Deserialize<Dictionary<string, Dictionary<string, string>>>(matLine); //var jsonMats = new JavaScriptSerializer().DeserializeObject(matLine); } StatusStripUpdate("Finished loading " + assetsfileList.Count.ToString() + " files with " + (assetListView.Items.Count + sceneTreeView.Nodes.Count).ToString() + " exportable assets."); progressBar1.Value = 0; treeSearch.Select(); TexEnv dsd = new TexEnv(); }
private void ExportTexture(Texture2D m_Texture2D, string exportFilename) { switch (m_Texture2D.m_TextureFormat) { #region DDS case 1: //Alpha8 case 2: //A4R4G4B4 case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure case 4: //G8R8A8B8 //confirmed on X360, iOS case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS case 10: //DXT1 case 12: //DXT5 case 13: //R4G4B4A4, iOS (only?) using (BinaryWriter writer = new BinaryWriter(File.Open(exportFilename, FileMode.Create))) { writer.Write(0x20534444); writer.Write(0x7C); writer.Write(m_Texture2D.dwFlags); writer.Write(m_Texture2D.m_Height); writer.Write(m_Texture2D.m_Width); writer.Write(m_Texture2D.dwPitchOrLinearSize); //should be main tex size without mips); writer.Write((int)0); //dwDepth not implemented writer.Write(m_Texture2D.dwMipMapCount); writer.Write(new byte[44]); //dwReserved1[11] writer.Write(m_Texture2D.dwSize); writer.Write(m_Texture2D.dwFlags2); writer.Write(m_Texture2D.dwFourCC); writer.Write(m_Texture2D.dwRGBBitCount); writer.Write(m_Texture2D.dwRBitMask); writer.Write(m_Texture2D.dwGBitMask); writer.Write(m_Texture2D.dwBBitMask); writer.Write(m_Texture2D.dwABitMask); writer.Write(m_Texture2D.dwCaps); writer.Write(m_Texture2D.dwCaps2); writer.Write(new byte[12]); //dwCaps3&4 & dwReserved2 writer.Write(m_Texture2D.image_data); writer.Close(); } try { Il.ilInit(); Ilu.iluInit(); Il.ilLoad(Il.IL_DDS, exportFilename); Ilu.iluFlipImage(); Il.ilSave(Il.IL_PNG, exportFilename.Replace(".dds", ".png")); //File.Delete(exportFilename); } catch { } break; #endregion #region PVR case 30: //PVRTC_RGB2 case 31: //PVRTC_RGBA2 case 32: //PVRTC_RGB4 case 33: //PVRTC_RGBA4 case 34: //ETC_RGB4 using (BinaryWriter writer = new BinaryWriter(File.Open(exportFilename, FileMode.Create))) { writer.Write(m_Texture2D.pvrVersion); writer.Write(m_Texture2D.pvrFlags); writer.Write(m_Texture2D.pvrPixelFormat); writer.Write(m_Texture2D.pvrColourSpace); writer.Write(m_Texture2D.pvrChannelType); writer.Write(m_Texture2D.m_Height); writer.Write(m_Texture2D.m_Width); writer.Write(m_Texture2D.pvrDepth); writer.Write(m_Texture2D.pvrNumSurfaces); writer.Write(m_Texture2D.pvrNumFaces); writer.Write(m_Texture2D.dwMipMapCount); writer.Write(m_Texture2D.pvrMetaDataSize); writer.Write(m_Texture2D.image_data); writer.Close(); } //PVRTexLibNET.PVRTexture.CreateTexture(exportFilename); pvrtextool.StartInfo.FileName = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "PVRTexToolCLI.exe"); pvrtextool.StartInfo.Arguments = "-i " + exportFilename + " -o temp.pvr -f RGBG8888 -d"; pvrtextool.StartInfo.UseShellExecute = false; pvrtextool.StartInfo.CreateNoWindow = true; string workingDirectory = Path.GetDirectoryName(exportFilename); pvrtextool.StartInfo.WorkingDirectory = workingDirectory; pvrtextool.Start(); pvrtextool.WaitForExit(); File.Delete(workingDirectory + Path.DirectorySeparatorChar + "temp.pvr"); //File.Delete(exportFilename); break; #endregion case 28: //DXT1 Crunched case 29: //DXT1 Crunched default: using (BinaryWriter writer = new BinaryWriter(File.Open(exportFilename, FileMode.Create))) { writer.Write(m_Texture2D.image_data); writer.Close(); } break; } }