Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c9394cd957 | |||
| 46c0e8ffe1 | |||
| d14c232015 | |||
| 4002bdecb8 | |||
| 17259e00c7 | |||
| 44b02b92d8 | |||
| 251854cc41 | |||
| 6f7b77245d | |||
| 6d99f5ebf6 | |||
| f1f2430f97 | |||
| b52696c965 | |||
| 5fba52dc83 | |||
| dfb74baf79 | |||
| 978e90a403 | |||
| c17d7d6331 | |||
| 9fef18d6ea | |||
| ee0cd4ab52 | |||
| f904bc138b | |||
| 7ed5345b1b | |||
| d7f652d572 | |||
| 32ce032655 | |||
| e1cf36aa3c | |||
| f644396a15 | |||
| 3e77c34bd5 | |||
| 052c60f629 | |||
| a1f2e3e7fe | |||
| 32ee8b326f | |||
| 06ce479eb6 | |||
| 03f74bac64 | |||
| 344b675745 | |||
| 86590d95a5 | |||
| bbea1341b2 | |||
| ca60dd9834 | |||
| 7aa35b5b8c | |||
| bd2decdb8f | |||
| 9b2c85bcae | |||
| efbab7c43a | |||
| 729a8a8263 | |||
| 0ec29f62ca | |||
| 796317f9d9 | |||
| 7596dcc7cd | |||
| 422851cdab | |||
| ec0a2a47f1 | |||
| 8ce5b947f6 | |||
| 419ca63f9d | |||
| 6fdb0c7b0e | |||
| 4e97b4b898 |
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -26,7 +27,7 @@ namespace AssetStudio.PInvoke
|
||||
|
||||
private static string GetDirectedDllDirectory()
|
||||
{
|
||||
var localPath = new Uri(typeof(DllLoader).Assembly.CodeBase).LocalPath;
|
||||
var localPath = Process.GetCurrentProcess().MainModule.FileName;
|
||||
var localDir = Path.GetDirectoryName(localPath);
|
||||
|
||||
var subDir = Environment.Is64BitProcess ? "x64" : "x86";
|
||||
|
||||
@@ -33,13 +33,6 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="7zip\Common\CommandLineParser.cs" />
|
||||
@@ -103,6 +96,7 @@
|
||||
<Compile Include="Classes\PPtr.cs" />
|
||||
<Compile Include="Classes\RectTransform.cs" />
|
||||
<Compile Include="Classes\Renderer.cs" />
|
||||
<Compile Include="Classes\ResourceManager.cs" />
|
||||
<Compile Include="Classes\RuntimeAnimatorController.cs" />
|
||||
<Compile Include="Classes\Shader.cs" />
|
||||
<Compile Include="Classes\SkinnedMeshRenderer.cs" />
|
||||
@@ -147,7 +141,6 @@
|
||||
<Compile Include="StreamFile.cs" />
|
||||
<Compile Include="TypeTreeHelper.cs" />
|
||||
<Compile Include="TypeTreeNode.cs" />
|
||||
<Compile Include="UType.cs" />
|
||||
<Compile Include="WebFile.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static AssetStudio.ImportHelper;
|
||||
|
||||
namespace AssetStudio
|
||||
@@ -86,7 +87,7 @@ namespace AssetStudio
|
||||
|
||||
foreach (var sharedFile in assetsFile.m_Externals)
|
||||
{
|
||||
var sharedFilePath = Path.GetDirectoryName(fullName) + "\\" + sharedFile.fileName;
|
||||
var sharedFilePath = Path.Combine(Path.GetDirectoryName(fullName), sharedFile.fileName);
|
||||
var sharedFileName = sharedFile.fileName;
|
||||
|
||||
if (!importFilesHash.Contains(sharedFileName))
|
||||
@@ -108,10 +109,10 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading assets file {fileName}", e);
|
||||
reader.Dispose();
|
||||
//Logger.Warning($"Unable to load assets file {fileName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -136,9 +137,9 @@ namespace AssetStudio
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
//Logger.Error($"Unable to load assets file {fileName} from {Path.GetFileName(originalPath)}");
|
||||
Logger.Error($"Error while reading assets file {fileName} from {Path.GetFileName(originalPath)}", e);
|
||||
resourceFileReaders.Add(fileName, reader);
|
||||
}
|
||||
}
|
||||
@@ -161,18 +162,18 @@ namespace AssetStudio
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceFileReaders.Add(file.fileName, subReader);
|
||||
resourceFileReaders[file.fileName] = subReader; //TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
/*var str = $"Unable to load bundle file {fileName}";
|
||||
var str = $"Error while reading bundle file {fileName}";
|
||||
if (parentPath != null)
|
||||
{
|
||||
str += $" from {Path.GetFileName(parentPath)}";
|
||||
}
|
||||
Logger.Error(str);*/
|
||||
Logger.Error(str, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -189,7 +190,7 @@ namespace AssetStudio
|
||||
var webFile = new WebFile(reader);
|
||||
foreach (var file in webFile.fileList)
|
||||
{
|
||||
var dummyPath = Path.GetDirectoryName(fullName) + "\\" + file.fileName;
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(fullName), file.fileName);
|
||||
switch (CheckFileType(file.stream, out var fileReader))
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
@@ -202,14 +203,14 @@ namespace AssetStudio
|
||||
LoadWebFile(dummyPath, fileReader);
|
||||
break;
|
||||
case FileType.ResourceFile:
|
||||
resourceFileReaders.Add(file.fileName, fileReader);
|
||||
resourceFileReaders[file.fileName] = fileReader; //TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
//Logger.Error($"Unable to load web file {fileName}");
|
||||
Logger.Error($"Error while reading web file {fileName}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -333,6 +334,9 @@ namespace AssetStudio
|
||||
case ClassIDType.VideoClip:
|
||||
obj = new VideoClip(objectReader);
|
||||
break;
|
||||
case ClassIDType.ResourceManager:
|
||||
obj = new ResourceManager(objectReader);
|
||||
break;
|
||||
default:
|
||||
obj = new Object(objectReader);
|
||||
break;
|
||||
@@ -341,13 +345,13 @@ namespace AssetStudio
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
/*var sb = new StringBuilder();
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Unable to load object")
|
||||
.AppendLine($"Assets {assetsFile.fileName}")
|
||||
.AppendLine($"Type {objectReader.type}")
|
||||
.AppendLine($"PathID {objectInfo.m_PathID}")
|
||||
.Append(e);
|
||||
Logger.Error(sb.ToString());*/
|
||||
Logger.Error(sb.ToString());
|
||||
}
|
||||
|
||||
Progress.Report(++i, progressCount);
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace AssetStudio
|
||||
{
|
||||
public enum BuildTarget
|
||||
{
|
||||
UnknownPlatform = 3716,
|
||||
NoTarget = -2,
|
||||
DashboardWidget = 1,
|
||||
StandaloneOSX = 2,
|
||||
StandaloneOSXPPC = 3,
|
||||
@@ -42,6 +42,12 @@ namespace AssetStudio
|
||||
WiiU,
|
||||
tvOS,
|
||||
Switch,
|
||||
NoTarget = -2
|
||||
Lumin,
|
||||
Stadia,
|
||||
CloudRendering,
|
||||
GameCoreXboxSeries,
|
||||
GameCoreXboxOne,
|
||||
PS5,
|
||||
UnknownPlatform = 9999
|
||||
}
|
||||
}
|
||||
|
||||
+22
-14
@@ -45,12 +45,19 @@ namespace AssetStudio
|
||||
{
|
||||
m_Header = new Header();
|
||||
m_Header.signature = reader.ReadStringToNull();
|
||||
m_Header.version = reader.ReadUInt32();
|
||||
m_Header.unityVersion = reader.ReadStringToNull();
|
||||
m_Header.unityRevision = reader.ReadStringToNull();
|
||||
switch (m_Header.signature)
|
||||
{
|
||||
case "UnityArchive":
|
||||
break; //TODO
|
||||
case "UnityWeb":
|
||||
case "UnityRaw":
|
||||
if (m_Header.version == 6)
|
||||
{
|
||||
goto case "UnityFS";
|
||||
}
|
||||
ReadHeaderAndBlocksInfo(reader);
|
||||
using (var blocksStream = CreateBlocksStream(path))
|
||||
{
|
||||
@@ -73,16 +80,13 @@ namespace AssetStudio
|
||||
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
|
||||
{
|
||||
var isCompressed = m_Header.signature == "UnityWeb";
|
||||
m_Header.version = reader.ReadUInt32();
|
||||
m_Header.unityVersion = reader.ReadStringToNull();
|
||||
m_Header.unityRevision = reader.ReadStringToNull();
|
||||
if (m_Header.version >= 4)
|
||||
{
|
||||
var hash = reader.ReadBytes(16);
|
||||
var crc = reader.ReadUInt32();
|
||||
}
|
||||
var minimumStreamedBytes = reader.ReadUInt32();
|
||||
var headerSize = reader.ReadUInt32();
|
||||
m_Header.size = reader.ReadUInt32();
|
||||
var numberOfLevelsToDownloadBeforeStreaming = reader.ReadUInt32();
|
||||
var levelCount = reader.ReadInt32();
|
||||
m_BlocksInfo = new StorageBlock[1];
|
||||
@@ -107,7 +111,7 @@ namespace AssetStudio
|
||||
{
|
||||
var fileInfoHeaderSize = reader.ReadUInt32();
|
||||
}
|
||||
reader.Position = headerSize;
|
||||
reader.Position = m_Header.size;
|
||||
}
|
||||
|
||||
private Stream CreateBlocksStream(string path)
|
||||
@@ -167,6 +171,7 @@ namespace AssetStudio
|
||||
var node = m_DirectoryInfo[i];
|
||||
var file = new StreamFile();
|
||||
fileList[i] = file;
|
||||
file.path = node.path;
|
||||
file.fileName = Path.GetFileName(node.path);
|
||||
if (node.size >= int.MaxValue)
|
||||
{
|
||||
@@ -174,7 +179,7 @@ namespace AssetStudio
|
||||
file.stream = memoryMappedFile.CreateViewStream();*/
|
||||
var extractPath = path + "_unpacked" + Path.DirectorySeparatorChar;
|
||||
Directory.CreateDirectory(extractPath);
|
||||
file.stream = File.Create(extractPath + file.fileName);
|
||||
file.stream = new FileStream(extractPath + file.fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -188,18 +193,23 @@ namespace AssetStudio
|
||||
|
||||
private void ReadHeader(EndianBinaryReader reader)
|
||||
{
|
||||
m_Header.version = reader.ReadUInt32();
|
||||
m_Header.unityVersion = reader.ReadStringToNull();
|
||||
m_Header.unityRevision = reader.ReadStringToNull();
|
||||
m_Header.size = reader.ReadInt64();
|
||||
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.flags = reader.ReadUInt32();
|
||||
if (m_Header.signature != "UnityFS")
|
||||
{
|
||||
reader.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader)
|
||||
{
|
||||
byte[] blocksInfoBytes;
|
||||
if (m_Header.version >= 7)
|
||||
{
|
||||
reader.AlignStream(16);
|
||||
}
|
||||
if ((m_Header.flags & 0x80) != 0) //kArchiveBlocksInfoAtTheEnd
|
||||
{
|
||||
var position = reader.Position;
|
||||
@@ -209,10 +219,6 @@ namespace AssetStudio
|
||||
}
|
||||
else //0x40 kArchiveBlocksAndDirectoryInfoCombined
|
||||
{
|
||||
if (m_Header.version >= 7)
|
||||
{
|
||||
reader.AlignStream(16);
|
||||
}
|
||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||
}
|
||||
var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes);
|
||||
@@ -226,7 +232,9 @@ namespace AssetStudio
|
||||
}
|
||||
case 1: //LZMA
|
||||
{
|
||||
blocksInfoUncompresseddStream = SevenZipHelper.StreamDecompress(blocksInfoCompressedStream);
|
||||
blocksInfoUncompresseddStream = new MemoryStream((int)(m_Header.uncompressedBlocksInfoSize));
|
||||
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
|
||||
blocksInfoUncompresseddStream.Position = 0;
|
||||
blocksInfoCompressedStream.Close();
|
||||
break;
|
||||
}
|
||||
|
||||
+103
-10
@@ -1,4 +1,5 @@
|
||||
namespace AssetStudio
|
||||
// official Class ID Reference: https://docs.unity3d.com/Manual/ClassIDReference.html
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum ClassIDType
|
||||
{
|
||||
@@ -26,7 +27,7 @@
|
||||
ParticleRenderer = 26,
|
||||
Texture = 27,
|
||||
Texture2D = 28,
|
||||
SceneSettings = 29,
|
||||
OcclusionCullingSettings = 29,
|
||||
GraphicsSettings = 30,
|
||||
MeshFilter = 33,
|
||||
OcclusionPortal = 41,
|
||||
@@ -49,7 +50,7 @@
|
||||
PhysicsMaterial2D = 62,
|
||||
MeshCollider = 64,
|
||||
BoxCollider = 65,
|
||||
SpriteCollider2D = 66,
|
||||
CompositeCollider2D = 66,
|
||||
EdgeCollider2D = 68,
|
||||
CapsuleCollider2D = 70,
|
||||
ComputeShader = 72,
|
||||
@@ -92,6 +93,7 @@
|
||||
FlareLayer = 124,
|
||||
HaloLayer = 125,
|
||||
NavMeshAreas = 126,
|
||||
NavMeshProjectSettings = 126,
|
||||
HaloManager = 127,
|
||||
Font = 128,
|
||||
PlayerSettings = 129,
|
||||
@@ -158,7 +160,7 @@
|
||||
BlendTree = 206,
|
||||
Motion = 207,
|
||||
NavMeshObstacle = 208,
|
||||
TerrainInstance = 210,
|
||||
SortingGroup = 210,
|
||||
SpriteRenderer = 212,
|
||||
Sprite = 213,
|
||||
CachedSpriteAtlas = 214,
|
||||
@@ -216,15 +218,19 @@
|
||||
PerformanceReportingManager = 305,
|
||||
UnityConnectSettings = 310,
|
||||
AvatarMask = 319,
|
||||
PlayableDirector = 320,
|
||||
VideoPlayer = 328,
|
||||
VideoClip = 329,
|
||||
ParticleSystemForceField = 330,
|
||||
SpriteMask = 331,
|
||||
WorldAnchor = 362,
|
||||
OcclusionCullingData = 363,
|
||||
//kLargestRuntimeClassID = 364
|
||||
SmallestEditorClassID = 1000,
|
||||
Prefab = 1001,
|
||||
PrefabInstance = 1001,
|
||||
EditorExtensionImpl = 1002,
|
||||
AssetImporter = 1003,
|
||||
AssetDatabase = 1004,
|
||||
AssetDatabaseV1 = 1004,
|
||||
Mesh3DSImporter = 1005,
|
||||
TextureImporter = 1006,
|
||||
ShaderImporter = 1007,
|
||||
@@ -259,13 +265,13 @@
|
||||
AnimatorState = 1102,
|
||||
HumanTemplate = 1105,
|
||||
AnimatorStateMachine = 1107,
|
||||
PreviewAssetType = 1108,
|
||||
PreviewAnimationClip = 1108,
|
||||
AnimatorTransition = 1109,
|
||||
SpeedTreeImporter = 1110,
|
||||
AnimatorTransitionBase = 1111,
|
||||
SubstanceImporter = 1112,
|
||||
LightmapParameters = 1113,
|
||||
LightmapSnapshot = 1120,
|
||||
LightingDataAsset = 1120,
|
||||
GISRaster = 1121,
|
||||
GISRasterImporter = 1122,
|
||||
CadImporter = 1123,
|
||||
@@ -276,11 +282,98 @@
|
||||
ActivationLogComponent = 2000,
|
||||
//kLargestEditorClassID = 2001
|
||||
//kClassIdOutOfHierarchy = 100000
|
||||
SubDerived = 367388927,
|
||||
//int = 100000,
|
||||
//bool = 100001,
|
||||
//float = 100002,
|
||||
MonoObject = 100003,
|
||||
Collision = 100004,
|
||||
Vector3f = 100005,
|
||||
RootMotionData = 100006,
|
||||
Collision2D = 100007,
|
||||
AudioMixerLiveUpdateFloat = 100008,
|
||||
AudioMixerLiveUpdateBool = 100009,
|
||||
Polygon2D = 100010,
|
||||
//void = 100011,
|
||||
TilemapCollider2D = 19719996,
|
||||
AssetImporterLog = 41386430,
|
||||
VFXRenderer = 73398921,
|
||||
SerializableManagedRefTestClass = 76251197,
|
||||
Grid = 156049354,
|
||||
ScenesUsingAssets = 156483287,
|
||||
ArticulationBody = 171741748,
|
||||
Preset = 181963792,
|
||||
EmptyObject = 277625683,
|
||||
IConstraint = 285090594,
|
||||
TestObjectWithSpecialLayoutOne = 293259124,
|
||||
AssemblyDefinitionReferenceImporter = 294290339,
|
||||
SiblingDerived = 334799969,
|
||||
TestObjectWithSerializedMapStringNonAlignedStruct = 342846651,
|
||||
SubDerived = 367388927,
|
||||
AssetImportInProgressProxy = 369655926,
|
||||
PluginBuildInfo = 382020655,
|
||||
EditorProjectAccess = 426301858,
|
||||
PrefabImporter = 468431735,
|
||||
TestObjectWithSerializedArray = 478637458,
|
||||
TestObjectWithSerializedAnimationCurve = 478637459,
|
||||
TilemapRenderer = 483693784,
|
||||
ScriptableCamera = 488575907,
|
||||
SpriteAtlasAsset = 612988286,
|
||||
SpriteAtlasDatabase = 638013454,
|
||||
AudioBuildInfo = 641289076,
|
||||
CachedSpriteAtlasRuntimeData = 644342135,
|
||||
RendererFake = 646504946,
|
||||
AssemblyDefinitionReferenceAsset = 662584278,
|
||||
BuiltAssetBundleInfoSet = 668709126,
|
||||
SpriteAtlas = 687078895,
|
||||
RayTracingShaderImporter = 747330370,
|
||||
RayTracingShader = 825902497,
|
||||
LightingSettings = 850595691,
|
||||
PlatformModuleSetup = 877146078,
|
||||
VersionControlSettings = 890905787,
|
||||
AimConstraint = 895512359,
|
||||
VFXManager = 937362698,
|
||||
VisualEffectSubgraph = 994735392,
|
||||
VisualEffectSubgraphOperator = 994735403,
|
||||
VisualEffectSubgraphBlock = 994735404,
|
||||
LocalizationImporter = 1027052791,
|
||||
Derived = 1091556383,
|
||||
PropertyModificationsTargetTestObject = 1111377672,
|
||||
ReferencesArtifactGenerator = 1114811875,
|
||||
AssemblyDefinitionAsset = 1152215463,
|
||||
SceneVisibilityState = 1154873562,
|
||||
LookAtConstraint = 1183024399,
|
||||
SpriteAtlasImporter = 1210832254,
|
||||
MultiArtifactTestImporter = 1223240404,
|
||||
GameObjectRecorder = 1268269756,
|
||||
LightingDataAssetParent = 1325145578,
|
||||
PresetManager = 1386491679,
|
||||
TestObjectWithSpecialLayoutTwo = 1392443030,
|
||||
StreamingManager = 1403656975,
|
||||
LowerResBlitTexture = 1480428607,
|
||||
RenderPassAttachment = 1571458007
|
||||
StreamingController = 1542919678,
|
||||
RenderPassAttachment = 1571458007,
|
||||
TestObjectVectorPairStringBool = 1628831178,
|
||||
GridLayout = 1742807556,
|
||||
AssemblyDefinitionImporter = 1766753193,
|
||||
ParentConstraint = 1773428102,
|
||||
FakeComponent = 1803986026,
|
||||
PositionConstraint = 1818360608,
|
||||
RotationConstraint = 1818360609,
|
||||
ScaleConstraint = 1818360610,
|
||||
Tilemap = 1839735485,
|
||||
PackageManifest = 1896753125,
|
||||
PackageManifestImporter = 1896753126,
|
||||
TerrainLayer = 1953259897,
|
||||
SpriteShapeRenderer = 1971053207,
|
||||
NativeObjectType = 1977754360,
|
||||
TestObjectWithSerializedMapStringBool = 1981279845,
|
||||
SerializableManagedHost = 1995898324,
|
||||
VisualEffectAsset = 2058629509,
|
||||
VisualEffectImporter = 2058629510,
|
||||
VisualEffectResource = 2058629511,
|
||||
VisualEffectObject = 2059678085,
|
||||
VisualEffect = 2083052967,
|
||||
LocalizationAsset = 2083778819,
|
||||
ScriptedImporter = 2089858483
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace AssetStudio
|
||||
public AudioCompressionFormat m_CompressionFormat;
|
||||
|
||||
public string m_Source;
|
||||
public long m_Offset;
|
||||
public ulong m_Offset;
|
||||
public long m_Size;
|
||||
public ResourceReader m_AudioData;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace AssetStudio
|
||||
var tsize = m_Size % 4 != 0 ? m_Size + 4 - m_Size % 4 : m_Size;
|
||||
if (reader.byteSize + reader.byteStart - reader.Position != tsize)
|
||||
{
|
||||
m_Offset = reader.ReadInt32();
|
||||
m_Offset = reader.ReadUInt32();
|
||||
m_Source = assetsFile.fullName + ".resS";
|
||||
}
|
||||
}
|
||||
@@ -72,8 +72,9 @@ namespace AssetStudio
|
||||
m_Legacy3D = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
|
||||
//StreamedResource m_Resource
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadInt64();
|
||||
m_Offset = reader.ReadUInt64();
|
||||
m_Size = reader.ReadInt64();
|
||||
m_CompressionFormat = (AudioCompressionFormat)reader.ReadInt32();
|
||||
}
|
||||
|
||||
@@ -19,11 +19,14 @@ namespace AssetStudio
|
||||
public class UnityPropertySheet
|
||||
{
|
||||
public KeyValuePair<string, UnityTexEnv>[] m_TexEnvs;
|
||||
public KeyValuePair<string, int>[] m_Ints;
|
||||
public KeyValuePair<string, float>[] m_Floats;
|
||||
public KeyValuePair<string, Color>[] m_Colors;
|
||||
|
||||
public UnityPropertySheet(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int m_TexEnvsSize = reader.ReadInt32();
|
||||
m_TexEnvs = new KeyValuePair<string, UnityTexEnv>[m_TexEnvsSize];
|
||||
for (int i = 0; i < m_TexEnvsSize; i++)
|
||||
@@ -31,6 +34,16 @@ namespace AssetStudio
|
||||
m_TexEnvs[i] = new KeyValuePair<string, UnityTexEnv>(reader.ReadAlignedString(), new UnityTexEnv(reader));
|
||||
}
|
||||
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
int m_IntsSize = reader.ReadInt32();
|
||||
m_Ints = new KeyValuePair<string, int>[m_IntsSize];
|
||||
for (int i = 0; i < m_IntsSize; i++)
|
||||
{
|
||||
m_Ints[i] = new KeyValuePair<string, int>(reader.ReadAlignedString(), reader.ReadInt32());
|
||||
}
|
||||
}
|
||||
|
||||
int m_FloatsSize = reader.ReadInt32();
|
||||
m_Floats = new KeyValuePair<string, float>[m_FloatsSize];
|
||||
for (int i = 0; i < m_FloatsSize; i++)
|
||||
@@ -95,6 +108,8 @@ namespace AssetStudio
|
||||
}
|
||||
|
||||
m_SavedProperties = new UnityPropertySheet(reader);
|
||||
|
||||
//vector m_BuildTextureStacks 2020 and up
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+120
-119
@@ -174,7 +174,7 @@ namespace AssetStudio
|
||||
GetStreams(version);
|
||||
}
|
||||
|
||||
m_DataSize = reader.ReadBytes(reader.ReadInt32());
|
||||
m_DataSize = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace AssetStudio
|
||||
if (m_Channel.dimension > 0)
|
||||
{
|
||||
chnMask |= 1u << chn;
|
||||
stride += m_Channel.dimension * MeshHelper.GetFormatSize(version, m_Channel.format);
|
||||
stride += m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,7 +253,7 @@ namespace AssetStudio
|
||||
m_Channel.dimension = 4;
|
||||
break;
|
||||
}
|
||||
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(version, m_Channel.format));
|
||||
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -446,7 +446,7 @@ namespace AssetStudio
|
||||
|
||||
public sealed class Mesh : NamedObject
|
||||
{
|
||||
private bool m_Use16BitIndices = true; //3.5.0 and newer always uses 16bit indices;
|
||||
private bool m_Use16BitIndices = true;
|
||||
public SubMesh[] m_SubMeshes;
|
||||
private uint[] m_IndexBuffer;
|
||||
public BlendShapeData m_Shapes;
|
||||
@@ -550,6 +550,7 @@ namespace AssetStudio
|
||||
((version[0] == 2017 && version[1] == 3) && m_MeshCompression == 0))//2017.3.xfx with no compression
|
||||
{
|
||||
var m_IndexFormat = reader.ReadInt32();
|
||||
m_Use16BitIndices = m_IndexFormat == 0;
|
||||
}
|
||||
|
||||
int m_IndexBuffer_size = reader.ReadInt32();
|
||||
@@ -652,9 +653,9 @@ namespace AssetStudio
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_BakedConvexCollisionMesh = reader.ReadBytes(reader.ReadInt32());
|
||||
var m_BakedConvexCollisionMesh = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
var m_BakedTriangleCollisionMesh = reader.ReadBytes(reader.ReadInt32());
|
||||
var m_BakedTriangleCollisionMesh = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
@@ -710,12 +711,13 @@ namespace AssetStudio
|
||||
var channelMask = new BitArray(new[] { (int)m_Stream.channelMask });
|
||||
if (channelMask.Get(chn))
|
||||
{
|
||||
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2)
|
||||
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2) //kShaderChannelColor && kChannelFormatColor
|
||||
{
|
||||
m_Channel.dimension = 4;
|
||||
}
|
||||
|
||||
var componentByteSize = (int)MeshHelper.GetFormatSize(version, m_Channel.format);
|
||||
var vertexFormat = MeshHelper.ToVertexFormat(m_Channel.format, version);
|
||||
var componentByteSize = (int)MeshHelper.GetFormatSize(vertexFormat);
|
||||
var componentBytes = new byte[m_VertexCount * m_Channel.dimension * componentByteSize];
|
||||
for (int v = 0; v < m_VertexCount; v++)
|
||||
{
|
||||
@@ -740,10 +742,10 @@ namespace AssetStudio
|
||||
|
||||
int[] componentsIntArray = null;
|
||||
float[] componentsFloatArray = null;
|
||||
if (MeshHelper.IsIntFormat(version, m_Channel.format))
|
||||
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, componentByteSize);
|
||||
if (MeshHelper.IsIntFormat(vertexFormat))
|
||||
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, vertexFormat);
|
||||
else
|
||||
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, componentByteSize);
|
||||
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
|
||||
|
||||
if (version[0] >= 2018)
|
||||
{
|
||||
@@ -1189,7 +1191,7 @@ namespace AssetStudio
|
||||
|
||||
public static class MeshHelper
|
||||
{
|
||||
private enum VertexChannelFormat
|
||||
public enum VertexChannelFormat
|
||||
{
|
||||
kChannelFormatFloat,
|
||||
kChannelFormatFloat16,
|
||||
@@ -1198,7 +1200,7 @@ namespace AssetStudio
|
||||
kChannelFormatUInt32
|
||||
}
|
||||
|
||||
private enum VertexFormat
|
||||
public enum VertexFormat2017
|
||||
{
|
||||
kVertexFormatFloat,
|
||||
kVertexFormatFloat16,
|
||||
@@ -1215,7 +1217,7 @@ namespace AssetStudio
|
||||
kVertexFormatSInt32
|
||||
}
|
||||
|
||||
private enum VertexFormatV2019
|
||||
public enum VertexFormat
|
||||
{
|
||||
kVertexFormatFloat,
|
||||
kVertexFormatFloat16,
|
||||
@@ -1231,147 +1233,146 @@ namespace AssetStudio
|
||||
kVertexFormatSInt32
|
||||
}
|
||||
|
||||
public static uint GetFormatSize(int[] version, int format)
|
||||
public static VertexFormat ToVertexFormat(int format, int[] version)
|
||||
{
|
||||
if (version[0] < 2017)
|
||||
{
|
||||
switch ((VertexChannelFormat)format)
|
||||
{
|
||||
case VertexChannelFormat.kChannelFormatFloat:
|
||||
return 4u;
|
||||
return VertexFormat.kVertexFormatFloat;
|
||||
case VertexChannelFormat.kChannelFormatFloat16:
|
||||
return 2u;
|
||||
return VertexFormat.kVertexFormatFloat16;
|
||||
case VertexChannelFormat.kChannelFormatColor: //in 4.x is size 4
|
||||
return 1u;
|
||||
return VertexFormat.kVertexFormatUNorm8;
|
||||
case VertexChannelFormat.kChannelFormatByte:
|
||||
return 1u;
|
||||
return VertexFormat.kVertexFormatUInt8;
|
||||
case VertexChannelFormat.kChannelFormatUInt32: //in 5.x
|
||||
return 4u;
|
||||
return VertexFormat.kVertexFormatUInt32;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
else if (version[0] < 2019)
|
||||
{
|
||||
switch ((VertexFormat)format)
|
||||
switch ((VertexFormat2017)format)
|
||||
{
|
||||
case VertexFormat2017.kVertexFormatFloat:
|
||||
return VertexFormat.kVertexFormatFloat;
|
||||
case VertexFormat2017.kVertexFormatFloat16:
|
||||
return VertexFormat.kVertexFormatFloat16;
|
||||
case VertexFormat2017.kVertexFormatColor:
|
||||
case VertexFormat2017.kVertexFormatUNorm8:
|
||||
return VertexFormat.kVertexFormatUNorm8;
|
||||
case VertexFormat2017.kVertexFormatSNorm8:
|
||||
return VertexFormat.kVertexFormatSNorm8;
|
||||
case VertexFormat2017.kVertexFormatUNorm16:
|
||||
return VertexFormat.kVertexFormatUNorm16;
|
||||
case VertexFormat2017.kVertexFormatSNorm16:
|
||||
return VertexFormat.kVertexFormatSNorm16;
|
||||
case VertexFormat2017.kVertexFormatUInt8:
|
||||
return VertexFormat.kVertexFormatUInt8;
|
||||
case VertexFormat2017.kVertexFormatSInt8:
|
||||
return VertexFormat.kVertexFormatSInt8;
|
||||
case VertexFormat2017.kVertexFormatUInt16:
|
||||
return VertexFormat.kVertexFormatUInt16;
|
||||
case VertexFormat2017.kVertexFormatSInt16:
|
||||
return VertexFormat.kVertexFormatSInt16;
|
||||
case VertexFormat2017.kVertexFormatUInt32:
|
||||
return VertexFormat.kVertexFormatUInt32;
|
||||
case VertexFormat2017.kVertexFormatSInt32:
|
||||
return VertexFormat.kVertexFormatSInt32;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (VertexFormat)format;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static uint GetFormatSize(VertexFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case VertexFormat.kVertexFormatFloat:
|
||||
case VertexFormat.kVertexFormatUInt32:
|
||||
case VertexFormat.kVertexFormatSInt32:
|
||||
return 4u;
|
||||
case VertexFormat.kVertexFormatFloat16:
|
||||
case VertexFormat.kVertexFormatUNorm16:
|
||||
case VertexFormat.kVertexFormatSNorm16:
|
||||
case VertexFormat.kVertexFormatUInt16:
|
||||
case VertexFormat.kVertexFormatSInt16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatUNorm8:
|
||||
case VertexFormat.kVertexFormatSNorm8:
|
||||
case VertexFormat.kVertexFormatUInt8:
|
||||
case VertexFormat.kVertexFormatSInt8:
|
||||
return 1u;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsIntFormat(VertexFormat format)
|
||||
{
|
||||
return format >= VertexFormat.kVertexFormatUInt8;
|
||||
}
|
||||
|
||||
public static float[] BytesToFloatArray(byte[] inputBytes, VertexFormat format)
|
||||
{
|
||||
var size = GetFormatSize(format);
|
||||
var len = inputBytes.Length / size;
|
||||
var result = new float[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case VertexFormat.kVertexFormatFloat:
|
||||
return 4u;
|
||||
result[i] = BitConverter.ToSingle(inputBytes, i * 4);
|
||||
break;
|
||||
case VertexFormat.kVertexFormatFloat16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatColor:
|
||||
return 1u;
|
||||
result[i] = Half.ToHalf(inputBytes, i * 2);
|
||||
break;
|
||||
case VertexFormat.kVertexFormatUNorm8:
|
||||
return 1u;
|
||||
result[i] = inputBytes[i] / 255f;
|
||||
break;
|
||||
case VertexFormat.kVertexFormatSNorm8:
|
||||
return 1u;
|
||||
result[i] = Math.Max((sbyte)inputBytes[i] / 127f, -1f);
|
||||
break;
|
||||
case VertexFormat.kVertexFormatUNorm16:
|
||||
return 2u;
|
||||
result[i] = BitConverter.ToUInt16(inputBytes, i * 2) / 65535f;
|
||||
break;
|
||||
case VertexFormat.kVertexFormatSNorm16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatUInt8:
|
||||
return 1u;
|
||||
case VertexFormat.kVertexFormatSInt8:
|
||||
return 1u;
|
||||
case VertexFormat.kVertexFormatUInt16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatSInt16:
|
||||
return 2u;
|
||||
case VertexFormat.kVertexFormatUInt32:
|
||||
return 4u;
|
||||
case VertexFormat.kVertexFormatSInt32:
|
||||
return 4u;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ((VertexFormatV2019)format)
|
||||
{
|
||||
case VertexFormatV2019.kVertexFormatFloat:
|
||||
return 4u;
|
||||
case VertexFormatV2019.kVertexFormatFloat16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatUNorm8:
|
||||
return 1u;
|
||||
case VertexFormatV2019.kVertexFormatSNorm8:
|
||||
return 1u;
|
||||
case VertexFormatV2019.kVertexFormatUNorm16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatSNorm16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatUInt8:
|
||||
return 1u;
|
||||
case VertexFormatV2019.kVertexFormatSInt8:
|
||||
return 1u;
|
||||
case VertexFormatV2019.kVertexFormatUInt16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatSInt16:
|
||||
return 2u;
|
||||
case VertexFormatV2019.kVertexFormatUInt32:
|
||||
return 4u;
|
||||
case VertexFormatV2019.kVertexFormatSInt32:
|
||||
return 4u;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsIntFormat(int[] version, int format)
|
||||
{
|
||||
if (version[0] < 2017)
|
||||
{
|
||||
return format == 4;
|
||||
}
|
||||
else if (version[0] < 2019)
|
||||
{
|
||||
return format >= 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
return format >= 6;
|
||||
}
|
||||
}
|
||||
|
||||
public static float[] BytesToFloatArray(byte[] inputBytes, int size)
|
||||
{
|
||||
var result = new float[inputBytes.Length / size];
|
||||
for (int i = 0; i < inputBytes.Length / size; i++)
|
||||
{
|
||||
var value = 0f;
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
value = inputBytes[i] / 255.0f;
|
||||
break;
|
||||
case 2:
|
||||
value = Half.ToHalf(inputBytes, i * 2);
|
||||
break;
|
||||
case 4:
|
||||
value = BitConverter.ToSingle(inputBytes, i * 4);
|
||||
result[i] = Math.Max(BitConverter.ToInt16(inputBytes, i * 2) / 32767f, -1f);
|
||||
break;
|
||||
}
|
||||
result[i] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int[] BytesToIntArray(byte[] inputBytes, int size)
|
||||
public static int[] BytesToIntArray(byte[] inputBytes, VertexFormat format)
|
||||
{
|
||||
var result = new int[inputBytes.Length / size];
|
||||
for (int i = 0; i < inputBytes.Length / size; i++)
|
||||
var size = GetFormatSize(format);
|
||||
var len = inputBytes.Length / size;
|
||||
var result = new int[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
switch (size)
|
||||
switch (format)
|
||||
{
|
||||
case 1:
|
||||
case VertexFormat.kVertexFormatUInt8:
|
||||
case VertexFormat.kVertexFormatSInt8:
|
||||
result[i] = inputBytes[i];
|
||||
break;
|
||||
case 2:
|
||||
case VertexFormat.kVertexFormatUInt16:
|
||||
case VertexFormat.kVertexFormatSInt16:
|
||||
result[i] = BitConverter.ToInt16(inputBytes, i * 2);
|
||||
break;
|
||||
case 4:
|
||||
case VertexFormat.kVertexFormatUInt32:
|
||||
case VertexFormat.kVertexFormatSInt32:
|
||||
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace AssetStudio
|
||||
public sealed class MonoScript : NamedObject
|
||||
{
|
||||
public string m_ClassName;
|
||||
public string m_Namespace = string.Empty;
|
||||
public string m_Namespace;
|
||||
public string m_AssemblyName;
|
||||
|
||||
public MonoScript(ObjectReader reader) : base(reader)
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace AssetStudio
|
||||
var m_Loop = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
m_AudioClip = new PPtr<AudioClip>(reader);
|
||||
m_MovieData = reader.ReadBytes(reader.ReadInt32());
|
||||
m_MovieData = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -43,7 +43,6 @@ namespace AssetStudio
|
||||
|
||||
public string Dump()
|
||||
{
|
||||
reader.Reset();
|
||||
if (serializedType?.m_Nodes != null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
@@ -53,6 +52,35 @@ namespace AssetStudio
|
||||
return null;
|
||||
}
|
||||
|
||||
public string Dump(List<TypeTreeNode> m_Nodes)
|
||||
{
|
||||
if (m_Nodes != null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
TypeTreeHelper.ReadTypeString(sb, m_Nodes, reader);
|
||||
return sb.ToString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OrderedDictionary ToType()
|
||||
{
|
||||
if (serializedType?.m_Nodes != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadType(serializedType.m_Nodes, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OrderedDictionary ToType(List<TypeTreeNode> m_Nodes)
|
||||
{
|
||||
if (m_Nodes != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadType(m_Nodes, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] GetRawData()
|
||||
{
|
||||
reader.Reset();
|
||||
|
||||
@@ -43,6 +43,10 @@ namespace AssetStudio
|
||||
{
|
||||
var m_DynamicOccludee = reader.ReadByte();
|
||||
}
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
var m_StaticShadowCaster = reader.ReadByte();
|
||||
}
|
||||
var m_MotionVectors = reader.ReadByte();
|
||||
var m_LightProbeUsage = reader.ReadByte();
|
||||
var m_ReflectionProbeUsage = reader.ReadByte();
|
||||
@@ -50,6 +54,10 @@ namespace AssetStudio
|
||||
{
|
||||
var m_RayTracingMode = reader.ReadByte();
|
||||
}
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_RayTraceProcedural = reader.ReadByte();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class ResourceManager : Object
|
||||
{
|
||||
public KeyValuePair<string, PPtr<Object>>[] m_Container;
|
||||
|
||||
public ResourceManager(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_ContainerSize = reader.ReadInt32();
|
||||
m_Container = new KeyValuePair<string, PPtr<Object>>[m_ContainerSize];
|
||||
for (int i = 0; i < m_ContainerSize; i++)
|
||||
{
|
||||
m_Container[i] = new KeyValuePair<string, PPtr<Object>>(reader.ReadAlignedString(), new PPtr<Object>(reader));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,16 @@ using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class Hash128
|
||||
{
|
||||
public byte[] bytes;
|
||||
|
||||
public Hash128(BinaryReader reader)
|
||||
{
|
||||
bytes = reader.ReadBytes(16);
|
||||
}
|
||||
}
|
||||
|
||||
public class StructParameter
|
||||
{
|
||||
public MatrixParameter[] m_MatrixParams;
|
||||
@@ -201,6 +211,7 @@ namespace AssetStudio
|
||||
public SerializedShaderFloatValue zTest;
|
||||
public SerializedShaderFloatValue zWrite;
|
||||
public SerializedShaderFloatValue culling;
|
||||
public SerializedShaderFloatValue conservative;
|
||||
public SerializedShaderFloatValue offsetFactor;
|
||||
public SerializedShaderFloatValue offsetUnits;
|
||||
public SerializedShaderFloatValue alphaToMask;
|
||||
@@ -239,6 +250,10 @@ namespace AssetStudio
|
||||
zTest = new SerializedShaderFloatValue(reader);
|
||||
zWrite = new SerializedShaderFloatValue(reader);
|
||||
culling = new SerializedShaderFloatValue(reader);
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
conservative = new SerializedShaderFloatValue(reader);
|
||||
}
|
||||
offsetFactor = new SerializedShaderFloatValue(reader);
|
||||
offsetUnits = new SerializedShaderFloatValue(reader);
|
||||
alphaToMask = new SerializedShaderFloatValue(reader);
|
||||
@@ -357,11 +372,18 @@ namespace AssetStudio
|
||||
{
|
||||
public int m_NameIndex;
|
||||
public int m_Index;
|
||||
public int m_ArraySize;
|
||||
|
||||
public BufferBinding(BinaryReader reader)
|
||||
public BufferBinding(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_NameIndex = reader.ReadInt32();
|
||||
m_Index = reader.ReadInt32();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
m_ArraySize = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +469,12 @@ namespace AssetStudio
|
||||
kShaderGpuProgramMetalVS = 23,
|
||||
kShaderGpuProgramMetalFS = 24,
|
||||
kShaderGpuProgramSPIRV = 25,
|
||||
kShaderGpuProgramConsole = 26
|
||||
kShaderGpuProgramConsoleVS = 26,
|
||||
kShaderGpuProgramConsoleFS = 27,
|
||||
kShaderGpuProgramConsoleHS = 28,
|
||||
kShaderGpuProgramConsoleDS = 29,
|
||||
kShaderGpuProgramConsoleGS = 30,
|
||||
kShaderGpuProgramRayTracing = 31,
|
||||
};
|
||||
|
||||
public class SerializedSubProgram
|
||||
@@ -553,7 +580,14 @@ namespace AssetStudio
|
||||
}
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
var m_ShaderRequirements = reader.ReadInt32();
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
var m_ShaderRequirements = reader.ReadInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
var m_ShaderRequirements = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -582,6 +616,10 @@ namespace AssetStudio
|
||||
|
||||
public class SerializedPass
|
||||
{
|
||||
public Hash128[] m_EditorDataHash;
|
||||
public byte[] m_Platforms;
|
||||
public ushort[] m_LocalKeywordMask;
|
||||
public ushort[] m_GlobalKeywordMask;
|
||||
public KeyValuePair<string, int>[] m_NameIndices;
|
||||
public PassType m_Type;
|
||||
public SerializedShaderState m_State;
|
||||
@@ -602,6 +640,23 @@ namespace AssetStudio
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
int numEditorDataHash = reader.ReadInt32();
|
||||
m_EditorDataHash = new Hash128[numEditorDataHash];
|
||||
for (int i = 0; i < numEditorDataHash; i++)
|
||||
{
|
||||
m_EditorDataHash[i] = new Hash128(reader);
|
||||
}
|
||||
reader.AlignStream();
|
||||
m_Platforms = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
m_LocalKeywordMask = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
m_GlobalKeywordMask = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
int numIndices = reader.ReadInt32();
|
||||
m_NameIndices = new KeyValuePair<string, int>[numIndices];
|
||||
for (int i = 0; i < numIndices; i++)
|
||||
@@ -681,6 +736,18 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
public class SerializedCustomEditorForRenderPipeline
|
||||
{
|
||||
public string customEditorName;
|
||||
public string renderPipelineType;
|
||||
|
||||
public SerializedCustomEditorForRenderPipeline(BinaryReader reader)
|
||||
{
|
||||
customEditorName = reader.ReadAlignedString();
|
||||
renderPipelineType = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
|
||||
public class SerializedShader
|
||||
{
|
||||
public SerializedProperties m_PropInfo;
|
||||
@@ -689,10 +756,13 @@ namespace AssetStudio
|
||||
public string m_CustomEditorName;
|
||||
public string m_FallbackName;
|
||||
public SerializedShaderDependency[] m_Dependencies;
|
||||
public SerializedCustomEditorForRenderPipeline[] m_CustomEditorForRenderPipelines;
|
||||
public bool m_DisableNoSubshadersMessage;
|
||||
|
||||
public SerializedShader(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_PropInfo = new SerializedProperties(reader);
|
||||
|
||||
int numSubShaders = reader.ReadInt32();
|
||||
@@ -713,6 +783,16 @@ namespace AssetStudio
|
||||
m_Dependencies[i] = new SerializedShaderDependency(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
int m_CustomEditorForRenderPipelinesSize = reader.ReadInt32();
|
||||
m_CustomEditorForRenderPipelines = new SerializedCustomEditorForRenderPipeline[m_CustomEditorForRenderPipelinesSize];
|
||||
for (int i = 0; i < m_CustomEditorForRenderPipelinesSize; i++)
|
||||
{
|
||||
m_CustomEditorForRenderPipelines[i] = new SerializedCustomEditorForRenderPipeline(reader);
|
||||
}
|
||||
}
|
||||
|
||||
m_DisableNoSubshadersMessage = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
@@ -741,7 +821,11 @@ namespace AssetStudio
|
||||
kShaderCompPlatformWiiU = 17,
|
||||
kShaderCompPlatformVulkan = 18,
|
||||
kShaderCompPlatformSwitch = 19,
|
||||
kShaderCompPlatformXboxOneD3D12 = 20
|
||||
kShaderCompPlatformXboxOneD3D12 = 20,
|
||||
kShaderCompPlatformGameCoreXboxOne = 21,
|
||||
kShaderCompPlatformGameCoreScarlett = 22,
|
||||
kShaderCompPlatformPS5 = 23,
|
||||
kShaderCompPlatformPS5NGGC = 24,
|
||||
};
|
||||
|
||||
public class Shader : NamedObject
|
||||
@@ -776,17 +860,17 @@ namespace AssetStudio
|
||||
compressedLengths = reader.ReadUInt32Array();
|
||||
decompressedLengths = reader.ReadUInt32Array();
|
||||
}
|
||||
compressedBlob = reader.ReadBytes(reader.ReadInt32());
|
||||
compressedBlob = reader.ReadUInt8Array();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Script = reader.ReadBytes(reader.ReadInt32());
|
||||
m_Script = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
var m_PathName = reader.ReadAlignedString();
|
||||
if (version[0] == 5 && version[1] >= 3) //5.3 - 5.4
|
||||
{
|
||||
decompressedSize = reader.ReadUInt32();
|
||||
m_SubProgramBlob = reader.ReadBytes(reader.ReadInt32());
|
||||
m_SubProgramBlob = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
@@ -88,7 +87,7 @@ namespace AssetStudio
|
||||
public ushort[] indices;
|
||||
public Matrix4x4[] m_Bindpose;
|
||||
public BoneWeights4[] m_SourceSkin;
|
||||
public RectangleF textureRect;
|
||||
public Rectf textureRect;
|
||||
public Vector2 textureRectOffset;
|
||||
public Vector2 atlasRectOffset;
|
||||
public SpriteSettings settingsRaw;
|
||||
@@ -124,7 +123,7 @@ namespace AssetStudio
|
||||
m_SubMeshes[i] = new SubMesh(reader);
|
||||
}
|
||||
|
||||
m_IndexBuffer = reader.ReadBytes(reader.ReadInt32());
|
||||
m_IndexBuffer = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
|
||||
m_VertexData = new VertexData(reader);
|
||||
@@ -156,7 +155,7 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
textureRect = reader.ReadRectangleF();
|
||||
textureRect = new Rectf(reader);
|
||||
textureRectOffset = reader.ReadVector2();
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
|
||||
{
|
||||
@@ -176,9 +175,25 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
public class Rectf
|
||||
{
|
||||
public float x;
|
||||
public float y;
|
||||
public float width;
|
||||
public float height;
|
||||
|
||||
public Rectf(BinaryReader reader)
|
||||
{
|
||||
x = reader.ReadSingle();
|
||||
y = reader.ReadSingle();
|
||||
width = reader.ReadSingle();
|
||||
height = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Sprite : NamedObject
|
||||
{
|
||||
public RectangleF m_Rect;
|
||||
public Rectf m_Rect;
|
||||
public Vector2 m_Offset;
|
||||
public Vector4 m_Border;
|
||||
public float m_PixelsToUnits;
|
||||
@@ -193,7 +208,7 @@ namespace AssetStudio
|
||||
|
||||
public Sprite(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Rect = reader.ReadRectangleF();
|
||||
m_Rect = new Rectf(reader);
|
||||
m_Offset = reader.ReadVector2();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
|
||||
{
|
||||
|
||||
@@ -7,19 +7,20 @@ namespace AssetStudio
|
||||
{
|
||||
public PPtr<Texture2D> texture;
|
||||
public PPtr<Texture2D> alphaTexture;
|
||||
public System.Drawing.RectangleF textureRect;
|
||||
public Rectf textureRect;
|
||||
public Vector2 textureRectOffset;
|
||||
public Vector2 atlasRectOffset;
|
||||
public Vector4 uvTransform;
|
||||
public float downscaleMultiplier;
|
||||
public SpriteSettings settingsRaw;
|
||||
public SecondarySpriteTexture[] secondaryTextures;
|
||||
|
||||
public SpriteAtlasData(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
texture = new PPtr<Texture2D>(reader);
|
||||
alphaTexture = new PPtr<Texture2D>(reader);
|
||||
textureRect = reader.ReadRectangleF();
|
||||
textureRect = new Rectf(reader);
|
||||
textureRectOffset = reader.ReadVector2();
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
@@ -28,6 +29,16 @@ namespace AssetStudio
|
||||
uvTransform = reader.ReadVector4();
|
||||
downscaleMultiplier = reader.ReadSingle();
|
||||
settingsRaw = new SpriteSettings(reader);
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var secondaryTexturesSize = reader.ReadInt32();
|
||||
secondaryTextures = new SecondarySpriteTexture[secondaryTexturesSize];
|
||||
for (int i = 0; i < secondaryTexturesSize; i++)
|
||||
{
|
||||
secondaryTextures[i] = new SecondarySpriteTexture(reader);
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace AssetStudio
|
||||
|
||||
public TextAsset(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Script = reader.ReadBytes(reader.ReadInt32());
|
||||
m_Script = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ namespace AssetStudio
|
||||
{
|
||||
var m_ForcedFallbackFormat = reader.ReadInt32();
|
||||
var m_DownscaleFallback = reader.ReadBoolean();
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var m_IsAlphaChannelOptional = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,22 @@ namespace AssetStudio
|
||||
{
|
||||
public class StreamingInfo
|
||||
{
|
||||
public uint offset;
|
||||
public ulong offset;
|
||||
public uint size;
|
||||
public string path;
|
||||
|
||||
public StreamingInfo(ObjectReader reader)
|
||||
{
|
||||
offset = reader.ReadUInt32();
|
||||
var version = reader.version;
|
||||
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
offset = reader.ReadUInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = reader.ReadUInt32();
|
||||
}
|
||||
size = reader.ReadUInt32();
|
||||
path = reader.ReadAlignedString();
|
||||
}
|
||||
@@ -59,6 +68,10 @@ namespace AssetStudio
|
||||
m_Width = reader.ReadInt32();
|
||||
m_Height = reader.ReadInt32();
|
||||
var m_CompleteImageSize = reader.ReadInt32();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_MipsStripped = reader.ReadInt32();
|
||||
}
|
||||
m_TextureFormat = (TextureFormat)reader.ReadInt32();
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down
|
||||
{
|
||||
@@ -68,9 +81,29 @@ namespace AssetStudio
|
||||
{
|
||||
m_MipCount = reader.ReadInt32();
|
||||
}
|
||||
var m_IsReadable = reader.ReadBoolean(); //2.6.0 and up
|
||||
var m_ReadAllowed = reader.ReadBoolean(); //3.0.0 - 5.4
|
||||
//bool m_StreamingMipmaps 2018.2 and up
|
||||
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and up
|
||||
{
|
||||
var m_IsReadable = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_IsPreProcessed = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] >= 3) //3.0.0 - 5.4
|
||||
{
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] <= 4))
|
||||
{
|
||||
var m_ReadAllowed = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||
{
|
||||
var m_StreamingMipmaps = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||
{
|
||||
@@ -87,6 +120,11 @@ namespace AssetStudio
|
||||
{
|
||||
var m_ColorSpace = reader.ReadInt32();
|
||||
}
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var m_PlatformBlob = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
var image_data_size = reader.ReadInt32();
|
||||
if (image_data_size == 0 && ((version[0] == 5 && version[1] >= 3) || version[0] > 5))//5.3.0 and up
|
||||
{
|
||||
@@ -171,5 +209,8 @@ namespace AssetStudio
|
||||
ASTC_HDR_8x8,
|
||||
ASTC_HDR_10x10,
|
||||
ASTC_HDR_12x12,
|
||||
RG32,
|
||||
RGB48,
|
||||
RGBA64
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StreamedResource
|
||||
{
|
||||
public string m_Source;
|
||||
public ulong m_Offset;
|
||||
public ulong m_Size;
|
||||
|
||||
public StreamedResource(BinaryReader reader)
|
||||
{
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadUInt64();
|
||||
m_Size = reader.ReadUInt64();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VideoClip : NamedObject
|
||||
{
|
||||
public ResourceReader m_VideoData;
|
||||
public string m_OriginalPath;
|
||||
public string m_Source;
|
||||
public ulong m_Size;
|
||||
public StreamedResource m_ExternalResources;
|
||||
|
||||
public VideoClip(ObjectReader reader) : base(reader)
|
||||
{
|
||||
@@ -32,20 +41,30 @@ namespace AssetStudio
|
||||
reader.AlignStream();
|
||||
var m_AudioSampleRate = reader.ReadUInt32Array();
|
||||
var m_AudioLanguage = reader.ReadStringArray();
|
||||
//StreamedResource m_ExternalResources
|
||||
m_Source = reader.ReadAlignedString();
|
||||
var m_Offset = reader.ReadUInt64();
|
||||
m_Size = reader.ReadUInt64();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_VideoShadersSize = reader.ReadInt32();
|
||||
var m_VideoShaders = new PPtr<Shader>[m_VideoShadersSize];
|
||||
for (int i = 0; i < m_VideoShadersSize; i++)
|
||||
{
|
||||
m_VideoShaders[i] = new PPtr<Shader>(reader);
|
||||
}
|
||||
}
|
||||
m_ExternalResources = new StreamedResource(reader);
|
||||
var m_HasSplitAlpha = reader.ReadBoolean();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_sRGB = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_Source))
|
||||
if (!string.IsNullOrEmpty(m_ExternalResources.m_Source))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_Source, assetsFile, (long)m_Offset, (int)m_Size);
|
||||
resourceReader = new ResourceReader(m_ExternalResources.m_Source, assetsFile, m_ExternalResources.m_Offset, (int)m_ExternalResources.m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size);
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_ExternalResources.m_Size);
|
||||
}
|
||||
m_VideoData = resourceReader;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,8 @@ namespace AssetStudio
|
||||
{1093, "m_CorrespondingSourceObject"},
|
||||
{1121, "m_PrefabInstance"},
|
||||
{1138, "m_PrefabAsset"},
|
||||
{1152, "FileSize"}
|
||||
{1152, "FileSize"},
|
||||
{1161, "Hash128"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,11 +72,6 @@ namespace AssetStudio
|
||||
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static System.Drawing.RectangleF ReadRectangleF(this BinaryReader reader)
|
||||
{
|
||||
return new System.Drawing.RectangleF(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static Color ReadColor4(this BinaryReader reader)
|
||||
{
|
||||
return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
@@ -102,6 +97,11 @@ namespace AssetStudio
|
||||
return ReadArray(reader.ReadBoolean, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static byte[] ReadUInt8Array(this BinaryReader reader)
|
||||
{
|
||||
return reader.ReadBytes(reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static ushort[] ReadUInt16Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt16, reader.ReadInt32());
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace AssetStudio
|
||||
foreach (var splitFile in splitFiles)
|
||||
{
|
||||
var destFile = Path.GetFileNameWithoutExtension(splitFile);
|
||||
var destPath = Path.GetDirectoryName(splitFile) + "\\";
|
||||
var destFull = destPath + destFile;
|
||||
var destPath = Path.GetDirectoryName(splitFile);
|
||||
var destFull = Path.Combine(destPath, destFile);
|
||||
if (!File.Exists(destFull))
|
||||
{
|
||||
var splitParts = Directory.GetFiles(destPath, destFile + ".split*");
|
||||
@@ -43,7 +43,7 @@ namespace AssetStudio
|
||||
public static string[] ProcessingSplitFiles(List<string> selectFile)
|
||||
{
|
||||
var splitFiles = selectFile.Where(x => x.Contains(".split"))
|
||||
.Select(x => Path.GetDirectoryName(x) + "\\" + Path.GetFileNameWithoutExtension(x))
|
||||
.Select(x => Path.Combine(Path.GetDirectoryName(x), Path.GetFileNameWithoutExtension(x)))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
selectFile.RemoveAll(x => x.Contains(".split"));
|
||||
@@ -65,7 +65,7 @@ namespace AssetStudio
|
||||
|
||||
public static FileType CheckFileType(string fileName, out EndianBinaryReader reader)
|
||||
{
|
||||
reader = new EndianBinaryReader(File.OpenRead(fileName));
|
||||
reader = new EndianBinaryReader(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
|
||||
return CheckFileType(reader);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,5 +14,13 @@ namespace AssetStudio
|
||||
public static void Info(string message) => Default.Log(LoggerEvent.Info, message);
|
||||
public static void Warning(string message) => Default.Log(LoggerEvent.Warning, message);
|
||||
public static void Error(string message) => Default.Log(LoggerEvent.Error, message);
|
||||
|
||||
public static void Error(string message, Exception e)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(message);
|
||||
sb.AppendLine(e.ToString());
|
||||
Default.Log(LoggerEvent.Error, sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@ namespace AssetStudio
|
||||
private BinaryReader reader;
|
||||
|
||||
|
||||
public ResourceReader(string path, SerializedFile assetsFile, long offset, int size)
|
||||
public ResourceReader(string path, SerializedFile assetsFile, ulong offset, int size)
|
||||
{
|
||||
needSearch = true;
|
||||
this.path = path;
|
||||
this.assetsFile = assetsFile;
|
||||
this.offset = offset;
|
||||
this.offset = (long)offset;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,15 +34,16 @@ namespace AssetStudio
|
||||
return newOutStream;
|
||||
}
|
||||
|
||||
public static void StreamDecompress(Stream inStream, Stream outStream, long inSize, long outSize)
|
||||
public static void StreamDecompress(Stream compressedStream, Stream decompressedStream, long compressedSize, long decompressedSize)
|
||||
{
|
||||
var basePosition = compressedStream.Position;
|
||||
var decoder = new Decoder();
|
||||
var properties = new byte[5];
|
||||
if (inStream.Read(properties, 0, 5) != 5)
|
||||
if (compressedStream.Read(properties, 0, 5) != 5)
|
||||
throw new Exception("input .lzma is too short");
|
||||
decoder.SetDecoderProperties(properties);
|
||||
inSize -= 5L;
|
||||
decoder.Code(inStream, outStream, inSize, outSize, null);
|
||||
decoder.Code(compressedStream, decompressedStream, compressedSize - 5, decompressedSize, null);
|
||||
compressedStream.Position = basePosition + compressedSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace AssetStudio
|
||||
{
|
||||
public class StreamFile
|
||||
{
|
||||
public string path;
|
||||
public string fileName;
|
||||
public Stream stream;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class TypeTreeHelper
|
||||
{
|
||||
public static void ReadTypeString(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader)
|
||||
public static void ReadTypeString(StringBuilder sb, List<TypeTreeNode> members, ObjectReader reader)
|
||||
{
|
||||
reader.Reset();
|
||||
for (int i = 0; i < members.Count; i++)
|
||||
{
|
||||
ReadStringValue(sb, members, reader, ref i);
|
||||
}
|
||||
var readed = reader.Position - reader.byteStart;
|
||||
if (readed != reader.byteSize)
|
||||
{
|
||||
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader, ref int i)
|
||||
@@ -151,15 +156,21 @@ namespace AssetStudio
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
public static UType ReadUType(List<TypeTreeNode> members, BinaryReader reader)
|
||||
public static OrderedDictionary ReadType(List<TypeTreeNode> members, ObjectReader reader)
|
||||
{
|
||||
var obj = new UType();
|
||||
reader.Reset();
|
||||
var obj = new OrderedDictionary();
|
||||
for (int i = 1; i < members.Count; i++)
|
||||
{
|
||||
var member = members[i];
|
||||
var varNameStr = member.m_Name;
|
||||
obj[varNameStr] = ReadValue(members, reader, ref i);
|
||||
}
|
||||
var readed = reader.Position - reader.byteStart;
|
||||
if (readed != reader.byteSize)
|
||||
{
|
||||
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -266,7 +277,7 @@ namespace AssetStudio
|
||||
{
|
||||
var @class = GetMembers(members, i);
|
||||
i += @class.Count - 1;
|
||||
var obj = new UType();
|
||||
var obj = new OrderedDictionary();
|
||||
for (int j = 1; j < @class.Count; j++)
|
||||
{
|
||||
var classmember = @class[j];
|
||||
|
||||
@@ -18,5 +18,15 @@ namespace AssetStudio
|
||||
public uint m_TypeStrOffset;
|
||||
public uint m_NameStrOffset;
|
||||
public ulong m_RefTypeHash;
|
||||
|
||||
public TypeTreeNode() { }
|
||||
|
||||
public TypeTreeNode(string type, string name, int level, bool align)
|
||||
{
|
||||
m_Type = type;
|
||||
m_Name = name;
|
||||
m_Level = level;
|
||||
m_MetaFlag = align ? 0x4000 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class UType : IDictionary<string, object>
|
||||
{
|
||||
private List<string> keys;
|
||||
private IDictionary<string, object> values;
|
||||
|
||||
public UType()
|
||||
{
|
||||
keys = new List<string>();
|
||||
values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public object this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!values.ContainsKey(key))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return values[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!values.ContainsKey(key))
|
||||
{
|
||||
keys.Add(key);
|
||||
}
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<string> Keys => keys;
|
||||
|
||||
public ICollection<object> Values => values.Values;
|
||||
|
||||
public int Count => keys.Count;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public void Add(string key, object value)
|
||||
{
|
||||
keys.Add(key);
|
||||
values.Add(key, value);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, object> item)
|
||||
{
|
||||
keys.Add(item.Key);
|
||||
values.Add(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
keys.Clear();
|
||||
values.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<string, object> item)
|
||||
{
|
||||
return values.Contains(item);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return values.ContainsKey(key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
|
||||
{
|
||||
values.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||
{
|
||||
return values.GetEnumerator();
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
keys.Remove(key);
|
||||
return values.Remove(key);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<string, object> item)
|
||||
{
|
||||
keys.Remove(item.Key);
|
||||
return values.Remove(item);
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out object value)
|
||||
{
|
||||
return values.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return values.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,7 @@ namespace AssetStudio
|
||||
{
|
||||
var data = dataList[i];
|
||||
var file = new StreamFile();
|
||||
file.path = data.path;
|
||||
file.fileName = Path.GetFileName(data.path);
|
||||
reader.BaseStream.Position = data.dataOffset;
|
||||
file.stream = new MemoryStream(reader.ReadBytes(data.dataLength));
|
||||
|
||||
@@ -98,15 +98,17 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AS_DLL;FBXSDK_SHARED;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_AS_DLL;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x86\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -115,16 +117,17 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AS_DLL;FBXSDK_SHARED;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_AS_DLL;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@@ -132,15 +135,17 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AS_DLL;FBXSDK_SHARED;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_AS_DLL;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -149,16 +154,17 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AS_DLL;FBXSDK_SHARED;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_AS_DLL;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
@@ -941,22 +941,22 @@ AS_API(int32_t) AsFbxAnimGetCurrentBlendShapeChannelCount(AsFbxAnimContext* pAni
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto lGeometry = dynamic_cast<FbxGeometry*>(pNode->GetNodeAttribute());
|
||||
pAnimContext->lGeometry = lGeometry;
|
||||
auto pMesh = pNode->GetMesh();
|
||||
pAnimContext->pMesh = pMesh;
|
||||
|
||||
if (lGeometry == nullptr)
|
||||
if (pMesh == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto blendShapeDeformerCount = lGeometry->GetDeformerCount(FbxDeformer::eBlendShape);
|
||||
auto blendShapeDeformerCount = pMesh->GetDeformerCount(FbxDeformer::eBlendShape);
|
||||
|
||||
if (blendShapeDeformerCount <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto lBlendShape = dynamic_cast<FbxBlendShape*>(lGeometry->GetDeformer(0, FbxDeformer::eBlendShape));
|
||||
auto lBlendShape = (FbxBlendShape*)pMesh->GetDeformer(0, FbxDeformer::eBlendShape);
|
||||
pAnimContext->lBlendShape = lBlendShape;
|
||||
|
||||
if (lBlendShape == nullptr)
|
||||
@@ -991,12 +991,12 @@ AS_API(bool32_t) AsFbxAnimIsBlendShapeChannelMatch(AsFbxAnimContext* pAnimContex
|
||||
|
||||
AS_API(void) AsFbxAnimBeginBlendShapeAnimCurve(AsFbxAnimContext* pAnimContext, int32_t channelIndex)
|
||||
{
|
||||
if (pAnimContext == nullptr || pAnimContext->lGeometry == nullptr || pAnimContext->lAnimLayer == nullptr)
|
||||
if (pAnimContext == nullptr || pAnimContext->pMesh == nullptr || pAnimContext->lAnimLayer == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pAnimContext->lAnimCurve = pAnimContext->lGeometry->GetShapeChannel(0, channelIndex, pAnimContext->lAnimLayer, true);
|
||||
pAnimContext->lAnimCurve = pAnimContext->pMesh->GetShapeChannel(0, channelIndex, pAnimContext->lAnimLayer, true);
|
||||
pAnimContext->lAnimCurve->KeyModifyBegin();
|
||||
}
|
||||
|
||||
@@ -1093,7 +1093,7 @@ AS_API(void) AsFbxMorphAddBlendShapeChannel(AsFbxContext* pContext, AsFbxMorphCo
|
||||
}
|
||||
}
|
||||
|
||||
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight)
|
||||
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight, const char* shapeName)
|
||||
{
|
||||
if (pContext == nullptr || pContext->pScene == nullptr)
|
||||
{
|
||||
@@ -1105,7 +1105,7 @@ AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMo
|
||||
return;
|
||||
}
|
||||
|
||||
auto lShape = FbxShape::Create(pContext->pScene, FbxString(weight));
|
||||
auto lShape = FbxShape::Create(pContext->pScene, shapeName);
|
||||
pMorphContext->lShape = lShape;
|
||||
|
||||
if (pMorphContext->lBlendShapeChannel != nullptr) {
|
||||
@@ -1126,12 +1126,9 @@ AS_API(void) AsFbxMorphCopyBlendShapeControlPoints(AsFbxMorphContext* pMorphCont
|
||||
|
||||
pMorphContext->lShape->InitControlPoints(vectorCount);
|
||||
|
||||
auto dstControlPoints = pMorphContext->lShape->GetControlPoints();
|
||||
|
||||
for (int j = 0; j < vectorCount; j++)
|
||||
{
|
||||
auto vertex = srcControlPoints[j];
|
||||
dstControlPoints[j] = FbxVector4(vertex);
|
||||
pMorphContext->lShape->SetControlPointAt(FbxVector4(srcControlPoints[j]), j);;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1142,7 +1139,25 @@ AS_API(void) AsFbxMorphSetBlendShapeVertex(AsFbxMorphContext* pMorphContext, uin
|
||||
return;
|
||||
}
|
||||
|
||||
auto pControlPoints = pMorphContext->lShape->GetControlPoints();
|
||||
|
||||
pControlPoints[index] = FbxVector4(x, y, z, 0);
|
||||
pMorphContext->lShape->SetControlPointAt(FbxVector4(x, y, z, 0), index);
|
||||
}
|
||||
|
||||
AS_API(void) AsFbxMorphCopyBlendShapeControlPointsNormal(AsFbxMorphContext* pMorphContext)
|
||||
{
|
||||
if (pMorphContext == nullptr || pMorphContext->pMesh == nullptr || pMorphContext->lShape == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pMorphContext->lShape->InitNormals(pMorphContext->pMesh);
|
||||
}
|
||||
|
||||
AS_API(void) AsFbxMorphSetBlendShapeVertexNormal(AsFbxMorphContext* pMorphContext, uint32_t index, float x, float y, float z)
|
||||
{
|
||||
if (pMorphContext == nullptr || pMorphContext->lShape == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pMorphContext->lShape->SetControlPointNormalAt(FbxVector4(x, y, z, 0), index);
|
||||
}
|
||||
|
||||
@@ -150,8 +150,12 @@ AS_API(void) AsFbxMorphDisposeContext(AsFbxMorphContext** ppMorphContext);
|
||||
|
||||
AS_API(void) AsFbxMorphAddBlendShapeChannel(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, const char* channelName);
|
||||
|
||||
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight);
|
||||
AS_API(void) AsFbxMorphAddBlendShapeChannelShape(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, float weight, const char* shapeName);
|
||||
|
||||
AS_API(void) AsFbxMorphCopyBlendShapeControlPoints(AsFbxMorphContext* pMorphContext);
|
||||
|
||||
AS_API(void) AsFbxMorphSetBlendShapeVertex(AsFbxMorphContext* pMorphContext, uint32_t index, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxMorphCopyBlendShapeControlPointsNormal(AsFbxMorphContext* pMorphContext);
|
||||
|
||||
AS_API(void) AsFbxMorphSetBlendShapeVertexNormal(AsFbxMorphContext* pMorphContext, uint32_t index, float x, float y, float z);
|
||||
|
||||
@@ -21,7 +21,7 @@ AsFbxAnimContext::AsFbxAnimContext(bool32_t eulerFilter)
|
||||
lCurveTY = nullptr;
|
||||
lCurveTZ = nullptr;
|
||||
|
||||
lGeometry = nullptr;
|
||||
pMesh = nullptr;
|
||||
lBlendShape = nullptr;
|
||||
lAnimCurve = nullptr;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ struct AsFbxAnimContext
|
||||
FbxAnimCurve* lCurveTY;
|
||||
FbxAnimCurve* lCurveTZ;
|
||||
|
||||
FbxGeometry* lGeometry;
|
||||
FbxMesh* pMesh;
|
||||
FbxBlendShape* lBlendShape;
|
||||
FbxAnimCurve* lAnimCurve;
|
||||
|
||||
|
||||
@@ -298,8 +298,16 @@ namespace AssetStudio.FbxInterop
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphAddBlendShapeChannel(IntPtr pContext, IntPtr pMorphContext, IntPtr strChannelName);
|
||||
|
||||
private static void AsFbxMorphAddBlendShapeChannelShape(IntPtr pContext, IntPtr pMorphContext, float weight, string shapeName)
|
||||
{
|
||||
using (var shapeNameUtf8 = new Utf8StringHandle(shapeName))
|
||||
{
|
||||
AsFbxMorphAddBlendShapeChannelShape(pContext, pMorphContext, weight, shapeNameUtf8.DangerousGetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphAddBlendShapeChannelShape(IntPtr pContext, IntPtr pMorphContext, float weight);
|
||||
private static extern void AsFbxMorphAddBlendShapeChannelShape(IntPtr pContext, IntPtr pMorphContext, float weight, IntPtr strShapeName);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphCopyBlendShapeControlPoints(IntPtr pMorphContext);
|
||||
@@ -307,5 +315,11 @@ namespace AssetStudio.FbxInterop
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphSetBlendShapeVertex(IntPtr pMorphContext, uint index, float x, float y, float z);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphCopyBlendShapeControlPointsNormal(IntPtr pMorphContext);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphSetBlendShapeVertexNormal(IntPtr pMorphContext, uint index, float x, float y, float z);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,9 +611,11 @@ namespace AssetStudio.FbxInterop
|
||||
{
|
||||
AsFbxMorphAddBlendShapeChannel(_pContext, pMorphContext, channel.Name);
|
||||
|
||||
foreach (var keyframe in channel.KeyframeList)
|
||||
for (var i = 0; i < channel.KeyframeList.Count; i++)
|
||||
{
|
||||
AsFbxMorphAddBlendShapeChannelShape(_pContext, pMorphContext, keyframe.Weight);
|
||||
var keyframe = channel.KeyframeList[i];
|
||||
|
||||
AsFbxMorphAddBlendShapeChannelShape(_pContext, pMorphContext, keyframe.Weight, i == 0 ? channel.Name : $"{channel.Name}_{i + 1}");
|
||||
|
||||
AsFbxMorphCopyBlendShapeControlPoints(pMorphContext);
|
||||
|
||||
@@ -622,6 +624,17 @@ namespace AssetStudio.FbxInterop
|
||||
var v = vertex.Vertex.Vertex;
|
||||
AsFbxMorphSetBlendShapeVertex(pMorphContext, vertex.Index, v.X, v.Y, v.Z);
|
||||
}
|
||||
|
||||
if (keyframe.hasNormals)
|
||||
{
|
||||
AsFbxMorphCopyBlendShapeControlPointsNormal(pMorphContext);
|
||||
|
||||
foreach (var vertex in keyframe.VertexList)
|
||||
{
|
||||
var v = vertex.Vertex.Normal;
|
||||
AsFbxMorphSetBlendShapeVertexNormal(pMorphContext, vertex.Index, v.X, v.Y, v.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=3.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\OpenTK.3.1.0\lib\net20\OpenTK.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -84,7 +87,6 @@
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Studio.cs" />
|
||||
<Compile Include="TGASharpLib.cs" />
|
||||
<EmbeddedResource Include="AssetStudioGUIForm.resx">
|
||||
<DependentUpon>AssetStudioGUIForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
@@ -127,18 +129,10 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>x86\fmod.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="Libraries\x86\libfbxsdk.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>x86\libfbxsdk.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="Libraries\x64\fmod.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>x64\fmod.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="Libraries\x64\libfbxsdk.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>x64\libfbxsdk.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
|
||||
|
||||
+141
-55
@@ -64,6 +64,11 @@
|
||||
this.toolStripMenuItem7 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem8 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem9 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripMenuItem10 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem11 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem13 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.filterTypeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.allToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.debugMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -87,6 +92,8 @@
|
||||
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.progressbarPanel = new System.Windows.Forms.Panel();
|
||||
this.progressBar1 = new System.Windows.Forms.ProgressBar();
|
||||
this.tabControl2 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage4 = new System.Windows.Forms.TabPage();
|
||||
this.previewPanel = new System.Windows.Forms.Panel();
|
||||
this.assetInfoLabel = new System.Windows.Forms.Label();
|
||||
this.FMODpanel = new System.Windows.Forms.Panel();
|
||||
@@ -101,15 +108,15 @@
|
||||
this.FMODpauseButton = new System.Windows.Forms.Button();
|
||||
this.FMODplayButton = new System.Windows.Forms.Button();
|
||||
this.fontPreviewBox = new System.Windows.Forms.RichTextBox();
|
||||
this.textPreviewBox = new System.Windows.Forms.TextBox();
|
||||
this.glControl1 = new OpenTK.GLControl();
|
||||
this.classPreviewPanel = new System.Windows.Forms.Panel();
|
||||
this.textPreviewBox = new System.Windows.Forms.TextBox();
|
||||
this.classTextBox = new System.Windows.Forms.TextBox();
|
||||
this.tabPage5 = new System.Windows.Forms.TabPage();
|
||||
this.dumpTextBox = new System.Windows.Forms.TextBox();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.timer = new System.Windows.Forms.Timer(this.components);
|
||||
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
|
||||
this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
|
||||
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exportSelectedAssetsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -126,11 +133,13 @@
|
||||
this.tabPage2.SuspendLayout();
|
||||
this.tabPage3.SuspendLayout();
|
||||
this.progressbarPanel.SuspendLayout();
|
||||
this.tabControl2.SuspendLayout();
|
||||
this.tabPage4.SuspendLayout();
|
||||
this.previewPanel.SuspendLayout();
|
||||
this.FMODpanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.FMODprogressBar)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.FMODvolumeBar)).BeginInit();
|
||||
this.classPreviewPanel.SuspendLayout();
|
||||
this.tabPage5.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.contextMenuStrip1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
@@ -310,7 +319,9 @@
|
||||
this.exportAnimatorWithSelectedAnimationClipToolStripMenuItem,
|
||||
this.toolStripSeparator4,
|
||||
this.toolStripMenuItem2,
|
||||
this.toolStripMenuItem3});
|
||||
this.toolStripMenuItem3,
|
||||
this.toolStripSeparator2,
|
||||
this.toolStripMenuItem10});
|
||||
this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
|
||||
this.exportToolStripMenuItem.Size = new System.Drawing.Size(58, 21);
|
||||
this.exportToolStripMenuItem.Text = "Export";
|
||||
@@ -415,6 +426,42 @@
|
||||
this.toolStripMenuItem9.Text = "Filtered assets";
|
||||
this.toolStripMenuItem9.Click += new System.EventHandler(this.toolStripMenuItem9_Click);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(396, 6);
|
||||
//
|
||||
// toolStripMenuItem10
|
||||
//
|
||||
this.toolStripMenuItem10.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripMenuItem11,
|
||||
this.toolStripMenuItem12,
|
||||
this.toolStripMenuItem13});
|
||||
this.toolStripMenuItem10.Name = "toolStripMenuItem10";
|
||||
this.toolStripMenuItem10.Size = new System.Drawing.Size(399, 34);
|
||||
this.toolStripMenuItem10.Text = "Asset list to XML";
|
||||
//
|
||||
// toolStripMenuItem11
|
||||
//
|
||||
this.toolStripMenuItem11.Name = "toolStripMenuItem11";
|
||||
this.toolStripMenuItem11.Size = new System.Drawing.Size(270, 34);
|
||||
this.toolStripMenuItem11.Text = "All assets";
|
||||
this.toolStripMenuItem11.Click += new System.EventHandler(this.toolStripMenuItem11_Click);
|
||||
//
|
||||
// toolStripMenuItem12
|
||||
//
|
||||
this.toolStripMenuItem12.Name = "toolStripMenuItem12";
|
||||
this.toolStripMenuItem12.Size = new System.Drawing.Size(270, 34);
|
||||
this.toolStripMenuItem12.Text = "Selected assets";
|
||||
this.toolStripMenuItem12.Click += new System.EventHandler(this.toolStripMenuItem12_Click);
|
||||
//
|
||||
// toolStripMenuItem13
|
||||
//
|
||||
this.toolStripMenuItem13.Name = "toolStripMenuItem13";
|
||||
this.toolStripMenuItem13.Size = new System.Drawing.Size(270, 34);
|
||||
this.toolStripMenuItem13.Text = "Filtered assets";
|
||||
this.toolStripMenuItem13.Click += new System.EventHandler(this.toolStripMenuItem13_Click);
|
||||
//
|
||||
// filterTypeToolStripMenuItem
|
||||
//
|
||||
this.filterTypeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
@@ -463,8 +510,7 @@
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.previewPanel);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.classPreviewPanel);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.tabControl2);
|
||||
this.splitContainer1.Panel2.Controls.Add(this.statusStrip1);
|
||||
this.splitContainer1.Panel2MinSize = 400;
|
||||
this.splitContainer1.Size = new System.Drawing.Size(1264, 656);
|
||||
@@ -653,6 +699,28 @@
|
||||
this.progressBar1.Step = 1;
|
||||
this.progressBar1.TabIndex = 1;
|
||||
//
|
||||
// tabControl2
|
||||
//
|
||||
this.tabControl2.Controls.Add(this.tabPage4);
|
||||
this.tabControl2.Controls.Add(this.tabPage5);
|
||||
this.tabControl2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabControl2.Location = new System.Drawing.Point(0, 0);
|
||||
this.tabControl2.Name = "tabControl2";
|
||||
this.tabControl2.SelectedIndex = 0;
|
||||
this.tabControl2.Size = new System.Drawing.Size(776, 632);
|
||||
this.tabControl2.TabIndex = 4;
|
||||
this.tabControl2.SelectedIndexChanged += new System.EventHandler(this.tabControl2_SelectedIndexChanged);
|
||||
//
|
||||
// tabPage4
|
||||
//
|
||||
this.tabPage4.Controls.Add(this.previewPanel);
|
||||
this.tabPage4.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage4.Name = "tabPage4";
|
||||
this.tabPage4.Size = new System.Drawing.Size(768, 606);
|
||||
this.tabPage4.TabIndex = 0;
|
||||
this.tabPage4.Text = "Preview";
|
||||
this.tabPage4.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// previewPanel
|
||||
//
|
||||
this.previewPanel.BackColor = System.Drawing.SystemColors.ControlDark;
|
||||
@@ -661,12 +729,13 @@
|
||||
this.previewPanel.Controls.Add(this.assetInfoLabel);
|
||||
this.previewPanel.Controls.Add(this.FMODpanel);
|
||||
this.previewPanel.Controls.Add(this.fontPreviewBox);
|
||||
this.previewPanel.Controls.Add(this.textPreviewBox);
|
||||
this.previewPanel.Controls.Add(this.glControl1);
|
||||
this.previewPanel.Controls.Add(this.textPreviewBox);
|
||||
this.previewPanel.Controls.Add(this.classTextBox);
|
||||
this.previewPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.previewPanel.Location = new System.Drawing.Point(0, 0);
|
||||
this.previewPanel.Name = "previewPanel";
|
||||
this.previewPanel.Size = new System.Drawing.Size(776, 632);
|
||||
this.previewPanel.Size = new System.Drawing.Size(768, 606);
|
||||
this.previewPanel.TabIndex = 1;
|
||||
this.previewPanel.Resize += new System.EventHandler(this.preview_Resize);
|
||||
//
|
||||
@@ -696,7 +765,7 @@
|
||||
this.FMODpanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.FMODpanel.Location = new System.Drawing.Point(0, 0);
|
||||
this.FMODpanel.Name = "FMODpanel";
|
||||
this.FMODpanel.Size = new System.Drawing.Size(776, 632);
|
||||
this.FMODpanel.Size = new System.Drawing.Size(768, 606);
|
||||
this.FMODpanel.TabIndex = 2;
|
||||
this.FMODpanel.Visible = false;
|
||||
//
|
||||
@@ -704,7 +773,7 @@
|
||||
//
|
||||
this.FMODcopyright.AutoSize = true;
|
||||
this.FMODcopyright.ForeColor = System.Drawing.SystemColors.ControlLight;
|
||||
this.FMODcopyright.Location = new System.Drawing.Point(232, 350);
|
||||
this.FMODcopyright.Location = new System.Drawing.Point(214, 337);
|
||||
this.FMODcopyright.Name = "FMODcopyright";
|
||||
this.FMODcopyright.Size = new System.Drawing.Size(341, 12);
|
||||
this.FMODcopyright.TabIndex = 9;
|
||||
@@ -714,7 +783,7 @@
|
||||
//
|
||||
this.FMODinfoLabel.AutoSize = true;
|
||||
this.FMODinfoLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
|
||||
this.FMODinfoLabel.Location = new System.Drawing.Point(287, 248);
|
||||
this.FMODinfoLabel.Location = new System.Drawing.Point(269, 235);
|
||||
this.FMODinfoLabel.Name = "FMODinfoLabel";
|
||||
this.FMODinfoLabel.Size = new System.Drawing.Size(0, 12);
|
||||
this.FMODinfoLabel.TabIndex = 8;
|
||||
@@ -722,7 +791,7 @@
|
||||
// FMODtimerLabel
|
||||
//
|
||||
this.FMODtimerLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
|
||||
this.FMODtimerLabel.Location = new System.Drawing.Point(422, 248);
|
||||
this.FMODtimerLabel.Location = new System.Drawing.Point(404, 235);
|
||||
this.FMODtimerLabel.Name = "FMODtimerLabel";
|
||||
this.FMODtimerLabel.Size = new System.Drawing.Size(155, 12);
|
||||
this.FMODtimerLabel.TabIndex = 7;
|
||||
@@ -732,7 +801,7 @@
|
||||
// FMODstatusLabel
|
||||
//
|
||||
this.FMODstatusLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight;
|
||||
this.FMODstatusLabel.Location = new System.Drawing.Point(231, 248);
|
||||
this.FMODstatusLabel.Location = new System.Drawing.Point(213, 235);
|
||||
this.FMODstatusLabel.Name = "FMODstatusLabel";
|
||||
this.FMODstatusLabel.Size = new System.Drawing.Size(50, 12);
|
||||
this.FMODstatusLabel.TabIndex = 6;
|
||||
@@ -741,7 +810,7 @@
|
||||
// FMODprogressBar
|
||||
//
|
||||
this.FMODprogressBar.AutoSize = false;
|
||||
this.FMODprogressBar.Location = new System.Drawing.Point(231, 266);
|
||||
this.FMODprogressBar.Location = new System.Drawing.Point(213, 253);
|
||||
this.FMODprogressBar.Maximum = 1000;
|
||||
this.FMODprogressBar.Name = "FMODprogressBar";
|
||||
this.FMODprogressBar.Size = new System.Drawing.Size(350, 22);
|
||||
@@ -754,7 +823,7 @@
|
||||
// FMODvolumeBar
|
||||
//
|
||||
this.FMODvolumeBar.LargeChange = 2;
|
||||
this.FMODvolumeBar.Location = new System.Drawing.Point(478, 293);
|
||||
this.FMODvolumeBar.Location = new System.Drawing.Point(460, 280);
|
||||
this.FMODvolumeBar.Name = "FMODvolumeBar";
|
||||
this.FMODvolumeBar.Size = new System.Drawing.Size(104, 45);
|
||||
this.FMODvolumeBar.TabIndex = 4;
|
||||
@@ -765,7 +834,7 @@
|
||||
// FMODloopButton
|
||||
//
|
||||
this.FMODloopButton.Appearance = System.Windows.Forms.Appearance.Button;
|
||||
this.FMODloopButton.Location = new System.Drawing.Point(417, 293);
|
||||
this.FMODloopButton.Location = new System.Drawing.Point(399, 280);
|
||||
this.FMODloopButton.Name = "FMODloopButton";
|
||||
this.FMODloopButton.Size = new System.Drawing.Size(55, 42);
|
||||
this.FMODloopButton.TabIndex = 3;
|
||||
@@ -776,7 +845,7 @@
|
||||
//
|
||||
// FMODstopButton
|
||||
//
|
||||
this.FMODstopButton.Location = new System.Drawing.Point(356, 293);
|
||||
this.FMODstopButton.Location = new System.Drawing.Point(338, 280);
|
||||
this.FMODstopButton.Name = "FMODstopButton";
|
||||
this.FMODstopButton.Size = new System.Drawing.Size(55, 42);
|
||||
this.FMODstopButton.TabIndex = 2;
|
||||
@@ -786,7 +855,7 @@
|
||||
//
|
||||
// FMODpauseButton
|
||||
//
|
||||
this.FMODpauseButton.Location = new System.Drawing.Point(295, 293);
|
||||
this.FMODpauseButton.Location = new System.Drawing.Point(277, 280);
|
||||
this.FMODpauseButton.Name = "FMODpauseButton";
|
||||
this.FMODpauseButton.Size = new System.Drawing.Size(55, 42);
|
||||
this.FMODpauseButton.TabIndex = 1;
|
||||
@@ -796,7 +865,7 @@
|
||||
//
|
||||
// FMODplayButton
|
||||
//
|
||||
this.FMODplayButton.Location = new System.Drawing.Point(234, 293);
|
||||
this.FMODplayButton.Location = new System.Drawing.Point(216, 280);
|
||||
this.FMODplayButton.Name = "FMODplayButton";
|
||||
this.FMODplayButton.Size = new System.Drawing.Size(55, 42);
|
||||
this.FMODplayButton.TabIndex = 0;
|
||||
@@ -811,33 +880,19 @@
|
||||
this.fontPreviewBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.fontPreviewBox.Name = "fontPreviewBox";
|
||||
this.fontPreviewBox.ReadOnly = true;
|
||||
this.fontPreviewBox.Size = new System.Drawing.Size(776, 632);
|
||||
this.fontPreviewBox.Size = new System.Drawing.Size(768, 606);
|
||||
this.fontPreviewBox.TabIndex = 0;
|
||||
this.fontPreviewBox.Text = resources.GetString("fontPreviewBox.Text");
|
||||
this.fontPreviewBox.Visible = false;
|
||||
this.fontPreviewBox.WordWrap = false;
|
||||
//
|
||||
// textPreviewBox
|
||||
//
|
||||
this.textPreviewBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.textPreviewBox.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.textPreviewBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.textPreviewBox.Multiline = true;
|
||||
this.textPreviewBox.Name = "textPreviewBox";
|
||||
this.textPreviewBox.ReadOnly = true;
|
||||
this.textPreviewBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.textPreviewBox.Size = new System.Drawing.Size(776, 632);
|
||||
this.textPreviewBox.TabIndex = 2;
|
||||
this.textPreviewBox.Visible = false;
|
||||
this.textPreviewBox.WordWrap = false;
|
||||
//
|
||||
// glControl1
|
||||
//
|
||||
this.glControl1.BackColor = System.Drawing.SystemColors.ControlDarkDark;
|
||||
this.glControl1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.glControl1.Location = new System.Drawing.Point(0, 0);
|
||||
this.glControl1.Name = "glControl1";
|
||||
this.glControl1.Size = new System.Drawing.Size(776, 632);
|
||||
this.glControl1.Size = new System.Drawing.Size(768, 606);
|
||||
this.glControl1.TabIndex = 4;
|
||||
this.glControl1.Visible = false;
|
||||
this.glControl1.VSync = false;
|
||||
@@ -848,15 +903,19 @@
|
||||
this.glControl1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseUp);
|
||||
this.glControl1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseWheel);
|
||||
//
|
||||
// classPreviewPanel
|
||||
// textPreviewBox
|
||||
//
|
||||
this.classPreviewPanel.Controls.Add(this.classTextBox);
|
||||
this.classPreviewPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.classPreviewPanel.Location = new System.Drawing.Point(0, 0);
|
||||
this.classPreviewPanel.Name = "classPreviewPanel";
|
||||
this.classPreviewPanel.Size = new System.Drawing.Size(776, 632);
|
||||
this.classPreviewPanel.TabIndex = 3;
|
||||
this.classPreviewPanel.Visible = false;
|
||||
this.textPreviewBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.textPreviewBox.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.textPreviewBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.textPreviewBox.Multiline = true;
|
||||
this.textPreviewBox.Name = "textPreviewBox";
|
||||
this.textPreviewBox.ReadOnly = true;
|
||||
this.textPreviewBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.textPreviewBox.Size = new System.Drawing.Size(768, 606);
|
||||
this.textPreviewBox.TabIndex = 2;
|
||||
this.textPreviewBox.Visible = false;
|
||||
this.textPreviewBox.WordWrap = false;
|
||||
//
|
||||
// classTextBox
|
||||
//
|
||||
@@ -866,10 +925,33 @@
|
||||
this.classTextBox.Name = "classTextBox";
|
||||
this.classTextBox.ReadOnly = true;
|
||||
this.classTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.classTextBox.Size = new System.Drawing.Size(776, 632);
|
||||
this.classTextBox.Size = new System.Drawing.Size(768, 606);
|
||||
this.classTextBox.TabIndex = 3;
|
||||
this.classTextBox.Visible = false;
|
||||
this.classTextBox.WordWrap = false;
|
||||
//
|
||||
// tabPage5
|
||||
//
|
||||
this.tabPage5.Controls.Add(this.dumpTextBox);
|
||||
this.tabPage5.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage5.Name = "tabPage5";
|
||||
this.tabPage5.Size = new System.Drawing.Size(768, 606);
|
||||
this.tabPage5.TabIndex = 1;
|
||||
this.tabPage5.Text = "Dump";
|
||||
this.tabPage5.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// dumpTextBox
|
||||
//
|
||||
this.dumpTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.dumpTextBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.dumpTextBox.Multiline = true;
|
||||
this.dumpTextBox.Name = "dumpTextBox";
|
||||
this.dumpTextBox.ReadOnly = true;
|
||||
this.dumpTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.dumpTextBox.Size = new System.Drawing.Size(768, 606);
|
||||
this.dumpTextBox.TabIndex = 0;
|
||||
this.dumpTextBox.WordWrap = false;
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
@@ -901,11 +983,6 @@
|
||||
this.openFileDialog1.Multiselect = true;
|
||||
this.openFileDialog1.RestoreDirectory = true;
|
||||
//
|
||||
// saveFileDialog1
|
||||
//
|
||||
this.saveFileDialog1.Filter = "FBX file|*.fbx";
|
||||
this.saveFileDialog1.RestoreDirectory = true;
|
||||
//
|
||||
// contextMenuStrip1
|
||||
//
|
||||
this.contextMenuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
@@ -922,7 +999,7 @@
|
||||
//
|
||||
this.copyToolStripMenuItem.Name = "copyToolStripMenuItem";
|
||||
this.copyToolStripMenuItem.Size = new System.Drawing.Size(326, 22);
|
||||
this.copyToolStripMenuItem.Text = "Copy";
|
||||
this.copyToolStripMenuItem.Text = "Copy text";
|
||||
this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click);
|
||||
//
|
||||
// exportSelectedAssetsToolStripMenuItem
|
||||
@@ -988,14 +1065,16 @@
|
||||
this.tabPage2.PerformLayout();
|
||||
this.tabPage3.ResumeLayout(false);
|
||||
this.progressbarPanel.ResumeLayout(false);
|
||||
this.tabControl2.ResumeLayout(false);
|
||||
this.tabPage4.ResumeLayout(false);
|
||||
this.previewPanel.ResumeLayout(false);
|
||||
this.previewPanel.PerformLayout();
|
||||
this.FMODpanel.ResumeLayout(false);
|
||||
this.FMODpanel.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.FMODprogressBar)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.FMODvolumeBar)).EndInit();
|
||||
this.classPreviewPanel.ResumeLayout(false);
|
||||
this.classPreviewPanel.PerformLayout();
|
||||
this.tabPage5.ResumeLayout(false);
|
||||
this.tabPage5.PerformLayout();
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.contextMenuStrip1.ResumeLayout(false);
|
||||
@@ -1052,7 +1131,6 @@
|
||||
private System.Windows.Forms.ToolStripMenuItem extractFileToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem extractFolderToolStripMenuItem;
|
||||
private System.Windows.Forms.OpenFileDialog openFileDialog1;
|
||||
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
|
||||
private System.Windows.Forms.ToolStripMenuItem showExpOpt;
|
||||
private GOHierarchy sceneTreeView;
|
||||
private System.Windows.Forms.ToolStripMenuItem debugMenuItem;
|
||||
@@ -1060,7 +1138,6 @@
|
||||
private System.Windows.Forms.ListView classesListView;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader2;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||
private System.Windows.Forms.Panel classPreviewPanel;
|
||||
private System.Windows.Forms.TextBox classTextBox;
|
||||
private System.Windows.Forms.ToolStripMenuItem exportClassStructuresMenuItem;
|
||||
private System.Windows.Forms.Label FMODcopyright;
|
||||
@@ -1092,6 +1169,15 @@
|
||||
private System.Windows.Forms.ColumnHeader columnHeaderContainer;
|
||||
private System.Windows.Forms.ColumnHeader columnHeaderPathID;
|
||||
private System.Windows.Forms.ToolStripMenuItem copyToolStripMenuItem;
|
||||
private System.Windows.Forms.TabControl tabControl2;
|
||||
private System.Windows.Forms.TabPage tabPage4;
|
||||
private System.Windows.Forms.TabPage tabPage5;
|
||||
private System.Windows.Forms.TextBox dumpTextBox;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
||||
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem10;
|
||||
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem11;
|
||||
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem12;
|
||||
private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem13;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AssetStudio;
|
||||
using Newtonsoft.Json;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
@@ -27,7 +28,6 @@ namespace AssetStudioGUI
|
||||
partial class AssetStudioGUIForm : Form
|
||||
{
|
||||
private AssetItem lastSelectedItem;
|
||||
private AssetItem lastLoadedAsset;
|
||||
private Bitmap imageTexture;
|
||||
private string tempClipboard;
|
||||
|
||||
@@ -150,21 +150,36 @@ namespace AssetStudioGUI
|
||||
}
|
||||
}
|
||||
|
||||
private void extractFileToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private async void extractFileToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (openFileDialog1.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
ExtractFile(openFileDialog1.FileNames);
|
||||
var saveFolderDialog = new OpenFolderDialog();
|
||||
saveFolderDialog.Title = "Select the save folder";
|
||||
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var fileNames = openFileDialog1.FileNames;
|
||||
var savePath = saveFolderDialog.Folder;
|
||||
var extractedCount = await Task.Run(() => ExtractFile(fileNames, savePath));
|
||||
StatusStripUpdate($"Finished extracting {extractedCount} files.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractFolderToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private async void extractFolderToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var openFolderDialog1 = new OpenFolderDialog();
|
||||
if (openFolderDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
var openFolderDialog = new OpenFolderDialog();
|
||||
if (openFolderDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var files = Directory.GetFiles(openFolderDialog1.Folder, "*.*", SearchOption.AllDirectories);
|
||||
ExtractFile(files);
|
||||
var saveFolderDialog = new OpenFolderDialog();
|
||||
saveFolderDialog.Title = "Select the save folder";
|
||||
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var path = openFolderDialog.Folder;
|
||||
var savePath = saveFolderDialog.Folder;
|
||||
var extractedCount = await Task.Run(() => ExtractFolder(path, savePath));
|
||||
StatusStripUpdate($"Finished extracting {extractedCount} files.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,31 +302,31 @@ namespace AssetStudioGUI
|
||||
{
|
||||
if (e.Control)
|
||||
{
|
||||
bool dirty = false;
|
||||
var need = false;
|
||||
switch (e.KeyCode)
|
||||
{
|
||||
case Keys.B:
|
||||
textureChannels[0] = !textureChannels[0];
|
||||
dirty = true;
|
||||
need = true;
|
||||
break;
|
||||
case Keys.G:
|
||||
textureChannels[1] = !textureChannels[1];
|
||||
dirty = true;
|
||||
need = true;
|
||||
break;
|
||||
case Keys.R:
|
||||
textureChannels[2] = !textureChannels[2];
|
||||
dirty = true;
|
||||
need = true;
|
||||
break;
|
||||
case Keys.A:
|
||||
textureChannels[3] = !textureChannels[3];
|
||||
dirty = true;
|
||||
need = true;
|
||||
break;
|
||||
}
|
||||
if (dirty)
|
||||
if (need)
|
||||
{
|
||||
PreviewAsset(lastLoadedAsset);
|
||||
if (lastSelectedItem != null && assetInfoLabel.Text != null)
|
||||
if (lastSelectedItem != null)
|
||||
{
|
||||
PreviewAsset(lastSelectedItem);
|
||||
assetInfoLabel.Text = lastSelectedItem.InfoText;
|
||||
}
|
||||
}
|
||||
@@ -332,7 +347,7 @@ namespace AssetStudioGUI
|
||||
Progress.Reset();
|
||||
foreach (TypeTreeItem item in classesListView.Items)
|
||||
{
|
||||
var versionPath = savePath + "\\" + item.Group.Header;
|
||||
var versionPath = Path.Combine(savePath, item.Group.Header);
|
||||
Directory.CreateDirectory(versionPath);
|
||||
|
||||
var saveFile = $"{versionPath}\\{item.SubItems[1].Text} {item.Text}.txt";
|
||||
@@ -354,9 +369,9 @@ namespace AssetStudioGUI
|
||||
|
||||
private void enablePreview_Check(object sender, EventArgs e)
|
||||
{
|
||||
if (lastLoadedAsset != null)
|
||||
if (lastSelectedItem != null)
|
||||
{
|
||||
switch (lastLoadedAsset.Type)
|
||||
switch (lastSelectedItem.Type)
|
||||
{
|
||||
case ClassIDType.Texture2D:
|
||||
case ClassIDType.Sprite:
|
||||
@@ -395,7 +410,7 @@ namespace AssetStudioGUI
|
||||
}
|
||||
else if (FMODpanel.Visible)
|
||||
{
|
||||
PreviewAsset(lastLoadedAsset);
|
||||
PreviewAsset(lastSelectedItem);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -406,8 +421,7 @@ namespace AssetStudioGUI
|
||||
}
|
||||
else if (lastSelectedItem != null && enablePreview.Checked)
|
||||
{
|
||||
lastLoadedAsset = lastSelectedItem;
|
||||
PreviewAsset(lastLoadedAsset);
|
||||
PreviewAsset(lastSelectedItem);
|
||||
}
|
||||
|
||||
Properties.Settings.Default.enablePreview = enablePreview.Checked;
|
||||
@@ -448,14 +462,8 @@ namespace AssetStudioGUI
|
||||
treeSearch.Select();
|
||||
break;
|
||||
case 1:
|
||||
classPreviewPanel.Visible = false;
|
||||
previewPanel.Visible = true;
|
||||
listSearch.Select();
|
||||
break;
|
||||
case 2:
|
||||
previewPanel.Visible = false;
|
||||
classPreviewPanel.Visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -617,13 +625,13 @@ namespace AssetStudioGUI
|
||||
{
|
||||
previewPanel.BackgroundImage = Properties.Resources.preview;
|
||||
previewPanel.BackgroundImageLayout = ImageLayout.Center;
|
||||
classTextBox.Visible = false;
|
||||
assetInfoLabel.Visible = false;
|
||||
assetInfoLabel.Text = null;
|
||||
textPreviewBox.Visible = false;
|
||||
fontPreviewBox.Visible = false;
|
||||
FMODpanel.Visible = false;
|
||||
glControl1.Visible = false;
|
||||
lastLoadedAsset = null;
|
||||
StatusStripUpdate("");
|
||||
|
||||
FMODreset();
|
||||
@@ -632,21 +640,32 @@ namespace AssetStudioGUI
|
||||
|
||||
if (e.IsSelected)
|
||||
{
|
||||
if (tabControl2.SelectedIndex == 1)
|
||||
{
|
||||
dumpTextBox.Text = DumpAsset(lastSelectedItem.Asset);
|
||||
}
|
||||
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;
|
||||
PreviewAsset(lastSelectedItem);
|
||||
if (displayInfo.Checked && lastSelectedItem.InfoText != null)
|
||||
{
|
||||
assetInfoLabel.Text = lastSelectedItem.InfoText;
|
||||
assetInfoLabel.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void classesListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
|
||||
{
|
||||
classTextBox.Visible = true;
|
||||
assetInfoLabel.Visible = false;
|
||||
assetInfoLabel.Text = null;
|
||||
textPreviewBox.Visible = false;
|
||||
fontPreviewBox.Visible = false;
|
||||
FMODpanel.Visible = false;
|
||||
glControl1.Visible = false;
|
||||
StatusStripUpdate("");
|
||||
if (e.IsSelected)
|
||||
{
|
||||
classTextBox.Text = ((TypeTreeItem)classesListView.SelectedItems[0]).ToString();
|
||||
@@ -880,10 +899,15 @@ namespace AssetStudioGUI
|
||||
var result = system.createSound(m_AudioData, FMOD.MODE.OPENMEMORY | loopMode, ref exinfo, out sound);
|
||||
if (ERRCHECK(result)) return;
|
||||
|
||||
result = sound.getSubSound(0, out var subsound);
|
||||
if (result == FMOD.RESULT.OK)
|
||||
sound.getNumSubSounds(out var numsubsounds);
|
||||
|
||||
if (numsubsounds > 0)
|
||||
{
|
||||
sound = subsound;
|
||||
result = sound.getSubSound(0, out var subsound);
|
||||
if (result == FMOD.RESULT.OK)
|
||||
{
|
||||
sound = subsound;
|
||||
}
|
||||
}
|
||||
|
||||
result = sound.getLength(out FMODlenms, FMOD.TIMEUNIT.MS);
|
||||
@@ -910,12 +934,20 @@ namespace AssetStudioGUI
|
||||
private void PreviewTextAsset(TextAsset m_TextAsset)
|
||||
{
|
||||
var text = Encoding.UTF8.GetString(m_TextAsset.m_Script);
|
||||
PreviewText(text.Replace("\n", "\r\n"));
|
||||
text = text.Replace("\n", "\r\n").Replace("\0", "");
|
||||
PreviewText(text);
|
||||
}
|
||||
|
||||
private void PreviewMonoBehaviour(MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
PreviewText(m_MonoBehaviour.Dump() ?? GetScriptString(m_MonoBehaviour.reader));
|
||||
var obj = m_MonoBehaviour.ToType();
|
||||
if (obj == null)
|
||||
{
|
||||
var nodes = MonoBehaviourToTypeTreeNodes(m_MonoBehaviour);
|
||||
obj = m_MonoBehaviour.ToType(nodes);
|
||||
}
|
||||
var str = JsonConvert.SerializeObject(obj, Formatting.Indented);
|
||||
PreviewText(str);
|
||||
}
|
||||
|
||||
private void PreviewFont(Font m_Font)
|
||||
@@ -1177,6 +1209,7 @@ namespace AssetStudioGUI
|
||||
{
|
||||
Text = $"AssetStudioGUI v{Application.ProductVersion}";
|
||||
assetsManager.Clear();
|
||||
assemblyLoader.Clear();
|
||||
exportableAssets.Clear();
|
||||
visibleAssets.Clear();
|
||||
sceneTreeView.Nodes.Clear();
|
||||
@@ -1193,7 +1226,6 @@ namespace AssetStudioGUI
|
||||
fontPreviewBox.Visible = false;
|
||||
glControl1.Visible = false;
|
||||
lastSelectedItem = null;
|
||||
lastLoadedAsset = null;
|
||||
sortColumn = -1;
|
||||
reverseSort = false;
|
||||
enableFiltering = false;
|
||||
@@ -1206,12 +1238,6 @@ namespace AssetStudioGUI
|
||||
}
|
||||
|
||||
FMODreset();
|
||||
|
||||
if (scriptDumper != null)
|
||||
{
|
||||
scriptDumper.Dispose();
|
||||
scriptDumper = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void assetListView_MouseClick(object sender, MouseEventArgs e)
|
||||
@@ -1248,7 +1274,7 @@ namespace AssetStudioGUI
|
||||
|
||||
private void exportSelectedAssetsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(2, ExportType.Convert);
|
||||
ExportAssets(ExportFilter.Selected, ExportType.Convert);
|
||||
}
|
||||
|
||||
private void showOriginalFileToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
@@ -1278,10 +1304,10 @@ namespace AssetStudioGUI
|
||||
|
||||
if (animator != null)
|
||||
{
|
||||
var saveFolderDialog1 = new OpenFolderDialog();
|
||||
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
var saveFolderDialog = new OpenFolderDialog();
|
||||
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var exportPath = saveFolderDialog1.Folder + "\\Animator\\";
|
||||
var exportPath = saveFolderDialog.Folder + "\\Animator\\";
|
||||
ExportAnimatorWithAnimationClip(animator, animationList, exportPath);
|
||||
}
|
||||
}
|
||||
@@ -1301,10 +1327,10 @@ namespace AssetStudioGUI
|
||||
{
|
||||
if (sceneTreeView.Nodes.Count > 0)
|
||||
{
|
||||
var saveFolderDialog1 = new OpenFolderDialog();
|
||||
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
var saveFolderDialog = new OpenFolderDialog();
|
||||
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var exportPath = saveFolderDialog1.Folder + "\\GameObject\\";
|
||||
var exportPath = saveFolderDialog.Folder + "\\GameObject\\";
|
||||
List<AssetItem> animationList = null;
|
||||
if (animation)
|
||||
{
|
||||
@@ -1372,57 +1398,72 @@ namespace AssetStudioGUI
|
||||
|
||||
private void exportAllAssetsMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(1, ExportType.Convert);
|
||||
ExportAssets(ExportFilter.All, ExportType.Convert);
|
||||
}
|
||||
|
||||
private void exportSelectedAssetsMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(2, ExportType.Convert);
|
||||
ExportAssets(ExportFilter.Selected, ExportType.Convert);
|
||||
}
|
||||
|
||||
private void exportFilteredAssetsMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(3, ExportType.Convert);
|
||||
ExportAssets(ExportFilter.Filtered, ExportType.Convert);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem4_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(1, ExportType.Raw);
|
||||
ExportAssets(ExportFilter.All, ExportType.Raw);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem5_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(2, ExportType.Raw);
|
||||
ExportAssets(ExportFilter.Selected, ExportType.Raw);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem6_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(3, ExportType.Raw);
|
||||
ExportAssets(ExportFilter.Filtered, ExportType.Raw);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem7_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(1, ExportType.Dump);
|
||||
ExportAssets(ExportFilter.All, ExportType.Dump);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem8_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(2, ExportType.Dump);
|
||||
ExportAssets(ExportFilter.Selected, ExportType.Dump);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem9_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssets(3, ExportType.Dump);
|
||||
ExportAssets(ExportFilter.Filtered, ExportType.Dump);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem11_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssetsList(ExportFilter.All);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem12_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssetsList(ExportFilter.Selected);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem13_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportAssetsList(ExportFilter.Filtered);
|
||||
}
|
||||
|
||||
private void exportAllObjectssplitToolStripMenuItem1_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (sceneTreeView.Nodes.Count > 0)
|
||||
{
|
||||
var saveFolderDialog1 = new OpenFolderDialog();
|
||||
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
var saveFolderDialog = new OpenFolderDialog();
|
||||
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var savePath = saveFolderDialog1.Folder + "\\";
|
||||
var savePath = saveFolderDialog.Folder + Path.DirectorySeparatorChar;
|
||||
ExportSplitObjects(savePath, sceneTreeView.Nodes);
|
||||
}
|
||||
}
|
||||
@@ -1475,29 +1516,62 @@ namespace AssetStudioGUI
|
||||
assetListView.EndUpdate();
|
||||
}
|
||||
|
||||
private void ExportAssets(int type, ExportType exportType)
|
||||
private void ExportAssets(ExportFilter type, ExportType exportType)
|
||||
{
|
||||
if (exportableAssets.Count > 0)
|
||||
{
|
||||
var saveFolderDialog1 = new OpenFolderDialog();
|
||||
if (saveFolderDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
var saveFolderDialog = new OpenFolderDialog();
|
||||
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
timer.Stop();
|
||||
|
||||
List<AssetItem> toExportAssets = null;
|
||||
switch (type)
|
||||
{
|
||||
case 1: //All Assets
|
||||
case ExportFilter.All:
|
||||
toExportAssets = exportableAssets;
|
||||
break;
|
||||
case 2: //Selected Assets
|
||||
case ExportFilter.Selected:
|
||||
toExportAssets = GetSelectedAssets();
|
||||
break;
|
||||
case 3: //Filtered Assets
|
||||
case ExportFilter.Filtered:
|
||||
toExportAssets = visibleAssets;
|
||||
break;
|
||||
}
|
||||
Studio.ExportAssets(saveFolderDialog1.Folder, toExportAssets, exportType);
|
||||
Studio.ExportAssets(saveFolderDialog.Folder, toExportAssets, exportType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusStripUpdate("No exportable assets loaded");
|
||||
}
|
||||
}
|
||||
|
||||
private void ExportAssetsList(ExportFilter type)
|
||||
{
|
||||
// XXX: Only exporting as XML for now, but would JSON(/CSV/other) be useful too?
|
||||
|
||||
if (exportableAssets.Count > 0)
|
||||
{
|
||||
var saveFolderDialog = new OpenFolderDialog();
|
||||
if (saveFolderDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
timer.Stop();
|
||||
|
||||
List<AssetItem> toExportAssets = null;
|
||||
switch (type)
|
||||
{
|
||||
case ExportFilter.All:
|
||||
toExportAssets = exportableAssets;
|
||||
break;
|
||||
case ExportFilter.Selected:
|
||||
toExportAssets = GetSelectedAssets();
|
||||
break;
|
||||
case ExportFilter.Filtered:
|
||||
toExportAssets = visibleAssets;
|
||||
break;
|
||||
}
|
||||
Studio.ExportAssetsList(saveFolderDialog.Folder, toExportAssets, ExportListType.XML);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1522,7 +1596,7 @@ namespace AssetStudioGUI
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
result = system.init(1, FMOD.INITFLAGS.NORMAL, IntPtr.Zero);
|
||||
result = system.init(2, FMOD.INITFLAGS.NORMAL, IntPtr.Zero);
|
||||
if (ERRCHECK(result)) { return; }
|
||||
|
||||
result = system.getMasterSoundGroup(out masterSoundGroup);
|
||||
@@ -1934,6 +2008,14 @@ namespace AssetStudioGUI
|
||||
glControl1.SwapBuffers();
|
||||
}
|
||||
|
||||
private void tabControl2_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (tabControl2.SelectedIndex == 1 && lastSelectedItem != null)
|
||||
{
|
||||
dumpTextBox.Text = DumpAsset(lastSelectedItem.Asset);
|
||||
}
|
||||
}
|
||||
|
||||
private void glControl1_MouseWheel(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (glControl1.Visible)
|
||||
|
||||
@@ -120,9 +120,6 @@
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>312, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>432, 17</value>
|
||||
</metadata>
|
||||
<data name="fontPreviewBox.Text" xml:space="preserve">
|
||||
<value>abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ
|
||||
1234567890.:,;'\"(!?)+-*/=
|
||||
@@ -141,15 +138,15 @@ The quick brown fox jumps over the lazy dog. 1234567890
|
||||
|
||||
The quick brown fox jumps over the lazy dog. 1234567890</value>
|
||||
</data>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>432, 17</value>
|
||||
</metadata>
|
||||
<metadata name="timer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>553, 17</value>
|
||||
</metadata>
|
||||
<metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>636, 17</value>
|
||||
</metadata>
|
||||
<metadata name="saveFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>784, 17</value>
|
||||
</metadata>
|
||||
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>147, 17</value>
|
||||
</metadata>
|
||||
|
||||
+82
-68
@@ -4,13 +4,14 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AssetStudio;
|
||||
using Newtonsoft.Json;
|
||||
using TGASharpLib;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
internal static class Exporter
|
||||
{
|
||||
public static bool ExportTexture2D(AssetItem item, string exportPathName)
|
||||
public static bool ExportTexture2D(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_Texture2D = (Texture2D)item.Asset;
|
||||
if (Properties.Settings.Default.convertTexture)
|
||||
@@ -36,25 +37,25 @@ namespace AssetStudioGUI
|
||||
tga = true;
|
||||
break;
|
||||
}
|
||||
var exportFullName = exportPathName + item.Text + "." + ext.ToLower();
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, "." + ext.ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
if (tga)
|
||||
{
|
||||
var file = new TGA(bitmap);
|
||||
file.Save(exportFullName);
|
||||
file.Save(exportFullPath);
|
||||
}
|
||||
else
|
||||
bitmap.Save(exportFullName, format);
|
||||
{
|
||||
bitmap.Save(exportFullPath, format);
|
||||
}
|
||||
bitmap.Dispose();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var exportFullName = exportPathName + item.Text + ".tex";
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, m_Texture2D.image_data.GetData());
|
||||
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -68,44 +69,29 @@ namespace AssetStudioGUI
|
||||
var converter = new AudioClipConverter(m_AudioClip);
|
||||
if (Properties.Settings.Default.convertAudio && converter.IsSupport)
|
||||
{
|
||||
var exportFullName = exportPath + item.Text + ".wav";
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".wav", out var exportFullPath))
|
||||
return false;
|
||||
var buffer = converter.ConvertToWav();
|
||||
if (buffer == null)
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, buffer);
|
||||
File.WriteAllBytes(exportFullPath, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var exportFullName = exportPath + item.Text + converter.GetExtensionName();
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, converter.GetExtensionName(), out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, m_AudioData);
|
||||
File.WriteAllBytes(exportFullPath, m_AudioData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportShader(AssetItem item, string exportPath)
|
||||
{
|
||||
var exportFullName = exportPath + item.Text + ".shader";
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".shader", out var exportFullPath))
|
||||
return false;
|
||||
var m_Shader = (Shader)item.Asset;
|
||||
if (m_Shader.compressedBlob != null) //5.5 and up
|
||||
{
|
||||
var strs = ShaderConverter.ConvertMultiple(m_Shader);
|
||||
for (int i = 0; i < strs.Length; i++)
|
||||
{
|
||||
var platformName = ShaderConverter.GetPlatformString(m_Shader.platforms[i]);
|
||||
File.WriteAllText($"{exportPath}{item.Text}_{platformName}.shader", strs[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var str = ShaderConverter.Convert(m_Shader);
|
||||
File.WriteAllText(exportFullName, str);
|
||||
}
|
||||
var str = m_Shader.Convert();
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -120,21 +106,25 @@ namespace AssetStudioGUI
|
||||
extension = Path.GetExtension(item.Container);
|
||||
}
|
||||
}
|
||||
var exportFullName = exportPath + item.Text + extension;
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, m_TextAsset.m_Script);
|
||||
File.WriteAllBytes(exportFullPath, m_TextAsset.m_Script);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportMonoBehaviour(AssetItem item, string exportPath)
|
||||
{
|
||||
var exportFullName = exportPath + item.Text + ".txt";
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".json", out var exportFullPath))
|
||||
return false;
|
||||
var m_MonoBehaviour = (MonoBehaviour)item.Asset;
|
||||
var str = m_MonoBehaviour.Dump() ?? Studio.GetScriptString(item.Asset.reader);
|
||||
File.WriteAllText(exportFullName, str);
|
||||
var type = m_MonoBehaviour.ToType();
|
||||
if (type == null)
|
||||
{
|
||||
var nodes = Studio.MonoBehaviourToTypeTreeNodes(m_MonoBehaviour);
|
||||
type = m_MonoBehaviour.ToType(nodes);
|
||||
}
|
||||
var str = JsonConvert.SerializeObject(type, Formatting.Indented);
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -148,10 +138,9 @@ namespace AssetStudioGUI
|
||||
{
|
||||
extension = ".otf";
|
||||
}
|
||||
var exportFullName = exportPath + item.Text + extension;
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, extension, out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, m_Font.m_FontData);
|
||||
File.WriteAllBytes(exportFullPath, m_Font.m_FontData);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -162,8 +151,7 @@ namespace AssetStudioGUI
|
||||
var m_Mesh = (Mesh)item.Asset;
|
||||
if (m_Mesh.m_VertexCount <= 0)
|
||||
return false;
|
||||
var exportFullName = exportPath + item.Text + ".obj";
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".obj", out var exportFullPath))
|
||||
return false;
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("g " + m_Mesh.m_Name);
|
||||
@@ -235,7 +223,7 @@ namespace AssetStudioGUI
|
||||
#endregion
|
||||
|
||||
sb.Replace("NaN", "0");
|
||||
File.WriteAllText(exportFullName, sb.ToString());
|
||||
File.WriteAllText(exportFullPath, sb.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -245,10 +233,9 @@ namespace AssetStudioGUI
|
||||
var m_VideoData = m_VideoClip.m_VideoData.GetData();
|
||||
if (m_VideoData != null && m_VideoData.Length != 0)
|
||||
{
|
||||
var exportFullName = exportPath + item.Text + Path.GetExtension(m_VideoClip.m_OriginalPath);
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, Path.GetExtension(m_VideoClip.m_OriginalPath), out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, m_VideoData);
|
||||
File.WriteAllBytes(exportFullPath, m_VideoData);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -257,10 +244,9 @@ namespace AssetStudioGUI
|
||||
public static bool ExportMovieTexture(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_MovieTexture = (MovieTexture)item.Asset;
|
||||
var exportFullName = exportPath + item.Text + ".ogv";
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".ogv", out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, m_MovieTexture.m_MovieData);
|
||||
File.WriteAllBytes(exportFullPath, m_MovieTexture.m_MovieData);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -284,8 +270,7 @@ namespace AssetStudioGUI
|
||||
tga = true;
|
||||
break;
|
||||
}
|
||||
var exportFullName = exportPath + item.Text + "." + type.ToLower();
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
var bitmap = ((Sprite)item.Asset).GetImage();
|
||||
if (bitmap != null)
|
||||
@@ -293,10 +278,12 @@ namespace AssetStudioGUI
|
||||
if (tga)
|
||||
{
|
||||
var file = new TGA(bitmap);
|
||||
file.Save(exportFullName);
|
||||
file.Save(exportFullPath);
|
||||
}
|
||||
else
|
||||
bitmap.Save(exportFullName, format);
|
||||
{
|
||||
bitmap.Save(exportFullPath, format);
|
||||
}
|
||||
bitmap.Dispose();
|
||||
return true;
|
||||
}
|
||||
@@ -305,43 +292,60 @@ namespace AssetStudioGUI
|
||||
|
||||
public static bool ExportRawFile(AssetItem item, string exportPath)
|
||||
{
|
||||
var exportFullName = exportPath + item.Text + ".dat";
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".dat", out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, item.Asset.GetRawData());
|
||||
File.WriteAllBytes(exportFullPath, item.Asset.GetRawData());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool ExportFileExists(string filename)
|
||||
private static bool TryExportFile(string dir, AssetItem item, string extension, out string fullPath)
|
||||
{
|
||||
if (File.Exists(filename))
|
||||
var fileName = FixFileName(item.Text);
|
||||
fullPath = Path.Combine(dir, fileName + extension);
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
Directory.CreateDirectory(dir);
|
||||
return true;
|
||||
}
|
||||
fullPath = Path.Combine(dir, fileName + item.UniqueID + extension);
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
Directory.CreateDirectory(dir);
|
||||
return true;
|
||||
}
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportAnimator(AssetItem item, string exportPath, List<AssetItem> animationList = null)
|
||||
{
|
||||
var exportFullPath = Path.Combine(exportPath, item.Text, item.Text + ".fbx");
|
||||
if (File.Exists(exportFullPath))
|
||||
{
|
||||
exportFullPath = Path.Combine(exportPath, item.Text + item.UniqueID, item.Text + ".fbx");
|
||||
}
|
||||
var m_Animator = (Animator)item.Asset;
|
||||
var convert = animationList != null ? new ModelConverter(m_Animator, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(m_Animator);
|
||||
exportPath = $"{exportPath}{item.Text}\\{item.Text}.fbx";
|
||||
ExportFbx(convert, exportPath);
|
||||
var convert = animationList != null
|
||||
? new ModelConverter(m_Animator, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
|
||||
: new ModelConverter(m_Animator, Properties.Settings.Default.convertType);
|
||||
ExportFbx(convert, exportFullPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
|
||||
{
|
||||
var convert = animationList != null ? new ModelConverter(gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(gameObject);
|
||||
exportPath = exportPath + Studio.FixFileName(gameObject.m_Name) + ".fbx";
|
||||
var convert = animationList != null
|
||||
? new ModelConverter(gameObject, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
|
||||
: new ModelConverter(gameObject, Properties.Settings.Default.convertType);
|
||||
exportPath = exportPath + FixFileName(gameObject.m_Name) + ".fbx";
|
||||
ExportFbx(convert, exportPath);
|
||||
}
|
||||
|
||||
public static void ExportGameObjectMerge(List<GameObject> gameObject, string exportPath, List<AssetItem> animationList = null)
|
||||
{
|
||||
var rootName = Path.GetFileNameWithoutExtension(exportPath);
|
||||
var convert = animationList != null ? new ModelConverter(rootName, gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(rootName, gameObject);
|
||||
var convert = animationList != null
|
||||
? new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
|
||||
: new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType);
|
||||
ExportFbx(convert, exportPath);
|
||||
}
|
||||
|
||||
@@ -364,13 +368,17 @@ namespace AssetStudioGUI
|
||||
|
||||
public static bool ExportDumpFile(AssetItem item, string exportPath)
|
||||
{
|
||||
var exportFullName = exportPath + item.Text + ".txt";
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath))
|
||||
return false;
|
||||
var str = item.Asset.Dump();
|
||||
if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
var nodes = Studio.MonoBehaviourToTypeTreeNodes(m_MonoBehaviour);
|
||||
str = m_MonoBehaviour.Dump(nodes);
|
||||
}
|
||||
if (str != null)
|
||||
{
|
||||
File.WriteAllText(exportFullName, str);
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -408,5 +416,11 @@ namespace AssetStudioGUI
|
||||
return ExportRawFile(item, exportPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static string FixFileName(string str)
|
||||
{
|
||||
if (str.Length >= 260) return Path.GetRandomFileName();
|
||||
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AssetStudio;
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
@@ -17,7 +15,16 @@ namespace AssetStudioGUI
|
||||
|
||||
public void Log(LoggerEvent loggerEvent, string message)
|
||||
{
|
||||
action(message);
|
||||
switch (loggerEvent)
|
||||
{
|
||||
case LoggerEvent.Error:
|
||||
MessageBox.Show(message);
|
||||
break;
|
||||
default:
|
||||
action(message);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+165
-76
@@ -7,6 +7,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml.Linq;
|
||||
using static AssetStudioGUI.Exporter;
|
||||
using Object = AssetStudio.Object;
|
||||
|
||||
@@ -19,58 +20,89 @@ namespace AssetStudioGUI
|
||||
Dump
|
||||
}
|
||||
|
||||
internal enum ExportFilter
|
||||
{
|
||||
All,
|
||||
Selected,
|
||||
Filtered
|
||||
}
|
||||
|
||||
internal enum ExportListType
|
||||
{
|
||||
XML
|
||||
}
|
||||
|
||||
internal static class Studio
|
||||
{
|
||||
public static AssetsManager assetsManager = new AssetsManager();
|
||||
public static ScriptDumper scriptDumper = new ScriptDumper();
|
||||
public static AssemblyLoader assemblyLoader = new AssemblyLoader();
|
||||
public static List<AssetItem> exportableAssets = new List<AssetItem>();
|
||||
public static List<AssetItem> visibleAssets = new List<AssetItem>();
|
||||
internal static Action<string> StatusStripUpdate = x => { };
|
||||
|
||||
public static void ExtractFile(string[] fileNames)
|
||||
public static int ExtractFolder(string path, string savePath)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
int extractedCount = 0;
|
||||
Progress.Reset();
|
||||
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
int extractedCount = 0;
|
||||
Progress.Reset();
|
||||
for (var i = 0; i < fileNames.Length; i++)
|
||||
{
|
||||
var fileName = fileNames[i];
|
||||
var type = ImportHelper.CheckFileType(fileName, out var reader);
|
||||
if (type == FileType.BundleFile)
|
||||
extractedCount += ExtractBundleFile(fileName, reader);
|
||||
else if (type == FileType.WebFile)
|
||||
extractedCount += ExtractWebDataFile(fileName, reader);
|
||||
else
|
||||
reader.Dispose();
|
||||
Progress.Report(i + 1, fileNames.Length);
|
||||
}
|
||||
|
||||
StatusStripUpdate($"Finished extracting {extractedCount} files.");
|
||||
});
|
||||
var file = files[i];
|
||||
var fileOriPath = Path.GetDirectoryName(file);
|
||||
var fileSavePath = fileOriPath.Replace(path, savePath);
|
||||
extractedCount += ExtractFile(file, fileSavePath);
|
||||
Progress.Report(i + 1, files.Length);
|
||||
}
|
||||
return extractedCount;
|
||||
}
|
||||
|
||||
private static int ExtractBundleFile(string bundleFileName, EndianBinaryReader reader)
|
||||
public static int ExtractFile(string[] fileNames, string savePath)
|
||||
{
|
||||
StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFileName)} ...");
|
||||
var bundleFile = new BundleFile(reader, bundleFileName);
|
||||
int extractedCount = 0;
|
||||
Progress.Reset();
|
||||
for (var i = 0; i < fileNames.Length; i++)
|
||||
{
|
||||
var fileName = fileNames[i];
|
||||
extractedCount += ExtractFile(fileName, savePath);
|
||||
Progress.Report(i + 1, fileNames.Length);
|
||||
}
|
||||
return extractedCount;
|
||||
}
|
||||
|
||||
public static int ExtractFile(string fileName, string savePath)
|
||||
{
|
||||
int extractedCount = 0;
|
||||
var type = ImportHelper.CheckFileType(fileName, out var reader);
|
||||
if (type == FileType.BundleFile)
|
||||
extractedCount += ExtractBundleFile(fileName, reader, savePath);
|
||||
else if (type == FileType.WebFile)
|
||||
extractedCount += ExtractWebDataFile(fileName, reader, savePath);
|
||||
else
|
||||
reader.Dispose();
|
||||
return extractedCount;
|
||||
}
|
||||
|
||||
private static int ExtractBundleFile(string bundleFilePath, EndianBinaryReader reader, string savePath)
|
||||
{
|
||||
StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFilePath)} ...");
|
||||
var bundleFile = new BundleFile(reader, bundleFilePath);
|
||||
reader.Dispose();
|
||||
if (bundleFile.fileList.Length > 0)
|
||||
{
|
||||
var extractPath = bundleFileName + "_unpacked\\";
|
||||
var extractPath = Path.Combine(savePath, Path.GetFileName(bundleFilePath) + "_unpacked");
|
||||
return ExtractStreamFile(extractPath, bundleFile.fileList);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int ExtractWebDataFile(string webFileName, EndianBinaryReader reader)
|
||||
private static int ExtractWebDataFile(string webFilePath, EndianBinaryReader reader, string savePath)
|
||||
{
|
||||
StatusStripUpdate($"Decompressing {Path.GetFileName(webFileName)} ...");
|
||||
StatusStripUpdate($"Decompressing {Path.GetFileName(webFilePath)} ...");
|
||||
var webFile = new WebFile(reader);
|
||||
reader.Dispose();
|
||||
if (webFile.fileList.Length > 0)
|
||||
{
|
||||
var extractPath = webFileName + "_unpacked\\";
|
||||
var extractPath = Path.Combine(savePath, Path.GetFileName(webFilePath) + "_unpacked");
|
||||
return ExtractStreamFile(extractPath, webFile.fileList);
|
||||
}
|
||||
return 0;
|
||||
@@ -81,14 +113,18 @@ namespace AssetStudioGUI
|
||||
int extractedCount = 0;
|
||||
foreach (var file in fileList)
|
||||
{
|
||||
var filePath = extractPath + file.fileName;
|
||||
if (!Directory.Exists(extractPath))
|
||||
var filePath = Path.Combine(extractPath, file.path);
|
||||
var fileDirectory = Path.GetDirectoryName(filePath);
|
||||
if (!Directory.Exists(fileDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(extractPath);
|
||||
Directory.CreateDirectory(fileDirectory);
|
||||
}
|
||||
if (!File.Exists(filePath) && file.stream is MemoryStream stream)
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
File.WriteAllBytes(filePath, stream.ToArray());
|
||||
using (var fileStream = File.Create(filePath))
|
||||
{
|
||||
file.stream.CopyTo(fileStream);
|
||||
}
|
||||
extractedCount += 1;
|
||||
}
|
||||
file.stream.Dispose();
|
||||
@@ -101,15 +137,13 @@ namespace AssetStudioGUI
|
||||
StatusStripUpdate("Building asset list...");
|
||||
|
||||
string productName = null;
|
||||
var assetsNameHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
|
||||
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
|
||||
var containers = new List<(PPtr<Object>, string)>();
|
||||
int i = 0;
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
{
|
||||
var tempExportableAssets = new List<AssetItem>();
|
||||
Dictionary<long, string> containers = null;
|
||||
foreach (var asset in assetsFile.Objects)
|
||||
{
|
||||
var assetItem = new AssetItem(asset);
|
||||
@@ -135,7 +169,7 @@ namespace AssetStudioGUI
|
||||
break;
|
||||
case VideoClip m_VideoClip:
|
||||
if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath))
|
||||
assetItem.FullSize = asset.byteSize + (long)m_VideoClip.m_Size;
|
||||
assetItem.FullSize = asset.byteSize + (long)m_VideoClip.m_ExternalResources.m_Size;
|
||||
assetItem.Text = m_VideoClip.m_Name;
|
||||
exportable = true;
|
||||
break;
|
||||
@@ -174,13 +208,24 @@ namespace AssetStudioGUI
|
||||
productName = m_PlayerSettings.productName;
|
||||
break;
|
||||
case AssetBundle m_AssetBundle:
|
||||
containers = new Dictionary<long, string>();
|
||||
foreach (var m_Container in m_AssetBundle.m_Container)
|
||||
{
|
||||
containers[m_Container.Value.asset.m_PathID] = m_Container.Key;
|
||||
var preloadIndex = m_Container.Value.preloadIndex;
|
||||
var preloadSize = m_Container.Value.preloadSize;
|
||||
var preloadEnd = preloadIndex + preloadSize;
|
||||
for (int k = preloadIndex; k < preloadEnd; k++)
|
||||
{
|
||||
containers.Add((m_AssetBundle.m_PreloadTable[k], m_Container.Key));
|
||||
}
|
||||
}
|
||||
assetItem.Text = m_AssetBundle.m_Name;
|
||||
break;
|
||||
case ResourceManager m_ResourceManager:
|
||||
foreach (var m_Container in m_ResourceManager.m_Container)
|
||||
{
|
||||
containers.Add((m_Container.Value, m_Container.Key));
|
||||
}
|
||||
break;
|
||||
case NamedObject m_NamedObject:
|
||||
assetItem.Text = m_NamedObject.m_Name;
|
||||
break;
|
||||
@@ -189,39 +234,27 @@ namespace AssetStudioGUI
|
||||
{
|
||||
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
|
||||
}
|
||||
//处理同名文件
|
||||
if (!assetsNameHash.Add(assetItem.TypeString + assetItem.Text))
|
||||
{
|
||||
assetItem.Text += assetItem.UniqueID;
|
||||
}
|
||||
//处理非法文件名
|
||||
assetItem.Text = FixFileName(assetItem.Text);
|
||||
if (Properties.Settings.Default.displayAll || exportable)
|
||||
{
|
||||
tempExportableAssets.Add(assetItem);
|
||||
exportableAssets.Add(assetItem);
|
||||
}
|
||||
Progress.Report(++i, objectCount);
|
||||
}
|
||||
foreach (var item in tempExportableAssets)
|
||||
{
|
||||
if (containers != null)
|
||||
{
|
||||
if (containers.TryGetValue(item.Asset.m_PathID, out var container))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(container))
|
||||
{
|
||||
item.Container = container;
|
||||
}
|
||||
}
|
||||
}
|
||||
item.SetSubItems();
|
||||
}
|
||||
exportableAssets.AddRange(tempExportableAssets);
|
||||
tempExportableAssets.Clear();
|
||||
containers?.Clear();
|
||||
}
|
||||
foreach ((var pptr, var container) in containers)
|
||||
{
|
||||
if (pptr.TryGet(out var obj))
|
||||
{
|
||||
objectAssetItemDic[obj].Container = container;
|
||||
}
|
||||
}
|
||||
foreach (var tmp in exportableAssets)
|
||||
{
|
||||
tmp.SetSubItems();
|
||||
}
|
||||
containers.Clear();
|
||||
|
||||
visibleAssets = exportableAssets;
|
||||
assetsNameHash.Clear();
|
||||
|
||||
StatusStripUpdate("Building tree structure...");
|
||||
|
||||
@@ -337,12 +370,6 @@ namespace AssetStudioGUI
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
public static string FixFileName(string str)
|
||||
{
|
||||
if (str.Length >= 260) return Path.GetRandomFileName();
|
||||
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
|
||||
}
|
||||
|
||||
public static void ExportAssets(string savePath, List<AssetItem> toExportAssets, ExportType exportType)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
@@ -372,7 +399,14 @@ namespace AssetStudioGUI
|
||||
}
|
||||
break;
|
||||
case 2: //source file
|
||||
exportPath = Path.Combine(savePath, asset.SourceFile.fullName + "_export");
|
||||
if (string.IsNullOrEmpty(asset.SourceFile.originalPath))
|
||||
{
|
||||
exportPath = Path.Combine(savePath, asset.SourceFile.fileName + "_export");
|
||||
}
|
||||
else
|
||||
{
|
||||
exportPath = Path.Combine(savePath, Path.GetFileName(asset.SourceFile.originalPath) + "_export", asset.SourceFile.fileName);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
exportPath = savePath;
|
||||
@@ -428,6 +462,51 @@ namespace AssetStudioGUI
|
||||
});
|
||||
}
|
||||
|
||||
public static void ExportAssetsList(string savePath, List<AssetItem> toExportAssets, ExportListType exportListType)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
|
||||
|
||||
Progress.Reset();
|
||||
|
||||
switch (exportListType)
|
||||
{
|
||||
case ExportListType.XML:
|
||||
var filename = Path.Combine(savePath, "assets.xml");
|
||||
var doc = new XDocument(
|
||||
new XElement("Assets",
|
||||
new XAttribute("filename", filename),
|
||||
new XAttribute("createdAt", DateTime.UtcNow.ToString("s")),
|
||||
toExportAssets.Select(
|
||||
asset => new XElement("Asset",
|
||||
new XElement("Name", asset.Text),
|
||||
new XElement("Container", asset.Container),
|
||||
new XElement("Type", new XAttribute("id", (int)asset.Type), asset.TypeString),
|
||||
new XElement("PathID", asset.m_PathID),
|
||||
new XElement("Source", asset.SourceFile.fullName),
|
||||
new XElement("Size", asset.FullSize)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
doc.Save(filename);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
var statusText = $"Finished exporting asset list with {toExportAssets.Count()} items.";
|
||||
|
||||
StatusStripUpdate(statusText);
|
||||
|
||||
if (Properties.Settings.Default.openAfterExport && toExportAssets.Count() > 0)
|
||||
{
|
||||
Process.Start(savePath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void ExportSplitObjects(string savePath, TreeNodeCollection nodes)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
@@ -601,23 +680,33 @@ namespace AssetStudioGUI
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetScriptString(ObjectReader reader)
|
||||
public static List<TypeTreeNode> MonoBehaviourToTypeTreeNodes(MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
if (scriptDumper == null)
|
||||
if (!assemblyLoader.Loaded)
|
||||
{
|
||||
var openFolderDialog = new OpenFolderDialog();
|
||||
openFolderDialog.Title = "Select Assembly Folder";
|
||||
if (openFolderDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
scriptDumper = new ScriptDumper(openFolderDialog.Folder);
|
||||
assemblyLoader.Load(openFolderDialog.Folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
scriptDumper = new ScriptDumper();
|
||||
assemblyLoader.Loaded = true;
|
||||
}
|
||||
}
|
||||
return m_MonoBehaviour.ConvertToTypeTreeNodes(assemblyLoader);
|
||||
}
|
||||
|
||||
return scriptDumper.DumpScript(reader);
|
||||
public static string DumpAsset(Object obj)
|
||||
{
|
||||
var str = obj.Dump();
|
||||
if (str == null && obj is MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
var nodes = MonoBehaviourToTypeTreeNodes(m_MonoBehaviour);
|
||||
str = m_MonoBehaviour.Dump(nodes);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net472" />
|
||||
<package id="OpenTK" version="3.1.0" targetFramework="net472" />
|
||||
<package id="OpenTK.GLControl" version="3.1.0" targetFramework="net472" />
|
||||
</packages>
|
||||
@@ -0,0 +1,65 @@
|
||||
using Mono.Cecil;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AssemblyLoader
|
||||
{
|
||||
public bool Loaded;
|
||||
private Dictionary<string, ModuleDefinition> moduleDic = new Dictionary<string, ModuleDefinition>();
|
||||
|
||||
public void Load(string path)
|
||||
{
|
||||
var files = Directory.GetFiles(path, "*.dll");
|
||||
var resolver = new MyAssemblyResolver();
|
||||
var readerParameters = new ReaderParameters();
|
||||
readerParameters.AssemblyResolver = resolver;
|
||||
try
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
var assembly = AssemblyDefinition.ReadAssembly(file, readerParameters);
|
||||
resolver.Register(assembly);
|
||||
moduleDic.Add(assembly.MainModule.Name, assembly.MainModule);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
Loaded = true;
|
||||
}
|
||||
|
||||
public TypeDefinition GetTypeDefinition(string assemblyName, string fullName)
|
||||
{
|
||||
if (moduleDic.TryGetValue(assemblyName, out var module))
|
||||
{
|
||||
var typeDef = module.GetType(fullName);
|
||||
if (typeDef == null && assemblyName == "UnityEngine.dll")
|
||||
{
|
||||
foreach (var pair in moduleDic)
|
||||
{
|
||||
typeDef = pair.Value.GetType(fullName);
|
||||
if (typeDef != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return typeDef;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var pair in moduleDic)
|
||||
{
|
||||
pair.Value.Dispose();
|
||||
}
|
||||
moduleDic.Clear();
|
||||
Loaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,9 +34,6 @@
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="dnlib">
|
||||
<HintPath>Libraries\dnlib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@@ -46,17 +43,45 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Unity.Cecil">
|
||||
<HintPath>Libraries\Unity.Cecil.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Unity.CecilTools">
|
||||
<HintPath>Libraries\Unity.CecilTools.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Unity.SerializationLogic">
|
||||
<HintPath>Libraries\Unity.SerializationLogic.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyLoader.cs" />
|
||||
<Compile Include="AudioClipConverter.cs" />
|
||||
<Compile Include="CSspv\Disassembler.cs" />
|
||||
<Compile Include="CSspv\EnumValuesExtensions.cs" />
|
||||
<Compile Include="CSspv\Instruction.cs" />
|
||||
<Compile Include="CSspv\Module.cs" />
|
||||
<Compile Include="CSspv\OperandType.cs" />
|
||||
<Compile Include="CSspv\ParsedInstruction.cs" />
|
||||
<Compile Include="CSspv\Reader.cs" />
|
||||
<Compile Include="CSspv\SpirV.Core.Grammar.cs" />
|
||||
<Compile Include="CSspv\SpirV.Meta.cs" />
|
||||
<Compile Include="CSspv\Types.cs" />
|
||||
<Compile Include="FMOD Studio API\fmod.cs" />
|
||||
<Compile Include="FMOD Studio API\fmod_dsp.cs" />
|
||||
<Compile Include="FMOD Studio API\fmod_errors.cs" />
|
||||
<Compile Include="ModelConverter.cs" />
|
||||
<Compile Include="ModelExporter.cs" />
|
||||
<Compile Include="MonoBehaviourConverter.cs" />
|
||||
<Compile Include="SerializedTypeHelper.cs" />
|
||||
<Compile Include="TGASharpLib.cs" />
|
||||
<Compile Include="TypeDefinitionConverter.cs" />
|
||||
<Compile Include="MyAssemblyResolver.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ScriptDumper.cs" />
|
||||
<Compile Include="ShaderConverter.cs" />
|
||||
<Compile Include="Smolv\OpData.cs" />
|
||||
<Compile Include="Smolv\SmolvDecoder.cs" />
|
||||
<Compile Include="Smolv\SpvOp.cs" />
|
||||
<Compile Include="SpirVShaderConverter.cs" />
|
||||
<Compile Include="SpriteHelper.cs" />
|
||||
<Compile Include="Texture2DConverter.cs" />
|
||||
<Compile Include="Texture2DExtensions.cs" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using FMOD;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -18,33 +19,53 @@ namespace AssetStudio
|
||||
var m_AudioData = m_AudioClip.m_AudioData.GetData();
|
||||
if (m_AudioData == null || m_AudioData.Length == 0)
|
||||
return null;
|
||||
var exinfo = new FMOD.CREATESOUNDEXINFO();
|
||||
var result = FMOD.Factory.System_Create(out var system);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
var exinfo = new CREATESOUNDEXINFO();
|
||||
var result = Factory.System_Create(out var system);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
result = system.init(1, FMOD.INITFLAGS.NORMAL, IntPtr.Zero);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
result = system.init(1, INITFLAGS.NORMAL, IntPtr.Zero);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
exinfo.cbsize = Marshal.SizeOf(exinfo);
|
||||
exinfo.length = (uint)m_AudioClip.m_Size;
|
||||
result = system.createSound(m_AudioData, FMOD.MODE.OPENMEMORY, ref exinfo, out var sound);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
result = system.createSound(m_AudioData, MODE.OPENMEMORY, ref exinfo, out var sound);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
result = sound.getSubSound(0, out var subsound);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
result = sound.getNumSubSounds(out var numsubsounds);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
result = subsound.getFormat(out var type, out var format, out int channels, out int bits);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
byte[] buff;
|
||||
if (numsubsounds > 0)
|
||||
{
|
||||
result = sound.getSubSound(0, out var subsound);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
buff = SoundToWav(subsound);
|
||||
subsound.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
buff = SoundToWav(sound);
|
||||
}
|
||||
sound.release();
|
||||
system.release();
|
||||
return buff;
|
||||
}
|
||||
|
||||
public byte[] SoundToWav(Sound sound)
|
||||
{
|
||||
var result = sound.getFormat(out _, out _, out int channels, out int bits);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
result = subsound.getDefaults(out var frequency, out int priority);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
result = sound.getDefaults(out var frequency, out _);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
var sampleRate = (int)frequency;
|
||||
result = subsound.getLength(out var length, FMOD.TIMEUNIT.PCMBYTES);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
result = sound.getLength(out var length, TIMEUNIT.PCMBYTES);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
result = subsound.@lock(0, length, out var ptr1, out var ptr2, out var len1, out var len2);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
result = sound.@lock(0, length, out var ptr1, out var ptr2, out var len1, out var len2);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
byte[] buffer = new byte[len1 + 44];
|
||||
//添加wav头
|
||||
@@ -61,12 +82,9 @@ namespace AssetStudio
|
||||
Encoding.UTF8.GetBytes("data").CopyTo(buffer, 36);
|
||||
BitConverter.GetBytes(len1).CopyTo(buffer, 40);
|
||||
Marshal.Copy(ptr1, buffer, 44, (int)len1);
|
||||
result = subsound.unlock(ptr1, ptr2, len1, len2);
|
||||
if (result != FMOD.RESULT.OK)
|
||||
result = sound.unlock(ptr1, ptr2, len1, len2);
|
||||
if (result != RESULT.OK)
|
||||
return null;
|
||||
subsound.release();
|
||||
sound.release();
|
||||
system.release();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
public struct ModuleHeader
|
||||
{
|
||||
public Version Version { get; set; }
|
||||
public string GeneratorVendor { get; set; }
|
||||
public string GeneratorName { get; set; }
|
||||
public int GeneratorVersion { get; set; }
|
||||
public uint Bound { get; set; }
|
||||
public uint Reserved { get; set; }
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DisassemblyOptions
|
||||
{
|
||||
None,
|
||||
ShowTypes,
|
||||
ShowNames,
|
||||
Default = ShowTypes | ShowNames
|
||||
}
|
||||
|
||||
public class Disassembler
|
||||
{
|
||||
public string Disassemble (Module module)
|
||||
{
|
||||
return Disassemble(module, DisassemblyOptions.Default);
|
||||
}
|
||||
|
||||
public string Disassemble(Module module, DisassemblyOptions options)
|
||||
{
|
||||
m_sb.AppendLine("; SPIR-V");
|
||||
m_sb.Append("; Version: ").Append(module.Header.Version).AppendLine();
|
||||
if (module.Header.GeneratorName == null)
|
||||
{
|
||||
m_sb.Append("; Generator: unknown; ").Append(module.Header.GeneratorVersion).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sb.Append("; Generator: ").Append(module.Header.GeneratorVendor).Append(' ').
|
||||
Append(module.Header.GeneratorName).Append("; ").Append(module.Header.GeneratorVersion).AppendLine();
|
||||
}
|
||||
m_sb.Append("; Bound: ").Append(module.Header.Bound).AppendLine();
|
||||
m_sb.Append("; Schema: ").Append(module.Header.Reserved).AppendLine();
|
||||
|
||||
string[] lines = new string[module.Instructions.Count + 1];
|
||||
lines[0] = m_sb.ToString();
|
||||
m_sb.Clear();
|
||||
|
||||
for (int i = 0; i < module.Instructions.Count; i++)
|
||||
{
|
||||
ParsedInstruction instruction = module.Instructions[i];
|
||||
PrintInstruction(m_sb, instruction, options);
|
||||
lines[i + 1] = m_sb.ToString();
|
||||
m_sb.Clear();
|
||||
}
|
||||
|
||||
int longestPrefix = 0;
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
string line = lines[i];
|
||||
longestPrefix = Math.Max(longestPrefix, line.IndexOf('='));
|
||||
if (longestPrefix > 50)
|
||||
{
|
||||
longestPrefix = 50;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_sb.Append(lines[0]);
|
||||
for (int i = 1; i < lines.Length; i++)
|
||||
{
|
||||
string line = lines[i];
|
||||
int index = line.IndexOf('=');
|
||||
if (index == -1)
|
||||
{
|
||||
m_sb.Append(' ', longestPrefix + 4);
|
||||
m_sb.Append(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
int pad = Math.Max(0, longestPrefix - index);
|
||||
m_sb.Append(' ', pad);
|
||||
m_sb.Append(line, 0, index);
|
||||
m_sb.Append('=');
|
||||
m_sb.Append(line, index + 1, line.Length - index - 1);
|
||||
}
|
||||
m_sb.AppendLine();
|
||||
}
|
||||
|
||||
string result = m_sb.ToString();
|
||||
m_sb.Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void PrintInstruction(StringBuilder sb, ParsedInstruction instruction, DisassemblyOptions options)
|
||||
{
|
||||
if (instruction.Operands.Count == 0)
|
||||
{
|
||||
sb.Append(instruction.Instruction.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
int currentOperand = 0;
|
||||
if (instruction.Instruction.Operands[currentOperand].Type is IdResultType)
|
||||
{
|
||||
if (options.HasFlag(DisassemblyOptions.ShowTypes))
|
||||
{
|
||||
instruction.ResultType.ToString(sb).Append(' ');
|
||||
}
|
||||
++currentOperand;
|
||||
}
|
||||
|
||||
if (currentOperand < instruction.Operands.Count && instruction.Instruction.Operands[currentOperand].Type is IdResult)
|
||||
{
|
||||
if (!options.HasFlag(DisassemblyOptions.ShowNames) || string.IsNullOrWhiteSpace(instruction.Name))
|
||||
{
|
||||
PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(instruction.Name);
|
||||
}
|
||||
sb.Append(" = ");
|
||||
|
||||
++currentOperand;
|
||||
}
|
||||
|
||||
sb.Append(instruction.Instruction.Name);
|
||||
sb.Append(' ');
|
||||
|
||||
for (; currentOperand < instruction.Operands.Count; ++currentOperand)
|
||||
{
|
||||
PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options);
|
||||
sb.Append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintOperandValue(StringBuilder sb, object value, DisassemblyOptions options)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case System.Type t:
|
||||
sb.Append(t.Name);
|
||||
break;
|
||||
|
||||
case string s:
|
||||
{
|
||||
sb.Append('"');
|
||||
sb.Append(s);
|
||||
sb.Append('"');
|
||||
}
|
||||
break;
|
||||
|
||||
case ObjectReference or:
|
||||
{
|
||||
if (options.HasFlag(DisassemblyOptions.ShowNames) && or.Reference != null && !string.IsNullOrWhiteSpace(or.Reference.Name))
|
||||
{
|
||||
sb.Append(or.Reference.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
or.ToString(sb);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IBitEnumOperandValue beov:
|
||||
PrintBitEnumValue(sb, beov, options);
|
||||
break;
|
||||
|
||||
case IValueEnumOperandValue veov:
|
||||
PrintValueEnumValue(sb, veov, options);
|
||||
break;
|
||||
|
||||
case VaryingOperandValue varOpVal:
|
||||
varOpVal.ToString(sb);
|
||||
break;
|
||||
|
||||
default:
|
||||
sb.Append(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintBitEnumValue(StringBuilder sb, IBitEnumOperandValue enumOperandValue, DisassemblyOptions options)
|
||||
{
|
||||
foreach (uint key in enumOperandValue.Values.Keys)
|
||||
{
|
||||
sb.Append(enumOperandValue.EnumerationType.GetEnumName(key));
|
||||
IReadOnlyList<object> value = enumOperandValue.Values[key];
|
||||
if (value.Count != 0)
|
||||
{
|
||||
sb.Append(' ');
|
||||
foreach (object v in value)
|
||||
{
|
||||
PrintOperandValue(sb, v, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintValueEnumValue(StringBuilder sb, IValueEnumOperandValue valueOperandValue, DisassemblyOptions options)
|
||||
{
|
||||
sb.Append(valueOperandValue.Key);
|
||||
if (valueOperandValue.Value is IList<object> valueList && valueList.Count > 0)
|
||||
{
|
||||
sb.Append(' ');
|
||||
foreach (object v in valueList)
|
||||
{
|
||||
PrintOperandValue(sb, v, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly StringBuilder m_sb = new StringBuilder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#if NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
public static class EnumValuesExtensions
|
||||
{
|
||||
public static Array GetEnumValues(this System.Type _this)
|
||||
{
|
||||
TypeInfo typeInfo = _this.GetTypeInfo ();
|
||||
if (!typeInfo.IsEnum) {
|
||||
throw new ArgumentException ("GetEnumValues: Type '" + _this.Name + "' is not an enum");
|
||||
}
|
||||
|
||||
return
|
||||
(
|
||||
from field in typeInfo.DeclaredFields
|
||||
where field.IsLiteral
|
||||
select field.GetValue (null)
|
||||
)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static string GetEnumName(this System.Type _this, object value)
|
||||
{
|
||||
TypeInfo typeInfo = _this.GetTypeInfo ();
|
||||
if (!typeInfo.IsEnum) {
|
||||
throw new ArgumentException ("GetEnumName: Type '" + _this.Name + "' is not an enum");
|
||||
}
|
||||
return
|
||||
(
|
||||
from field in typeInfo.DeclaredFields
|
||||
where field.IsLiteral && (uint)field.GetValue(null) == (uint)value
|
||||
select field.Name
|
||||
)
|
||||
.First();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
public enum OperandQuantifier
|
||||
{
|
||||
/// <summary>
|
||||
/// 1
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// 0 or 1
|
||||
/// </summary>
|
||||
Optional,
|
||||
/// <summary>
|
||||
/// 0+
|
||||
/// </summary>
|
||||
Varying
|
||||
}
|
||||
|
||||
public class Operand
|
||||
{
|
||||
public Operand(OperandType kind, string name, OperandQuantifier quantifier)
|
||||
{
|
||||
Name = name;
|
||||
Type = kind;
|
||||
Quantifier = quantifier;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public OperandType Type { get; }
|
||||
public OperandQuantifier Quantifier { get; }
|
||||
}
|
||||
|
||||
public class Instruction
|
||||
{
|
||||
public Instruction (string name)
|
||||
: this (name, new List<Operand> ())
|
||||
{
|
||||
}
|
||||
|
||||
public Instruction (string name, IReadOnlyList<Operand> operands)
|
||||
{
|
||||
Operands = operands;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public IReadOnlyList<Operand> Operands { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017, Matthäus G. Chajdas
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,426 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
public class Module
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct FloatUIntUnion
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public uint Int;
|
||||
[FieldOffset(0)]
|
||||
public float Float;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct DoubleULongUnion
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public ulong Long;
|
||||
[FieldOffset(0)]
|
||||
public double Double;
|
||||
}
|
||||
|
||||
public Module(ModuleHeader header, IReadOnlyList<ParsedInstruction> instructions)
|
||||
{
|
||||
Header = header;
|
||||
Instructions = instructions;
|
||||
|
||||
Read(Instructions, objects_);
|
||||
}
|
||||
|
||||
public static bool IsDebugInstruction(ParsedInstruction instruction)
|
||||
{
|
||||
return debugInstructions_.Contains(instruction.Instruction.Name);
|
||||
}
|
||||
|
||||
private static void Read(IReadOnlyList<ParsedInstruction> instructions, Dictionary<uint, ParsedInstruction> objects)
|
||||
{
|
||||
// Debug instructions can be only processed after everything
|
||||
// else has been parsed, as they may reference types which haven't
|
||||
// been seen in the file yet
|
||||
List<ParsedInstruction> debugInstructions = new List<ParsedInstruction>();
|
||||
// Entry points contain forward references
|
||||
// Those need to be resolved afterwards
|
||||
List<ParsedInstruction> entryPoints = new List<ParsedInstruction>();
|
||||
|
||||
foreach (var instruction in instructions)
|
||||
{
|
||||
if (IsDebugInstruction(instruction))
|
||||
{
|
||||
debugInstructions.Add(instruction);
|
||||
continue;
|
||||
}
|
||||
if (instruction.Instruction is OpEntryPoint)
|
||||
{
|
||||
entryPoints.Add(instruction);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (instruction.Instruction.Name.StartsWith("OpType", StringComparison.Ordinal))
|
||||
{
|
||||
ProcessTypeInstruction(instruction, objects);
|
||||
}
|
||||
|
||||
instruction.ResolveResultType(objects);
|
||||
if (instruction.HasResult)
|
||||
{
|
||||
objects[instruction.ResultId] = instruction;
|
||||
}
|
||||
|
||||
switch (instruction.Instruction)
|
||||
{
|
||||
// Constants require that the result type has been resolved
|
||||
case OpSpecConstant sc:
|
||||
case OpConstant oc:
|
||||
{
|
||||
Type t = instruction.ResultType;
|
||||
Debug.Assert (t != null);
|
||||
Debug.Assert (t is ScalarType);
|
||||
|
||||
object constant = ConvertConstant(instruction.ResultType as ScalarType, instruction.Words, 3);
|
||||
instruction.Operands[2].Value = constant;
|
||||
instruction.Value = constant;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ParsedInstruction instruction in debugInstructions)
|
||||
{
|
||||
switch (instruction.Instruction)
|
||||
{
|
||||
case OpMemberName mn:
|
||||
{
|
||||
StructType t = (StructType)objects[instruction.Words[1]].ResultType;
|
||||
t.SetMemberName((uint)instruction.Operands[1].Value, (string)instruction.Operands[2].Value);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpName n:
|
||||
{
|
||||
// We skip naming objects we don't know about
|
||||
ParsedInstruction t = objects[instruction.Words[1]];
|
||||
t.Name = (string)instruction.Operands[1].Value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ParsedInstruction instruction in instructions)
|
||||
{
|
||||
instruction.ResolveReferences(objects);
|
||||
}
|
||||
}
|
||||
|
||||
public static Module ReadFrom(Stream stream)
|
||||
{
|
||||
BinaryReader br = new BinaryReader(stream);
|
||||
Reader reader = new Reader(br);
|
||||
|
||||
uint versionNumber = reader.ReadDWord();
|
||||
int majorVersion = (int)(versionNumber >> 16);
|
||||
int minorVersion = (int)((versionNumber >> 8) & 0xFF);
|
||||
Version version = new Version(majorVersion, minorVersion);
|
||||
|
||||
uint generatorMagicNumber = reader.ReadDWord();
|
||||
int generatorToolId = (int)(generatorMagicNumber >> 16);
|
||||
string generatorVendor = "unknown";
|
||||
string generatorName = null;
|
||||
|
||||
if (Meta.Tools.ContainsKey(generatorToolId))
|
||||
{
|
||||
Meta.ToolInfo toolInfo = Meta.Tools[generatorToolId];
|
||||
generatorVendor = toolInfo.Vendor;
|
||||
if (toolInfo.Name != null)
|
||||
{
|
||||
generatorName = toolInfo.Name;
|
||||
}
|
||||
}
|
||||
|
||||
// Read header
|
||||
ModuleHeader header = new ModuleHeader();
|
||||
header.Version = version;
|
||||
header.GeneratorName = generatorName;
|
||||
header.GeneratorVendor = generatorVendor;
|
||||
header.GeneratorVersion = (int)(generatorMagicNumber & 0xFFFF);
|
||||
header.Bound = reader.ReadDWord();
|
||||
header.Reserved = reader.ReadDWord();
|
||||
|
||||
List<ParsedInstruction> instructions = new List<ParsedInstruction>();
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
uint instructionStart = reader.ReadDWord ();
|
||||
ushort wordCount = (ushort)(instructionStart >> 16);
|
||||
int opCode = (int)(instructionStart & 0xFFFF);
|
||||
|
||||
uint[] words = new uint[wordCount];
|
||||
words[0] = instructionStart;
|
||||
for (ushort i = 1; i < wordCount; ++i)
|
||||
{
|
||||
words[i] = reader.ReadDWord();
|
||||
}
|
||||
|
||||
ParsedInstruction instruction = new ParsedInstruction(opCode, words);
|
||||
instructions.Add(instruction);
|
||||
}
|
||||
|
||||
return new Module(header, instructions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collect types from OpType* instructions
|
||||
/// </summary>
|
||||
private static void ProcessTypeInstruction(ParsedInstruction i, IReadOnlyDictionary<uint, ParsedInstruction> objects)
|
||||
{
|
||||
switch (i.Instruction)
|
||||
{
|
||||
case OpTypeInt t:
|
||||
{
|
||||
i.ResultType = new IntegerType((int)i.Words[2], i.Words[3] == 1u);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeFloat t:
|
||||
{
|
||||
i.ResultType = new FloatingPointType((int)i.Words[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeVector t:
|
||||
{
|
||||
i.ResultType = new VectorType((ScalarType)objects[i.Words[2]].ResultType, (int)i.Words[3]);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeMatrix t:
|
||||
{
|
||||
i.ResultType = new MatrixType((VectorType)objects[i.Words[2]].ResultType, (int)i.Words[3]);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeArray t:
|
||||
{
|
||||
object constant = objects[i.Words[3]].Value;
|
||||
int size = 0;
|
||||
|
||||
switch (constant)
|
||||
{
|
||||
case ushort u16:
|
||||
size = u16;
|
||||
break;
|
||||
|
||||
case uint u32:
|
||||
size = (int)u32;
|
||||
break;
|
||||
|
||||
case ulong u64:
|
||||
size = (int)u64;
|
||||
break;
|
||||
|
||||
case short i16:
|
||||
size = i16;
|
||||
break;
|
||||
|
||||
case int i32:
|
||||
size = i32;
|
||||
break;
|
||||
|
||||
case long i64:
|
||||
size = (int)i64;
|
||||
break;
|
||||
}
|
||||
|
||||
i.ResultType = new ArrayType(objects[i.Words[2]].ResultType, size);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeRuntimeArray t:
|
||||
{
|
||||
i.ResultType = new RuntimeArrayType((Type)objects[i.Words[2]].ResultType);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeBool t:
|
||||
{
|
||||
i.ResultType = new BoolType();
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeOpaque t:
|
||||
{
|
||||
i.ResultType = new OpaqueType();
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeVoid t:
|
||||
{
|
||||
i.ResultType = new VoidType();
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeImage t:
|
||||
{
|
||||
Type sampledType = objects[i.Operands[1].GetId ()].ResultType;
|
||||
Dim dim = i.Operands[2].GetSingleEnumValue<Dim>();
|
||||
uint depth = (uint)i.Operands[3].Value;
|
||||
bool isArray = (uint)i.Operands[4].Value != 0;
|
||||
bool isMultiSampled = (uint)i.Operands[5].Value != 0;
|
||||
uint sampled = (uint)i.Operands[6].Value;
|
||||
ImageFormat imageFormat = i.Operands[7].GetSingleEnumValue<ImageFormat>();
|
||||
|
||||
i.ResultType = new ImageType(sampledType,
|
||||
dim,
|
||||
(int)depth, isArray, isMultiSampled,
|
||||
(int)sampled, imageFormat,
|
||||
i.Operands.Count > 8 ? i.Operands[8].GetSingleEnumValue<AccessQualifier>() : AccessQualifier.ReadOnly);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeSampler st:
|
||||
{
|
||||
i.ResultType = new SamplerType();
|
||||
break;
|
||||
}
|
||||
|
||||
case OpTypeSampledImage t:
|
||||
{
|
||||
i.ResultType = new SampledImageType((ImageType)objects[i.Words[2]].ResultType);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeFunction t:
|
||||
{
|
||||
List<Type> parameterTypes = new List<Type>();
|
||||
for (int j = 3; j < i.Words.Count; ++j)
|
||||
{
|
||||
parameterTypes.Add(objects[i.Words[j]].ResultType);
|
||||
}
|
||||
i.ResultType = new FunctionType(objects[i.Words[2]].ResultType, parameterTypes);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeForwardPointer t:
|
||||
{
|
||||
// We create a normal pointer, but with unspecified type
|
||||
// This will get resolved later on
|
||||
i.ResultType = new PointerType((StorageClass)i.Words[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypePointer t:
|
||||
{
|
||||
if (objects.ContainsKey(i.Words[1]))
|
||||
{
|
||||
// If there is something present, it must have been
|
||||
// a forward reference. The storage type must
|
||||
// match
|
||||
PointerType pt = (PointerType)i.ResultType;
|
||||
Debug.Assert (pt != null);
|
||||
Debug.Assert (pt.StorageClass == (StorageClass)i.Words[2]);
|
||||
pt.ResolveForwardReference (objects[i.Words[3]].ResultType);
|
||||
}
|
||||
else
|
||||
{
|
||||
i.ResultType = new PointerType((StorageClass)i.Words[2], objects[i.Words[3]].ResultType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OpTypeStruct t:
|
||||
{
|
||||
List<Type> memberTypes = new List<Type>();
|
||||
for (int j = 2; j < i.Words.Count; ++j)
|
||||
{
|
||||
memberTypes.Add(objects[i.Words[j]].ResultType);
|
||||
}
|
||||
i.ResultType = new StructType(memberTypes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static object ConvertConstant(ScalarType type, IReadOnlyList<uint> words, int index)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case IntegerType i:
|
||||
{
|
||||
if (i.Signed)
|
||||
{
|
||||
if (i.Width == 16)
|
||||
{
|
||||
return unchecked((short)(words[index]));
|
||||
}
|
||||
else if (i.Width == 32)
|
||||
{
|
||||
return unchecked((int)(words[index]));
|
||||
}
|
||||
else if (i.Width == 64)
|
||||
{
|
||||
return unchecked((long)(words[index] | (ulong)(words[index + 1]) << 32));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i.Width == 16)
|
||||
{
|
||||
return unchecked((ushort)(words[index]));
|
||||
}
|
||||
else if (i.Width == 32)
|
||||
{
|
||||
return words[index];
|
||||
}
|
||||
else if (i.Width == 64)
|
||||
{
|
||||
return words[index] | (ulong)(words[index + 1]) << 32;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception ("Cannot construct integer literal.");
|
||||
}
|
||||
|
||||
case FloatingPointType f:
|
||||
{
|
||||
if (f.Width == 32)
|
||||
{
|
||||
return new FloatUIntUnion { Int = words[0] }.Float;
|
||||
}
|
||||
else if (f.Width == 64)
|
||||
{
|
||||
return new DoubleULongUnion { Long = (words[index] | (ulong)(words[index + 1]) << 32) }.Double;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot construct floating point literal.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ModuleHeader Header { get; }
|
||||
public IReadOnlyList<ParsedInstruction> Instructions { get; }
|
||||
|
||||
private static HashSet<string> debugInstructions_ = new HashSet<string>
|
||||
{
|
||||
"OpSourceContinued",
|
||||
"OpSource",
|
||||
"OpSourceExtension",
|
||||
"OpName",
|
||||
"OpMemberName",
|
||||
"OpString",
|
||||
"OpLine",
|
||||
"OpNoLine",
|
||||
"OpModuleProcessed"
|
||||
};
|
||||
|
||||
private readonly Dictionary<uint, ParsedInstruction> objects_ = new Dictionary<uint, ParsedInstruction>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
public class OperandType
|
||||
{
|
||||
public virtual bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
// This returns the dynamic type
|
||||
value = GetType();
|
||||
wordsUsed = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class Literal : OperandType
|
||||
{
|
||||
}
|
||||
|
||||
public class LiteralNumber : Literal
|
||||
{
|
||||
}
|
||||
|
||||
// The SPIR-V JSON file uses only literal integers
|
||||
public class LiteralInteger : LiteralNumber
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
value = words[index];
|
||||
wordsUsed = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class LiteralString : Literal
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
// This is just a fail-safe -- the loop below must terminate
|
||||
wordsUsed = 1;
|
||||
int bytesUsed = 0;
|
||||
byte[] bytes = new byte[(words.Count - index) * 4];
|
||||
for (int i = index; i < words.Count; ++i)
|
||||
{
|
||||
uint word = words[i];
|
||||
byte b0 = (byte)(word & 0xFF);
|
||||
if (b0 == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes[bytesUsed++] = b0;
|
||||
}
|
||||
|
||||
byte b1 = (byte)((word >> 8) & 0xFF);
|
||||
if (b1 == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes[bytesUsed++] = b1;
|
||||
}
|
||||
|
||||
byte b2 = (byte)((word >> 16) & 0xFF);
|
||||
if (b2 == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes[bytesUsed++] = b2;
|
||||
}
|
||||
|
||||
byte b3 = (byte)(word >> 24);
|
||||
if (b3 == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes[bytesUsed++] = b3;
|
||||
}
|
||||
wordsUsed++;
|
||||
}
|
||||
|
||||
value = Encoding.UTF8.GetString(bytes, 0, bytesUsed);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class LiteralContextDependentNumber : Literal
|
||||
{
|
||||
// This is handled during parsing by ConvertConstant
|
||||
}
|
||||
|
||||
public class LiteralExtInstInteger : Literal
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
value = words[index];
|
||||
wordsUsed = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class LiteralSpecConstantOpInteger : Literal
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
List<ObjectReference> result = new List<ObjectReference>();
|
||||
for (int i = index; i < words.Count; i++)
|
||||
{
|
||||
ObjectReference objRef = new ObjectReference(words[i]);
|
||||
result.Add(objRef);
|
||||
}
|
||||
|
||||
value = result;
|
||||
wordsUsed = words.Count - index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class Parameter
|
||||
{
|
||||
public virtual IReadOnlyList<OperandType> OperandTypes { get; }
|
||||
}
|
||||
|
||||
public class ParameterFactory
|
||||
{
|
||||
public virtual Parameter CreateParameter(object value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class EnumType<T> : EnumType<T, ParameterFactory>
|
||||
where T : Enum
|
||||
{
|
||||
};
|
||||
|
||||
public class EnumType<T, U> : OperandType
|
||||
where T : Enum
|
||||
where U : ParameterFactory, new ()
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
int wordsUsedForParameters = 0;
|
||||
if (typeof(T).GetTypeInfo().GetCustomAttributes<FlagsAttribute>().Any())
|
||||
{
|
||||
Dictionary<uint, IReadOnlyList<object>> result = new Dictionary<uint, IReadOnlyList<object>>();
|
||||
foreach (object enumValue in EnumerationType.GetEnumValues())
|
||||
{
|
||||
uint bit = (uint)enumValue;
|
||||
// bit == 0 and words[0] == 0 handles the 0x0 = None cases
|
||||
if ((words[index] & bit) != 0 || (bit == 0 && words[index] == 0))
|
||||
{
|
||||
Parameter p = parameterFactory_.CreateParameter(bit);
|
||||
if (p == null)
|
||||
{
|
||||
result.Add(bit, Array.Empty<object>());
|
||||
}
|
||||
else
|
||||
{
|
||||
object[] resultItems = new object[p.OperandTypes.Count];
|
||||
for (int j = 0; j < p.OperandTypes.Count; ++j)
|
||||
{
|
||||
p.OperandTypes[j].ReadValue(words, 1 + wordsUsedForParameters, out object pValue, out int pWordsUsed);
|
||||
wordsUsedForParameters += pWordsUsed;
|
||||
resultItems[j] = pValue;
|
||||
}
|
||||
result.Add(bit, resultItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
value = new BitEnumOperandValue<T>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
object[] resultItems;
|
||||
Parameter p = parameterFactory_.CreateParameter(words[index]);
|
||||
if (p == null)
|
||||
{
|
||||
resultItems = Array.Empty<object>();
|
||||
}
|
||||
else
|
||||
{
|
||||
resultItems = new object[p.OperandTypes.Count];
|
||||
for (int j = 0; j < p.OperandTypes.Count; ++j)
|
||||
{
|
||||
p.OperandTypes[j].ReadValue(words, 1 + wordsUsedForParameters, out object pValue, out int pWordsUsed);
|
||||
wordsUsedForParameters += pWordsUsed;
|
||||
resultItems[j] = pValue;
|
||||
}
|
||||
}
|
||||
value = new ValueEnumOperandValue<T>((T)(object)words[index], resultItems);
|
||||
}
|
||||
|
||||
wordsUsed = wordsUsedForParameters + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
public System.Type EnumerationType => typeof(T);
|
||||
|
||||
private U parameterFactory_ = new U();
|
||||
}
|
||||
|
||||
public class IdScope : OperandType
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
value = (Scope)words[index];
|
||||
wordsUsed = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class IdMemorySemantics : OperandType
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
value = (MemorySemantics)words[index];
|
||||
wordsUsed = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class IdType : OperandType
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
value = words[index];
|
||||
wordsUsed = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class IdResult : IdType
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
value = new ObjectReference(words[index]);
|
||||
wordsUsed = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class IdResultType : IdType
|
||||
{
|
||||
}
|
||||
|
||||
public class IdRef : IdType
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
value = new ObjectReference(words[index]);
|
||||
wordsUsed = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class PairIdRefIdRef : OperandType
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
ObjectReference variable = new ObjectReference(words[index]);
|
||||
ObjectReference parent = new ObjectReference(words[index + 1]);
|
||||
value = new { Variable = variable, Parent = parent };
|
||||
wordsUsed = 2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class PairIdRefLiteralInteger : OperandType
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
ObjectReference type = new ObjectReference(words[index]);
|
||||
uint word = words[index + 1];
|
||||
value = new { Type = type, Member = word };
|
||||
wordsUsed = 2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class PairLiteralIntegerIdRef : OperandType
|
||||
{
|
||||
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||
{
|
||||
uint selector = words[index];
|
||||
ObjectReference label = new ObjectReference(words[index + 1]);
|
||||
value = new { Selector = selector, Label = label };
|
||||
wordsUsed = 2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
public class ParsedOperand
|
||||
{
|
||||
public ParsedOperand(IReadOnlyList<uint> words, int index, int count, object value, Operand operand)
|
||||
{
|
||||
uint[] array = new uint[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
array[i] = words[index + i];
|
||||
}
|
||||
|
||||
Words = array;
|
||||
Value = value;
|
||||
Operand = operand;
|
||||
}
|
||||
|
||||
public T GetSingleEnumValue<T>()
|
||||
where T : Enum
|
||||
{
|
||||
IValueEnumOperandValue v = (IValueEnumOperandValue)Value;
|
||||
if (v.Value.Count == 0)
|
||||
{
|
||||
// If there's no value at all, the enum is probably something like ImageFormat.
|
||||
// In which case we just return the enum value
|
||||
return (T)v.Key;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This means the enum has a value attached to it, so we return the attached value
|
||||
return (T)((IValueEnumOperandValue)Value).Value[0];
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetId()
|
||||
{
|
||||
return ((ObjectReference)Value).Id;
|
||||
}
|
||||
|
||||
public T GetBitEnumValue<T>()
|
||||
where T : Enum
|
||||
{
|
||||
var v = Value as IBitEnumOperandValue;
|
||||
|
||||
uint result = 0;
|
||||
foreach (var k in v.Values.Keys)
|
||||
{
|
||||
result |= k;
|
||||
}
|
||||
|
||||
return (T)(object)result;
|
||||
}
|
||||
|
||||
public IReadOnlyList<uint> Words { get; }
|
||||
public object Value { get; set; }
|
||||
public Operand Operand { get; }
|
||||
}
|
||||
|
||||
public class VaryingOperandValue
|
||||
{
|
||||
public VaryingOperandValue(IReadOnlyList<object> values)
|
||||
{
|
||||
Values = values;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ToString(sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
for (int i = 0; i < Values.Count; ++i)
|
||||
{
|
||||
if (Values[i] is ObjectReference objRef)
|
||||
{
|
||||
objRef.ToString(sb);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(Values[i]);
|
||||
}
|
||||
if (i < (Values.Count - 1))
|
||||
{
|
||||
sb.Append(' ');
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
public IReadOnlyList<object> Values { get; }
|
||||
}
|
||||
|
||||
public interface IEnumOperandValue
|
||||
{
|
||||
System.Type EnumerationType { get; }
|
||||
}
|
||||
|
||||
public interface IBitEnumOperandValue : IEnumOperandValue
|
||||
{
|
||||
IReadOnlyDictionary<uint, IReadOnlyList<object>> Values { get; }
|
||||
}
|
||||
|
||||
public interface IValueEnumOperandValue : IEnumOperandValue
|
||||
{
|
||||
object Key { get; }
|
||||
IReadOnlyList<object> Value { get; }
|
||||
}
|
||||
|
||||
public class ValueEnumOperandValue<T> : IValueEnumOperandValue
|
||||
where T : Enum
|
||||
{
|
||||
public ValueEnumOperandValue(T key, IReadOnlyList<object> value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public System.Type EnumerationType => typeof(T);
|
||||
public object Key { get; }
|
||||
public IReadOnlyList<object> Value { get; }
|
||||
}
|
||||
|
||||
public class BitEnumOperandValue<T> : IBitEnumOperandValue
|
||||
where T : Enum
|
||||
{
|
||||
public BitEnumOperandValue(Dictionary<uint, IReadOnlyList<object>> values)
|
||||
{
|
||||
Values = values;
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<uint, IReadOnlyList<object>> Values { get; }
|
||||
public System.Type EnumerationType => typeof(T);
|
||||
}
|
||||
|
||||
public class ObjectReference
|
||||
{
|
||||
public ObjectReference(uint id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public void Resolve(IReadOnlyDictionary<uint, ParsedInstruction> objects)
|
||||
{
|
||||
Reference = objects[Id];
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"%{Id}";
|
||||
}
|
||||
|
||||
public StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return sb.Append('%').Append(Id);
|
||||
}
|
||||
|
||||
public uint Id { get; }
|
||||
public ParsedInstruction Reference { get; private set; }
|
||||
}
|
||||
|
||||
public class ParsedInstruction
|
||||
{
|
||||
public ParsedInstruction(int opCode, IReadOnlyList<uint> words)
|
||||
{
|
||||
Words = words;
|
||||
Instruction = Instructions.OpcodeToInstruction[opCode];
|
||||
ParseOperands();
|
||||
}
|
||||
|
||||
private void ParseOperands()
|
||||
{
|
||||
if (Instruction.Operands.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Word 0 describes this instruction so we can ignore it
|
||||
int currentWord = 1;
|
||||
int currentOperand = 0;
|
||||
List<object> varyingOperandValues = new List<object>();
|
||||
int varyingWordStart = 0;
|
||||
Operand varyingOperand = null;
|
||||
|
||||
while (currentWord < Words.Count)
|
||||
{
|
||||
Operand operand = Instruction.Operands[currentOperand];
|
||||
operand.Type.ReadValue(Words, currentWord, out object value, out int wordsUsed);
|
||||
if (operand.Quantifier == OperandQuantifier.Varying)
|
||||
{
|
||||
varyingOperandValues.Add(value);
|
||||
varyingWordStart = currentWord;
|
||||
varyingOperand = operand;
|
||||
}
|
||||
else
|
||||
{
|
||||
int wordCount = Math.Min(Words.Count - currentWord, wordsUsed);
|
||||
ParsedOperand parsedOperand = new ParsedOperand(Words, currentWord, wordCount, value, operand);
|
||||
Operands.Add(parsedOperand);
|
||||
}
|
||||
|
||||
currentWord += wordsUsed;
|
||||
if (operand.Quantifier != OperandQuantifier.Varying)
|
||||
{
|
||||
++currentOperand;
|
||||
}
|
||||
}
|
||||
|
||||
if (varyingOperand != null)
|
||||
{
|
||||
VaryingOperandValue varOperantValue = new VaryingOperandValue(varyingOperandValues);
|
||||
ParsedOperand parsedOperand = new ParsedOperand(Words, currentWord, Words.Count - currentWord, varOperantValue, varyingOperand);
|
||||
Operands.Add(parsedOperand);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResolveResultType(IReadOnlyDictionary<uint, ParsedInstruction> objects)
|
||||
{
|
||||
if (Instruction.Operands.Count > 0 && Instruction.Operands[0].Type is IdResultType)
|
||||
{
|
||||
ResultType = objects[(uint)Operands[0].Value].ResultType;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResolveReferences (IReadOnlyDictionary<uint, ParsedInstruction> objects)
|
||||
{
|
||||
foreach (var operand in Operands)
|
||||
{
|
||||
if (operand.Value is ObjectReference objectReference)
|
||||
{
|
||||
objectReference.Resolve (objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Type ResultType { get; set; }
|
||||
public uint ResultId
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < Instruction.Operands.Count; ++i)
|
||||
{
|
||||
if (Instruction.Operands[i].Type is IdResult)
|
||||
{
|
||||
return Operands[i].GetId();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public bool HasResult => ResultId != 0;
|
||||
|
||||
public IReadOnlyList<uint> Words { get; }
|
||||
public Instruction Instruction { get; }
|
||||
public IList<ParsedOperand> Operands { get; } = new List<ParsedOperand>();
|
||||
public string Name { get; set; }
|
||||
public object Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
internal sealed class Reader
|
||||
{
|
||||
public Reader(BinaryReader reader)
|
||||
{
|
||||
reader_ = reader;
|
||||
uint magicNumber = reader_.ReadUInt32();
|
||||
if (magicNumber == Meta.MagicNumber)
|
||||
{
|
||||
littleEndian_ = true;
|
||||
}
|
||||
else if (Reverse(magicNumber) == Meta.MagicNumber)
|
||||
{
|
||||
littleEndian_ = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Invalid magic number");
|
||||
}
|
||||
}
|
||||
|
||||
public uint ReadDWord()
|
||||
{
|
||||
if (littleEndian_)
|
||||
{
|
||||
return reader_.ReadUInt32 ();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Reverse(reader_.ReadUInt32());
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint Reverse(uint u)
|
||||
{
|
||||
return (u << 24) | (u & 0xFF00U) << 8 | (u >> 8) & 0xFF00U | (u >> 24);
|
||||
}
|
||||
|
||||
public bool EndOfStream => reader_.BaseStream.Position == reader_.BaseStream.Length;
|
||||
|
||||
private readonly BinaryReader reader_;
|
||||
private readonly bool littleEndian_;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
internal class Meta
|
||||
{
|
||||
public class ToolInfo
|
||||
{
|
||||
public ToolInfo(string vendor)
|
||||
{
|
||||
Vendor = vendor;
|
||||
}
|
||||
|
||||
public ToolInfo(string vendor, string name)
|
||||
{
|
||||
Vendor = vendor;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string Vendor { get; }
|
||||
}
|
||||
|
||||
public static uint MagicNumber => 119734787U;
|
||||
public static uint Version => 66048U;
|
||||
public static uint Revision => 2U;
|
||||
public static uint OpCodeMask => 65535U;
|
||||
public static uint WordCountShift => 16U;
|
||||
|
||||
public static IReadOnlyDictionary<int, ToolInfo> Tools => toolInfos_;
|
||||
|
||||
private readonly static Dictionary<int, ToolInfo> toolInfos_ = new Dictionary<int, ToolInfo>
|
||||
{
|
||||
{ 0, new ToolInfo("Khronos") },
|
||||
{ 1, new ToolInfo("LunarG") },
|
||||
{ 2, new ToolInfo("Valve") },
|
||||
{ 3, new ToolInfo("Codeplay") },
|
||||
{ 4, new ToolInfo("NVIDIA") },
|
||||
{ 5, new ToolInfo("ARM") },
|
||||
{ 6, new ToolInfo("Khronos", "LLVM/SPIR-V Translator") },
|
||||
{ 7, new ToolInfo("Khronos", "SPIR-V Tools Assembler") },
|
||||
{ 8, new ToolInfo("Khronos", "Glslang Reference Front End") },
|
||||
{ 9, new ToolInfo("Qualcomm") },
|
||||
{ 10, new ToolInfo("AMD") },
|
||||
{ 11, new ToolInfo("Intel") },
|
||||
{ 12, new ToolInfo("Imagination") },
|
||||
{ 13, new ToolInfo("Google", "Shaderc over Glslang") },
|
||||
{ 14, new ToolInfo("Google", "spiregg") },
|
||||
{ 15, new ToolInfo("Google", "rspirv") },
|
||||
{ 16, new ToolInfo("X-LEGEND", "Mesa-IR/SPIR-V Translator") },
|
||||
{ 17, new ToolInfo("Khronos", "SPIR-V Tools Linker") },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SpirV
|
||||
{
|
||||
public class Type
|
||||
{
|
||||
public virtual StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
|
||||
public class VoidType : Type
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "void";
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return sb.Append("void");
|
||||
}
|
||||
}
|
||||
|
||||
public class ScalarType : Type
|
||||
{
|
||||
}
|
||||
|
||||
public class BoolType : ScalarType
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "bool";
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return sb.Append("bool");
|
||||
}
|
||||
}
|
||||
|
||||
public class IntegerType : ScalarType
|
||||
{
|
||||
public IntegerType (int width, bool signed)
|
||||
{
|
||||
Width = width;
|
||||
Signed = signed;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Signed)
|
||||
{
|
||||
return $"i{Width}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"u{Width}";
|
||||
}
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
if (Signed)
|
||||
{
|
||||
sb.Append('i').Append(Width);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append('u').Append(Width);
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
public int Width { get; }
|
||||
public bool Signed { get; }
|
||||
}
|
||||
|
||||
public class FloatingPointType : ScalarType
|
||||
{
|
||||
public FloatingPointType (int width)
|
||||
{
|
||||
Width = width;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"f{Width}";
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return sb.Append('f').Append(Width);
|
||||
}
|
||||
|
||||
public int Width { get; }
|
||||
}
|
||||
|
||||
public class VectorType : Type
|
||||
{
|
||||
public VectorType (ScalarType scalarType, int componentCount)
|
||||
{
|
||||
ComponentType = scalarType;
|
||||
ComponentCount = componentCount;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ComponentType}_{ComponentCount}";
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return ComponentType.ToString(sb).Append('_').Append(ComponentCount);
|
||||
}
|
||||
|
||||
public ScalarType ComponentType { get; }
|
||||
public int ComponentCount { get; }
|
||||
}
|
||||
|
||||
public class MatrixType : Type
|
||||
{
|
||||
public MatrixType (VectorType vectorType, int columnCount)
|
||||
{
|
||||
ColumnType = vectorType;
|
||||
ColumnCount = columnCount;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return $"{ColumnType}x{ColumnCount}";
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return sb.Append(ColumnType).Append('x').Append(ColumnCount);
|
||||
}
|
||||
|
||||
public VectorType ColumnType { get; }
|
||||
public int ColumnCount { get; }
|
||||
public int RowCount => ColumnType.ComponentCount;
|
||||
}
|
||||
|
||||
public class ImageType : Type
|
||||
{
|
||||
public ImageType (Type sampledType, Dim dim, int depth, bool isArray, bool isMultisampled, int sampleCount,
|
||||
ImageFormat imageFormat, AccessQualifier accessQualifier)
|
||||
{
|
||||
SampledType = sampledType;
|
||||
Dim = dim;
|
||||
Depth = depth;
|
||||
IsArray = isArray;
|
||||
IsMultisampled = isMultisampled;
|
||||
SampleCount = sampleCount;
|
||||
Format = imageFormat;
|
||||
AccessQualifier = accessQualifier;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
ToString(sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
switch (AccessQualifier)
|
||||
{
|
||||
case AccessQualifier.ReadWrite:
|
||||
sb.Append("read_write ");
|
||||
break;
|
||||
case AccessQualifier.WriteOnly:
|
||||
sb.Append("write_only ");
|
||||
break;
|
||||
case AccessQualifier.ReadOnly:
|
||||
sb.Append("read_only ");
|
||||
break;
|
||||
}
|
||||
|
||||
sb.Append("Texture");
|
||||
switch (Dim)
|
||||
{
|
||||
case Dim.Dim1D:
|
||||
sb.Append("1D");
|
||||
break;
|
||||
case Dim.Dim2D:
|
||||
sb.Append("2D");
|
||||
break;
|
||||
case Dim.Dim3D:
|
||||
sb.Append("3D");
|
||||
break;
|
||||
case Dim.Cube:
|
||||
sb.Append("Cube");
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsMultisampled)
|
||||
{
|
||||
sb.Append("MS");
|
||||
}
|
||||
if (IsArray)
|
||||
{
|
||||
sb.Append("Array");
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
public Type SampledType { get; }
|
||||
public Dim Dim { get; }
|
||||
public int Depth { get; }
|
||||
public bool IsArray { get; }
|
||||
public bool IsMultisampled { get; }
|
||||
public int SampleCount { get; }
|
||||
public ImageFormat Format { get; }
|
||||
public AccessQualifier AccessQualifier { get; }
|
||||
}
|
||||
|
||||
public class SamplerType : Type
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "sampler";
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return sb.Append("sampler");
|
||||
}
|
||||
}
|
||||
|
||||
public class SampledImageType : Type
|
||||
{
|
||||
public SampledImageType (ImageType imageType)
|
||||
{
|
||||
ImageType = imageType;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ImageType}Sampled";
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return ImageType.ToString(sb).Append("Sampled");
|
||||
}
|
||||
|
||||
public ImageType ImageType { get; }
|
||||
}
|
||||
|
||||
public class ArrayType : Type
|
||||
{
|
||||
public ArrayType (Type elementType, int elementCount)
|
||||
{
|
||||
ElementType = elementType;
|
||||
ElementCount = elementCount;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ElementType}[{ElementCount}]";
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
return ElementType.ToString(sb).Append('[').Append(ElementCount).Append(']');
|
||||
}
|
||||
|
||||
public int ElementCount { get; }
|
||||
public Type ElementType { get; }
|
||||
}
|
||||
|
||||
public class RuntimeArrayType : Type
|
||||
{
|
||||
public RuntimeArrayType(Type elementType)
|
||||
{
|
||||
ElementType = elementType;
|
||||
}
|
||||
|
||||
public Type ElementType { get; }
|
||||
}
|
||||
|
||||
public class StructType : Type
|
||||
{
|
||||
public StructType(IReadOnlyList<Type> memberTypes)
|
||||
{
|
||||
MemberTypes = memberTypes;
|
||||
memberNames_ = new List<string>();
|
||||
|
||||
for (int i = 0; i < memberTypes.Count; ++i)
|
||||
{
|
||||
memberNames_.Add(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMemberName(uint member, string name)
|
||||
{
|
||||
memberNames_[(int)member] = name;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ToString(sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
sb.Append("struct {");
|
||||
for (int i = 0; i < MemberTypes.Count; ++i)
|
||||
{
|
||||
Type memberType = MemberTypes[i];
|
||||
memberType.ToString(sb);
|
||||
if (!string.IsNullOrEmpty(memberNames_[i]))
|
||||
{
|
||||
sb.Append(' ');
|
||||
sb.Append(MemberNames[i]);
|
||||
}
|
||||
|
||||
sb.Append(';');
|
||||
if (i < (MemberTypes.Count - 1))
|
||||
{
|
||||
sb.Append(' ');
|
||||
}
|
||||
}
|
||||
sb.Append('}');
|
||||
return sb;
|
||||
}
|
||||
|
||||
public IReadOnlyList<Type> MemberTypes { get; }
|
||||
public IReadOnlyList<string> MemberNames => memberNames_;
|
||||
|
||||
private List<string> memberNames_;
|
||||
}
|
||||
|
||||
public class OpaqueType : Type
|
||||
{
|
||||
}
|
||||
|
||||
public class PointerType : Type
|
||||
{
|
||||
public PointerType(StorageClass storageClass, Type type)
|
||||
{
|
||||
StorageClass = storageClass;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public PointerType(StorageClass storageClass)
|
||||
{
|
||||
StorageClass = storageClass;
|
||||
}
|
||||
|
||||
public void ResolveForwardReference(Type t)
|
||||
{
|
||||
Type = t;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Type == null)
|
||||
{
|
||||
return $"{StorageClass} *";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{StorageClass} {Type}*";
|
||||
}
|
||||
}
|
||||
|
||||
public override StringBuilder ToString(StringBuilder sb)
|
||||
{
|
||||
sb.Append(StorageClass.ToString()).Append(' ');
|
||||
if (Type != null)
|
||||
{
|
||||
Type.ToString(sb);
|
||||
}
|
||||
sb.Append('*');
|
||||
return sb;
|
||||
}
|
||||
|
||||
public StorageClass StorageClass { get; }
|
||||
public Type Type { get; private set; }
|
||||
}
|
||||
|
||||
public class FunctionType : Type
|
||||
{
|
||||
public FunctionType(Type returnType, IReadOnlyList<Type> parameterTypes)
|
||||
{
|
||||
ReturnType = returnType;
|
||||
ParameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
public Type ReturnType { get; }
|
||||
public IReadOnlyList<Type> ParameterTypes { get; }
|
||||
}
|
||||
|
||||
public class EventType : Type
|
||||
{
|
||||
}
|
||||
|
||||
public class DeviceEventType : Type
|
||||
{
|
||||
}
|
||||
|
||||
public class ReserveIdType : Type
|
||||
{
|
||||
}
|
||||
|
||||
public class QueueType : Type
|
||||
{
|
||||
}
|
||||
|
||||
public class PipeType : Type
|
||||
{
|
||||
}
|
||||
|
||||
public class PipeStorage : Type
|
||||
{
|
||||
}
|
||||
|
||||
public class NamedBarrier : Type
|
||||
{
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,6 +4,7 @@ using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TGASharpLib;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
@@ -16,6 +17,7 @@ namespace AssetStudio
|
||||
public List<ImportedKeyframedAnimation> AnimationList { get; protected set; } = new List<ImportedKeyframedAnimation>();
|
||||
public List<ImportedMorph> MorphList { get; protected set; } = new List<ImportedMorph>();
|
||||
|
||||
private string imageFormat;
|
||||
private Avatar avatar;
|
||||
private HashSet<AnimationClip> animationClipHashSet = new HashSet<AnimationClip>();
|
||||
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
|
||||
@@ -23,8 +25,9 @@ namespace AssetStudio
|
||||
private Dictionary<Transform, ImportedFrame> transformDictionary = new Dictionary<Transform, ImportedFrame>();
|
||||
Dictionary<uint, string> morphChannelNames = new Dictionary<uint, string>();
|
||||
|
||||
public ModelConverter(GameObject m_GameObject, AnimationClip[] animationList = null)
|
||||
public ModelConverter(GameObject m_GameObject, string imageFormat, AnimationClip[] animationList = null)
|
||||
{
|
||||
this.imageFormat = imageFormat;
|
||||
if (m_GameObject.m_Animator != null)
|
||||
{
|
||||
InitWithAnimator(m_GameObject.m_Animator);
|
||||
@@ -47,8 +50,9 @@ namespace AssetStudio
|
||||
ConvertAnimations();
|
||||
}
|
||||
|
||||
public ModelConverter(string rootName, List<GameObject> m_GameObjects, AnimationClip[] animationList = null)
|
||||
public ModelConverter(string rootName, List<GameObject> m_GameObjects, string imageFormat, AnimationClip[] animationList = null)
|
||||
{
|
||||
this.imageFormat = imageFormat;
|
||||
RootFrame = CreateFrame(rootName, Vector3.Zero, new Quaternion(0, 0, 0, 0), Vector3.One);
|
||||
foreach (var m_GameObject in m_GameObjects)
|
||||
{
|
||||
@@ -76,8 +80,9 @@ namespace AssetStudio
|
||||
ConvertAnimations();
|
||||
}
|
||||
|
||||
public ModelConverter(Animator m_Animator, AnimationClip[] animationList = null)
|
||||
public ModelConverter(Animator m_Animator, string imageFormat, AnimationClip[] animationList = null)
|
||||
{
|
||||
this.imageFormat = imageFormat;
|
||||
InitWithAnimator(m_Animator);
|
||||
if (animationList == null)
|
||||
{
|
||||
@@ -435,17 +440,17 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Logger.Error("");
|
||||
}
|
||||
}
|
||||
else
|
||||
if (boneType == 0)
|
||||
{
|
||||
//尝试使用m_BoneNameHashes 4.3 and up
|
||||
if (mesh.m_BindPose.Length > 0 && (mesh.m_BindPose.Length == mesh.m_BoneNameHashes?.Length))
|
||||
{
|
||||
boneType = 2;
|
||||
var verifiedBoneCount = mesh.m_BoneNameHashes.Count(x => FixBonePath(GetPathFromHash(x)) != null);
|
||||
if (verifiedBoneCount > 0)
|
||||
{
|
||||
boneType = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,7 +505,7 @@ namespace AssetStudio
|
||||
crc.Update(bytes, 0, (uint)bytes.Length);
|
||||
morphChannelNames[crc.GetDigest()] = blendShapeName;
|
||||
|
||||
channel.Name = shapeChannel.name;
|
||||
channel.Name = shapeChannel.name.Split('.').Last();
|
||||
channel.KeyframeList = new List<ImportedMorphKeyframe>(shapeChannel.frameCount);
|
||||
var frameEnd = shapeChannel.frameIndex + shapeChannel.frameCount;
|
||||
for (int frameIdx = shapeChannel.frameIndex; frameIdx < frameEnd; frameIdx++)
|
||||
@@ -689,15 +694,16 @@ namespace AssetStudio
|
||||
|
||||
texture.Dest = dest;
|
||||
|
||||
var ext = $".{imageFormat.ToLower()}";
|
||||
if (textureNameDictionary.TryGetValue(m_Texture2D, out var textureName))
|
||||
{
|
||||
texture.Name = textureName;
|
||||
}
|
||||
else if (ImportedHelpers.FindTexture(m_Texture2D.m_Name + ".png", TextureList) != null) //已有相同名字的图片
|
||||
else if (ImportedHelpers.FindTexture(m_Texture2D.m_Name + ext, TextureList) != null) //已有相同名字的图片
|
||||
{
|
||||
for (int i = 1; ; i++)
|
||||
{
|
||||
var name = m_Texture2D.m_Name + $" ({i}).png";
|
||||
var name = m_Texture2D.m_Name + $" ({i}){ext}";
|
||||
if (ImportedHelpers.FindTexture(name, TextureList) == null)
|
||||
{
|
||||
texture.Name = name;
|
||||
@@ -708,7 +714,7 @@ namespace AssetStudio
|
||||
}
|
||||
else
|
||||
{
|
||||
texture.Name = m_Texture2D.m_Name + ".png";
|
||||
texture.Name = m_Texture2D.m_Name + ext;
|
||||
textureNameDictionary.Add(m_Texture2D, texture.Name);
|
||||
}
|
||||
|
||||
@@ -739,7 +745,22 @@ namespace AssetStudio
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
bitmap.Save(stream, ImageFormat.Png);
|
||||
switch (imageFormat)
|
||||
{
|
||||
case "BMP":
|
||||
bitmap.Save(stream, ImageFormat.Bmp);
|
||||
break;
|
||||
case "PNG":
|
||||
bitmap.Save(stream, ImageFormat.Png);
|
||||
break;
|
||||
case "JPEG":
|
||||
bitmap.Save(stream, ImageFormat.Jpeg);
|
||||
break;
|
||||
case "TGA":
|
||||
var tga = new TGA(bitmap);
|
||||
tga.Save(stream);
|
||||
break;
|
||||
}
|
||||
iTex = new ImportedTexture(stream, name);
|
||||
TextureList.Add(iTex);
|
||||
bitmap.Dispose();
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class MonoBehaviourConverter
|
||||
{
|
||||
public static List<TypeTreeNode> ConvertToTypeTreeNodes(this MonoBehaviour m_MonoBehaviour, AssemblyLoader assemblyLoader)
|
||||
{
|
||||
var nodes = new List<TypeTreeNode>();
|
||||
var helper = new SerializedTypeHelper(m_MonoBehaviour.version);
|
||||
helper.AddMonoBehaviour(nodes, 0);
|
||||
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
var typeDef = assemblyLoader.GetTypeDefinition(m_Script.m_AssemblyName, string.IsNullOrEmpty(m_Script.m_Namespace) ? m_Script.m_ClassName : $"{m_Script.m_Namespace}.{m_Script.m_ClassName}");
|
||||
if (typeDef != null)
|
||||
{
|
||||
var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, helper, 1);
|
||||
nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNodes());
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Mono.Cecil;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class MyAssemblyResolver : DefaultAssemblyResolver
|
||||
{
|
||||
public void Register(AssemblyDefinition assembly)
|
||||
{
|
||||
RegisterAssembly(assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,492 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using dnlib.DotNet;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
//TODO to json file
|
||||
public sealed class ScriptDumper : IDisposable
|
||||
{
|
||||
private Dictionary<string, ModuleDef> moduleDic = new Dictionary<string, ModuleDef>();
|
||||
|
||||
public ScriptDumper() { }
|
||||
|
||||
public ScriptDumper(string path)
|
||||
{
|
||||
var files = Directory.GetFiles(path, "*.dll");
|
||||
var moduleContext = new ModuleContext();
|
||||
var asmResolver = new AssemblyResolver(moduleContext);
|
||||
var resolver = new Resolver(asmResolver);
|
||||
moduleContext.AssemblyResolver = asmResolver;
|
||||
moduleContext.Resolver = resolver;
|
||||
try
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
var module = ModuleDefMD.Load(file, moduleContext);
|
||||
asmResolver.AddToCache(module);
|
||||
moduleDic.Add(Path.GetFileName(file), module);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public string DumpScript(ObjectReader reader)
|
||||
{
|
||||
var m_MonoBehaviour = new MonoBehaviour(reader);
|
||||
var sb = CreateMonoBehaviourHeader(m_MonoBehaviour);
|
||||
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
|
||||
{
|
||||
if (!moduleDic.TryGetValue(m_Script.m_AssemblyName, out var module))
|
||||
{
|
||||
return sb.ToString();
|
||||
}
|
||||
var typeDef = module.Assembly.Find(m_Script.m_Namespace != "" ? $"{m_Script.m_Namespace}.{m_Script.m_ClassName}" : m_Script.m_ClassName, false);
|
||||
if (typeDef != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
DumpType(typeDef.ToTypeSig(), sb, reader, null, -1, true);
|
||||
var readed = reader.Position - reader.byteStart;
|
||||
if (readed != reader.byteSize)
|
||||
{
|
||||
Logger.Error($"Error while dump type, read {readed} bytes but expected {reader.byteSize} bytes");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
sb = CreateMonoBehaviourHeader(m_MonoBehaviour);
|
||||
Logger.Error("Error while dump type");
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (moduleDic != null)
|
||||
{
|
||||
foreach (var pair in moduleDic)
|
||||
{
|
||||
pair.Value.Dispose();
|
||||
}
|
||||
moduleDic.Clear();
|
||||
moduleDic = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static StringBuilder CreateMonoBehaviourHeader(MonoBehaviour m_MonoBehaviour)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("PPtr<GameObject> m_GameObject");
|
||||
sb.AppendLine($"\tint m_FileID = {m_MonoBehaviour.m_GameObject.m_FileID}");
|
||||
sb.AppendLine($"\tint64 m_PathID = {m_MonoBehaviour.m_GameObject.m_PathID}");
|
||||
sb.AppendLine($"UInt8 m_Enabled = {m_MonoBehaviour.m_Enabled}");
|
||||
sb.AppendLine("PPtr<MonoScript> m_Script");
|
||||
sb.AppendLine($"\tint m_FileID = {m_MonoBehaviour.m_Script.m_FileID}");
|
||||
sb.AppendLine($"\tint64 m_PathID = {m_MonoBehaviour.m_Script.m_PathID}");
|
||||
sb.AppendLine($"string m_Name = \"{m_MonoBehaviour.m_Name}\"");
|
||||
return sb;
|
||||
}
|
||||
|
||||
private static void DumpType(TypeSig typeSig, StringBuilder sb, ObjectReader reader, string name, int indent, bool isRoot = false, bool align = true)
|
||||
{
|
||||
var typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||
if (typeSig.IsPrimitive)
|
||||
{
|
||||
object value = null;
|
||||
switch (typeSig.TypeName)
|
||||
{
|
||||
case "Boolean":
|
||||
value = reader.ReadBoolean();
|
||||
break;
|
||||
case "Byte":
|
||||
value = reader.ReadByte();
|
||||
break;
|
||||
case "SByte":
|
||||
value = reader.ReadSByte();
|
||||
break;
|
||||
case "Int16":
|
||||
value = reader.ReadInt16();
|
||||
break;
|
||||
case "UInt16":
|
||||
value = reader.ReadUInt16();
|
||||
break;
|
||||
case "Int32":
|
||||
value = reader.ReadInt32();
|
||||
break;
|
||||
case "UInt32":
|
||||
value = reader.ReadUInt32();
|
||||
break;
|
||||
case "Int64":
|
||||
value = reader.ReadInt64();
|
||||
break;
|
||||
case "UInt64":
|
||||
value = reader.ReadUInt64();
|
||||
break;
|
||||
case "Single":
|
||||
value = reader.ReadSingle();
|
||||
break;
|
||||
case "Double":
|
||||
value = reader.ReadDouble();
|
||||
break;
|
||||
case "Char":
|
||||
value = reader.ReadChar();
|
||||
break;
|
||||
}
|
||||
if (align)
|
||||
reader.AlignStream();
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {value}");
|
||||
return;
|
||||
}
|
||||
if (typeSig.FullName == "System.String")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = \"{reader.ReadAlignedString()}\"");
|
||||
return;
|
||||
}
|
||||
if (typeSig.FullName == "System.Object")
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (typeDef.IsDelegate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (typeSig is ArraySigBase)
|
||||
{
|
||||
if (!typeDef.IsEnum && !IsBaseType(typeDef) && !IsAssignFromUnityObject(typeDef) && !IsEngineType(typeDef) && !typeDef.IsSerializable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var size = reader.ReadInt32();
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeSig.TypeName} {name}");
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}");
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent + 2)}[{i}]");
|
||||
DumpType(typeDef.ToTypeSig(), sb, reader, "data", indent + 2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!isRoot && typeSig is GenericInstSig genericInstSig)
|
||||
{
|
||||
if (genericInstSig.GenericArguments.Count == 1)
|
||||
{
|
||||
var genericType = genericInstSig.GenericType.ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||
var type = genericInstSig.GenericArguments[0].ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||
if (genericInstSig.GenericArguments[0] is ArraySigBase)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!type.IsEnum && !IsBaseType(type) && !IsAssignFromUnityObject(type) && !IsEngineType(type) && !type.IsSerializable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeSig.TypeName} {name}");
|
||||
if (genericType.Interfaces.Any(x => x.Interface.FullName == "System.Collections.Generic.ICollection`1<T>")) //System.Collections.Generic.IEnumerable`1<T>
|
||||
{
|
||||
var size = reader.ReadInt32();
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}");
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent + 2)}[{i}]");
|
||||
DumpType(genericInstSig.GenericArguments[0], sb, reader, "data", indent + 2, false, false);
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
DumpType(genericType.ToTypeSig(), sb, reader, "data", indent + 1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (indent != -1 && IsAssignFromUnityObject(typeDef))
|
||||
{
|
||||
var pptr = new PPtr<Object>(reader);
|
||||
sb.AppendLine($"{new string('\t', indent)}PPtr<{typeDef.Name}> {name} = {{fileID: {pptr.m_FileID}, pathID: {pptr.m_PathID}}}");
|
||||
return;
|
||||
}
|
||||
if (typeDef.IsEnum)
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {reader.ReadUInt32()}");
|
||||
return;
|
||||
}
|
||||
if (!isRoot && !IsEngineType(typeDef) && !typeDef.IsSerializable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.AnimationCurve")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}<truncated>");
|
||||
var animationCurve = new AnimationCurve<float>(reader, reader.ReadSingle);
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.Bounds")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}<truncated>");
|
||||
new AABB(reader);
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.BoundsInt")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}<truncated>");
|
||||
reader.Position += 24;
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.Color32")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
var prefix = new string('\t', indent + 1);
|
||||
sb.AppendLine($"{prefix}byte r = {reader.ReadByte()}");
|
||||
sb.AppendLine($"{prefix}byte g = {reader.ReadByte()}");
|
||||
sb.AppendLine($"{prefix}byte b = {reader.ReadByte()}");
|
||||
sb.AppendLine($"{prefix}byte a = {reader.ReadByte()}");
|
||||
reader.AlignStream();
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.Gradient")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}<truncated>");
|
||||
if (reader.version[0] == 5 && reader.version[1] < 5)
|
||||
reader.Position += 68;
|
||||
else if (reader.version[0] == 5 && reader.version[1] < 6)
|
||||
reader.Position += 72;
|
||||
else
|
||||
reader.Position += 168;
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.GUIStyle") //TODO
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.LayerMask")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}uint m_Bits = {reader.ReadUInt32()}");
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.PropertyName")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}int id = {reader.ReadInt32()}");
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.Rect")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
var prefix = new string('\t', indent + 1);
|
||||
sb.AppendLine($"{prefix}float x = {reader.ReadSingle()}");
|
||||
sb.AppendLine($"{prefix}float y = {reader.ReadSingle()}");
|
||||
sb.AppendLine($"{prefix}float width = {reader.ReadSingle()}");
|
||||
sb.AppendLine($"{prefix}float height = {reader.ReadSingle()}");
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.RectInt")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
var prefix = new string('\t', indent + 1);
|
||||
sb.AppendLine($"{prefix}int x = {reader.ReadInt32()}");
|
||||
sb.AppendLine($"{prefix}int y = {reader.ReadInt32()}");
|
||||
sb.AppendLine($"{prefix}int width = {reader.ReadInt32()}");
|
||||
sb.AppendLine($"{prefix}int height = {reader.ReadInt32()}");
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.RectOffset")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
var prefix = new string('\t', indent + 1);
|
||||
sb.AppendLine($"{prefix}float left = {reader.ReadSingle()}");
|
||||
sb.AppendLine($"{prefix}float right = {reader.ReadSingle()}");
|
||||
sb.AppendLine($"{prefix}float top = {reader.ReadSingle()}");
|
||||
sb.AppendLine($"{prefix}float bottom = {reader.ReadSingle()}");
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.Vector2Int")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
var prefix = new string('\t', indent + 1);
|
||||
sb.AppendLine($"{prefix}int x = {reader.ReadInt32()}");
|
||||
sb.AppendLine($"{prefix}int y = {reader.ReadInt32()}");
|
||||
return;
|
||||
}
|
||||
if (typeDef.FullName == "UnityEngine.Vector3Int")
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
var prefix = new string('\t', indent + 1);
|
||||
sb.AppendLine($"{prefix}int x = {reader.ReadInt32()}");
|
||||
sb.AppendLine($"{prefix}int y = {reader.ReadInt32()}");
|
||||
sb.AppendLine($"{prefix}int z = {reader.ReadInt32()}");
|
||||
return;
|
||||
}
|
||||
if (typeDef.IsClass || typeDef.IsValueType)
|
||||
{
|
||||
if (name != null && indent != -1)
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}");
|
||||
}
|
||||
if (indent == -1 && typeDef.BaseType.FullName != "UnityEngine.Object")
|
||||
{
|
||||
DumpType(typeDef.BaseType.ToTypeSig(), sb, reader, null, indent, true);
|
||||
}
|
||||
if (indent != -1 && typeDef.BaseType.FullName != "System.Object")
|
||||
{
|
||||
DumpType(typeDef.BaseType.ToTypeSig(), sb, reader, null, indent, true);
|
||||
}
|
||||
foreach (var fieldDef in typeDef.Fields)
|
||||
{
|
||||
var flag = false;
|
||||
var access = fieldDef.Access & FieldAttributes.FieldAccessMask;
|
||||
if (access != FieldAttributes.Public)
|
||||
{
|
||||
if (fieldDef.CustomAttributes.Any(x => x.TypeFullName == "UnityEngine.SerializeField"))
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
else if ((fieldDef.Attributes & FieldAttributes.Static) == 0 && (fieldDef.Attributes & FieldAttributes.InitOnly) == 0 && (fieldDef.Attributes & FieldAttributes.NotSerialized) == 0)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
if (fieldDef.FieldType.IsGenericParameter)
|
||||
{
|
||||
for (var i = 0; i < typeDef.GenericParameters.Count; i++)
|
||||
{
|
||||
var g = typeDef.GenericParameters[i];
|
||||
if (g.FullName == fieldDef.FieldType.FullName)
|
||||
{
|
||||
var type = ((GenericInstSig)typeSig).GenericArguments[i];
|
||||
DumpType(type, sb, reader, fieldDef.Name, indent + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fieldDef.FieldType is GenericInstSig genericSig && genericSig.GenericArguments.Count == 1 && genericSig.GenericArguments[0].IsGenericParameter)
|
||||
{
|
||||
for (var i = 0; i < typeDef.GenericParameters.Count; i++)
|
||||
{
|
||||
var g = typeDef.GenericParameters[i];
|
||||
if (g.FullName == genericSig.GenericArguments[0].FullName)
|
||||
{
|
||||
var type = ((GenericInstSig)typeSig).GenericArguments[i];
|
||||
var fieldTypeDef = fieldDef.FieldType.ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||
if (fieldTypeDef.Interfaces.Any(x => x.Interface.FullName == "System.Collections.Generic.ICollection`1<T>")) //System.Collections.Generic.IEnumerable`1<T>
|
||||
{
|
||||
var size = reader.ReadInt32();
|
||||
sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}");
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
sb.AppendLine($"{new string('\t', indent + 2)}[{i}]");
|
||||
DumpType(type, sb, reader, "data", indent + 2, false, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsAssignFromUnityObject(TypeDef typeDef)
|
||||
{
|
||||
if (typeDef.FullName == "UnityEngine.Object")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (typeDef.BaseType != null)
|
||||
{
|
||||
if (typeDef.BaseType.FullName == "UnityEngine.Object")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
typeDef = typeDef.BaseType.ResolveTypeDefThrow();
|
||||
if (typeDef.BaseType == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (typeDef.BaseType.FullName == "UnityEngine.Object")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsBaseType(IFullName typeDef)
|
||||
{
|
||||
switch (typeDef.FullName)
|
||||
{
|
||||
case "System.Boolean":
|
||||
case "System.Byte":
|
||||
case "System.SByte":
|
||||
case "System.Int16":
|
||||
case "System.UInt16":
|
||||
case "System.Int32":
|
||||
case "System.UInt32":
|
||||
case "System.Int64":
|
||||
case "System.UInt64":
|
||||
case "System.Single":
|
||||
case "System.Double":
|
||||
case "System.String":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsEngineType(IFullName typeDef)
|
||||
{
|
||||
switch (typeDef.FullName)
|
||||
{
|
||||
case "UnityEngine.AnimationCurve":
|
||||
case "UnityEngine.Bounds":
|
||||
case "UnityEngine.BoundsInt":
|
||||
case "UnityEngine.Color":
|
||||
case "UnityEngine.Color32":
|
||||
case "UnityEngine.Gradient":
|
||||
case "UnityEngine.GUIStyle":
|
||||
case "UnityEngine.LayerMask":
|
||||
case "UnityEngine.Matrix4x4":
|
||||
case "UnityEngine.PropertyName":
|
||||
case "UnityEngine.Quaternion":
|
||||
case "UnityEngine.Rect":
|
||||
case "UnityEngine.RectInt":
|
||||
case "UnityEngine.RectOffset":
|
||||
case "UnityEngine.Vector2":
|
||||
case "UnityEngine.Vector2Int":
|
||||
case "UnityEngine.Vector3":
|
||||
case "UnityEngine.Vector3Int":
|
||||
case "UnityEngine.Vector4":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class SerializedTypeHelper
|
||||
{
|
||||
private readonly int[] version;
|
||||
|
||||
public SerializedTypeHelper(int[] version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void AddMonoBehaviour(List<TypeTreeNode> nodes, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("MonoBehaviour", "Base", indent, false));
|
||||
AddPPtr(nodes, "GameObject", "m_GameObject", indent + 1);
|
||||
nodes.Add(new TypeTreeNode("UInt8", "m_Enabled", indent + 1, true));
|
||||
AddPPtr(nodes, "MonoScript", "m_Script", indent + 1);
|
||||
AddString(nodes, "m_Name", indent + 1);
|
||||
}
|
||||
|
||||
public void AddPPtr(List<TypeTreeNode> nodes, string type, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode($"PPtr<{type}>", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_FileID", indent + 1, false));
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("SInt64", "m_PathID", indent + 1, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("int", "m_PathID", indent + 1, false));
|
||||
}
|
||||
}
|
||||
|
||||
public void AddString(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("string", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("Array", "Array", indent + 1, true));
|
||||
nodes.Add(new TypeTreeNode("int", "size", indent + 2, false));
|
||||
nodes.Add(new TypeTreeNode("char", "data", indent + 2, false));
|
||||
}
|
||||
|
||||
public void AddArray(List<TypeTreeNode> nodes, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("Array", "Array", indent, false));
|
||||
nodes.Add(new TypeTreeNode("int", "size", indent + 1, false));
|
||||
}
|
||||
|
||||
public void AddAnimationCurve(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("AnimationCurve", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("vector", "m_Curve", indent + 1, false));
|
||||
AddArray(nodes, indent + 2); //TODO 2017 and up Array align but no effect
|
||||
nodes.Add(new TypeTreeNode("Keyframe", "data", indent + 3, false));
|
||||
nodes.Add(new TypeTreeNode("float", "time", indent + 4, false));
|
||||
nodes.Add(new TypeTreeNode("float", "value", indent + 4, false));
|
||||
nodes.Add(new TypeTreeNode("float", "inSlope", indent + 4, false));
|
||||
nodes.Add(new TypeTreeNode("float", "outSlope", indent + 4, false));
|
||||
if (version[0] >= 2018) //2018 and up
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("int", "weightedMode", indent + 4, false));
|
||||
nodes.Add(new TypeTreeNode("float", "inWeight", indent + 4, false));
|
||||
nodes.Add(new TypeTreeNode("float", "outWeight", indent + 4, false));
|
||||
}
|
||||
nodes.Add(new TypeTreeNode("int", "m_PreInfinity", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_PostInfinity", indent + 1, false));
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 3)) //5.3 and up
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("int", "m_RotationOrder", indent + 1, false));
|
||||
}
|
||||
}
|
||||
|
||||
public void AddGradient(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("Gradient", name, indent, false));
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
|
||||
{
|
||||
AddColorRGBA(nodes, "key0", indent + 1);
|
||||
AddColorRGBA(nodes, "key1", indent + 1);
|
||||
AddColorRGBA(nodes, "key2", indent + 1);
|
||||
AddColorRGBA(nodes, "key3", indent + 1);
|
||||
AddColorRGBA(nodes, "key4", indent + 1);
|
||||
AddColorRGBA(nodes, "key5", indent + 1);
|
||||
AddColorRGBA(nodes, "key6", indent + 1);
|
||||
AddColorRGBA(nodes, "key7", indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddColor32(nodes, "key0", indent + 1);
|
||||
AddColor32(nodes, "key1", indent + 1);
|
||||
AddColor32(nodes, "key2", indent + 1);
|
||||
AddColor32(nodes, "key3", indent + 1);
|
||||
AddColor32(nodes, "key4", indent + 1);
|
||||
AddColor32(nodes, "key5", indent + 1);
|
||||
AddColor32(nodes, "key6", indent + 1);
|
||||
AddColor32(nodes, "key7", indent + 1);
|
||||
}
|
||||
nodes.Add(new TypeTreeNode("UInt16", "ctime0", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "ctime1", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "ctime2", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "ctime3", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "ctime4", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "ctime5", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "ctime6", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "ctime7", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "atime0", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "atime1", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "atime2", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "atime3", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "atime4", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "atime5", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "atime6", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt16", "atime7", indent + 1, false));
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5)) //5.5 and up
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("int", "m_Mode", indent + 1, false));
|
||||
}
|
||||
nodes.Add(new TypeTreeNode("UInt8", "m_NumColorKeys", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("UInt8", "m_NumAlphaKeys", indent + 1, true));
|
||||
}
|
||||
|
||||
public void AddGUIStyle(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("GUIStyle", name, indent, false));
|
||||
AddString(nodes, "m_Name", indent + 1);
|
||||
AddGUIStyleState(nodes, "m_Normal", indent + 1);
|
||||
AddGUIStyleState(nodes, "m_Hover", indent + 1);
|
||||
AddGUIStyleState(nodes, "m_Active", indent + 1);
|
||||
AddGUIStyleState(nodes, "m_Focused", indent + 1);
|
||||
AddGUIStyleState(nodes, "m_OnNormal", indent + 1);
|
||||
AddGUIStyleState(nodes, "m_OnHover", indent + 1);
|
||||
AddGUIStyleState(nodes, "m_OnActive", indent + 1);
|
||||
AddGUIStyleState(nodes, "m_OnFocused", indent + 1);
|
||||
AddRectOffset(nodes, "m_Border", indent + 1);
|
||||
if (version[0] >= 4) //4 and up
|
||||
{
|
||||
AddRectOffset(nodes, "m_Margin", indent + 1);
|
||||
AddRectOffset(nodes, "m_Padding", indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRectOffset(nodes, "m_Padding", indent + 1);
|
||||
AddRectOffset(nodes, "m_Margin", indent + 1);
|
||||
}
|
||||
AddRectOffset(nodes, "m_Overflow", indent + 1);
|
||||
AddPPtr(nodes, "Font", "m_Font", indent + 1);
|
||||
if (version[0] >= 4) //4 and up
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("int", "m_FontSize", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_FontStyle", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_Alignment", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("bool", "m_WordWrap", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("bool", "m_RichText", indent + 1, true));
|
||||
nodes.Add(new TypeTreeNode("int", "m_TextClipping", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_ImagePosition", indent + 1, false));
|
||||
AddVector2f(nodes, "m_ContentOffset", indent + 1);
|
||||
nodes.Add(new TypeTreeNode("float", "m_FixedWidth", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "m_FixedHeight", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("bool", "m_StretchWidth", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("bool", "m_StretchHeight", indent + 1, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("int", "m_ImagePosition", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_Alignment", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("bool", "m_WordWrap", indent + 1, true));
|
||||
nodes.Add(new TypeTreeNode("int", "m_TextClipping", indent + 1, false));
|
||||
AddVector2f(nodes, "m_ContentOffset", indent + 1);
|
||||
AddVector2f(nodes, "m_ClipOffset", indent + 1);
|
||||
nodes.Add(new TypeTreeNode("float", "m_FixedWidth", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "m_FixedHeight", indent + 1, false));
|
||||
if (version[0] >= 3) //3 and up
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("int", "m_FontSize", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_FontStyle", indent + 1, false));
|
||||
}
|
||||
nodes.Add(new TypeTreeNode("bool", "m_StretchWidth", indent + 1, true));
|
||||
nodes.Add(new TypeTreeNode("bool", "m_StretchHeight", indent + 1, true));
|
||||
}
|
||||
}
|
||||
|
||||
public void AddGUIStyleState(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("GUIStyleState", name, indent, false));
|
||||
AddPPtr(nodes, "Texture2D", "m_Background", indent + 1);
|
||||
AddColorRGBA(nodes, "m_TextColor", indent + 1);
|
||||
}
|
||||
|
||||
public void AddVector2f(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("Vector2f", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("float", "x", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "y", indent + 1, false));
|
||||
}
|
||||
|
||||
public void AddRectOffset(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("RectOffset", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_Left", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_Right", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_Top", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("int", "m_Bottom", indent + 1, false));
|
||||
}
|
||||
|
||||
public void AddColorRGBA(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("ColorRGBA", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("float", "r", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "g", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "b", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "a", indent + 1, false));
|
||||
}
|
||||
|
||||
public void AddColor32(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("ColorRGBA", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("unsigned int", "rgba", indent + 1, false));
|
||||
}
|
||||
|
||||
public void AddMatrix4x4(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("Matrix4x4f", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e00", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e01", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e02", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e03", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e10", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e11", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e12", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e13", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e20", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e21", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e22", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e23", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e30", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e31", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e32", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "e33", indent + 1, false));
|
||||
}
|
||||
|
||||
public void AddSphericalHarmonicsL2(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("SphericalHarmonicsL2", name, indent, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 0]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 1]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 2]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 3]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 4]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 5]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 6]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 7]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 8]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[ 9]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[10]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[11]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[12]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[13]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[14]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[15]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[16]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[17]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[18]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[19]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[20]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[21]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[22]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[23]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[24]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[25]", indent + 1, false));
|
||||
nodes.Add(new TypeTreeNode("float", "sh[26]", indent + 1, false));
|
||||
}
|
||||
|
||||
public void AddPropertyName(List<TypeTreeNode> nodes, string name, int indent)
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("PropertyName", name, indent, false));
|
||||
AddString(nodes, "id", indent + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace AssetStudio
|
||||
{
|
||||
public static class ShaderConverter
|
||||
{
|
||||
public static string Convert(Shader shader)
|
||||
public static string Convert(this Shader shader)
|
||||
{
|
||||
if (shader.m_SubProgramBlob != null) //5.3 - 5.4
|
||||
{
|
||||
@@ -21,47 +21,40 @@ namespace AssetStudio
|
||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||
{
|
||||
var program = new ShaderProgram(blobReader, shader.version);
|
||||
return program.Export(Encoding.UTF8.GetString(shader.m_Script));
|
||||
return header + program.Export(Encoding.UTF8.GetString(shader.m_Script));
|
||||
}
|
||||
}
|
||||
|
||||
if (shader.compressedBlob != null) //5.5 and up
|
||||
{
|
||||
return ConvertMultiple(shader)[0];
|
||||
return header + ConvertSerializedShader(shader);
|
||||
}
|
||||
|
||||
return header + Encoding.UTF8.GetString(shader.m_Script);
|
||||
}
|
||||
|
||||
public static string[] ConvertMultiple(Shader shader)
|
||||
private static string ConvertSerializedShader(Shader shader)
|
||||
{
|
||||
if (shader.compressedBlob != null) //5.5 and up
|
||||
var shaderPrograms = new ShaderProgram[shader.platforms.Length];
|
||||
for (var i = 0; i < shader.platforms.Length; i++)
|
||||
{
|
||||
var strs = new string[shader.platforms.Length];
|
||||
for (var i = 0; i < shader.platforms.Length; i++)
|
||||
var compressedBytes = new byte[shader.compressedLengths[i]];
|
||||
Buffer.BlockCopy(shader.compressedBlob, (int)shader.offsets[i], compressedBytes, 0, (int)shader.compressedLengths[i]);
|
||||
var decompressedBytes = new byte[shader.decompressedLengths[i]];
|
||||
using (var decoder = new Lz4DecoderStream(new MemoryStream(compressedBytes)))
|
||||
{
|
||||
var compressedBytes = new byte[shader.compressedLengths[i]];
|
||||
Buffer.BlockCopy(shader.compressedBlob, (int)shader.offsets[i], compressedBytes, 0, (int)shader.compressedLengths[i]);
|
||||
var decompressedBytes = new byte[shader.decompressedLengths[i]];
|
||||
using (var decoder = new Lz4DecoderStream(new MemoryStream(compressedBytes)))
|
||||
{
|
||||
decoder.Read(decompressedBytes, 0, (int)shader.decompressedLengths[i]);
|
||||
}
|
||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||
{
|
||||
var program = new ShaderProgram(blobReader, shader.version);
|
||||
var m_Script = ConvertSerializedShader(shader.m_ParsedForm, shader.platforms[i]);
|
||||
strs[i] = header + program.Export(m_Script);
|
||||
}
|
||||
decoder.Read(decompressedBytes, 0, (int)shader.decompressedLengths[i]);
|
||||
}
|
||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||
{
|
||||
shaderPrograms[i] = new ShaderProgram(blobReader, shader.version);
|
||||
}
|
||||
|
||||
return strs;
|
||||
}
|
||||
|
||||
return null;
|
||||
return ConvertSerializedShader(shader.m_ParsedForm, shader.platforms, shaderPrograms);
|
||||
}
|
||||
|
||||
private static string ConvertSerializedShader(SerializedShader m_ParsedForm, ShaderCompilerPlatform platform)
|
||||
private static string ConvertSerializedShader(SerializedShader m_ParsedForm, ShaderCompilerPlatform[] platforms, ShaderProgram[] shaderPrograms)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"Shader \"{m_ParsedForm.m_Name}\" {{\n");
|
||||
@@ -70,7 +63,7 @@ namespace AssetStudio
|
||||
|
||||
foreach (var m_SubShader in m_ParsedForm.m_SubShaders)
|
||||
{
|
||||
sb.Append(ConvertSerializedSubShader(m_SubShader, platform));
|
||||
sb.Append(ConvertSerializedSubShader(m_SubShader, platforms, shaderPrograms));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(m_ParsedForm.m_FallbackName))
|
||||
@@ -87,7 +80,7 @@ namespace AssetStudio
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string ConvertSerializedSubShader(SerializedSubShader m_SubShader, ShaderCompilerPlatform platform)
|
||||
private static string ConvertSerializedSubShader(SerializedSubShader m_SubShader, ShaderCompilerPlatform[] platforms, ShaderProgram[] shaderPrograms)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("SubShader {\n");
|
||||
@@ -100,13 +93,13 @@ namespace AssetStudio
|
||||
|
||||
foreach (var m_Passe in m_SubShader.m_Passes)
|
||||
{
|
||||
sb.Append(ConvertSerializedPass(m_Passe, platform));
|
||||
sb.Append(ConvertSerializedPass(m_Passe, platforms, shaderPrograms));
|
||||
}
|
||||
sb.Append("}\n");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string ConvertSerializedPass(SerializedPass m_Passe, ShaderCompilerPlatform platform)
|
||||
private static string ConvertSerializedPass(SerializedPass m_Passe, ShaderCompilerPlatform[] platforms, ShaderProgram[] shaderPrograms)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
switch (m_Passe.m_Type)
|
||||
@@ -143,35 +136,35 @@ namespace AssetStudio
|
||||
if (m_Passe.progVertex.m_SubPrograms.Length > 0)
|
||||
{
|
||||
sb.Append("Program \"vp\" {\n");
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progVertex.m_SubPrograms, platform));
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progVertex.m_SubPrograms, platforms, shaderPrograms));
|
||||
sb.Append("}\n");
|
||||
}
|
||||
|
||||
if (m_Passe.progFragment.m_SubPrograms.Length > 0)
|
||||
{
|
||||
sb.Append("Program \"fp\" {\n");
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progFragment.m_SubPrograms, platform));
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progFragment.m_SubPrograms, platforms, shaderPrograms));
|
||||
sb.Append("}\n");
|
||||
}
|
||||
|
||||
if (m_Passe.progGeometry.m_SubPrograms.Length > 0)
|
||||
{
|
||||
sb.Append("Program \"gp\" {\n");
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progGeometry.m_SubPrograms, platform));
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progGeometry.m_SubPrograms, platforms, shaderPrograms));
|
||||
sb.Append("}\n");
|
||||
}
|
||||
|
||||
if (m_Passe.progHull.m_SubPrograms.Length > 0)
|
||||
{
|
||||
sb.Append("Program \"hp\" {\n");
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progHull.m_SubPrograms, platform));
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progHull.m_SubPrograms, platforms, shaderPrograms));
|
||||
sb.Append("}\n");
|
||||
}
|
||||
|
||||
if (m_Passe.progDomain.m_SubPrograms.Length > 0)
|
||||
{
|
||||
sb.Append("Program \"dp\" {\n");
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progDomain.m_SubPrograms, platform));
|
||||
sb.Append(ConvertSerializedSubPrograms(m_Passe.progDomain.m_SubPrograms, platforms, shaderPrograms));
|
||||
sb.Append("}\n");
|
||||
}
|
||||
}
|
||||
@@ -180,7 +173,7 @@ namespace AssetStudio
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string ConvertSerializedSubPrograms(SerializedSubProgram[] m_SubPrograms, ShaderCompilerPlatform platform)
|
||||
private static string ConvertSerializedSubPrograms(SerializedSubProgram[] m_SubPrograms, ShaderCompilerPlatform[] platforms, ShaderProgram[] shaderPrograms)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var groups = m_SubPrograms.GroupBy(x => x.m_BlobIndex);
|
||||
@@ -189,22 +182,26 @@ namespace AssetStudio
|
||||
var programs = group.GroupBy(x => x.m_GpuProgramType);
|
||||
foreach (var program in programs)
|
||||
{
|
||||
if (CheckGpuProgramUsable(platform, program.Key))
|
||||
for (int i = 0; i < platforms.Length; i++)
|
||||
{
|
||||
var subPrograms = program.ToList();
|
||||
var isTier = subPrograms.Count > 1;
|
||||
foreach (var subProgram in subPrograms)
|
||||
var platform = platforms[i];
|
||||
if (CheckGpuProgramUsable(platform, program.Key))
|
||||
{
|
||||
sb.Append($"SubProgram \"{GetPlatformString(platform)} ");
|
||||
if (isTier)
|
||||
var subPrograms = program.ToList();
|
||||
var isTier = subPrograms.Count > 1;
|
||||
foreach (var subProgram in subPrograms)
|
||||
{
|
||||
sb.Append($"hw_tier{subProgram.m_ShaderHardwareTier:00} ");
|
||||
sb.Append($"SubProgram \"{GetPlatformString(platform)} ");
|
||||
if (isTier)
|
||||
{
|
||||
sb.Append($"hw_tier{subProgram.m_ShaderHardwareTier:00} ");
|
||||
}
|
||||
sb.Append("\" {\n");
|
||||
sb.Append(shaderPrograms[i].m_SubPrograms[subProgram.m_BlobIndex].Export());
|
||||
sb.Append("\n}\n");
|
||||
}
|
||||
sb.Append("\" {\n");
|
||||
sb.Append($"GpuProgramIndex {subProgram.m_BlobIndex}\n");
|
||||
sb.Append("}\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -439,9 +436,17 @@ namespace AssetStudio
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramDX9PixelSM20
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramDX9PixelSM30;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformXbox360:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformPS3:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformD3D11:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramDX11VertexSM40
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramDX11VertexSM50
|
||||
@@ -465,11 +470,23 @@ namespace AssetStudio
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramGLES31
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramGLES3;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformPSP2:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformPS4:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformXboxOne:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformPSM: //Unknown
|
||||
throw new NotSupportedException();
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformMetal:
|
||||
@@ -480,15 +497,31 @@ namespace AssetStudio
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramGLCore41
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramGLCore43;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformN3DS:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformWiiU:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformVulkan:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramSPIRV;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformSwitch:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
case ShaderCompilerPlatform.kShaderCompPlatformXboxOneD3D12:
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsole;
|
||||
return programType == ShaderGpuProgramType.kShaderGpuProgramConsoleVS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleFS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleHS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleDS
|
||||
|| programType == ShaderGpuProgramType.kShaderGpuProgramConsoleGS;
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
@@ -554,7 +587,7 @@ namespace AssetStudio
|
||||
|
||||
public class ShaderProgram
|
||||
{
|
||||
private ShaderSubProgram[] m_SubPrograms;
|
||||
public ShaderSubProgram[] m_SubPrograms;
|
||||
|
||||
public ShaderProgram(BinaryReader reader, int[] version)
|
||||
{
|
||||
@@ -607,7 +640,7 @@ namespace AssetStudio
|
||||
//201609010 - Unity 5.6, 2017.1 & 2017.2
|
||||
//201708220 - Unity 2017.3, Unity 2017.4 & Unity 2018.1
|
||||
//201802150 - Unity 2018.2 & Unity 2018.3
|
||||
//201806140 - Unity 2019.1
|
||||
//201806140 - Unity 2019.1~2020.1
|
||||
m_Version = reader.ReadInt32();
|
||||
m_ProgramType = (ShaderGpuProgramType)reader.ReadInt32();
|
||||
reader.BaseStream.Position += 12;
|
||||
@@ -630,7 +663,7 @@ namespace AssetStudio
|
||||
m_LocalKeywords[i] = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
m_ProgramCode = reader.ReadBytes(reader.ReadInt32());
|
||||
m_ProgramCode = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
|
||||
//TODO
|
||||
@@ -694,14 +727,14 @@ namespace AssetStudio
|
||||
case ShaderGpuProgramType.kShaderGpuProgramDX11HullSM50:
|
||||
case ShaderGpuProgramType.kShaderGpuProgramDX11DomainSM50:
|
||||
{
|
||||
int start = 6;
|
||||
/*int start = 6;
|
||||
if (m_Version == 201509030) // 5.3
|
||||
{
|
||||
start = 5;
|
||||
}
|
||||
var buff = new byte[m_ProgramCode.Length - start];
|
||||
Buffer.BlockCopy(m_ProgramCode, start, buff, 0, buff.Length);
|
||||
/*var shaderBytecode = new ShaderBytecode(buff);
|
||||
var shaderBytecode = new ShaderBytecode(buff);
|
||||
sb.Append(shaderBytecode.Disassemble());*/
|
||||
sb.Append("// shader disassembly not supported on DXBC");
|
||||
break;
|
||||
@@ -722,10 +755,20 @@ namespace AssetStudio
|
||||
}
|
||||
break;
|
||||
case ShaderGpuProgramType.kShaderGpuProgramSPIRV:
|
||||
sb.Append("// shader disassembly not supported on SPIR-V\n");
|
||||
sb.Append("// https://github.com/KhronosGroup/SPIRV-Cross");
|
||||
try
|
||||
{
|
||||
sb.Append(SpirVShaderConverter.Convert(m_ProgramCode));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
sb.Append($"// disassembly error {e.Message}\n");
|
||||
}
|
||||
break;
|
||||
case ShaderGpuProgramType.kShaderGpuProgramConsole:
|
||||
case ShaderGpuProgramType.kShaderGpuProgramConsoleVS:
|
||||
case ShaderGpuProgramType.kShaderGpuProgramConsoleFS:
|
||||
case ShaderGpuProgramType.kShaderGpuProgramConsoleHS:
|
||||
case ShaderGpuProgramType.kShaderGpuProgramConsoleDS:
|
||||
case ShaderGpuProgramType.kShaderGpuProgramConsoleGS:
|
||||
sb.Append(Encoding.UTF8.GetString(m_ProgramCode));
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
namespace Smolv
|
||||
{
|
||||
public struct OpData
|
||||
{
|
||||
public OpData(byte hasResult, byte hasType, sbyte deltaFromResult, byte varrest)
|
||||
{
|
||||
this.hasResult = hasResult;
|
||||
this.hasType = hasType;
|
||||
this.deltaFromResult = deltaFromResult;
|
||||
this.varrest = varrest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does it have result ID?
|
||||
/// </summary>
|
||||
public byte hasResult;
|
||||
/// <summary>
|
||||
/// Does it have type ID?
|
||||
/// </summary>
|
||||
public byte hasType;
|
||||
/// <summary>
|
||||
/// How many words after (optional) type+result to write out as deltas from result?
|
||||
/// </summary>
|
||||
public sbyte deltaFromResult;
|
||||
/// <summary>
|
||||
/// Should the rest of words be written in varint encoding?
|
||||
/// </summary>
|
||||
public byte varrest;
|
||||
|
||||
public static readonly OpData[] SpirvOpData =
|
||||
{
|
||||
new OpData(0, 0, 0, 0), // Nop
|
||||
new OpData(1, 1, 0, 0), // Undef
|
||||
new OpData(0, 0, 0, 0), // SourceContinued
|
||||
new OpData(0, 0, 0, 1), // Source
|
||||
new OpData(0, 0, 0, 0), // SourceExtension
|
||||
new OpData(0, 0, 0, 0), // Name
|
||||
new OpData(0, 0, 0, 0), // MemberName
|
||||
new OpData(0, 0, 0, 0), // String
|
||||
new OpData(0, 0, 0, 1), // Line
|
||||
new OpData(1, 1, 0, 0), // #9
|
||||
new OpData(0, 0, 0, 0), // Extension
|
||||
new OpData(1, 0, 0, 0), // ExtInstImport
|
||||
new OpData(1, 1, 0, 1), // ExtInst
|
||||
new OpData(1, 1, 2, 1), // VectorShuffleCompact - new in SMOLV
|
||||
new OpData(0, 0, 0, 1), // MemoryModel
|
||||
new OpData(0, 0, 0, 1), // EntryPoint
|
||||
new OpData(0, 0, 0, 1), // ExecutionMode
|
||||
new OpData(0, 0, 0, 1), // Capability
|
||||
new OpData(1, 1, 0, 0), // #18
|
||||
new OpData(1, 0, 0, 1), // TypeVoid
|
||||
new OpData(1, 0, 0, 1), // TypeBool
|
||||
new OpData(1, 0, 0, 1), // TypeInt
|
||||
new OpData(1, 0, 0, 1), // TypeFloat
|
||||
new OpData(1, 0, 0, 1), // TypeVector
|
||||
new OpData(1, 0, 0, 1), // TypeMatrix
|
||||
new OpData(1, 0, 0, 1), // TypeImage
|
||||
new OpData(1, 0, 0, 1), // TypeSampler
|
||||
new OpData(1, 0, 0, 1), // TypeSampledImage
|
||||
new OpData(1, 0, 0, 1), // TypeArray
|
||||
new OpData(1, 0, 0, 1), // TypeRuntimeArray
|
||||
new OpData(1, 0, 0, 1), // TypeStruct
|
||||
new OpData(1, 0, 0, 1), // TypeOpaque
|
||||
new OpData(1, 0, 0, 1), // TypePointer
|
||||
new OpData(1, 0, 0, 1), // TypeFunction
|
||||
new OpData(1, 0, 0, 1), // TypeEvent
|
||||
new OpData(1, 0, 0, 1), // TypeDeviceEvent
|
||||
new OpData(1, 0, 0, 1), // TypeReserveId
|
||||
new OpData(1, 0, 0, 1), // TypeQueue
|
||||
new OpData(1, 0, 0, 1), // TypePipe
|
||||
new OpData(0, 0, 0, 1), // TypeForwardPointer
|
||||
new OpData(1, 1, 0, 0), // #40
|
||||
new OpData(1, 1, 0, 0), // ConstantTrue
|
||||
new OpData(1, 1, 0, 0), // ConstantFalse
|
||||
new OpData(1, 1, 0, 0), // Constant
|
||||
new OpData(1, 1, 9, 0), // ConstantComposite
|
||||
new OpData(1, 1, 0, 1), // ConstantSampler
|
||||
new OpData(1, 1, 0, 0), // ConstantNull
|
||||
new OpData(1, 1, 0, 0), // #47
|
||||
new OpData(1, 1, 0, 0), // SpecConstantTrue
|
||||
new OpData(1, 1, 0, 0), // SpecConstantFalse
|
||||
new OpData(1, 1, 0, 0), // SpecConstant
|
||||
new OpData(1, 1, 9, 0), // SpecConstantComposite
|
||||
new OpData(1, 1, 0, 0), // SpecConstantOp
|
||||
new OpData(1, 1, 0, 0), // #53
|
||||
new OpData(1, 1, 0, 1), // Function
|
||||
new OpData(1, 1, 0, 0), // FunctionParameter
|
||||
new OpData(0, 0, 0, 0), // FunctionEnd
|
||||
new OpData(1, 1, 9, 0), // FunctionCall
|
||||
new OpData(1, 1, 0, 0), // #58
|
||||
new OpData(1, 1, 0, 1), // Variable
|
||||
new OpData(1, 1, 0, 0), // ImageTexelPointer
|
||||
new OpData(1, 1, 1, 1), // Load
|
||||
new OpData(0, 0, 2, 1), // Store
|
||||
new OpData(0, 0, 0, 0), // CopyMemory
|
||||
new OpData(0, 0, 0, 0), // CopyMemorySized
|
||||
new OpData(1, 1, 0, 1), // AccessChain
|
||||
new OpData(1, 1, 0, 0), // InBoundsAccessChain
|
||||
new OpData(1, 1, 0, 0), // PtrAccessChain
|
||||
new OpData(1, 1, 0, 0), // ArrayLength
|
||||
new OpData(1, 1, 0, 0), // GenericPtrMemSemantics
|
||||
new OpData(1, 1, 0, 0), // InBoundsPtrAccessChain
|
||||
new OpData(0, 0, 0, 1), // Decorate
|
||||
new OpData(0, 0, 0, 1), // MemberDecorate
|
||||
new OpData(1, 0, 0, 0), // DecorationGroup
|
||||
new OpData(0, 0, 0, 0), // GroupDecorate
|
||||
new OpData(0, 0, 0, 0), // GroupMemberDecorate
|
||||
new OpData(1, 1, 0, 0), // #76
|
||||
new OpData(1, 1, 1, 1), // VectorExtractDynamic
|
||||
new OpData(1, 1, 2, 1), // VectorInsertDynamic
|
||||
new OpData(1, 1, 2, 1), // VectorShuffle
|
||||
new OpData(1, 1, 9, 0), // CompositeConstruct
|
||||
new OpData(1, 1, 1, 1), // CompositeExtract
|
||||
new OpData(1, 1, 2, 1), // CompositeInsert
|
||||
new OpData(1, 1, 1, 0), // CopyObject
|
||||
new OpData(1, 1, 0, 0), // Transpose
|
||||
new OpData(1, 1, 0, 0), // #85
|
||||
new OpData(1, 1, 0, 0), // SampledImage
|
||||
new OpData(1, 1, 2, 1), // ImageSampleImplicitLod
|
||||
new OpData(1, 1, 2, 1), // ImageSampleExplicitLod
|
||||
new OpData(1, 1, 3, 1), // ImageSampleDrefImplicitLod
|
||||
new OpData(1, 1, 3, 1), // ImageSampleDrefExplicitLod
|
||||
new OpData(1, 1, 2, 1), // ImageSampleProjImplicitLod
|
||||
new OpData(1, 1, 2, 1), // ImageSampleProjExplicitLod
|
||||
new OpData(1, 1, 3, 1), // ImageSampleProjDrefImplicitLod
|
||||
new OpData(1, 1, 3, 1), // ImageSampleProjDrefExplicitLod
|
||||
new OpData(1, 1, 2, 1), // ImageFetch
|
||||
new OpData(1, 1, 3, 1), // ImageGather
|
||||
new OpData(1, 1, 3, 1), // ImageDrefGather
|
||||
new OpData(1, 1, 2, 1), // ImageRead
|
||||
new OpData(0, 0, 3, 1), // ImageWrite
|
||||
new OpData(1, 1, 1, 0), // Image
|
||||
new OpData(1, 1, 1, 0), // ImageQueryFormat
|
||||
new OpData(1, 1, 1, 0), // ImageQueryOrder
|
||||
new OpData(1, 1, 2, 0), // ImageQuerySizeLod
|
||||
new OpData(1, 1, 1, 0), // ImageQuerySize
|
||||
new OpData(1, 1, 2, 0), // ImageQueryLod
|
||||
new OpData(1, 1, 1, 0), // ImageQueryLevels
|
||||
new OpData(1, 1, 1, 0), // ImageQuerySamples
|
||||
new OpData(1, 1, 0, 0), // #108
|
||||
new OpData(1, 1, 1, 0), // ConvertFToU
|
||||
new OpData(1, 1, 1, 0), // ConvertFToS
|
||||
new OpData(1, 1, 1, 0), // ConvertSToF
|
||||
new OpData(1, 1, 1, 0), // ConvertUToF
|
||||
new OpData(1, 1, 1, 0), // UConvert
|
||||
new OpData(1, 1, 1, 0), // SConvert
|
||||
new OpData(1, 1, 1, 0), // FConvert
|
||||
new OpData(1, 1, 1, 0), // QuantizeToF16
|
||||
new OpData(1, 1, 1, 0), // ConvertPtrToU
|
||||
new OpData(1, 1, 1, 0), // SatConvertSToU
|
||||
new OpData(1, 1, 1, 0), // SatConvertUToS
|
||||
new OpData(1, 1, 1, 0), // ConvertUToPtr
|
||||
new OpData(1, 1, 1, 0), // PtrCastToGeneric
|
||||
new OpData(1, 1, 1, 0), // GenericCastToPtr
|
||||
new OpData(1, 1, 1, 1), // GenericCastToPtrExplicit
|
||||
new OpData(1, 1, 1, 0), // Bitcast
|
||||
new OpData(1, 1, 0, 0), // #125
|
||||
new OpData(1, 1, 1, 0), // SNegate
|
||||
new OpData(1, 1, 1, 0), // FNegate
|
||||
new OpData(1, 1, 2, 0), // IAdd
|
||||
new OpData(1, 1, 2, 0), // FAdd
|
||||
new OpData(1, 1, 2, 0), // ISub
|
||||
new OpData(1, 1, 2, 0), // FSub
|
||||
new OpData(1, 1, 2, 0), // IMul
|
||||
new OpData(1, 1, 2, 0), // FMul
|
||||
new OpData(1, 1, 2, 0), // UDiv
|
||||
new OpData(1, 1, 2, 0), // SDiv
|
||||
new OpData(1, 1, 2, 0), // FDiv
|
||||
new OpData(1, 1, 2, 0), // UMod
|
||||
new OpData(1, 1, 2, 0), // SRem
|
||||
new OpData(1, 1, 2, 0), // SMod
|
||||
new OpData(1, 1, 2, 0), // FRem
|
||||
new OpData(1, 1, 2, 0), // FMod
|
||||
new OpData(1, 1, 2, 0), // VectorTimesScalar
|
||||
new OpData(1, 1, 2, 0), // MatrixTimesScalar
|
||||
new OpData(1, 1, 2, 0), // VectorTimesMatrix
|
||||
new OpData(1, 1, 2, 0), // MatrixTimesVector
|
||||
new OpData(1, 1, 2, 0), // MatrixTimesMatrix
|
||||
new OpData(1, 1, 2, 0), // OuterProduct
|
||||
new OpData(1, 1, 2, 0), // Dot
|
||||
new OpData(1, 1, 2, 0), // IAddCarry
|
||||
new OpData(1, 1, 2, 0), // ISubBorrow
|
||||
new OpData(1, 1, 2, 0), // UMulExtended
|
||||
new OpData(1, 1, 2, 0), // SMulExtended
|
||||
new OpData(1, 1, 0, 0), // #153
|
||||
new OpData(1, 1, 1, 0), // Any
|
||||
new OpData(1, 1, 1, 0), // All
|
||||
new OpData(1, 1, 1, 0), // IsNan
|
||||
new OpData(1, 1, 1, 0), // IsInf
|
||||
new OpData(1, 1, 1, 0), // IsFinite
|
||||
new OpData(1, 1, 1, 0), // IsNormal
|
||||
new OpData(1, 1, 1, 0), // SignBitSet
|
||||
new OpData(1, 1, 2, 0), // LessOrGreater
|
||||
new OpData(1, 1, 2, 0), // Ordered
|
||||
new OpData(1, 1, 2, 0), // Unordered
|
||||
new OpData(1, 1, 2, 0), // LogicalEqual
|
||||
new OpData(1, 1, 2, 0), // LogicalNotEqual
|
||||
new OpData(1, 1, 2, 0), // LogicalOr
|
||||
new OpData(1, 1, 2, 0), // LogicalAnd
|
||||
new OpData(1, 1, 1, 0), // LogicalNot
|
||||
new OpData(1, 1, 3, 0), // Select
|
||||
new OpData(1, 1, 2, 0), // IEqual
|
||||
new OpData(1, 1, 2, 0), // INotEqual
|
||||
new OpData(1, 1, 2, 0), // UGreaterThan
|
||||
new OpData(1, 1, 2, 0), // SGreaterThan
|
||||
new OpData(1, 1, 2, 0), // UGreaterThanEqual
|
||||
new OpData(1, 1, 2, 0), // SGreaterThanEqual
|
||||
new OpData(1, 1, 2, 0), // ULessThan
|
||||
new OpData(1, 1, 2, 0), // SLessThan
|
||||
new OpData(1, 1, 2, 0), // ULessThanEqual
|
||||
new OpData(1, 1, 2, 0), // SLessThanEqual
|
||||
new OpData(1, 1, 2, 0), // FOrdEqual
|
||||
new OpData(1, 1, 2, 0), // FUnordEqual
|
||||
new OpData(1, 1, 2, 0), // FOrdNotEqual
|
||||
new OpData(1, 1, 2, 0), // FUnordNotEqual
|
||||
new OpData(1, 1, 2, 0), // FOrdLessThan
|
||||
new OpData(1, 1, 2, 0), // FUnordLessThan
|
||||
new OpData(1, 1, 2, 0), // FOrdGreaterThan
|
||||
new OpData(1, 1, 2, 0), // FUnordGreaterThan
|
||||
new OpData(1, 1, 2, 0), // FOrdLessThanEqual
|
||||
new OpData(1, 1, 2, 0), // FUnordLessThanEqual
|
||||
new OpData(1, 1, 2, 0), // FOrdGreaterThanEqual
|
||||
new OpData(1, 1, 2, 0), // FUnordGreaterThanEqual
|
||||
new OpData(1, 1, 0, 0), // #192
|
||||
new OpData(1, 1, 0, 0), // #193
|
||||
new OpData(1, 1, 2, 0), // ShiftRightLogical
|
||||
new OpData(1, 1, 2, 0), // ShiftRightArithmetic
|
||||
new OpData(1, 1, 2, 0), // ShiftLeftLogical
|
||||
new OpData(1, 1, 2, 0), // BitwiseOr
|
||||
new OpData(1, 1, 2, 0), // BitwiseXor
|
||||
new OpData(1, 1, 2, 0), // BitwiseAnd
|
||||
new OpData(1, 1, 1, 0), // Not
|
||||
new OpData(1, 1, 4, 0), // BitFieldInsert
|
||||
new OpData(1, 1, 3, 0), // BitFieldSExtract
|
||||
new OpData(1, 1, 3, 0), // BitFieldUExtract
|
||||
new OpData(1, 1, 1, 0), // BitReverse
|
||||
new OpData(1, 1, 1, 0), // BitCount
|
||||
new OpData(1, 1, 0, 0), // #206
|
||||
new OpData(1, 1, 0, 0), // DPdx
|
||||
new OpData(1, 1, 0, 0), // DPdy
|
||||
new OpData(1, 1, 0, 0), // Fwidth
|
||||
new OpData(1, 1, 0, 0), // DPdxFine
|
||||
new OpData(1, 1, 0, 0), // DPdyFine
|
||||
new OpData(1, 1, 0, 0), // FwidthFine
|
||||
new OpData(1, 1, 0, 0), // DPdxCoarse
|
||||
new OpData(1, 1, 0, 0), // DPdyCoarse
|
||||
new OpData(1, 1, 0, 0), // FwidthCoarse
|
||||
new OpData(1, 1, 0, 0), // #216
|
||||
new OpData(1, 1, 0, 0), // #217
|
||||
new OpData(0, 0, 0, 0), // EmitVertex
|
||||
new OpData(0, 0, 0, 0), // EndPrimitive
|
||||
new OpData(0, 0, 0, 0), // EmitStreamVertex
|
||||
new OpData(0, 0, 0, 0), // EndStreamPrimitive
|
||||
new OpData(1, 1, 0, 0), // #222
|
||||
new OpData(1, 1, 0, 0), // #223
|
||||
new OpData(0, 0, -3, 0), // ControlBarrier
|
||||
new OpData(0, 0, -2, 0), // MemoryBarrier
|
||||
new OpData(1, 1, 0, 0), // #226
|
||||
new OpData(1, 1, 0, 0), // AtomicLoad
|
||||
new OpData(0, 0, 0, 0), // AtomicStore
|
||||
new OpData(1, 1, 0, 0), // AtomicExchange
|
||||
new OpData(1, 1, 0, 0), // AtomicCompareExchange
|
||||
new OpData(1, 1, 0, 0), // AtomicCompareExchangeWeak
|
||||
new OpData(1, 1, 0, 0), // AtomicIIncrement
|
||||
new OpData(1, 1, 0, 0), // AtomicIDecrement
|
||||
new OpData(1, 1, 0, 0), // AtomicIAdd
|
||||
new OpData(1, 1, 0, 0), // AtomicISub
|
||||
new OpData(1, 1, 0, 0), // AtomicSMin
|
||||
new OpData(1, 1, 0, 0), // AtomicUMin
|
||||
new OpData(1, 1, 0, 0), // AtomicSMax
|
||||
new OpData(1, 1, 0, 0), // AtomicUMax
|
||||
new OpData(1, 1, 0, 0), // AtomicAnd
|
||||
new OpData(1, 1, 0, 0), // AtomicOr
|
||||
new OpData(1, 1, 0, 0), // AtomicXor
|
||||
new OpData(1, 1, 0, 0), // #243
|
||||
new OpData(1, 1, 0, 0), // #244
|
||||
new OpData(1, 1, 0, 0), // Phi
|
||||
new OpData(0, 0, -2, 1), // LoopMerge
|
||||
new OpData(0, 0, -1, 1), // SelectionMerge
|
||||
new OpData(1, 0, 0, 0), // Label
|
||||
new OpData(0, 0, -1, 0), // Branch
|
||||
new OpData(0, 0, -3, 1), // BranchConditional
|
||||
new OpData(0, 0, 0, 0), // Switch
|
||||
new OpData(0, 0, 0, 0), // Kill
|
||||
new OpData(0, 0, 0, 0), // Return
|
||||
new OpData(0, 0, 0, 0), // ReturnValue
|
||||
new OpData(0, 0, 0, 0), // Unreachable
|
||||
new OpData(0, 0, 0, 0), // LifetimeStart
|
||||
new OpData(0, 0, 0, 0), // LifetimeStop
|
||||
new OpData(1, 1, 0, 0), // #258
|
||||
new OpData(1, 1, 0, 0), // GroupAsyncCopy
|
||||
new OpData(0, 0, 0, 0), // GroupWaitEvents
|
||||
new OpData(1, 1, 0, 0), // GroupAll
|
||||
new OpData(1, 1, 0, 0), // GroupAny
|
||||
new OpData(1, 1, 0, 0), // GroupBroadcast
|
||||
new OpData(1, 1, 0, 0), // GroupIAdd
|
||||
new OpData(1, 1, 0, 0), // GroupFAdd
|
||||
new OpData(1, 1, 0, 0), // GroupFMin
|
||||
new OpData(1, 1, 0, 0), // GroupUMin
|
||||
new OpData(1, 1, 0, 0), // GroupSMin
|
||||
new OpData(1, 1, 0, 0), // GroupFMax
|
||||
new OpData(1, 1, 0, 0), // GroupUMax
|
||||
new OpData(1, 1, 0, 0), // GroupSMax
|
||||
new OpData(1, 1, 0, 0), // #272
|
||||
new OpData(1, 1, 0, 0), // #273
|
||||
new OpData(1, 1, 0, 0), // ReadPipe
|
||||
new OpData(1, 1, 0, 0), // WritePipe
|
||||
new OpData(1, 1, 0, 0), // ReservedReadPipe
|
||||
new OpData(1, 1, 0, 0), // ReservedWritePipe
|
||||
new OpData(1, 1, 0, 0), // ReserveReadPipePackets
|
||||
new OpData(1, 1, 0, 0), // ReserveWritePipePackets
|
||||
new OpData(0, 0, 0, 0), // CommitReadPipe
|
||||
new OpData(0, 0, 0, 0), // CommitWritePipe
|
||||
new OpData(1, 1, 0, 0), // IsValidReserveId
|
||||
new OpData(1, 1, 0, 0), // GetNumPipePackets
|
||||
new OpData(1, 1, 0, 0), // GetMaxPipePackets
|
||||
new OpData(1, 1, 0, 0), // GroupReserveReadPipePackets
|
||||
new OpData(1, 1, 0, 0), // GroupReserveWritePipePackets
|
||||
new OpData(0, 0, 0, 0), // GroupCommitReadPipe
|
||||
new OpData(0, 0, 0, 0), // GroupCommitWritePipe
|
||||
new OpData(1, 1, 0, 0), // #289
|
||||
new OpData(1, 1, 0, 0), // #290
|
||||
new OpData(1, 1, 0, 0), // EnqueueMarker
|
||||
new OpData(1, 1, 0, 0), // EnqueueKernel
|
||||
new OpData(1, 1, 0, 0), // GetKernelNDrangeSubGroupCount
|
||||
new OpData(1, 1, 0, 0), // GetKernelNDrangeMaxSubGroupSize
|
||||
new OpData(1, 1, 0, 0), // GetKernelWorkGroupSize
|
||||
new OpData(1, 1, 0, 0), // GetKernelPreferredWorkGroupSizeMultiple
|
||||
new OpData(0, 0, 0, 0), // RetainEvent
|
||||
new OpData(0, 0, 0, 0), // ReleaseEvent
|
||||
new OpData(1, 1, 0, 0), // CreateUserEvent
|
||||
new OpData(1, 1, 0, 0), // IsValidEvent
|
||||
new OpData(0, 0, 0, 0), // SetUserEventStatus
|
||||
new OpData(0, 0, 0, 0), // CaptureEventProfilingInfo
|
||||
new OpData(1, 1, 0, 0), // GetDefaultQueue
|
||||
new OpData(1, 1, 0, 0), // BuildNDRange
|
||||
new OpData(1, 1, 2, 1), // ImageSparseSampleImplicitLod
|
||||
new OpData(1, 1, 2, 1), // ImageSparseSampleExplicitLod
|
||||
new OpData(1, 1, 3, 1), // ImageSparseSampleDrefImplicitLod
|
||||
new OpData(1, 1, 3, 1), // ImageSparseSampleDrefExplicitLod
|
||||
new OpData(1, 1, 2, 1), // ImageSparseSampleProjImplicitLod
|
||||
new OpData(1, 1, 2, 1), // ImageSparseSampleProjExplicitLod
|
||||
new OpData(1, 1, 3, 1), // ImageSparseSampleProjDrefImplicitLod
|
||||
new OpData(1, 1, 3, 1), // ImageSparseSampleProjDrefExplicitLod
|
||||
new OpData(1, 1, 2, 1), // ImageSparseFetch
|
||||
new OpData(1, 1, 3, 1), // ImageSparseGather
|
||||
new OpData(1, 1, 3, 1), // ImageSparseDrefGather
|
||||
new OpData(1, 1, 1, 0), // ImageSparseTexelsResident
|
||||
new OpData(0, 0, 0, 0), // NoLine
|
||||
new OpData(1, 1, 0, 0), // AtomicFlagTestAndSet
|
||||
new OpData(0, 0, 0, 0), // AtomicFlagClear
|
||||
new OpData(1, 1, 0, 0), // ImageSparseRead
|
||||
new OpData(1, 1, 0, 0), // SizeOf
|
||||
new OpData(1, 1, 0, 0), // TypePipeStorage
|
||||
new OpData(1, 1, 0, 0), // ConstantPipeStorage
|
||||
new OpData(1, 1, 0, 0), // CreatePipeFromPipeStorage
|
||||
new OpData(1, 1, 0, 0), // GetKernelLocalSizeForSubgroupCount
|
||||
new OpData(1, 1, 0, 0), // GetKernelMaxNumSubgroups
|
||||
new OpData(1, 1, 0, 0), // TypeNamedBarrier
|
||||
new OpData(1, 1, 0, 1), // NamedBarrierInitialize
|
||||
new OpData(0, 0, -2, 1), // MemoryNamedBarrier
|
||||
new OpData(1, 1, 0, 0), // ModuleProcessed
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Smolv
|
||||
{
|
||||
public static class SmolvDecoder
|
||||
{
|
||||
public static int GetDecodedBufferSize(byte[] data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
if (!CheckSmolHeader(data))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int size = BitConverter.ToInt32(data, 5 * sizeof(uint));
|
||||
return size;
|
||||
}
|
||||
|
||||
public static int GetDecodedBufferSize(Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
throw new ArgumentException(nameof(stream));
|
||||
}
|
||||
if (stream.Position + HeaderSize > stream.Length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
long initPosition = stream.Position;
|
||||
stream.Position += HeaderSize - sizeof(uint);
|
||||
int size = stream.ReadByte() | stream.ReadByte() << 8 | stream.ReadByte() << 16 | stream.ReadByte() << 24;
|
||||
stream.Position = initPosition;
|
||||
return size;
|
||||
}
|
||||
|
||||
public static byte[] Decode(byte[] data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
int bufferSize = GetDecodedBufferSize(data);
|
||||
if (bufferSize == 0)
|
||||
{
|
||||
// invalid SMOL-V
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] output = new byte[bufferSize];
|
||||
if (Decode(data, output))
|
||||
{
|
||||
return output;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool Decode(byte[] data, byte[] output)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
if (output == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(output));
|
||||
}
|
||||
|
||||
int bufferSize = GetDecodedBufferSize(data);
|
||||
if (bufferSize > output.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using (MemoryStream outputStream = new MemoryStream(output))
|
||||
{
|
||||
return Decode(data, outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Decode(byte[] data, Stream outputStream)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
using (MemoryStream inputStream = new MemoryStream(data))
|
||||
{
|
||||
return Decode(inputStream, data.Length, outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Decode(Stream inputStream, int inputSize, Stream outputStream)
|
||||
{
|
||||
if (inputStream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(inputStream));
|
||||
}
|
||||
if (outputStream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(outputStream));
|
||||
}
|
||||
if (inputStream.Length < HeaderSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using (BinaryReader input = new BinaryReader(inputStream, Encoding.UTF8, true))
|
||||
{
|
||||
using (BinaryWriter output = new BinaryWriter(outputStream, Encoding.UTF8, true))
|
||||
{
|
||||
long inputEndPosition = input.BaseStream.Position + inputSize;
|
||||
long outputStartPosition = output.BaseStream.Position;
|
||||
|
||||
// Header
|
||||
output.Write(SpirVHeaderMagic);
|
||||
input.BaseStream.Position += sizeof(uint);
|
||||
uint version = input.ReadUInt32();
|
||||
output.Write(version);
|
||||
uint generator = input.ReadUInt32();
|
||||
output.Write(generator);
|
||||
int bound = input.ReadInt32();
|
||||
output.Write(bound);
|
||||
uint schema = input.ReadUInt32();
|
||||
output.Write(schema);
|
||||
int decodedSize = input.ReadInt32();
|
||||
|
||||
// Body
|
||||
int prevResult = 0;
|
||||
int prevDecorate = 0;
|
||||
while (input.BaseStream.Position < inputEndPosition)
|
||||
{
|
||||
// read length + opcode
|
||||
if (!ReadLengthOp(input, out uint instrLen, out SpvOp op))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wasSwizzle = op == SpvOp.VectorShuffleCompact;
|
||||
if (wasSwizzle)
|
||||
{
|
||||
op = SpvOp.VectorShuffle;
|
||||
}
|
||||
output.Write((instrLen << 16) | (uint)op);
|
||||
|
||||
uint ioffs = 1;
|
||||
// read type as varint, if we have it
|
||||
if (op.OpHasType())
|
||||
{
|
||||
if (!ReadVarint(input, out uint value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
output.Write(value);
|
||||
ioffs++;
|
||||
}
|
||||
|
||||
// read result as delta+varint, if we have it
|
||||
if (op.OpHasResult())
|
||||
{
|
||||
if (!ReadVarint(input, out uint value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int zds = prevResult + ZigDecode(value);
|
||||
output.Write(zds);
|
||||
prevResult = zds;
|
||||
ioffs++;
|
||||
}
|
||||
|
||||
// Decorate: IDs relative to previous decorate
|
||||
if (op == SpvOp.Decorate || op == SpvOp.MemberDecorate)
|
||||
{
|
||||
if (!ReadVarint(input, out uint value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int zds = prevDecorate + unchecked((int)value);
|
||||
output.Write(zds);
|
||||
prevDecorate = zds;
|
||||
ioffs++;
|
||||
}
|
||||
|
||||
// Read this many IDs, that are relative to result ID
|
||||
int relativeCount = op.OpDeltaFromResult();
|
||||
bool inverted = false;
|
||||
if (relativeCount < 0)
|
||||
{
|
||||
inverted = true;
|
||||
relativeCount = -relativeCount;
|
||||
}
|
||||
for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
|
||||
{
|
||||
if (!ReadVarint(input, out uint value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int zd = inverted ? ZigDecode(value) : unchecked((int)value);
|
||||
output.Write(prevResult - zd);
|
||||
}
|
||||
|
||||
if (wasSwizzle && instrLen <= 9)
|
||||
{
|
||||
uint swizzle = input.ReadByte();
|
||||
if (instrLen > 5) output.Write(swizzle >> 6);
|
||||
if (instrLen > 6) output.Write((swizzle >> 4) & 3);
|
||||
if (instrLen > 7) output.Write((swizzle >> 2) & 3);
|
||||
if (instrLen > 8) output.Write(swizzle & 3);
|
||||
}
|
||||
else if (op.OpVarRest())
|
||||
{
|
||||
// read rest of words with variable encoding
|
||||
for (; ioffs < instrLen; ++ioffs)
|
||||
{
|
||||
if (!ReadVarint(input, out uint value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
output.Write(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// read rest of words without any encoding
|
||||
for (; ioffs < instrLen; ++ioffs)
|
||||
{
|
||||
if (input.BaseStream.Position + 4 > input.BaseStream.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uint val = input.ReadUInt32();
|
||||
output.Write(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (output.BaseStream.Position != outputStartPosition + decodedSize)
|
||||
{
|
||||
// something went wrong during decoding? we should have decoded to exact output size
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CheckSmolHeader(byte[] data)
|
||||
{
|
||||
if (!CheckGenericHeader(data, SmolHeaderMagic))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CheckGenericHeader(byte[] data, uint expectedMagic)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (data.Length < HeaderSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint headerMagic = BitConverter.ToUInt32(data, 0 * sizeof(uint));
|
||||
if (headerMagic != expectedMagic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint headerVersion = BitConverter.ToUInt32(data, 1 * sizeof(uint));
|
||||
if (headerVersion < 0x00010000 || headerVersion > 0x00010300)
|
||||
{
|
||||
// only support 1.0 through 1.3
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool ReadVarint(BinaryReader input, out uint value)
|
||||
{
|
||||
uint v = 0;
|
||||
int shift = 0;
|
||||
while (input.BaseStream.Position < input.BaseStream.Length)
|
||||
{
|
||||
byte b = input.ReadByte();
|
||||
v |= unchecked((uint)(b & 127) << shift);
|
||||
shift += 7;
|
||||
if ((b & 128) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value = v;
|
||||
// @TODO: report failures
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool ReadLengthOp(BinaryReader input, out uint len, out SpvOp op)
|
||||
{
|
||||
len = default;
|
||||
op = default;
|
||||
if (!ReadVarint(input, out uint value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
len = ((value >> 20) << 4) | ((value >> 4) & 0xF);
|
||||
op = (SpvOp) (((value >> 4) & 0xFFF0) | (value & 0xF));
|
||||
|
||||
op = RemapOp(op);
|
||||
len = DecodeLen(op, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remap most common Op codes (Load, Store, Decorate, VectorShuffle etc.) to be in < 16 range, for
|
||||
/// more compact varint encoding. This basically swaps rarely used op values that are < 16 with the
|
||||
/// ones that are common.
|
||||
/// </summary>
|
||||
private static SpvOp RemapOp(SpvOp op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
// 0: 24%
|
||||
case SpvOp.Decorate:
|
||||
return SpvOp.Nop;
|
||||
case SpvOp.Nop:
|
||||
return SpvOp.Decorate;
|
||||
|
||||
// 1: 17%
|
||||
case SpvOp.Load:
|
||||
return SpvOp.Undef;
|
||||
case SpvOp.Undef:
|
||||
return SpvOp.Load;
|
||||
|
||||
// 2: 9%
|
||||
case SpvOp.Store:
|
||||
return SpvOp.SourceContinued;
|
||||
case SpvOp.SourceContinued:
|
||||
return SpvOp.Store;
|
||||
|
||||
// 3: 7.2%
|
||||
case SpvOp.AccessChain:
|
||||
return SpvOp.Source;
|
||||
case SpvOp.Source:
|
||||
return SpvOp.AccessChain;
|
||||
|
||||
// 4: 5.0%
|
||||
// Name - already small enum value - 5: 4.4%
|
||||
// MemberName - already small enum value - 6: 2.9%
|
||||
case SpvOp.VectorShuffle:
|
||||
return SpvOp.SourceExtension;
|
||||
case SpvOp.SourceExtension:
|
||||
return SpvOp.VectorShuffle;
|
||||
|
||||
// 7: 4.0%
|
||||
case SpvOp.MemberDecorate:
|
||||
return SpvOp.String;
|
||||
case SpvOp.String:
|
||||
return SpvOp.MemberDecorate;
|
||||
|
||||
// 8: 0.9%
|
||||
case SpvOp.Label:
|
||||
return SpvOp.Line;
|
||||
case SpvOp.Line:
|
||||
return SpvOp.Label;
|
||||
|
||||
// 9: 3.9%
|
||||
case SpvOp.Variable:
|
||||
return (SpvOp)9;
|
||||
case (SpvOp)9:
|
||||
return SpvOp.Variable;
|
||||
|
||||
// 10: 3.9%
|
||||
case SpvOp.FMul:
|
||||
return SpvOp.Extension;
|
||||
case SpvOp.Extension:
|
||||
return SpvOp.FMul;
|
||||
|
||||
// 11: 2.5%
|
||||
// ExtInst - already small enum value - 12: 1.2%
|
||||
// VectorShuffleCompact - already small enum value - used for compact shuffle encoding
|
||||
case SpvOp.FAdd:
|
||||
return SpvOp.ExtInstImport;
|
||||
case SpvOp.ExtInstImport:
|
||||
return SpvOp.FAdd;
|
||||
|
||||
// 14: 2.2%
|
||||
case SpvOp.TypePointer:
|
||||
return SpvOp.MemoryModel;
|
||||
case SpvOp.MemoryModel:
|
||||
return SpvOp.TypePointer;
|
||||
|
||||
// 15: 1.1%
|
||||
case SpvOp.FNegate:
|
||||
return SpvOp.EntryPoint;
|
||||
case SpvOp.EntryPoint:
|
||||
return SpvOp.FNegate;
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
private static uint DecodeLen(SpvOp op, uint len)
|
||||
{
|
||||
len++;
|
||||
switch (op)
|
||||
{
|
||||
case SpvOp.VectorShuffle:
|
||||
len += 4;
|
||||
break;
|
||||
case SpvOp.VectorShuffleCompact:
|
||||
len += 4;
|
||||
break;
|
||||
case SpvOp.Decorate:
|
||||
len += 2;
|
||||
break;
|
||||
case SpvOp.Load:
|
||||
len += 3;
|
||||
break;
|
||||
case SpvOp.AccessChain:
|
||||
len += 3;
|
||||
break;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
private static int DecorationExtraOps(int dec)
|
||||
{
|
||||
// RelaxedPrecision, Block..ColMajor
|
||||
if (dec == 0 || (dec >= 2 && dec <= 5))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// Stream..XfbStride
|
||||
if (dec >= 29 && dec <= 37)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// unknown, encode length
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int ZigDecode(uint u)
|
||||
{
|
||||
return (u & 1) != 0 ? unchecked((int)(~(u >> 1))) : unchecked((int)(u >> 1));
|
||||
}
|
||||
|
||||
public const uint SpirVHeaderMagic = 0x07230203;
|
||||
/// <summary>
|
||||
/// 'SMOL' ascii
|
||||
/// </summary>
|
||||
public const uint SmolHeaderMagic = 0x534D4F4C;
|
||||
|
||||
private const int HeaderSize = 6 * sizeof(uint);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
namespace Smolv
|
||||
{
|
||||
public enum SpvOp
|
||||
{
|
||||
Nop = 0,
|
||||
Undef = 1,
|
||||
SourceContinued = 2,
|
||||
Source = 3,
|
||||
SourceExtension = 4,
|
||||
Name = 5,
|
||||
MemberName = 6,
|
||||
String = 7,
|
||||
Line = 8,
|
||||
Extension = 10,
|
||||
ExtInstImport = 11,
|
||||
ExtInst = 12,
|
||||
/// <summary>
|
||||
/// Not in SPIR-V, added for SMOL-V!
|
||||
/// </summary>
|
||||
VectorShuffleCompact = 13,
|
||||
MemoryModel = 14,
|
||||
EntryPoint = 15,
|
||||
ExecutionMode = 16,
|
||||
Capability = 17,
|
||||
TypeVoid = 19,
|
||||
TypeBool = 20,
|
||||
TypeInt = 21,
|
||||
TypeFloat = 22,
|
||||
TypeVector = 23,
|
||||
TypeMatrix = 24,
|
||||
TypeImage = 25,
|
||||
TypeSampler = 26,
|
||||
TypeSampledImage = 27,
|
||||
TypeArray = 28,
|
||||
TypeRuntimeArray = 29,
|
||||
TypeStruct = 30,
|
||||
TypeOpaque = 31,
|
||||
TypePointer = 32,
|
||||
TypeFunction = 33,
|
||||
TypeEvent = 34,
|
||||
TypeDeviceEvent = 35,
|
||||
TypeReserveId = 36,
|
||||
TypeQueue = 37,
|
||||
TypePipe = 38,
|
||||
TypeForwardPointer = 39,
|
||||
ConstantTrue = 41,
|
||||
ConstantFalse = 42,
|
||||
Constant = 43,
|
||||
ConstantComposite = 44,
|
||||
ConstantSampler = 45,
|
||||
ConstantNull = 46,
|
||||
SpecConstantTrue = 48,
|
||||
SpecConstantFalse = 49,
|
||||
SpecConstant = 50,
|
||||
SpecConstantComposite = 51,
|
||||
SpecConstantOp = 52,
|
||||
Function = 54,
|
||||
FunctionParameter = 55,
|
||||
FunctionEnd = 56,
|
||||
FunctionCall = 57,
|
||||
Variable = 59,
|
||||
ImageTexelPointer = 60,
|
||||
Load = 61,
|
||||
Store = 62,
|
||||
CopyMemory = 63,
|
||||
CopyMemorySized = 64,
|
||||
AccessChain = 65,
|
||||
InBoundsAccessChain = 66,
|
||||
PtrAccessChain = 67,
|
||||
ArrayLength = 68,
|
||||
GenericPtrMemSemantics = 69,
|
||||
InBoundsPtrAccessChain = 70,
|
||||
Decorate = 71,
|
||||
MemberDecorate = 72,
|
||||
DecorationGroup = 73,
|
||||
GroupDecorate = 74,
|
||||
GroupMemberDecorate = 75,
|
||||
VectorExtractDynamic = 77,
|
||||
VectorInsertDynamic = 78,
|
||||
VectorShuffle = 79,
|
||||
CompositeConstruct = 80,
|
||||
CompositeExtract = 81,
|
||||
CompositeInsert = 82,
|
||||
CopyObject = 83,
|
||||
Transpose = 84,
|
||||
SampledImage = 86,
|
||||
ImageSampleImplicitLod = 87,
|
||||
ImageSampleExplicitLod = 88,
|
||||
ImageSampleDrefImplicitLod = 89,
|
||||
ImageSampleDrefExplicitLod = 90,
|
||||
ImageSampleProjImplicitLod = 91,
|
||||
ImageSampleProjExplicitLod = 92,
|
||||
ImageSampleProjDrefImplicitLod = 93,
|
||||
ImageSampleProjDrefExplicitLod = 94,
|
||||
ImageFetch = 95,
|
||||
ImageGather = 96,
|
||||
ImageDrefGather = 97,
|
||||
ImageRead = 98,
|
||||
ImageWrite = 99,
|
||||
Image = 100,
|
||||
ImageQueryFormat = 101,
|
||||
ImageQueryOrder = 102,
|
||||
ImageQuerySizeLod = 103,
|
||||
ImageQuerySize = 104,
|
||||
ImageQueryLod = 105,
|
||||
ImageQueryLevels = 106,
|
||||
ImageQuerySamples = 107,
|
||||
ConvertFToU = 109,
|
||||
ConvertFToS = 110,
|
||||
ConvertSToF = 111,
|
||||
ConvertUToF = 112,
|
||||
UConvert = 113,
|
||||
SConvert = 114,
|
||||
FConvert = 115,
|
||||
QuantizeToF16 = 116,
|
||||
ConvertPtrToU = 117,
|
||||
SatConvertSToU = 118,
|
||||
SatConvertUToS = 119,
|
||||
ConvertUToPtr = 120,
|
||||
PtrCastToGeneric = 121,
|
||||
GenericCastToPtr = 122,
|
||||
GenericCastToPtrExplicit = 123,
|
||||
Bitcast = 124,
|
||||
SNegate = 126,
|
||||
FNegate = 127,
|
||||
IAdd = 128,
|
||||
FAdd = 129,
|
||||
ISub = 130,
|
||||
FSub = 131,
|
||||
IMul = 132,
|
||||
FMul = 133,
|
||||
UDiv = 134,
|
||||
SDiv = 135,
|
||||
FDiv = 136,
|
||||
UMod = 137,
|
||||
SRem = 138,
|
||||
SMod = 139,
|
||||
FRem = 140,
|
||||
FMod = 141,
|
||||
VectorTimesScalar = 142,
|
||||
MatrixTimesScalar = 143,
|
||||
VectorTimesMatrix = 144,
|
||||
MatrixTimesVector = 145,
|
||||
MatrixTimesMatrix = 146,
|
||||
OuterProduct = 147,
|
||||
Dot = 148,
|
||||
IAddCarry = 149,
|
||||
ISubBorrow = 150,
|
||||
UMulExtended = 151,
|
||||
SMulExtended = 152,
|
||||
Any = 154,
|
||||
All = 155,
|
||||
IsNan = 156,
|
||||
IsInf = 157,
|
||||
IsFinite = 158,
|
||||
IsNormal = 159,
|
||||
SignBitSet = 160,
|
||||
LessOrGreater = 161,
|
||||
Ordered = 162,
|
||||
Unordered = 163,
|
||||
LogicalEqual = 164,
|
||||
LogicalNotEqual = 165,
|
||||
LogicalOr = 166,
|
||||
LogicalAnd = 167,
|
||||
LogicalNot = 168,
|
||||
Select = 169,
|
||||
IEqual = 170,
|
||||
INotEqual = 171,
|
||||
UGreaterThan = 172,
|
||||
SGreaterThan = 173,
|
||||
UGreaterThanEqual = 174,
|
||||
SGreaterThanEqual = 175,
|
||||
ULessThan = 176,
|
||||
SLessThan = 177,
|
||||
ULessThanEqual = 178,
|
||||
SLessThanEqual = 179,
|
||||
FOrdEqual = 180,
|
||||
FUnordEqual = 181,
|
||||
FOrdNotEqual = 182,
|
||||
FUnordNotEqual = 183,
|
||||
FOrdLessThan = 184,
|
||||
FUnordLessThan = 185,
|
||||
FOrdGreaterThan = 186,
|
||||
FUnordGreaterThan = 187,
|
||||
FOrdLessThanEqual = 188,
|
||||
FUnordLessThanEqual = 189,
|
||||
FOrdGreaterThanEqual = 190,
|
||||
FUnordGreaterThanEqual = 191,
|
||||
ShiftRightLogical = 194,
|
||||
ShiftRightArithmetic = 195,
|
||||
ShiftLeftLogical = 196,
|
||||
BitwiseOr = 197,
|
||||
BitwiseXor = 198,
|
||||
BitwiseAnd = 199,
|
||||
Not = 200,
|
||||
BitFieldInsert = 201,
|
||||
BitFieldSExtract = 202,
|
||||
BitFieldUExtract = 203,
|
||||
BitReverse = 204,
|
||||
BitCount = 205,
|
||||
DPdx = 207,
|
||||
DPdy = 208,
|
||||
Fwidth = 209,
|
||||
DPdxFine = 210,
|
||||
DPdyFine = 211,
|
||||
FwidthFine = 212,
|
||||
DPdxCoarse = 213,
|
||||
DPdyCoarse = 214,
|
||||
FwidthCoarse = 215,
|
||||
EmitVertex = 218,
|
||||
EndPrimitive = 219,
|
||||
EmitStreamVertex = 220,
|
||||
EndStreamPrimitive = 221,
|
||||
ControlBarrier = 224,
|
||||
MemoryBarrier = 225,
|
||||
AtomicLoad = 227,
|
||||
AtomicStore = 228,
|
||||
AtomicExchange = 229,
|
||||
AtomicCompareExchange = 230,
|
||||
AtomicCompareExchangeWeak = 231,
|
||||
AtomicIIncrement = 232,
|
||||
AtomicIDecrement = 233,
|
||||
AtomicIAdd = 234,
|
||||
AtomicISub = 235,
|
||||
AtomicSMin = 236,
|
||||
AtomicUMin = 237,
|
||||
AtomicSMax = 238,
|
||||
AtomicUMax = 239,
|
||||
AtomicAnd = 240,
|
||||
AtomicOr = 241,
|
||||
AtomicXor = 242,
|
||||
Phi = 245,
|
||||
LoopMerge = 246,
|
||||
SelectionMerge = 247,
|
||||
Label = 248,
|
||||
Branch = 249,
|
||||
BranchConditional = 250,
|
||||
Switch = 251,
|
||||
Kill = 252,
|
||||
Return = 253,
|
||||
ReturnValue = 254,
|
||||
Unreachable = 255,
|
||||
LifetimeStart = 256,
|
||||
LifetimeStop = 257,
|
||||
GroupAsyncCopy = 259,
|
||||
GroupWaitEvents = 260,
|
||||
GroupAll = 261,
|
||||
GroupAny = 262,
|
||||
GroupBroadcast = 263,
|
||||
GroupIAdd = 264,
|
||||
GroupFAdd = 265,
|
||||
GroupFMin = 266,
|
||||
GroupUMin = 267,
|
||||
GroupSMin = 268,
|
||||
GroupFMax = 269,
|
||||
GroupUMax = 270,
|
||||
GroupSMax = 271,
|
||||
ReadPipe = 274,
|
||||
WritePipe = 275,
|
||||
ReservedReadPipe = 276,
|
||||
ReservedWritePipe = 277,
|
||||
ReserveReadPipePackets = 278,
|
||||
ReserveWritePipePackets = 279,
|
||||
CommitReadPipe = 280,
|
||||
CommitWritePipe = 281,
|
||||
IsValidReserveId = 282,
|
||||
GetNumPipePackets = 283,
|
||||
GetMaxPipePackets = 284,
|
||||
GroupReserveReadPipePackets = 285,
|
||||
GroupReserveWritePipePackets = 286,
|
||||
GroupCommitReadPipe = 287,
|
||||
GroupCommitWritePipe = 288,
|
||||
EnqueueMarker = 291,
|
||||
EnqueueKernel = 292,
|
||||
GetKernelNDrangeSubGroupCount = 293,
|
||||
GetKernelNDrangeMaxSubGroupSize = 294,
|
||||
GetKernelWorkGroupSize = 295,
|
||||
GetKernelPreferredWorkGroupSizeMultiple = 296,
|
||||
RetainEvent = 297,
|
||||
ReleaseEvent = 298,
|
||||
CreateUserEvent = 299,
|
||||
IsValidEvent = 300,
|
||||
SetUserEventStatus = 301,
|
||||
CaptureEventProfilingInfo = 302,
|
||||
GetDefaultQueue = 303,
|
||||
BuildNDRange = 304,
|
||||
ImageSparseSampleImplicitLod = 305,
|
||||
ImageSparseSampleExplicitLod = 306,
|
||||
ImageSparseSampleDrefImplicitLod = 307,
|
||||
ImageSparseSampleDrefExplicitLod = 308,
|
||||
ImageSparseSampleProjImplicitLod = 309,
|
||||
ImageSparseSampleProjExplicitLod = 310,
|
||||
ImageSparseSampleProjDrefImplicitLod = 311,
|
||||
ImageSparseSampleProjDrefExplicitLod = 312,
|
||||
ImageSparseFetch = 313,
|
||||
ImageSparseGather = 314,
|
||||
ImageSparseDrefGather = 315,
|
||||
ImageSparseTexelsResident = 316,
|
||||
NoLine = 317,
|
||||
AtomicFlagTestAndSet = 318,
|
||||
AtomicFlagClear = 319,
|
||||
ImageSparseRead = 320,
|
||||
SizeOf = 321,
|
||||
TypePipeStorage = 322,
|
||||
ConstantPipeStorage = 323,
|
||||
CreatePipeFromPipeStorage = 324,
|
||||
GetKernelLocalSizeForSubgroupCount = 325,
|
||||
GetKernelMaxNumSubgroups = 326,
|
||||
TypeNamedBarrier = 327,
|
||||
NamedBarrierInitialize = 328,
|
||||
MemoryNamedBarrier = 329,
|
||||
ModuleProcessed = 330,
|
||||
|
||||
KnownOpsCount,
|
||||
}
|
||||
|
||||
public static class SpvOpExtensions
|
||||
{
|
||||
public static bool OpHasResult(this SpvOp _this)
|
||||
{
|
||||
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return OpData.SpirvOpData[(int)_this].hasResult != 0;
|
||||
}
|
||||
|
||||
public static bool OpHasType(this SpvOp _this)
|
||||
{
|
||||
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return OpData.SpirvOpData[(int)_this].hasType != 0;
|
||||
}
|
||||
|
||||
public static int OpDeltaFromResult(this SpvOp _this)
|
||||
{
|
||||
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return OpData.SpirvOpData[(int)_this].deltaFromResult;
|
||||
}
|
||||
|
||||
public static bool OpVarRest(this SpvOp _this)
|
||||
{
|
||||
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return OpData.SpirvOpData[(int)_this].varrest != 0;
|
||||
}
|
||||
|
||||
public static bool OpDebugInfo(this SpvOp _this)
|
||||
{
|
||||
return
|
||||
_this == SpvOp.SourceContinued ||
|
||||
_this == SpvOp.Source ||
|
||||
_this == SpvOp.SourceExtension ||
|
||||
_this == SpvOp.Name ||
|
||||
_this == SpvOp.MemberName ||
|
||||
_this == SpvOp.String ||
|
||||
_this == SpvOp.Line ||
|
||||
_this == SpvOp.NoLine ||
|
||||
_this == SpvOp.ModuleProcessed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using Smolv;
|
||||
using SpirV;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class SpirVShaderConverter
|
||||
{
|
||||
public static string Convert(byte[] m_ProgramCode)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
using (var ms = new MemoryStream(m_ProgramCode))
|
||||
{
|
||||
using (var reader = new BinaryReader(ms))
|
||||
{
|
||||
int requirements = reader.ReadInt32();
|
||||
int minOffset = m_ProgramCode.Length;
|
||||
int snippetCount = 5;
|
||||
/*if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
snippetCount = 6;
|
||||
}*/
|
||||
for (int i = 0; i < snippetCount; i++)
|
||||
{
|
||||
if (reader.BaseStream.Position >= minOffset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
int offset = reader.ReadInt32();
|
||||
int size = reader.ReadInt32();
|
||||
if (size > 0)
|
||||
{
|
||||
if (offset < minOffset)
|
||||
{
|
||||
minOffset = offset;
|
||||
}
|
||||
var pos = ms.Position;
|
||||
sb.Append(ExportSnippet(ms, offset, size));
|
||||
ms.Position = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string ExportSnippet(Stream stream, int offset, int size)
|
||||
{
|
||||
stream.Position = offset;
|
||||
int decodedSize = SmolvDecoder.GetDecodedBufferSize(stream);
|
||||
if (decodedSize == 0)
|
||||
{
|
||||
throw new Exception("Invalid SMOL-V shader header");
|
||||
}
|
||||
using (var decodedStream = new MemoryStream(new byte[decodedSize]))
|
||||
{
|
||||
if (SmolvDecoder.Decode(stream, size, decodedStream))
|
||||
{
|
||||
decodedStream.Position = 0;
|
||||
var module = Module.ReadFrom(decodedStream);
|
||||
var disassembler = new Disassembler();
|
||||
return disassembler.Disassemble(module, DisassemblyOptions.Default).Replace("\r\n", "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to decode SMOL-V shader");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace AssetStudio
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Bitmap CutImage(Texture2D m_Texture2D, Sprite m_Sprite, RectangleF textureRect, Vector2 textureRectOffset, SpriteSettings settingsRaw)
|
||||
private static Bitmap CutImage(Texture2D m_Texture2D, Sprite m_Sprite, Rectf textureRect, Vector2 textureRectOffset, SpriteSettings settingsRaw)
|
||||
{
|
||||
var originalImage = m_Texture2D.ConvertToBitmap(false);
|
||||
if (originalImage != null)
|
||||
@@ -36,12 +36,21 @@ namespace AssetStudio
|
||||
using (originalImage)
|
||||
{
|
||||
//var spriteImage = originalImage.Clone(textureRect, PixelFormat.Format32bppArgb);
|
||||
var textureRectI = Rectangle.Round(textureRect);
|
||||
var spriteImage = new Bitmap(textureRectI.Width, textureRectI.Height, PixelFormat.Format32bppArgb);
|
||||
var destRect = new Rectangle(0, 0, textureRectI.Width, textureRectI.Height);
|
||||
var rectf = new RectangleF(textureRect.x, textureRect.y, textureRect.width, textureRect.height);
|
||||
var rect = Rectangle.Round(rectf);
|
||||
if (rect.Width == 0)
|
||||
{
|
||||
rect.Width = 1;
|
||||
}
|
||||
if (rect.Height == 0)
|
||||
{
|
||||
rect.Height = 1;
|
||||
}
|
||||
var spriteImage = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
|
||||
var destRect = new Rectangle(0, 0, rect.Width, rect.Height);
|
||||
using (var graphic = Graphics.FromImage(spriteImage))
|
||||
{
|
||||
graphic.DrawImage(originalImage, destRect, textureRectI, GraphicsUnit.Pixel);
|
||||
graphic.DrawImage(originalImage, destRect, rect, GraphicsUnit.Pixel);
|
||||
}
|
||||
if (settingsRaw.packed == 1)
|
||||
{
|
||||
@@ -83,21 +92,22 @@ namespace AssetStudio
|
||||
|| (version[0] == 5 && version[1] < 4)
|
||||
|| (version[0] == 5 && version[1] == 4 && version[2] <= 1)) //5.4.1p3 down
|
||||
{
|
||||
matr.Translate(m_Sprite.m_Rect.Width * 0.5f - textureRectOffset.X, m_Sprite.m_Rect.Height * 0.5f - textureRectOffset.Y);
|
||||
matr.Translate(m_Sprite.m_Rect.width * 0.5f - textureRectOffset.X, m_Sprite.m_Rect.height * 0.5f - textureRectOffset.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
matr.Translate(m_Sprite.m_Rect.Width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.Height * m_Sprite.m_Pivot.Y - textureRectOffset.Y);
|
||||
matr.Translate(m_Sprite.m_Rect.width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.height * m_Sprite.m_Pivot.Y - textureRectOffset.Y);
|
||||
}
|
||||
matr.Scale(m_Sprite.m_PixelsToUnits, m_Sprite.m_PixelsToUnits);
|
||||
path.Transform(matr);
|
||||
var bitmap = new Bitmap(textureRectI.Width, textureRectI.Height);
|
||||
var bitmap = new Bitmap(rect.Width, rect.Height);
|
||||
using (var graphic = Graphics.FromImage(bitmap))
|
||||
{
|
||||
using (var brush = new TextureBrush(spriteImage))
|
||||
{
|
||||
graphic.FillPath(brush, path);
|
||||
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
||||
spriteImage.Dispose();
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
@@ -136,43 +146,43 @@ namespace AssetStudio
|
||||
}
|
||||
return triangles;
|
||||
}
|
||||
|
||||
return GetTriangles(m_RD.m_VertexData, m_RD.m_SubMeshes, m_RD.m_IndexBuffer); //5.6 and up
|
||||
}
|
||||
|
||||
private static Vector2[][] GetTriangles(VertexData m_VertexData, SubMesh[] m_SubMeshes, byte[] m_IndexBuffer)
|
||||
{
|
||||
var triangles = new List<Vector2[]>();
|
||||
var m_Channel = m_VertexData.m_Channels[0]; //kShaderChannelVertex
|
||||
var m_Stream = m_VertexData.m_Streams[m_Channel.stream];
|
||||
using (BinaryReader vertexReader = new BinaryReader(new MemoryStream(m_VertexData.m_DataSize)),
|
||||
indexReader = new BinaryReader(new MemoryStream(m_IndexBuffer)))
|
||||
else //5.6 and up
|
||||
{
|
||||
foreach (var subMesh in m_SubMeshes)
|
||||
var triangles = new List<Vector2[]>();
|
||||
var m_VertexData = m_RD.m_VertexData;
|
||||
var m_Channel = m_VertexData.m_Channels[0]; //kShaderChannelVertex
|
||||
var m_Stream = m_VertexData.m_Streams[m_Channel.stream];
|
||||
using (var vertexReader = new BinaryReader(new MemoryStream(m_VertexData.m_DataSize)))
|
||||
{
|
||||
vertexReader.BaseStream.Position = m_Stream.offset + subMesh.firstVertex * m_Stream.stride + m_Channel.offset;
|
||||
|
||||
var vertices = new Vector2[subMesh.vertexCount];
|
||||
for (int v = 0; v < subMesh.vertexCount; v++)
|
||||
using (var indexReader = new BinaryReader(new MemoryStream(m_RD.m_IndexBuffer)))
|
||||
{
|
||||
vertices[v] = vertexReader.ReadVector3();
|
||||
vertexReader.BaseStream.Position += m_Stream.stride - 12;
|
||||
}
|
||||
foreach (var subMesh in m_RD.m_SubMeshes)
|
||||
{
|
||||
vertexReader.BaseStream.Position = m_Stream.offset + subMesh.firstVertex * m_Stream.stride + m_Channel.offset;
|
||||
|
||||
indexReader.BaseStream.Position = subMesh.firstByte;
|
||||
var vertices = new Vector2[subMesh.vertexCount];
|
||||
for (int v = 0; v < subMesh.vertexCount; v++)
|
||||
{
|
||||
vertices[v] = vertexReader.ReadVector3();
|
||||
vertexReader.BaseStream.Position += m_Stream.stride - 12;
|
||||
}
|
||||
|
||||
var triangleCount = subMesh.indexCount / 3u;
|
||||
for (int i = 0; i < triangleCount; i++)
|
||||
{
|
||||
var first = indexReader.ReadUInt16() - subMesh.firstVertex;
|
||||
var second = indexReader.ReadUInt16() - subMesh.firstVertex;
|
||||
var third = indexReader.ReadUInt16() - subMesh.firstVertex;
|
||||
var triangle = new[] { vertices[first], vertices[second], vertices[third] };
|
||||
triangles.Add(triangle);
|
||||
indexReader.BaseStream.Position = subMesh.firstByte;
|
||||
|
||||
var triangleCount = subMesh.indexCount / 3u;
|
||||
for (int i = 0; i < triangleCount; i++)
|
||||
{
|
||||
var first = indexReader.ReadUInt16() - subMesh.firstVertex;
|
||||
var second = indexReader.ReadUInt16() - subMesh.firstVertex;
|
||||
var third = indexReader.ReadUInt16() - subMesh.firstVertex;
|
||||
var triangle = new[] { vertices[first], vertices[second], vertices[third] };
|
||||
triangles.Add(triangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return triangles.ToArray();
|
||||
}
|
||||
return triangles.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
using Mono.Cecil;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.CecilTools;
|
||||
using Unity.SerializationLogic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class TypeDefinitionConverter
|
||||
{
|
||||
private readonly TypeDefinition TypeDef;
|
||||
private readonly TypeResolver TypeResolver;
|
||||
private readonly SerializedTypeHelper Helper;
|
||||
private readonly int Indent;
|
||||
|
||||
public TypeDefinitionConverter(TypeDefinition typeDef, SerializedTypeHelper helper, int indent)
|
||||
{
|
||||
TypeDef = typeDef;
|
||||
TypeResolver = new TypeResolver(null);
|
||||
Helper = helper;
|
||||
Indent = indent;
|
||||
}
|
||||
|
||||
public List<TypeTreeNode> ConvertToTypeTreeNodes()
|
||||
{
|
||||
var nodes = new List<TypeTreeNode>();
|
||||
|
||||
Stack<TypeReference> baseTypes = new Stack<TypeReference>();
|
||||
TypeReference baseType = TypeDef.BaseType;
|
||||
while (!UnitySerializationLogic.IsNonSerialized(baseType))
|
||||
{
|
||||
GenericInstanceType genericInstanceType = baseType as GenericInstanceType;
|
||||
if (genericInstanceType != null)
|
||||
{
|
||||
TypeResolver.Add(genericInstanceType);
|
||||
}
|
||||
baseTypes.Push(baseType);
|
||||
baseType = baseType.Resolve().BaseType;
|
||||
}
|
||||
while (baseTypes.Count > 0)
|
||||
{
|
||||
TypeReference typeReference = baseTypes.Pop();
|
||||
TypeDefinition typeDefinition = typeReference.Resolve();
|
||||
foreach (var fieldDefinition in typeDefinition.Fields.Where(WillUnitySerialize))
|
||||
{
|
||||
if (!IsHiddenByParentClass(baseTypes, fieldDefinition, TypeDef))
|
||||
{
|
||||
nodes.AddRange(ProcessingFieldRef(ResolveGenericFieldReference(fieldDefinition)));
|
||||
}
|
||||
}
|
||||
|
||||
var genericInstanceType2 = typeReference as GenericInstanceType;
|
||||
if (genericInstanceType2 != null)
|
||||
{
|
||||
TypeResolver.Remove(genericInstanceType2);
|
||||
}
|
||||
}
|
||||
foreach (FieldDefinition fieldDefinition2 in FilteredFields())
|
||||
{
|
||||
nodes.AddRange(ProcessingFieldRef(fieldDefinition2));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
private bool WillUnitySerialize(FieldDefinition fieldDefinition)
|
||||
{
|
||||
bool result;
|
||||
try
|
||||
{
|
||||
TypeReference typeReference = TypeResolver.Resolve(fieldDefinition.FieldType);
|
||||
if (UnitySerializationLogic.ShouldNotTryToResolve(typeReference))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!UnityEngineTypePredicates.IsUnityEngineObject(typeReference))
|
||||
{
|
||||
if (typeReference.FullName == fieldDefinition.DeclaringType.FullName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
result = UnitySerializationLogic.WillUnitySerialize(fieldDefinition, TypeResolver);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception(string.Format("Exception while processing {0} {1}, error {2}", fieldDefinition.FieldType.FullName, fieldDefinition.FullName, ex.Message));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool IsHiddenByParentClass(IEnumerable<TypeReference> parentTypes, FieldDefinition fieldDefinition, TypeDefinition processingType)
|
||||
{
|
||||
return processingType.Fields.Any((FieldDefinition f) => f.Name == fieldDefinition.Name) || parentTypes.Any((TypeReference t) => t.Resolve().Fields.Any((FieldDefinition f) => f.Name == fieldDefinition.Name));
|
||||
}
|
||||
|
||||
private IEnumerable<FieldDefinition> FilteredFields()
|
||||
{
|
||||
foreach (var f in TypeDef.Fields.Where(WillUnitySerialize))
|
||||
{
|
||||
if (UnitySerializationLogic.IsSupportedCollection(f.FieldType) || !f.FieldType.IsGenericInstance || UnitySerializationLogic.ShouldImplementIDeserializable(f.FieldType.Resolve()))
|
||||
{
|
||||
yield return f;
|
||||
}
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
private FieldReference ResolveGenericFieldReference(FieldReference fieldRef)
|
||||
{
|
||||
FieldReference field = new FieldReference(fieldRef.Name, fieldRef.FieldType, ResolveDeclaringType(fieldRef.DeclaringType));
|
||||
return TypeDef.Module.ImportReference(field);
|
||||
}
|
||||
|
||||
private TypeReference ResolveDeclaringType(TypeReference declaringType)
|
||||
{
|
||||
TypeDefinition typeDefinition = declaringType.Resolve();
|
||||
TypeReference result;
|
||||
if (typeDefinition == null || !typeDefinition.HasGenericParameters)
|
||||
{
|
||||
result = typeDefinition;
|
||||
}
|
||||
else
|
||||
{
|
||||
GenericInstanceType genericInstanceType = new GenericInstanceType(typeDefinition);
|
||||
foreach (GenericParameter item in typeDefinition.GenericParameters)
|
||||
{
|
||||
genericInstanceType.GenericArguments.Add(item);
|
||||
}
|
||||
result = TypeResolver.Resolve(genericInstanceType);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<TypeTreeNode> ProcessingFieldRef(FieldReference fieldDef)
|
||||
{
|
||||
var typeRef = TypeResolver.Resolve(fieldDef.FieldType);
|
||||
return TypeRefToTypeTreeNodes(typeRef, fieldDef.Name, Indent, false);
|
||||
}
|
||||
|
||||
private static bool IsStruct(TypeReference typeRef)
|
||||
{
|
||||
return typeRef.IsValueType && !IsEnum(typeRef) && !typeRef.IsPrimitive;
|
||||
}
|
||||
|
||||
private static bool IsEnum(TypeReference typeRef)
|
||||
{
|
||||
return !typeRef.IsArray && typeRef.Resolve().IsEnum;
|
||||
}
|
||||
|
||||
private static bool RequiresAlignment(TypeReference typeRef)
|
||||
{
|
||||
bool result;
|
||||
switch (typeRef.MetadataType)
|
||||
{
|
||||
case MetadataType.Boolean:
|
||||
case MetadataType.Char:
|
||||
case MetadataType.SByte:
|
||||
case MetadataType.Byte:
|
||||
case MetadataType.Int16:
|
||||
case MetadataType.UInt16:
|
||||
result = true;
|
||||
break;
|
||||
default:
|
||||
result = (UnitySerializationLogic.IsSupportedCollection(typeRef) && RequiresAlignment(CecilUtils.ElementTypeOfCollection(typeRef)));
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool IsSystemString(TypeReference typeRef)
|
||||
{
|
||||
return typeRef.FullName == "System.String";
|
||||
}
|
||||
|
||||
private List<TypeTreeNode> TypeRefToTypeTreeNodes(TypeReference typeRef, string name, int indent, bool isElement)
|
||||
{
|
||||
var align = false;
|
||||
|
||||
if (!IsStruct(TypeDef) || !UnityEngineTypePredicates.IsUnityEngineValueType(TypeDef))
|
||||
{
|
||||
if (IsStruct(typeRef) || RequiresAlignment(typeRef))
|
||||
{
|
||||
align = true;
|
||||
}
|
||||
}
|
||||
|
||||
var nodes = new List<TypeTreeNode>();
|
||||
if (typeRef.IsPrimitive)
|
||||
{
|
||||
var primitiveName = typeRef.Name;
|
||||
switch (primitiveName)
|
||||
{
|
||||
case "Boolean":
|
||||
primitiveName = "bool";
|
||||
break;
|
||||
case "Byte":
|
||||
primitiveName = "UInt8";
|
||||
break;
|
||||
case "SByte":
|
||||
primitiveName = "SInt8";
|
||||
break;
|
||||
case "Int16":
|
||||
primitiveName = "SInt16";
|
||||
break;
|
||||
case "UInt16":
|
||||
primitiveName = "UInt16";
|
||||
break;
|
||||
case "Int32":
|
||||
primitiveName = "SInt32";
|
||||
break;
|
||||
case "UInt32":
|
||||
primitiveName = "UInt32";
|
||||
break;
|
||||
case "Int64":
|
||||
primitiveName = "SInt64";
|
||||
break;
|
||||
case "UInt64":
|
||||
primitiveName = "UInt64";
|
||||
break;
|
||||
case "Char":
|
||||
primitiveName = "char";
|
||||
break;
|
||||
case "Double":
|
||||
primitiveName = "double";
|
||||
break;
|
||||
case "Single":
|
||||
primitiveName = "float";
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
if (isElement)
|
||||
{
|
||||
align = false;
|
||||
}
|
||||
nodes.Add(new TypeTreeNode(primitiveName, name, indent, align));
|
||||
}
|
||||
else if (IsSystemString(typeRef))
|
||||
{
|
||||
Helper.AddString(nodes, name, indent);
|
||||
}
|
||||
else if (IsEnum(typeRef))
|
||||
{
|
||||
nodes.Add(new TypeTreeNode("SInt32", name, indent, align));
|
||||
}
|
||||
else if (CecilUtils.IsGenericList(typeRef))
|
||||
{
|
||||
var elementRef = CecilUtils.ElementTypeOfCollection(typeRef);
|
||||
nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align));
|
||||
Helper.AddArray(nodes, indent + 1);
|
||||
nodes.AddRange(TypeRefToTypeTreeNodes(elementRef, "data", indent + 2, true));
|
||||
}
|
||||
else if (typeRef.IsArray)
|
||||
{
|
||||
var elementRef = typeRef.GetElementType();
|
||||
nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align));
|
||||
Helper.AddArray(nodes, indent + 1);
|
||||
nodes.AddRange(TypeRefToTypeTreeNodes(elementRef, "data", indent + 2, true));
|
||||
}
|
||||
else if (UnityEngineTypePredicates.IsUnityEngineObject(typeRef))
|
||||
{
|
||||
Helper.AddPPtr(nodes, typeRef.Name, name, indent);
|
||||
}
|
||||
else if (UnityEngineTypePredicates.IsSerializableUnityClass(typeRef) || UnityEngineTypePredicates.IsSerializableUnityStruct(typeRef))
|
||||
{
|
||||
switch (typeRef.FullName)
|
||||
{
|
||||
case "UnityEngine.AnimationCurve":
|
||||
Helper.AddAnimationCurve(nodes, name, indent + 1);
|
||||
break;
|
||||
case "UnityEngine.Gradient":
|
||||
Helper.AddGradient(nodes, name, indent + 1);
|
||||
break;
|
||||
case "UnityEngine.GUIStyle":
|
||||
Helper.AddGUIStyle(nodes, name, indent + 1);
|
||||
break;
|
||||
case "UnityEngine.RectOffset":
|
||||
Helper.AddRectOffset(nodes, name, indent + 1);
|
||||
break;
|
||||
case "UnityEngine.Color32":
|
||||
Helper.AddColor32(nodes, name, indent + 1);
|
||||
break;
|
||||
case "UnityEngine.Matrix4x4":
|
||||
Helper.AddMatrix4x4(nodes, name, indent + 1);
|
||||
break;
|
||||
case "UnityEngine.Rendering.SphericalHarmonicsL2":
|
||||
Helper.AddSphericalHarmonicsL2(nodes, name, indent + 1);
|
||||
break;
|
||||
case "UnityEngine.PropertyName":
|
||||
Helper.AddPropertyName(nodes, name, indent + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align));
|
||||
var typeDef = typeRef.Resolve();
|
||||
var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, Helper, indent + 1);
|
||||
nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNodes());
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ AssetStudio is a tool for exploring, extracting and exporting assets and assetbu
|
||||
|
||||
## Features
|
||||
* Support version:
|
||||
* 2.5 - 2019.3
|
||||
* 2.5 - 2021.1
|
||||
* Support asset types:
|
||||
* **Texture2D** : convert to png, tga, jpeg, bmp
|
||||
* **Sprite** : crop Texture2D to png, tga, jpeg, bmp
|
||||
@@ -18,32 +18,53 @@ AssetStudio is a tool for exploring, extracting and exporting assets and assetbu
|
||||
* **Shader**
|
||||
* **MovieTexture**
|
||||
* **VideoClip**
|
||||
* **MonoBehaviour**
|
||||
* **MonoBehaviour** : json
|
||||
* **Animator** : export to FBX file with bound AnimationClip
|
||||
|
||||
## Usage
|
||||
### Requirements
|
||||
## Requirements
|
||||
|
||||
- [.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472)
|
||||
- [Microsoft Visual C++ 2017 Redistributable](https://support.microsoft.com/help/2977003/the-latest-supported-visual-c-downloads)
|
||||
|
||||
### How to use
|
||||
## Usage
|
||||
|
||||
### Load Assets/AssetBundles
|
||||
|
||||
Use **File-Load file** or **File-Load folder**.
|
||||
|
||||
When AssetStudio loads AssetBundles, it decompresses and reads it directly in memory, which may cause a large amount of memory to be used. You can use **File-Extract file** or **File-Extract folder** to extract AssetBundles to another folder, and then read.
|
||||
|
||||
### Extract/Decompress AssetBundles
|
||||
|
||||
Use **File-Extract file** or **File-Extract folder**.
|
||||
|
||||
### Export Assets
|
||||
|
||||
use **Export** menu.
|
||||
|
||||
### Export Model
|
||||
|
||||
Export model from "Scene Hierarchy" using the **Model** menu.
|
||||
|
||||
Export Animator from "Asset List" using the **Export** menu.
|
||||
|
||||
#### With AnimationClip
|
||||
|
||||
Select model from "Scene Hierarchy" then select the AnimationClip from "Asset List", using **Model-Export selected objects with AnimationClip** to export.
|
||||
|
||||
Export Animator will export bound AnimationClip or use **Ctrl** to select Animator and AnimationClip from "Asset List", using **Export-Export Animator with selected AnimationClip** to export.
|
||||
|
||||
### Export MonoBehaviour
|
||||
|
||||
When you select an asset of the MonoBehaviour type for the first time, AssetStudio will ask you the directory where the assembly is located, please select the directory where the assembly is located, such as the `Managed` folder.
|
||||
|
||||
#### For Il2Cpp
|
||||
|
||||
First, use my another program [Il2CppDumper](https://github.com/Perfare/Il2CppDumper) to generate dummy dll, then when using AssetStudio to select the assembly directory, select the dummy dll folder.
|
||||
|
||||
* Use **File-Load file**, **File-Load folder** to load assets or assetbundles from multiple files or folder
|
||||
* Use **File-Extract file**, **File-Extract folder** to export assetbundles to assets from multiple files or folder
|
||||
* Export assets: use **Export** menu
|
||||
* Export model:
|
||||
* Export model from "Scene Hierarchy" using the **Model** menu
|
||||
* Export Animator from "Asset List" using the **Export** menu
|
||||
* With AnimationClip:
|
||||
* Select model from "Scene Hierarchy" then select the AnimationClip from "Asset List", using **Model-Export selected objects with AnimationClip** to export
|
||||
* Export Animator will export bound AnimationClip or use **Ctrl** to select Animator and AnimationClip from "Asset List", using **Export-Export Animator with selected AnimationClip** to export
|
||||
|
||||
## Build
|
||||
|
||||
* Visual Studio 2019 or newer
|
||||
* **AssetStudioFBX** uses FBX SDK 2020.0.1 VS2017, before building, you need to install the FBX SDK and modify the project file, change include directory and library directory to point to the FBX SDK directory
|
||||
* If you want to change the FBX SDK version, you need to replace `libfbxsdk.dll` which in `AssetStudioGUI/Libraries/x86/` and `AssetStudioGUI/Libraries/x64/` directory to the new version
|
||||
* **AssetStudioFBXNative** uses FBX SDK 2020.0.1 VS2017, before building, you need to install the FBX SDK and modify the project file, change include directory and library directory to point to the FBX SDK directory
|
||||
|
||||
## Open source libraries used
|
||||
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -187,6 +188,7 @@
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
Reference in New Issue
Block a user