using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System.Threading; using System.Globalization; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Diagnostics; using System.Drawing.Text; using OpenTK; using OpenTK.Graphics.OpenGL; using static AssetStudio.Studio; using static AssetStudio.Importer; namespace AssetStudio { partial class AssetStudioForm : Form { private AssetPreloadData lastSelectedItem; private AssetPreloadData lastLoadedAsset; private FMOD.System system; private FMOD.Sound sound; private FMOD.Channel channel; private FMOD.SoundGroup masterSoundGroup; private FMOD.MODE loopMode = FMOD.MODE.LOOP_OFF; private uint FMODlenms; private float FMODVolume = 0.8f; private Bitmap imageTexture; #region OpenTK private int pgmID, pgmColorID, pgmBlackID; private int attributeVertexPosition; private int attributeNormalDirection; private int attributeVertexColor; private int uniformModelMatrix; private int uniformViewMatrix; private int vao; private Vector3[] vertexData; private Vector3[] normalData; private Vector3[] normal2Data; private Vector4[] colorData; private Matrix4 modelMatrixData; private Matrix4 viewMatrixData; private int[] indiceData; private int wireFrameMode; private int shadeMode; private int normalMode; #endregion //asset list sorting helpers private int firstSortColumn = -1; private int secondSortColumn; private bool reverseSort; private bool enableFiltering; //tree search private int nextGObject; private List treeSrcResults = new List(); [DllImport("gdi32.dll")] private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts); private void loadFile_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { resetForm(); ThreadPool.QueueUserWorkItem(state => { mainPath = Path.GetDirectoryName(openFileDialog1.FileNames[0]); MergeSplitAssets(mainPath); var readFile = ProcessingSplitFiles(openFileDialog1.FileNames.ToList()); foreach (var i in readFile) { importFiles.Add(i); importFilesHash.Add(Path.GetFileName(i).ToUpper()); } SetProgressBarValue(0); SetProgressBarMaximum(importFiles.Count); //use a for loop because list size can change for (int f = 0; f < importFiles.Count; f++) { LoadFile(importFiles[f]); ProgressBarPerformStep(); } importFilesHash.Clear(); assetsfileListHash.Clear(); BuildAssetStrucutres(); }); } } private void loadFolder_Click(object sender, EventArgs e) { var openFolderDialog1 = new OpenFolderDialog(); if (openFolderDialog1.ShowDialog(this) == DialogResult.OK) { resetForm(); ThreadPool.QueueUserWorkItem(state => { mainPath = openFolderDialog1.Folder; MergeSplitAssets(mainPath); var files = Directory.GetFiles(mainPath, "*.*", SearchOption.AllDirectories).ToList(); var readFile = ProcessingSplitFiles(files); foreach (var i in readFile) { importFiles.Add(i); importFilesHash.Add(Path.GetFileName(i)); } SetProgressBarValue(0); SetProgressBarMaximum(importFiles.Count); //use a for loop because list size can change for (int f = 0; f < importFiles.Count; f++) { LoadFile(importFiles[f]); ProgressBarPerformStep(); } importFilesHash.Clear(); assetsfileListHash.Clear(); BuildAssetStrucutres(); }); } } private void extractFileToolStripMenuItem_Click(object sender, EventArgs e) { var openBundleDialog = new OpenFileDialog { Filter = "All types|*.*", FilterIndex = 1, RestoreDirectory = true, Multiselect = true }; if (openBundleDialog.ShowDialog() == DialogResult.OK) { progressBar1.Value = 0; progressBar1.Maximum = openBundleDialog.FileNames.Length; ExtractFile(openBundleDialog.FileNames); } } private void extractFolderToolStripMenuItem_Click(object sender, EventArgs e) { var openFolderDialog1 = new OpenFolderDialog(); if (openFolderDialog1.ShowDialog(this) == DialogResult.OK) { var files = Directory.GetFiles(openFolderDialog1.Folder, "*.*", SearchOption.AllDirectories); progressBar1.Value = 0; progressBar1.Maximum = files.Length; ExtractFile(files); } } private void BuildAssetStrucutres() { if (assetsfileList.Count == 0) { StatusStripUpdate("No file was loaded."); return; } BuildAssetStructures(!dontLoadAssetsMenuItem.Checked, displayAll.Checked, !dontBuildHierarchyMenuItem.Checked, buildClassStructuresMenuItem.Checked, displayOriginalName.Checked, out var fileNodes); BeginInvoke(new Action(() => { if (!string.IsNullOrEmpty(productName)) { Text = $"AssetStudio - {productName} - {assetsfileList[0].m_Version} - {assetsfileList[0].platformStr}"; } else if (assetsfileList.Count > 0) { Text = $"AssetStudio - no productName - {assetsfileList[0].m_Version} - {assetsfileList[0].platformStr}"; } if (!dontLoadAssetsMenuItem.Checked) { assetListView.VirtualListSize = visibleAssets.Count; //will only work if ListView is visible resizeAssetListColumns(); } if (!dontBuildHierarchyMenuItem.Checked) { sceneTreeView.BeginUpdate(); sceneTreeView.Nodes.AddRange(fileNodes.ToArray()); foreach (TreeNode node in sceneTreeView.Nodes) { node.HideCheckBox(); } sceneTreeView.EndUpdate(); } if (buildClassStructuresMenuItem.Checked) { 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(); } var types = exportableAssets.Select(x => x.Type).Distinct().ToArray(); foreach (var type in types) { var typeItem = new ToolStripMenuItem { CheckOnClick = true, Name = type.ToString(), Size = new Size(180, 22), Text = type.ToString() }; typeItem.Click += typeToolStripMenuItem_Click; showTypeToolStripMenuItem.DropDownItems.Add(typeItem); } allToolStripMenuItem.Checked = true; StatusStripUpdate($"Finished loading {assetsfileList.Count} files with {assetListView.Items.Count} exportable assets."); treeSearch.Select(); })); } private void typeToolStripMenuItem_Click(object sender, EventArgs e) { var typeItem = (ToolStripMenuItem)sender; if (typeItem != allToolStripMenuItem) { allToolStripMenuItem.Checked = false; } else if (allToolStripMenuItem.Checked) { for (var i = 1; i < showTypeToolStripMenuItem.DropDownItems.Count; i++) { var item = (ToolStripMenuItem)showTypeToolStripMenuItem.DropDownItems[i]; item.Checked = false; } } FilterAssetList(); } private void AssetStudioForm_KeyDown(object sender, KeyEventArgs e) { if (e.Control && e.Alt && e.KeyCode == Keys.D) { debugMenuItem.Visible = !debugMenuItem.Visible; buildClassStructuresMenuItem.Checked = debugMenuItem.Visible; dontLoadAssetsMenuItem.Checked = debugMenuItem.Visible; dontBuildHierarchyMenuItem.Checked = debugMenuItem.Visible; if (tabControl1.TabPages.Contains(tabPage3)) { tabControl1.TabPages.Remove(tabPage3); } else { tabControl1.TabPages.Add(tabPage3); } } if (glControl1.Visible) { switch (e.KeyCode) { case Keys.D: // --> Right if (e.Shift) //Move { viewMatrixData *= Matrix4.CreateTranslation(0.1f, 0, 0); } else //Rotate { viewMatrixData *= Matrix4.CreateRotationY(0.1f); } glControl1.Invalidate(); break; case Keys.A: // <-- Left if (e.Shift) //Move { viewMatrixData *= Matrix4.CreateTranslation(-0.1f, 0, 0); } else //Rotate { viewMatrixData *= Matrix4.CreateRotationY(-0.1f); } glControl1.Invalidate(); break; case Keys.W: // Up if (e.Control) //Toggle WireFrame { wireFrameMode = (wireFrameMode + 1) % 3; glControl1.Invalidate(); } else if (e.Shift) //Move { viewMatrixData *= Matrix4.CreateTranslation(0, 0.1f, 0); } else //Rotate { viewMatrixData *= Matrix4.CreateRotationX(0.1f); } glControl1.Invalidate(); break; case Keys.S: // Down if (e.Control) //Toggle Shade { shadeMode = (shadeMode + 1) % 2; glControl1.Invalidate(); } else if (e.Shift) //Move { viewMatrixData *= Matrix4.CreateTranslation(0, -0.1f, 0); } else //Rotate { viewMatrixData *= Matrix4.CreateRotationX(-0.1f); } glControl1.Invalidate(); break; case Keys.Q: // Zoom Out viewMatrixData *= Matrix4.CreateScale(0.9f); glControl1.Invalidate(); break; case Keys.E: // Zoom In viewMatrixData *= Matrix4.CreateScale(1.1f); glControl1.Invalidate(); break; } // Normal mode if (e.Control && e.KeyCode == Keys.N) { normalMode = (normalMode + 1) % 2; createVAO(); glControl1.Invalidate(); } // Toggle Timer if (e.KeyCode == Keys.T) { timerOpenTK.Enabled = !timerOpenTK.Enabled; } } } private void dontLoadAssetsMenuItem_CheckedChanged(object sender, EventArgs e) { if (dontLoadAssetsMenuItem.Checked) { dontBuildHierarchyMenuItem.Checked = true; dontBuildHierarchyMenuItem.Enabled = false; } else { dontBuildHierarchyMenuItem.Enabled = true; } } private void exportClassStructuresMenuItem_Click(object sender, EventArgs e) { if (AllClassStructures.Count > 0) { var saveFolderDialog1 = new OpenFolderDialog(); if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK) { progressBar1.Value = 0; progressBar1.Maximum = AllClassStructures.Count; var savePath = saveFolderDialog1.Folder; foreach (var version in AllClassStructures) { if (version.Value.Count > 0) { string versionPath = savePath + "\\" + version.Key; Directory.CreateDirectory(versionPath); foreach (var uclass in version.Value) { string saveFile = $"{versionPath}\\{uclass.Key} {uclass.Value.Text}.txt"; using (StreamWriter TXTwriter = new StreamWriter(saveFile)) { TXTwriter.Write(uclass.Value.ToString()); } } } progressBar1.PerformStep(); } StatusStripUpdate("Finished exporting class structures"); progressBar1.Value = 0; } } } private void enablePreview_Check(object sender, EventArgs e) { if (lastLoadedAsset != null) { switch (lastLoadedAsset.Type) { case ClassIDReference.Texture2D: case ClassIDReference.Sprite: { if (enablePreview.Checked && imageTexture != null) { previewPanel.BackgroundImage = imageTexture; } else { previewPanel.BackgroundImage = Properties.Resources.preview; previewPanel.BackgroundImageLayout = ImageLayout.Center; } } break; case ClassIDReference.Shader: case ClassIDReference.TextAsset: case ClassIDReference.MonoBehaviour: textPreviewBox.Visible = !textPreviewBox.Visible; break; case ClassIDReference.Font: fontPreviewBox.Visible = !fontPreviewBox.Visible; break; case ClassIDReference.AudioClip: { FMODpanel.Visible = !FMODpanel.Visible; if (sound != null && channel != null) { var result = channel.isPlaying(out var playing); if (result == FMOD.RESULT.OK && playing) { result = channel.stop(); FMODreset(); } } else if (FMODpanel.Visible) { PreviewAsset(lastLoadedAsset); } break; } } } else if (lastSelectedItem != null && enablePreview.Checked) { lastLoadedAsset = lastSelectedItem; PreviewAsset(lastLoadedAsset); } Properties.Settings.Default["enablePreview"] = enablePreview.Checked; Properties.Settings.Default.Save(); } private void displayAssetInfo_Check(object sender, EventArgs e) { if (displayInfo.Checked && assetInfoLabel.Text != null) { assetInfoLabel.Visible = true; } else { assetInfoLabel.Visible = false; } Properties.Settings.Default["displayInfo"] = displayInfo.Checked; Properties.Settings.Default.Save(); } private void MenuItem_CheckedChanged(object sender, EventArgs e) { Properties.Settings.Default[((ToolStripMenuItem)sender).Name] = ((ToolStripMenuItem)sender).Checked; Properties.Settings.Default.Save(); } private void assetGroupOptions_SelectedIndexChanged(object sender, EventArgs e) { Properties.Settings.Default["assetGroupOption"] = ((ToolStripComboBox)sender).SelectedIndex; Properties.Settings.Default.Save(); } private void showExpOpt_Click(object sender, EventArgs e) { ExportOptions exportOpt = new ExportOptions(); exportOpt.ShowDialog(); } private void assetListView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) { e.Item = visibleAssets[e.ItemIndex]; } private void tabPageSelected(object sender, TabControlEventArgs e) { switch (e.TabPageIndex) { case 0: treeSearch.Select(); break; case 1: resizeAssetListColumns(); //required because the ListView is not visible on app launch classPreviewPanel.Visible = false; previewPanel.Visible = true; listSearch.Select(); break; case 2: previewPanel.Visible = false; classPreviewPanel.Visible = true; break; } } private void treeSearch_Enter(object sender, EventArgs e) { if (treeSearch.Text == " Search ") { treeSearch.Text = ""; treeSearch.ForeColor = SystemColors.WindowText; } } private void treeSearch_Leave(object sender, EventArgs e) { if (treeSearch.Text == "") { treeSearch.Text = " Search "; treeSearch.ForeColor = SystemColors.GrayText; } } private void treeSearch_TextChanged(object sender, EventArgs e) { treeSrcResults.Clear(); nextGObject = 0; } private void treeSearch_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { if (treeSrcResults.Count == 0) { foreach (var aFile in assetsfileList) { foreach (var gObject in aFile.GameObjectList.Values) { if (gObject.Text.IndexOf(treeSearch.Text, StringComparison.CurrentCultureIgnoreCase) >= 0) { treeSrcResults.Add(gObject); } } } } if (treeSrcResults.Count > 0) { if (nextGObject >= treeSrcResults.Count) { nextGObject = 0; } treeSrcResults[nextGObject].EnsureVisible(); sceneTreeView.SelectedNode = treeSrcResults[nextGObject]; nextGObject++; } } } private void sceneTreeView_AfterCheck(object sender, TreeViewEventArgs e) { foreach (GameObject childNode in e.Node.Nodes) { childNode.Checked = e.Node.Checked; } } private void resizeAssetListColumns() { assetListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.HeaderSize); assetListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent); assetListView.AutoResizeColumn(2, ColumnHeaderAutoResizeStyle.HeaderSize); assetListView.AutoResizeColumn(2, ColumnHeaderAutoResizeStyle.ColumnContent); var vscrollwidth = SystemInformation.VerticalScrollBarWidth; var hasvscroll = (visibleAssets.Count / (float)assetListView.Height) > 0.0567f; columnHeaderName.Width = assetListView.Width - columnHeaderType.Width - columnHeaderSize.Width - (hasvscroll ? (5 + vscrollwidth) : 5); } private void tabPage2_Resize(object sender, EventArgs e) { resizeAssetListColumns(); } private void listSearch_Enter(object sender, EventArgs e) { if (listSearch.Text == " Filter ") { listSearch.Text = ""; listSearch.ForeColor = SystemColors.WindowText; enableFiltering = true; } } private void listSearch_Leave(object sender, EventArgs e) { if (listSearch.Text == "") { enableFiltering = false; listSearch.Text = " Filter "; listSearch.ForeColor = SystemColors.GrayText; } } private void ListSearchTextChanged(object sender, EventArgs e) { if (enableFiltering) { FilterAssetList(); } } private void assetListView_ColumnClick(object sender, ColumnClickEventArgs e) { if (firstSortColumn != e.Column) { //sorting column has been changed reverseSort = false; secondSortColumn = firstSortColumn; } else { reverseSort = !reverseSort; } firstSortColumn = e.Column; assetListView.BeginUpdate(); assetListView.SelectedIndices.Clear(); switch (e.Column) { case 0: visibleAssets.Sort(delegate (AssetPreloadData a, AssetPreloadData b) { int xdiff = reverseSort ? b.Text.CompareTo(a.Text) : a.Text.CompareTo(b.Text); if (xdiff != 0) return xdiff; return secondSortColumn == 1 ? a.TypeString.CompareTo(b.TypeString) : a.fullSize.CompareTo(b.fullSize); }); break; case 1: visibleAssets.Sort(delegate (AssetPreloadData a, AssetPreloadData b) { int xdiff = reverseSort ? b.TypeString.CompareTo(a.TypeString) : a.TypeString.CompareTo(b.TypeString); if (xdiff != 0) return xdiff; return secondSortColumn == 2 ? a.fullSize.CompareTo(b.fullSize) : a.Text.CompareTo(b.Text); }); break; case 2: visibleAssets.Sort(delegate (AssetPreloadData a, AssetPreloadData b) { int xdiff = reverseSort ? b.fullSize.CompareTo(a.fullSize) : a.fullSize.CompareTo(b.fullSize); if (xdiff != 0) return xdiff; return secondSortColumn == 1 ? a.TypeString.CompareTo(b.TypeString) : a.Text.CompareTo(b.Text); }); break; } assetListView.EndUpdate(); resizeAssetListColumns(); } private void selectAsset(object sender, ListViewItemSelectionChangedEventArgs e) { previewPanel.BackgroundImage = Properties.Resources.preview; previewPanel.BackgroundImageLayout = ImageLayout.Center; assetInfoLabel.Visible = false; assetInfoLabel.Text = null; textPreviewBox.Visible = false; fontPreviewBox.Visible = false; FMODpanel.Visible = false; glControl1.Visible = false; lastLoadedAsset = null; StatusStripUpdate(""); FMODreset(); lastSelectedItem = (AssetPreloadData)e.Item; if (e.IsSelected) { if (enablePreview.Checked) { lastLoadedAsset = lastSelectedItem; PreviewAsset(lastLoadedAsset); } if (displayInfo.Checked && assetInfoLabel.Text != null)//only display the label if asset has info text { assetInfoLabel.Text = lastSelectedItem.InfoText; assetInfoLabel.Visible = true; } } } private void classesListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) { if (e.IsSelected) { classTextBox.Text = ((ClassStruct)classesListView.SelectedItems[0]).ToString(); } } private void PreviewAsset(AssetPreloadData asset) { switch (asset.Type) { case ClassIDReference.Texture2D: { imageTexture?.Dispose(); var m_Texture2D = new Texture2DConverter(new Texture2D(asset, true)); imageTexture = m_Texture2D.ConvertToBitmap(true); if (imageTexture != null) { previewPanel.BackgroundImage = imageTexture; if (imageTexture.Width > previewPanel.Width || imageTexture.Height > previewPanel.Height) previewPanel.BackgroundImageLayout = ImageLayout.Zoom; else previewPanel.BackgroundImageLayout = ImageLayout.Center; } else { StatusStripUpdate("Unsupported image for preview"); } break; } case ClassIDReference.AudioClip: { AudioClip m_AudioClip = new AudioClip(asset, true); if (m_AudioClip.m_AudioData == null) break; FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO(); exinfo.cbsize = Marshal.SizeOf(exinfo); exinfo.length = (uint)m_AudioClip.m_Size; var result = system.createSound(m_AudioClip.m_AudioData, FMOD.MODE.OPENMEMORY | loopMode, ref exinfo, out sound); if (ERRCHECK(result)) { break; } result = sound.getSubSound(0, out var subsound); if (result == FMOD.RESULT.OK) { sound = subsound; } result = sound.getLength(out FMODlenms, FMOD.TIMEUNIT.MS); if (ERRCHECK(result)) { break; } result = system.playSound(sound, null, true, out channel); if (ERRCHECK(result)) { break; } FMODpanel.Visible = true; result = channel.getFrequency(out var frequency); if (ERRCHECK(result)) { break; } FMODinfoLabel.Text = frequency + " Hz"; FMODtimerLabel.Text = $"0:0.0 / {FMODlenms / 1000 / 60}:{FMODlenms / 1000 % 60}.{FMODlenms / 10 % 100}"; break; } case ClassIDReference.Shader: { Shader m_TextAsset = new Shader(asset, true); string m_Script_Text = Encoding.UTF8.GetString(m_TextAsset.m_Script); m_Script_Text = Regex.Replace(m_Script_Text, "(? 0) { 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; } } break; } } StatusStripUpdate("Unsupported font for preview. Try to export."); break; } case ClassIDReference.Mesh: { var m_Mesh = new Mesh(asset, true); if (m_Mesh.m_VertexCount > 0) { viewMatrixData = Matrix4.CreateRotationY(-(float)Math.PI / 4) * Matrix4.CreateRotationX(-(float)Math.PI / 6); #region Vertices if (m_Mesh.m_Vertices == null || m_Mesh.m_Vertices.Length == 0) { StatusStripUpdate("Mesh can't be previewed."); return; } int count = 3; if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) { count = 4; } vertexData = new Vector3[m_Mesh.m_VertexCount]; // Calculate Bounding float[] min = new float[3]; float[] max = new float[3]; for (int i = 0; i < 3; i++) { min[i] = m_Mesh.m_Vertices[i]; max[i] = m_Mesh.m_Vertices[i]; } for (int v = 0; v < m_Mesh.m_VertexCount; v++) { for (int i = 0; i < 3; i++) { min[i] = Math.Min(min[i], m_Mesh.m_Vertices[v * count + i]); max[i] = Math.Max(max[i], m_Mesh.m_Vertices[v * count + i]); } vertexData[v] = new Vector3( m_Mesh.m_Vertices[v * count], m_Mesh.m_Vertices[v * count + 1], m_Mesh.m_Vertices[v * count + 2]); } // Calculate modelMatrix Vector3 dist = Vector3.One, offset = Vector3.Zero; for (int i = 0; i < 3; i++) { dist[i] = max[i] - min[i]; offset[i] = (max[i] + min[i]) / 2; } float d = Math.Max(1e-5f, dist.Length); modelMatrixData = Matrix4.CreateTranslation(-offset) * Matrix4.CreateScale(2f / d); #endregion #region Indicies indiceData = new int[m_Mesh.m_Indices.Count]; for (int i = 0; i < m_Mesh.m_Indices.Count; i = i + 3) { indiceData[i] = (int)m_Mesh.m_Indices[i]; indiceData[i + 1] = (int)m_Mesh.m_Indices[i + 1]; indiceData[i + 2] = (int)m_Mesh.m_Indices[i + 2]; } #endregion #region Normals if (m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) { if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) count = 3; else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) count = 4; normalData = new Vector3[m_Mesh.m_VertexCount]; for (int n = 0; n < m_Mesh.m_VertexCount; n++) { normalData[n] = new Vector3( m_Mesh.m_Normals[n * count], m_Mesh.m_Normals[n * count + 1], m_Mesh.m_Normals[n * count + 2]); } } else normalData = null; // calculate normal by ourself normal2Data = new Vector3[m_Mesh.m_VertexCount]; int[] normalCalculatedCount = new int[m_Mesh.m_VertexCount]; for (int i = 0; i < m_Mesh.m_VertexCount; i++) { normal2Data[i] = Vector3.Zero; normalCalculatedCount[i] = 0; } for (int i = 0; i < m_Mesh.m_Indices.Count; i = i + 3) { Vector3 dir1 = vertexData[indiceData[i + 1]] - vertexData[indiceData[i]]; Vector3 dir2 = vertexData[indiceData[i + 2]] - vertexData[indiceData[i]]; Vector3 normal = Vector3.Cross(dir1, dir2); normal.Normalize(); for (int j = 0; j < 3; j++) { normal2Data[indiceData[i + j]] += normal; normalCalculatedCount[indiceData[i + j]]++; } } for (int i = 0; i < m_Mesh.m_VertexCount; i++) { if (normalCalculatedCount[i] == 0) normal2Data[i] = new Vector3(0, 1, 0); else normal2Data[i] /= normalCalculatedCount[i]; } #endregion #region Colors if (m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length == m_Mesh.m_VertexCount * 3) { colorData = new Vector4[m_Mesh.m_VertexCount]; for (int c = 0; c < m_Mesh.m_VertexCount; c++) { colorData[c] = new Vector4( m_Mesh.m_Colors[c * 3], m_Mesh.m_Colors[c * 3 + 1], m_Mesh.m_Colors[c * 3 + 2], 1.0f); } } else if (m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length == m_Mesh.m_VertexCount * 4) { colorData = new Vector4[m_Mesh.m_VertexCount]; for (int c = 0; c < m_Mesh.m_VertexCount; c++) { colorData[c] = new Vector4( m_Mesh.m_Colors[c * 4], m_Mesh.m_Colors[c * 4 + 1], m_Mesh.m_Colors[c * 4 + 2], m_Mesh.m_Colors[c * 4 + 3]); } } else { colorData = new Vector4[m_Mesh.m_VertexCount]; for (int c = 0; c < m_Mesh.m_VertexCount; c++) { colorData[c] = new Vector4(0.5f, 0.5f, 0.5f, 1.0f); } } #endregion glControl1.Visible = true; createVAO(); } StatusStripUpdate("Using OpenGL Version: " + GL.GetString(StringName.Version) + "\n" + "'T'=Start/Stop Rotation | 'WASD'=Manual Rotate | 'Shift WASD'=Move | 'Q/E'=Zoom \n" + "'Ctrl W'=Wireframe | 'Ctrl S'=Shade | 'Ctrl N'=ReNormal "); } break; case ClassIDReference.VideoClip: case ClassIDReference.MovieTexture: { StatusStripUpdate("Only supported export."); break; } case ClassIDReference.Sprite: { imageTexture?.Dispose(); imageTexture = SpriteHelper.GetImageFromSprite(asset); if (imageTexture != null) { previewPanel.BackgroundImage = imageTexture; if (imageTexture.Width > previewPanel.Width || imageTexture.Height > previewPanel.Height) previewPanel.BackgroundImageLayout = ImageLayout.Zoom; else previewPanel.BackgroundImageLayout = ImageLayout.Center; } else { StatusStripUpdate("Unsupported sprite for preview."); } break; } case ClassIDReference.Animator: { StatusStripUpdate("Can be exported to FBX file."); break; } case ClassIDReference.AnimationClip: { StatusStripUpdate("Can be exported with Animator or objects"); break; } default: { var str = asset.GetClassString(); if (str != null) { textPreviewBox.Text = str; textPreviewBox.Visible = true; } else StatusStripUpdate("Only supported export the raw file."); break; } } } private void FMODinit() { FMODreset(); var result = FMOD.Factory.System_Create(out system); if (ERRCHECK(result)) { return; } result = system.getVersion(out var version); ERRCHECK(result); if (version < FMOD.VERSION.number) { MessageBox.Show($"Error! You are using an old version of FMOD {version:X}. This program requires {FMOD.VERSION.number:X}."); Application.Exit(); } result = system.init(1, FMOD.INITFLAGS.NORMAL, IntPtr.Zero); if (ERRCHECK(result)) { return; } result = system.getMasterSoundGroup(out masterSoundGroup); if (ERRCHECK(result)) { return; } result = masterSoundGroup.setVolume(FMODVolume); if (ERRCHECK(result)) { return; } } private void FMODreset() { timer.Stop(); FMODprogressBar.Value = 0; FMODtimerLabel.Text = "0:00.0 / 0:00.0"; FMODstatusLabel.Text = "Stopped"; FMODinfoLabel.Text = ""; if (sound != null && sound.isValid()) { var result = sound.release(); ERRCHECK(result); sound = null; } } private void FMODplayButton_Click(object sender, EventArgs e) { if (sound != null && channel != null) { timer.Start(); var result = channel.isPlaying(out var playing); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { return; } } if (playing) { result = channel.stop(); if (ERRCHECK(result)) { return; } result = system.playSound(sound, null, false, out channel); if (ERRCHECK(result)) { return; } FMODpauseButton.Text = "Pause"; } else { result = system.playSound(sound, null, false, out channel); if (ERRCHECK(result)) { return; } FMODstatusLabel.Text = "Playing"; if (FMODprogressBar.Value > 0) { uint newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; result = channel.setPosition(newms, FMOD.TIMEUNIT.MS); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { return; } } } } } } private void FMODpauseButton_Click(object sender, EventArgs e) { if (sound != null && channel != null) { var result = channel.isPlaying(out var playing); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { return; } } if (playing) { result = channel.getPaused(out var paused); if (ERRCHECK(result)) { return; } result = channel.setPaused(!paused); if (ERRCHECK(result)) { return; } if (paused) { FMODstatusLabel.Text = "Playing"; FMODpauseButton.Text = "Pause"; timer.Start(); } else { FMODstatusLabel.Text = "Paused"; FMODpauseButton.Text = "Resume"; timer.Stop(); } } } } private void FMODstopButton_Click(object sender, EventArgs e) { if (channel != null) { var result = channel.isPlaying(out var playing); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { return; } } if (playing) { result = channel.stop(); if (ERRCHECK(result)) { return; } //channel = null; //don't FMODreset, it will nullify the sound timer.Stop(); FMODprogressBar.Value = 0; FMODtimerLabel.Text = "0:00.0 / 0:00.0"; FMODstatusLabel.Text = "Stopped"; FMODpauseButton.Text = "Pause"; } } } private void FMODloopButton_CheckedChanged(object sender, EventArgs e) { FMOD.RESULT result; loopMode = FMODloopButton.Checked ? FMOD.MODE.LOOP_NORMAL : FMOD.MODE.LOOP_OFF; if (sound != null) { result = sound.setMode(loopMode); if (ERRCHECK(result)) { return; } } if (channel != null) { result = channel.isPlaying(out var playing); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { return; } } result = channel.getPaused(out var paused); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { return; } } if (playing || paused) { result = channel.setMode(loopMode); if (ERRCHECK(result)) { return; } } } } private void FMODvolumeBar_ValueChanged(object sender, EventArgs e) { FMODVolume = Convert.ToSingle(FMODvolumeBar.Value) / 10; var result = masterSoundGroup.setVolume(FMODVolume); if (ERRCHECK(result)) { return; } } private void FMODprogressBar_Scroll(object sender, EventArgs e) { if (channel != null) { uint newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; FMODtimerLabel.Text = $"{newms / 1000 / 60}:{newms / 1000 % 60}.{newms / 10 % 100}/{FMODlenms / 1000 / 60}:{FMODlenms / 1000 % 60}.{FMODlenms / 10 % 100}"; } } private void FMODprogressBar_MouseDown(object sender, MouseEventArgs e) { timer.Stop(); } private void FMODprogressBar_MouseUp(object sender, MouseEventArgs e) { if (channel != null) { uint newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; var result = channel.setPosition(newms, FMOD.TIMEUNIT.MS); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { return; } } result = channel.isPlaying(out var playing); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { if (ERRCHECK(result)) { return; } } if (playing) { timer.Start(); } } } private void timer_Tick(object sender, EventArgs e) { uint ms = 0; bool playing = false; bool paused = false; if (channel != null) { var result = channel.getPosition(out ms, FMOD.TIMEUNIT.MS); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { ERRCHECK(result); } result = channel.isPlaying(out playing); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { ERRCHECK(result); } result = channel.getPaused(out paused); if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) { ERRCHECK(result); } } FMODtimerLabel.Text = $"{ms / 1000 / 60}:{ms / 1000 % 60}.{ms / 10 % 100} / {FMODlenms / 1000 / 60}:{FMODlenms / 1000 % 60}.{FMODlenms / 10 % 100}"; FMODprogressBar.Value = (int)(ms * 1000 / FMODlenms); FMODstatusLabel.Text = paused ? "Paused " : playing ? "Playing" : "Stopped"; if (system != null && channel != null) { system.update(); } } private bool ERRCHECK(FMOD.RESULT result) { if (result != FMOD.RESULT.OK) { FMODreset(); StatusStripUpdate($"FMOD error! {result} - {FMOD.Error.String(result)}"); return true; } return false; } private void exportallobjectssplitToolStripMenuItem_Click(object sender, EventArgs e) { if (sceneTreeView.Nodes.Count > 0) { var saveFolderDialog1 = new OpenFolderDialog(); if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK) { var savePath = saveFolderDialog1.Folder + "\\"; progressBar1.Value = 0; progressBar1.Maximum = sceneTreeView.Nodes.Cast().Sum(x => x.Nodes.Count); ExportSplitObjects(savePath, sceneTreeView.Nodes); } } else { StatusStripUpdate("No Objects available for export"); } } private void ExportObjects_Click(object sender, EventArgs e) { if (sceneTreeView.Nodes.Count > 0) { var exportAll = ((ToolStripItem)sender).Name == "exportallobjectsMenuItem"; saveFileDialog1.FileName = productName + DateTime.Now.ToString("_yy_MM_dd__HH_mm_ss"); if (saveFileDialog1.ShowDialog() == DialogResult.OK) { var gameObjects = new List(); foreach (var assetsFile in assetsfileList) { foreach (var m_GameObject in assetsFile.GameObjectList.Values) { if (m_GameObject.Checked || exportAll) { gameObjects.Add(m_GameObject); } } } progressBar1.Value = 0; progressBar1.Maximum = 1; if (gameObjects.Count == 0) { progressBar1.PerformStep(); toolStripStatusLabel1.Text = "Nothing exported."; return; } toolStripStatusLabel1.Text = $"Exporting {Path.GetFileName(saveFileDialog1.FileName)}"; FBXExporter.WriteFBX(saveFileDialog1.FileName, gameObjects); toolStripStatusLabel1.Text = $"Finished exporting {Path.GetFileName(saveFileDialog1.FileName)}"; progressBar1.PerformStep(); if (openAfterExport.Checked && File.Exists(saveFileDialog1.FileName)) { Process.Start(Path.GetDirectoryName(saveFileDialog1.FileName)); } } } else { toolStripStatusLabel1.Text = "No Objects available for export"; } } private void ExportAssets_Click(object sender, EventArgs e) { if (exportableAssets.Count > 0) { var saveFolderDialog1 = new OpenFolderDialog(); if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK) { timer.Stop(); List toExportAssets = null; switch (((ToolStripItem)sender).Name) { case "exportAllAssetsMenuItem": toExportAssets = exportableAssets; break; case "exportFilteredAssetsMenuItem": toExportAssets = visibleAssets; break; case "exportSelectedAssetsMenuItem": toExportAssets = new List(assetListView.SelectedIndices.Count); foreach (int i in assetListView.SelectedIndices) { toExportAssets.Add((AssetPreloadData)assetListView.Items[i]); } break; } ExportAssets(saveFolderDialog1.Folder, toExportAssets, assetGroupOptions.SelectedIndex, openAfterExport.Checked); } } else { StatusStripUpdate("No exportable assets loaded"); } } private void SetProgressBarValue(int value) { if (InvokeRequired) { BeginInvoke(new Action(() => { progressBar1.Value = value; })); } else { progressBar1.Value = value; } } private void SetProgressBarMaximum(int value) { if (InvokeRequired) { BeginInvoke(new Action(() => { progressBar1.Maximum = value; })); } else { progressBar1.Maximum = value; } } private void ProgressBarPerformStep() { if (InvokeRequired) { BeginInvoke(new Action(() => { progressBar1.PerformStep(); })); } else { progressBar1.PerformStep(); } } private void StatusStripUpdate(string statusText) { if (InvokeRequired) { BeginInvoke(new Action(() => { toolStripStatusLabel1.Text = statusText; })); } else { toolStripStatusLabel1.Text = statusText; } } private void ProgressBarMaximumAdd(int value) { if (InvokeRequired) { BeginInvoke(new Action(() => { progressBar1.Maximum += value; })); } else { progressBar1.Maximum += value; } } public AssetStudioForm() { Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); InitializeComponent(); displayOriginalName.Checked = (bool)Properties.Settings.Default["displayOriginalName"]; displayAll.Checked = (bool)Properties.Settings.Default["displayAll"]; displayInfo.Checked = (bool)Properties.Settings.Default["displayInfo"]; enablePreview.Checked = (bool)Properties.Settings.Default["enablePreview"]; openAfterExport.Checked = (bool)Properties.Settings.Default["openAfterExport"]; assetGroupOptions.SelectedIndex = (int)Properties.Settings.Default["assetGroupOption"]; FMODinit(); //UI Studio.SetProgressBarValue = SetProgressBarValue; Studio.SetProgressBarMaximum = SetProgressBarMaximum; Studio.ProgressBarPerformStep = ProgressBarPerformStep; Studio.StatusStripUpdate = StatusStripUpdate; Studio.ProgressBarMaximumAdd = ProgressBarMaximumAdd; } private void timerOpenTK_Tick(object sender, EventArgs e) { if (glControl1.Visible) { viewMatrixData *= Matrix4.CreateRotationY(-0.1f); glControl1.Invalidate(); } } private void initOpenTK() { GL.Viewport(0, 0, glControl1.ClientSize.Width, glControl1.ClientSize.Height); GL.ClearColor(Color.CadetBlue); pgmID = GL.CreateProgram(); loadShader("vs", ShaderType.VertexShader, pgmID, out int vsID); loadShader("fs", ShaderType.FragmentShader, pgmID, out int fsID); GL.LinkProgram(pgmID); pgmColorID = GL.CreateProgram(); loadShader("vs", ShaderType.VertexShader, pgmColorID, out vsID); loadShader("fsColor", ShaderType.FragmentShader, pgmColorID, out fsID); GL.LinkProgram(pgmColorID); pgmBlackID = GL.CreateProgram(); loadShader("vs", ShaderType.VertexShader, pgmBlackID, out vsID); loadShader("fsBlack", ShaderType.FragmentShader, pgmBlackID, out fsID); GL.LinkProgram(pgmBlackID); attributeVertexPosition = GL.GetAttribLocation(pgmID, "vertexPosition"); attributeNormalDirection = GL.GetAttribLocation(pgmID, "normalDirection"); attributeVertexColor = GL.GetAttribLocation(pgmColorID, "vertexColor"); uniformModelMatrix = GL.GetUniformLocation(pgmID, "modelMatrix"); uniformViewMatrix = GL.GetUniformLocation(pgmID, "viewMatrix"); glControl1.Visible = false; } private void loadShader(string filename, ShaderType type, int program, out int address) { address = GL.CreateShader(type); var str = (string)Properties.Resources.ResourceManager.GetObject(filename); GL.ShaderSource(address, str); GL.CompileShader(address); GL.AttachShader(program, address); GL.DeleteShader(address); } private void createVBO(out int vboAddress, Vector3[] data, int address) { GL.GenBuffers(1, out vboAddress); GL.BindBuffer(BufferTarget.ArrayBuffer, vboAddress); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * Vector3.SizeInBytes), data, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(address, 3, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(address); } private void createVBO(out int vboAddress, Vector4[] data, int address) { GL.GenBuffers(1, out vboAddress); GL.BindBuffer(BufferTarget.ArrayBuffer, vboAddress); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * Vector4.SizeInBytes), data, BufferUsageHint.StaticDraw); GL.VertexAttribPointer(address, 4, VertexAttribPointerType.Float, false, 0, 0); GL.EnableVertexAttribArray(address); } private void createVBO(out int vboAddress, Matrix4 data, int address) { GL.GenBuffers(1, out vboAddress); GL.UniformMatrix4(address, false, ref data); } private void createEBO(out int address, int[] data) { GL.GenBuffers(1, out address); GL.BindBuffer(BufferTarget.ElementArrayBuffer, address); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(data.Length * sizeof(int)), data, BufferUsageHint.StaticDraw); } private void createVAO() { timerOpenTK.Stop(); GL.DeleteVertexArray(vao); GL.GenVertexArrays(1, out vao); GL.BindVertexArray(vao); createVBO(out var vboPositions, vertexData, attributeVertexPosition); if (normalMode == 0) { createVBO(out var vboNormals, normal2Data, attributeNormalDirection); } else { if (normalData != null) createVBO(out var vboNormals, normalData, attributeNormalDirection); } createVBO(out var vboColors, colorData, attributeVertexColor); createVBO(out var vboModelMatrix, modelMatrixData, uniformModelMatrix); createVBO(out var vboViewMatrix, viewMatrixData, uniformViewMatrix); createEBO(out var eboElements, indiceData); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindVertexArray(0); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); initOpenTK(); } private void glControl1_Paint(object sender, PaintEventArgs e) { glControl1.MakeCurrent(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.Enable(EnableCap.DepthTest); GL.DepthFunc(DepthFunction.Lequal); GL.BindVertexArray(vao); if (wireFrameMode == 0 || wireFrameMode == 2) { GL.UseProgram(shadeMode == 0 ? pgmID : pgmColorID); GL.UniformMatrix4(uniformModelMatrix, false, ref modelMatrixData); GL.UniformMatrix4(uniformViewMatrix, false, ref viewMatrixData); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.DrawElements(BeginMode.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0); } //Wireframe if (wireFrameMode == 1 || wireFrameMode == 2) { GL.Enable(EnableCap.PolygonOffsetLine); GL.PolygonOffset(-1, -1); GL.UseProgram(pgmBlackID); GL.UniformMatrix4(uniformModelMatrix, false, ref modelMatrixData); GL.UniformMatrix4(uniformViewMatrix, false, ref viewMatrixData); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); GL.DrawElements(BeginMode.Triangles, indiceData.Length, DrawElementsType.UnsignedInt, 0); GL.Disable(EnableCap.PolygonOffsetLine); } GL.BindVertexArray(0); GL.Flush(); glControl1.SwapBuffers(); } private void glControl1_MouseWheel(object sender, MouseEventArgs e) { if (glControl1.Visible) { viewMatrixData *= Matrix4.CreateScale(1 + e.Delta / 1000f); glControl1.Invalidate(); } } private void resetForm() { Text = "AssetStudio"; importFiles.Clear(); foreach (var assetsFile in assetsfileList) { assetsFile.reader.Dispose(); } assetsfileList.Clear(); exportableAssets.Clear(); visibleAssets.Clear(); foreach (var resourceFileReader in resourceFileReaders) { resourceFileReader.Value.Dispose(); } resourceFileReaders.Clear(); sharedFileIndex.Clear(); productName = ""; sceneTreeView.Nodes.Clear(); assetListView.VirtualListSize = 0; assetListView.Items.Clear(); classesListView.Items.Clear(); classesListView.Groups.Clear(); previewPanel.BackgroundImage = Properties.Resources.preview; previewPanel.BackgroundImageLayout = ImageLayout.Center; assetInfoLabel.Visible = false; assetInfoLabel.Text = null; textPreviewBox.Visible = false; fontPreviewBox.Visible = false; glControl1.Visible = false; lastSelectedItem = null; lastLoadedAsset = null; firstSortColumn = -1; secondSortColumn = 0; reverseSort = false; enableFiltering = false; listSearch.Text = " Filter "; var count = showTypeToolStripMenuItem.DropDownItems.Count; for (var i = 1; i < count; i++) { showTypeToolStripMenuItem.DropDownItems.RemoveAt(1); } FMODreset(); moduleLoaded = false; LoadedModuleDic.Clear(); } private void assetListView_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right && assetListView.SelectedIndices.Count > 0) { jumpToSceneHierarchyToolStripMenuItem.Visible = false; showOriginalFileToolStripMenuItem.Visible = false; exportAnimatorwithselectedAnimationClipMenuItem.Visible = false; exportobjectswithselectedAnimationClipMenuItem.Visible = false; if (assetListView.SelectedIndices.Count == 1) { jumpToSceneHierarchyToolStripMenuItem.Visible = true; showOriginalFileToolStripMenuItem.Visible = true; } if (assetListView.SelectedIndices.Count >= 1) { var selectedAssets = GetSelectedAssets(); if (selectedAssets.Any(x => x.Type == ClassIDReference.Animator) && selectedAssets.Any(x => x.Type == ClassIDReference.AnimationClip)) { exportAnimatorwithselectedAnimationClipMenuItem.Visible = true; } else if (selectedAssets.All(x => x.Type == ClassIDReference.AnimationClip)) { exportobjectswithselectedAnimationClipMenuItem.Visible = true; } } contextMenuStrip1.Show(assetListView, e.X, e.Y); } } private void exportSelectedAssetsToolStripMenuItem_Click(object sender, EventArgs e) { var saveFolderDialog1 = new OpenFolderDialog(); if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK) { timer.Stop(); ExportAssets(saveFolderDialog1.Folder, GetSelectedAssets(), assetGroupOptions.SelectedIndex, openAfterExport.Checked); } } private void showOriginalFileToolStripMenuItem_Click(object sender, EventArgs e) { var selectasset = (AssetPreloadData)assetListView.Items[assetListView.SelectedIndices[0]]; var args = $"/select, {selectasset.sourceFile.parentPath ?? selectasset.sourceFile.filePath}"; var pfi = new ProcessStartInfo("explorer.exe", args); Process.Start(pfi); } private void exportAnimatorwithAnimationClipMenuItem_Click(object sender, EventArgs e) { AssetPreloadData animator = null; List animationList = new List(); var selectedAssets = GetSelectedAssets(); foreach (var assetPreloadData in selectedAssets) { if (assetPreloadData.Type == ClassIDReference.Animator) { animator = assetPreloadData; } else if (assetPreloadData.Type == ClassIDReference.AnimationClip) { animationList.Add(assetPreloadData); } } if (animator != null) { var saveFolderDialog1 = new OpenFolderDialog(); if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK) { var exportPath = saveFolderDialog1.Folder + "\\Animator\\"; progressBar1.Value = 0; progressBar1.Maximum = 1; ExportAnimatorWithAnimationClip(animator, animationList, exportPath); } } } private void exportSelectedObjectsToolStripMenuItem_Click(object sender, EventArgs e) { if (sceneTreeView.Nodes.Count > 0) { var saveFolderDialog1 = new OpenFolderDialog(); if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK) { var exportPath = saveFolderDialog1.Folder + "\\GameObject\\"; ExportObjectsWithAnimationClip(exportPath, sceneTreeView.Nodes); } } else { StatusStripUpdate("No Objects available for export"); } } private void exportObjectswithAnimationClipMenuItem_Click(object sender, EventArgs e) { if (sceneTreeView.Nodes.Count > 0) { var saveFolderDialog1 = new OpenFolderDialog(); if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK) { var exportPath = saveFolderDialog1.Folder + "\\GameObject\\"; ExportObjectsWithAnimationClip(exportPath, sceneTreeView.Nodes, GetSelectedAssets()); } } else { StatusStripUpdate("No Objects available for export"); } } private void jumpToSceneHierarchyToolStripMenuItem_Click(object sender, EventArgs e) { var selectasset = (AssetPreloadData)assetListView.Items[assetListView.SelectedIndices[0]]; if (selectasset.gameObject != null) { sceneTreeView.SelectedNode = selectasset.gameObject; tabControl1.SelectedTab = tabPage1; } } private void exportAllObjectssplitToolStripMenuItem1_Click(object sender, EventArgs e) { if (sceneTreeView.Nodes.Count > 0) { var saveFolderDialog1 = new OpenFolderDialog(); if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK) { var savePath = saveFolderDialog1.Folder + "\\"; progressBar1.Value = 0; progressBar1.Maximum = sceneTreeView.Nodes.Cast().Sum(x => x.Nodes.Count); ; ExportSplitObjects(savePath, sceneTreeView.Nodes, true); } } else { StatusStripUpdate("No Objects available for export"); } } private List GetSelectedAssets() { var selectedAssets = new List(); foreach (int index in assetListView.SelectedIndices) { selectedAssets.Add((AssetPreloadData)assetListView.Items[index]); } return selectedAssets; } private void FilterAssetList() { assetListView.BeginUpdate(); assetListView.SelectedIndices.Clear(); var show = new List(); if (!allToolStripMenuItem.Checked) { for (var i = 1; i < showTypeToolStripMenuItem.DropDownItems.Count; i++) { var item = (ToolStripMenuItem)showTypeToolStripMenuItem.DropDownItems[i]; if (item.Checked) { show.Add((ClassIDReference)Enum.Parse(typeof(ClassIDReference), item.Text)); } } visibleAssets = exportableAssets.FindAll(x => show.Contains(x.Type)); } else { visibleAssets = exportableAssets; } if (listSearch.Text != " Filter ") { visibleAssets = visibleAssets.FindAll(x => x.Text.IndexOf(listSearch.Text, StringComparison.CurrentCultureIgnoreCase) >= 0); } assetListView.VirtualListSize = visibleAssets.Count; assetListView.EndUpdate(); } } }