Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 50485a9bd3 | |||
| dbb3d3fef7 | |||
| e1cfff63c3 | |||
| 44514a4e10 | |||
| b1205808e2 | |||
| 7d3a4a10fc | |||
| b909857820 | |||
| b674e66407 | |||
| d7dcd3f405 | |||
| 44145e0b9c | |||
| d4e21f824c | |||
| e7a4604a65 | |||
| 8d193a63cd | |||
| e61a317185 | |||
| 0e1a886e0b |
@@ -0,0 +1,57 @@
|
||||
name: AssetStudioBuild
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/setup-msbuild@v1.1
|
||||
|
||||
- name: Download FBX SDK
|
||||
run: |
|
||||
md fbx
|
||||
cd fbx
|
||||
Invoke-WebRequest "https://damassets.autodesk.net/content/dam/autodesk/www/adn/fbx/2020-2-1/fbx202021_fbxsdk_vs2019_win.exe" -OutFile "fbxsdk.exe"
|
||||
Start-Process -FilePath "fbxsdk.exe" /S -Wait
|
||||
Invoke-WebRequest "https://damassets.autodesk.net/content/dam/autodesk/www/adn/fbx/2020-2-1/fbx202021_fbxsdk_vs2019_pdbs.exe" -OutFile "fbxpdb.exe"
|
||||
Start-Process -FilePath "fbxpdb.exe" /S -Wait
|
||||
cd ..
|
||||
|
||||
- name: Nuget Restore
|
||||
run: nuget restore
|
||||
|
||||
- name: Build .Net472
|
||||
run: msbuild /p:Configuration=Release /p:TargetFramework=net472 /verbosity:minimal
|
||||
|
||||
- name: Build .Net5
|
||||
run: msbuild /t:AssetStudioGUI:publish /p:Configuration=Release /p:TargetFramework=net5.0-windows /p:SelfContained=false /verbosity:minimal
|
||||
|
||||
- name: Build .Net6
|
||||
run: msbuild /t:AssetStudioGUI:publish /p:Configuration=Release /p:TargetFramework=net6.0-windows /p:SelfContained=false /verbosity:minimal
|
||||
|
||||
- name: Upload .Net472 Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: AssetStudio.net472
|
||||
path: AssetStudioGUI/bin/Release/net472
|
||||
|
||||
- name: Upload .Net5 Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: AssetStudio.net5
|
||||
path: AssetStudioGUI/bin/Release/net5.0-windows/publish
|
||||
|
||||
- name: Upload .Net6 Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: AssetStudio.net6
|
||||
path: AssetStudioGUI/bin/Release/net6.0-windows/publish
|
||||
@@ -6,7 +6,8 @@
|
||||
<Version>0.16.0.0</Version>
|
||||
<AssemblyVersion>0.16.0.0</AssemblyVersion>
|
||||
<FileVersion>0.16.0.0</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2020-2021; Copyright © hozuki 2020</Copyright>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
<Version>0.16.0.0</Version>
|
||||
<AssemblyVersion>0.16.0.0</AssemblyVersion>
|
||||
<FileVersion>0.16.0.0</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2021</Copyright>
|
||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net472' ">
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
|
||||
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||
<PackageReference Include="System.IO.Compression" Version="4.0.0" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.1.11" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
+125
-13
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static AssetStudio.ImportHelper;
|
||||
@@ -84,6 +85,9 @@ namespace AssetStudio
|
||||
case FileType.BrotliFile:
|
||||
LoadFile(DecompressBrotli(reader));
|
||||
break;
|
||||
case FileType.ZipFile:
|
||||
LoadZipFile(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +95,7 @@ namespace AssetStudio
|
||||
{
|
||||
if (!assetsFileListHash.Contains(reader.FileName))
|
||||
{
|
||||
Logger.Info($"Loading {reader.FileName}");
|
||||
Logger.Info($"Loading {reader.FullPath}");
|
||||
try
|
||||
{
|
||||
var assetsFile = new SerializedFile(reader, this);
|
||||
@@ -125,12 +129,13 @@ namespace AssetStudio
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading assets file {reader.FileName}", e);
|
||||
Logger.Error($"Error while reading assets file {reader.FullPath}", e);
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info($"Skipping {reader.FullPath}");
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -153,15 +158,17 @@ namespace AssetStudio
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading assets file {reader.FileName} from {Path.GetFileName(originalPath)}", e);
|
||||
Logger.Error($"Error while reading assets file {reader.FullPath} from {Path.GetFileName(originalPath)}", e);
|
||||
resourceFileReaders.Add(reader.FileName, reader);
|
||||
}
|
||||
}
|
||||
else
|
||||
Logger.Info($"Skipping {originalPath} ({reader.FileName})");
|
||||
}
|
||||
|
||||
private void LoadBundleFile(FileReader reader, string originalPath = null)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
Logger.Info("Loading " + reader.FullPath);
|
||||
try
|
||||
{
|
||||
var bundleFile = new BundleFile(reader);
|
||||
@@ -181,7 +188,7 @@ namespace AssetStudio
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var str = $"Error while reading bundle file {reader.FileName}";
|
||||
var str = $"Error while reading bundle file {reader.FullPath}";
|
||||
if (originalPath != null)
|
||||
{
|
||||
str += $" from {Path.GetFileName(originalPath)}";
|
||||
@@ -196,7 +203,7 @@ namespace AssetStudio
|
||||
|
||||
private void LoadWebFile(FileReader reader)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
Logger.Info("Loading " + reader.FullPath);
|
||||
try
|
||||
{
|
||||
var webFile = new WebFile(reader);
|
||||
@@ -223,7 +230,107 @@ namespace AssetStudio
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading web file {reader.FileName}", e);
|
||||
Logger.Error($"Error while reading web file {reader.FullPath}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadZipFile(FileReader reader)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
try
|
||||
{
|
||||
using (ZipArchive archive = new ZipArchive(reader.BaseStream, ZipArchiveMode.Read))
|
||||
{
|
||||
List<string> splitFiles = new List<string>();
|
||||
// register all files before parsing the assets so that the external references can be found
|
||||
// and find split files
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
if (entry.Name.Contains(".split"))
|
||||
{
|
||||
string baseName = Path.GetFileNameWithoutExtension(entry.Name);
|
||||
string basePath = Path.Combine(Path.GetDirectoryName(entry.FullName), baseName);
|
||||
if (!splitFiles.Contains(basePath))
|
||||
{
|
||||
splitFiles.Add(basePath);
|
||||
importFilesHash.Add(baseName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
importFilesHash.Add(entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// merge split files and load the result
|
||||
foreach (string basePath in splitFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream splitStream = new MemoryStream();
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
string path = $"{basePath}.split{i++}";
|
||||
ZipArchiveEntry entry = archive.GetEntry(path);
|
||||
if (entry == null)
|
||||
break;
|
||||
using (Stream entryStream = entry.Open())
|
||||
{
|
||||
entryStream.CopyTo(splitStream);
|
||||
}
|
||||
}
|
||||
splitStream.Seek(0, SeekOrigin.Begin);
|
||||
FileReader entryReader = new FileReader(basePath, splitStream);
|
||||
LoadFile(entryReader);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading zip split file {basePath}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// load all entries
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
string dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), reader.FileName, entry.FullName);
|
||||
// create a new stream
|
||||
// - to store the deflated stream in
|
||||
// - to keep the data for later extraction
|
||||
Stream streamReader = new MemoryStream();
|
||||
using (Stream entryStream = entry.Open())
|
||||
{
|
||||
entryStream.CopyTo(streamReader);
|
||||
}
|
||||
streamReader.Position = 0;
|
||||
|
||||
FileReader entryReader = new FileReader(dummyPath, streamReader);
|
||||
LoadFile(entryReader);
|
||||
if (entryReader.FileType == FileType.ResourceFile)
|
||||
{
|
||||
entryReader.Position = 0;
|
||||
if (!resourceFileReaders.ContainsKey(entry.Name))
|
||||
{
|
||||
resourceFileReaders.Add(entry.Name, entryReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading zip entry {entry.FullName}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading zip file {reader.FileName}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -373,6 +480,7 @@ namespace AssetStudio
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Unable to load object")
|
||||
.AppendLine($"Assets {assetsFile.fileName}")
|
||||
.AppendLine($"Path {assetsFile.originalPath}")
|
||||
.AppendLine($"Type {objectReader.type}")
|
||||
.AppendLine($"PathID {objectInfo.m_PathID}")
|
||||
.Append(e);
|
||||
@@ -424,10 +532,6 @@ namespace AssetStudio
|
||||
}
|
||||
else if (obj is SpriteAtlas m_SpriteAtlas)
|
||||
{
|
||||
if (m_SpriteAtlas.m_IsVariant)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (var m_PackedSprite in m_SpriteAtlas.m_PackedSprites)
|
||||
{
|
||||
if (m_PackedSprite.TryGet(out var m_Sprite))
|
||||
@@ -436,6 +540,14 @@ namespace AssetStudio
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld);
|
||||
if (m_SpriteAtlaOld.m_IsVariant)
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,4 +555,4 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,7 +605,7 @@ namespace AssetStudio
|
||||
if ((version[0] == 2020 && version[1] > 3) ||
|
||||
(version[0] == 2020 && version[1] == 3 && version[2] >= 2) || //2020.3.2f1 and up
|
||||
(version[0] == 2021 && version[1] > 1) ||
|
||||
(version[0] == 2021 && version[1] == 1 && version[2] >= 4)) //2021.1.4f1 and up
|
||||
(version[0] == 2021 && version[1] == 1 && version[2] >= 1)) //2021.1.1f1 and up
|
||||
{
|
||||
m_Parameters = new SerializedProgramParameters(reader);
|
||||
}
|
||||
@@ -704,7 +704,7 @@ namespace AssetStudio
|
||||
if ((version[0] == 2020 && version[1] > 3) ||
|
||||
(version[0] == 2020 && version[1] == 3 && version[2] >= 2) || //2020.3.2f1 and up
|
||||
(version[0] == 2021 && version[1] > 1) ||
|
||||
(version[0] == 2021 && version[1] == 1 && version[2] >= 4)) //2021.1.4f1 and up
|
||||
(version[0] == 2021 && version[1] == 1 && version[2] >= 1)) //2021.1.1f1 and up
|
||||
{
|
||||
m_CommonParameters = new SerializedProgramParameters(reader);
|
||||
}
|
||||
@@ -959,9 +959,9 @@ namespace AssetStudio
|
||||
//5.5 and up
|
||||
public SerializedShader m_ParsedForm;
|
||||
public ShaderCompilerPlatform[] platforms;
|
||||
public uint[] offsets;
|
||||
public uint[] compressedLengths;
|
||||
public uint[] decompressedLengths;
|
||||
public uint[][] offsets;
|
||||
public uint[][] compressedLengths;
|
||||
public uint[][] decompressedLengths;
|
||||
public byte[] compressedBlob;
|
||||
|
||||
public Shader(ObjectReader reader) : base(reader)
|
||||
@@ -972,15 +972,15 @@ namespace AssetStudio
|
||||
platforms = reader.ReadUInt32Array().Select(x => (ShaderCompilerPlatform)x).ToArray();
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
offsets = reader.ReadUInt32ArrayArray().Select(x => x[0]).ToArray();
|
||||
compressedLengths = reader.ReadUInt32ArrayArray().Select(x => x[0]).ToArray();
|
||||
decompressedLengths = reader.ReadUInt32ArrayArray().Select(x => x[0]).ToArray();
|
||||
offsets = reader.ReadUInt32ArrayArray();
|
||||
compressedLengths = reader.ReadUInt32ArrayArray();
|
||||
decompressedLengths = reader.ReadUInt32ArrayArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
offsets = reader.ReadUInt32Array();
|
||||
compressedLengths = reader.ReadUInt32Array();
|
||||
decompressedLengths = reader.ReadUInt32Array();
|
||||
offsets = reader.ReadUInt32Array().Select(x => new[] { x }).ToArray();
|
||||
compressedLengths = reader.ReadUInt32Array().Select(x => new[] { x }).ToArray();
|
||||
decompressedLengths = reader.ReadUInt32Array().Select(x => new[] { x }).ToArray();
|
||||
}
|
||||
compressedBlob = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
|
||||
@@ -154,7 +154,8 @@ namespace AssetStudio
|
||||
RGB565 = 7,
|
||||
R16 = 9,
|
||||
DXT1,
|
||||
DXT5 = 12,
|
||||
DXT3,
|
||||
DXT5,
|
||||
RGBA4444,
|
||||
BGRA32,
|
||||
RHalf,
|
||||
@@ -165,11 +166,11 @@ namespace AssetStudio
|
||||
RGBAFloat,
|
||||
YUY2,
|
||||
RGB9e5Float,
|
||||
BC4 = 26,
|
||||
BC5,
|
||||
BC6H = 24,
|
||||
BC7,
|
||||
DXT1Crunched = 28,
|
||||
BC4,
|
||||
BC5,
|
||||
DXT1Crunched,
|
||||
DXT5Crunched,
|
||||
PVRTC_RGB2,
|
||||
PVRTC_RGBA2,
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace AssetStudio
|
||||
|
||||
private static readonly byte[] gzipMagic = { 0x1f, 0x8b };
|
||||
private static readonly byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
|
||||
private static readonly byte[] zipMagic = { 0x50, 0x4B, 0x03, 0x04 };
|
||||
private static readonly byte[] zipSpannedMagic = { 0x50, 0x4B, 0x07, 0x08 };
|
||||
|
||||
public FileReader(string path) : this(path, File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { }
|
||||
|
||||
@@ -36,7 +38,7 @@ namespace AssetStudio
|
||||
return FileType.WebFile;
|
||||
default:
|
||||
{
|
||||
var magic = ReadBytes(2);
|
||||
byte[] magic = ReadBytes(2);
|
||||
Position = 0;
|
||||
if (gzipMagic.SequenceEqual(magic))
|
||||
{
|
||||
@@ -53,10 +55,11 @@ namespace AssetStudio
|
||||
{
|
||||
return FileType.AssetsFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FileType.ResourceFile;
|
||||
}
|
||||
magic = ReadBytes(4);
|
||||
Position = 0;
|
||||
if (zipMagic.SequenceEqual(magic) || zipSpannedMagic.SequenceEqual(magic))
|
||||
return FileType.ZipFile;
|
||||
return FileType.ResourceFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace AssetStudio
|
||||
WebFile,
|
||||
ResourceFile,
|
||||
GZipFile,
|
||||
BrotliFile
|
||||
BrotliFile,
|
||||
ZipFile
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public interface IProgress
|
||||
{
|
||||
void Report(int value);
|
||||
}
|
||||
|
||||
public sealed class DummyProgress : IProgress
|
||||
{
|
||||
public void Report(int value) { }
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
namespace AssetStudio
|
||||
using System;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class Progress
|
||||
{
|
||||
public static IProgress Default = new DummyProgress();
|
||||
public static IProgress<int> Default = new Progress<int>();
|
||||
private static int preValue;
|
||||
|
||||
public static void Reset()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
@@ -190,9 +191,11 @@ namespace AssetStudio
|
||||
value = reader.ReadSByte();
|
||||
break;
|
||||
case "UInt8":
|
||||
case "char":
|
||||
value = reader.ReadByte();
|
||||
break;
|
||||
case "char":
|
||||
value = BitConverter.ToChar(reader.ReadBytes(2), 0);
|
||||
break;
|
||||
case "short":
|
||||
case "SInt16":
|
||||
value = reader.ReadInt16();
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
<Version>0.16.0.0</Version>
|
||||
<AssemblyVersion>0.16.0.0</AssemblyVersion>
|
||||
<FileVersion>0.16.0.0</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2021; Copyright © hozuki 2020</Copyright>
|
||||
<Copyright>Copyright © Perfare 2018-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<Version>0.16.0.0</Version>
|
||||
<AssemblyVersion>0.16.0.0</AssemblyVersion>
|
||||
<FileVersion>0.16.0.0</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2021</Copyright>
|
||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace AssetStudioGUI
|
||||
|
||||
logger = new GUILogger(StatusStripUpdate);
|
||||
Logger.Default = logger;
|
||||
Progress.Default = new GUIProgress(SetProgressBarValue);
|
||||
Progress.Default = new Progress<int>(SetProgressBarValue);
|
||||
Studio.StatusStripUpdate = StatusStripUpdate;
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace AssetStudioGUI
|
||||
private async void loadFile_Click(object sender, EventArgs e)
|
||||
{
|
||||
openFileDialog1.InitialDirectory = openDirectoryBackup;
|
||||
if (openFileDialog1.ShowDialog() == DialogResult.OK)
|
||||
if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
ResetForm();
|
||||
openDirectoryBackup = Path.GetDirectoryName(openFileDialog1.FileNames[0]);
|
||||
@@ -167,7 +167,7 @@ namespace AssetStudioGUI
|
||||
|
||||
private async void extractFileToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (openFileDialog1.ShowDialog() == DialogResult.OK)
|
||||
if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
var saveFolderDialog = new OpenFolderDialog();
|
||||
saveFolderDialog.Title = "Select the save folder";
|
||||
@@ -222,10 +222,6 @@ namespace AssetStudioGUI
|
||||
|
||||
sceneTreeView.BeginUpdate();
|
||||
sceneTreeView.Nodes.AddRange(treeNodeCollection.ToArray());
|
||||
foreach (var node in treeNodeCollection)
|
||||
{
|
||||
node.HideCheckBox();
|
||||
}
|
||||
sceneTreeView.EndUpdate();
|
||||
treeNodeCollection.Clear();
|
||||
|
||||
@@ -461,7 +457,7 @@ namespace AssetStudioGUI
|
||||
private void showExpOpt_Click(object sender, EventArgs e)
|
||||
{
|
||||
var exportOpt = new ExportOptions();
|
||||
exportOpt.ShowDialog();
|
||||
exportOpt.ShowDialog(this);
|
||||
}
|
||||
|
||||
private void assetListView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
|
||||
@@ -759,7 +755,7 @@ namespace AssetStudioGUI
|
||||
var image = m_Texture2D.ConvertToImage(true);
|
||||
if (image != null)
|
||||
{
|
||||
var bitmap = new DirectBitmap(image.ConvertToBgra32Bytes(), m_Texture2D.m_Width, m_Texture2D.m_Height);
|
||||
var bitmap = new DirectBitmap(image.ConvertToBytes(), m_Texture2D.m_Width, m_Texture2D.m_Height);
|
||||
image.Dispose();
|
||||
assetItem.InfoText = $"Width: {m_Texture2D.m_Width}\nHeight: {m_Texture2D.m_Height}\nFormat: {m_Texture2D.m_TextureFormat}";
|
||||
switch (m_Texture2D.m_TextureSettings.m_FilterMode)
|
||||
@@ -1167,7 +1163,7 @@ namespace AssetStudioGUI
|
||||
var image = m_Sprite.GetImage();
|
||||
if (image != null)
|
||||
{
|
||||
var bitmap = new DirectBitmap(image.ConvertToBgra32Bytes(), image.Width, image.Height);
|
||||
var bitmap = new DirectBitmap(image.ConvertToBytes(), image.Width, image.Height);
|
||||
image.Dispose();
|
||||
assetItem.InfoText = $"Width: {bitmap.Width}\nHeight: {bitmap.Height}\n";
|
||||
PreviewTexture(bitmap);
|
||||
@@ -1384,25 +1380,32 @@ namespace AssetStudioGUI
|
||||
{
|
||||
var gameObjects = new List<GameObject>();
|
||||
GetSelectedParentNode(sceneTreeView.Nodes, gameObjects);
|
||||
var saveFileDialog = new SaveFileDialog();
|
||||
saveFileDialog.FileName = gameObjects[0].m_Name + " (merge).fbx";
|
||||
saveFileDialog.AddExtension = false;
|
||||
saveFileDialog.Filter = "Fbx file (*.fbx)|*.fbx";
|
||||
saveFileDialog.InitialDirectory = saveDirectoryBackup;
|
||||
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
||||
if (gameObjects.Count > 0)
|
||||
{
|
||||
saveDirectoryBackup = Path.GetDirectoryName(saveFileDialog.FileName);
|
||||
var exportPath = saveFileDialog.FileName;
|
||||
List<AssetItem> animationList = null;
|
||||
if (animation)
|
||||
var saveFileDialog = new SaveFileDialog();
|
||||
saveFileDialog.FileName = gameObjects[0].m_Name + " (merge).fbx";
|
||||
saveFileDialog.AddExtension = false;
|
||||
saveFileDialog.Filter = "Fbx file (*.fbx)|*.fbx";
|
||||
saveFileDialog.InitialDirectory = saveDirectoryBackup;
|
||||
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
animationList = GetSelectedAssets().Where(x => x.Type == ClassIDType.AnimationClip).ToList();
|
||||
if (animationList.Count == 0)
|
||||
saveDirectoryBackup = Path.GetDirectoryName(saveFileDialog.FileName);
|
||||
var exportPath = saveFileDialog.FileName;
|
||||
List<AssetItem> animationList = null;
|
||||
if (animation)
|
||||
{
|
||||
animationList = null;
|
||||
animationList = GetSelectedAssets().Where(x => x.Type == ClassIDType.AnimationClip).ToList();
|
||||
if (animationList.Count == 0)
|
||||
{
|
||||
animationList = null;
|
||||
}
|
||||
}
|
||||
ExportObjectsMergeWithAnimationClip(exportPath, gameObjects, animationList);
|
||||
}
|
||||
ExportObjectsMergeWithAnimationClip(exportPath, gameObjects, animationList);
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusStripUpdate("No Object selected for export.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,6 @@ namespace AssetStudioGUI
|
||||
{
|
||||
public GameObject gameObject;
|
||||
|
||||
public GameObjectTreeNode(string name)
|
||||
{
|
||||
Text = name;
|
||||
}
|
||||
|
||||
public GameObjectTreeNode(GameObject gameObject)
|
||||
{
|
||||
this.gameObject = gameObject;
|
||||
|
||||
@@ -14,12 +14,12 @@ namespace AssetStudioGUI
|
||||
|
||||
internal DialogResult ShowDialog(IWin32Window owner = null)
|
||||
{
|
||||
#if NETFRAMEWORK
|
||||
//#if NETFRAMEWORK
|
||||
if (Environment.OSVersion.Version.Major >= 6)
|
||||
{
|
||||
return ShowVistaDialog(owner);
|
||||
}
|
||||
#endif
|
||||
//#endif
|
||||
return ShowFolderBrowserDialog(owner);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
internal static class TreeViewExtensions
|
||||
{
|
||||
private const int TVIF_STATE = 0x8;
|
||||
private const int TVIS_STATEIMAGEMASK = 0xF000;
|
||||
private const int TV_FIRST = 0x1100;
|
||||
private const int TVM_SETITEM = TV_FIRST + 63;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
|
||||
private struct TVITEM
|
||||
{
|
||||
public int mask;
|
||||
public IntPtr hItem;
|
||||
public int state;
|
||||
public int stateMask;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpszText;
|
||||
public int cchTextMax;
|
||||
public int iImage;
|
||||
public int iSelectedImage;
|
||||
public int cChildren;
|
||||
public IntPtr lParam;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref TVITEM lParam);
|
||||
|
||||
/// <summary>
|
||||
/// Hides the checkbox for the specified node on a TreeView control.
|
||||
/// </summary>
|
||||
public static void HideCheckBox(this TreeNode node)
|
||||
{
|
||||
var tvi = new TVITEM
|
||||
{
|
||||
hItem = node.Handle,
|
||||
mask = TVIF_STATE,
|
||||
stateMask = TVIS_STATEIMAGEMASK,
|
||||
state = 0
|
||||
};
|
||||
SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,6 +152,7 @@ namespace AssetStudioGUI
|
||||
#region UV
|
||||
if (m_Mesh.m_UV0?.Length > 0)
|
||||
{
|
||||
c = 4;
|
||||
if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 2)
|
||||
{
|
||||
c = 2;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AssetStudio;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
class GUIProgress : IProgress
|
||||
{
|
||||
private Action<int> action;
|
||||
|
||||
public GUIProgress(Action<int> action)
|
||||
{
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public void Report(int value)
|
||||
{
|
||||
action(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,7 +265,7 @@ namespace AssetStudioGUI
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsManager.assetsFileList)
|
||||
{
|
||||
var fileNode = new GameObjectTreeNode(assetsFile.fileName); //RootNode
|
||||
var fileNode = new TreeNode(assetsFile.fileName); //RootNode
|
||||
|
||||
foreach (var obj in assetsFile.Objects)
|
||||
{
|
||||
@@ -307,11 +307,12 @@ namespace AssetStudioGUI
|
||||
{
|
||||
if (m_Father.m_GameObject.TryGet(out var parentGameObject))
|
||||
{
|
||||
if (!treeNodeDictionary.TryGetValue(parentGameObject, out parentNode))
|
||||
if (!treeNodeDictionary.TryGetValue(parentGameObject, out var parentGameObjectNode))
|
||||
{
|
||||
parentNode = new GameObjectTreeNode(parentGameObject);
|
||||
treeNodeDictionary.Add(parentGameObject, parentNode);
|
||||
parentGameObjectNode = new GameObjectTreeNode(parentGameObject);
|
||||
treeNodeDictionary.Add(parentGameObject, parentGameObjectNode);
|
||||
}
|
||||
parentNode = parentGameObjectNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,7 +515,7 @@ namespace AssetStudioGUI
|
||||
var count = nodes.Cast<TreeNode>().Sum(x => x.Nodes.Count);
|
||||
int k = 0;
|
||||
Progress.Reset();
|
||||
foreach (GameObjectTreeNode node in nodes)
|
||||
foreach (TreeNode node in nodes)
|
||||
{
|
||||
//遍历一级子节点
|
||||
foreach (GameObjectTreeNode j in node.Nodes)
|
||||
@@ -635,7 +636,7 @@ namespace AssetStudioGUI
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusStripUpdate("No Object can be exported.");
|
||||
StatusStripUpdate("No Object selected for export.");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -667,11 +668,11 @@ namespace AssetStudioGUI
|
||||
|
||||
public static void GetSelectedParentNode(TreeNodeCollection nodes, List<GameObject> gameObjects)
|
||||
{
|
||||
foreach (GameObjectTreeNode i in nodes)
|
||||
foreach (TreeNode i in nodes)
|
||||
{
|
||||
if (i.Checked)
|
||||
if (i is GameObjectTreeNode gameObjectTreeNode && i.Checked)
|
||||
{
|
||||
gameObjects.Add(i.gameObject);
|
||||
gameObjects.Add(gameObjectTreeNode.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
<Version>0.16.0.0</Version>
|
||||
<AssemblyVersion>0.16.0.0</AssemblyVersion>
|
||||
<FileVersion>0.16.0.0</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2021</Copyright>
|
||||
<Copyright>Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace AssetStudio
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static byte[] ConvertToBgra32Bytes(this Image<Bgra32> image)
|
||||
public static byte[] ConvertToBytes<TPixel>(this Image<TPixel> image) where TPixel : unmanaged, IPixel<TPixel>
|
||||
{
|
||||
if (image.TryGetSinglePixelSpan(out var pixelSpan))
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace AssetStudio
|
||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||
{
|
||||
var program = new ShaderProgram(blobReader, shader.version);
|
||||
program.Read(blobReader, 0);
|
||||
return header + program.Export(Encoding.UTF8.GetString(shader.m_Script));
|
||||
}
|
||||
}
|
||||
@@ -33,16 +34,25 @@ namespace AssetStudio
|
||||
|
||||
private static string ConvertSerializedShader(Shader shader)
|
||||
{
|
||||
var shaderPrograms = new ShaderProgram[shader.platforms.Length];
|
||||
for (var i = 0; i < shader.platforms.Length; i++)
|
||||
var length = shader.platforms.Length;
|
||||
var shaderPrograms = new ShaderProgram[length];
|
||||
for (var i = 0; i < 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]];
|
||||
LZ4Codec.Decode(compressedBytes, decompressedBytes);
|
||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||
for (var j = 0; j < shader.offsets[i].Length; j++)
|
||||
{
|
||||
shaderPrograms[i] = new ShaderProgram(blobReader, shader.version);
|
||||
var offset = shader.offsets[i][j];
|
||||
var compressedLength = shader.compressedLengths[i][j];
|
||||
var decompressedLength = shader.decompressedLengths[i][j];
|
||||
var decompressedBytes = new byte[decompressedLength];
|
||||
LZ4Codec.Decode(shader.compressedBlob, (int)offset, (int)compressedLength, decompressedBytes, 0, (int)decompressedLength);
|
||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
shaderPrograms[i] = new ShaderProgram(blobReader, shader.version);
|
||||
}
|
||||
shaderPrograms[i].Read(blobReader, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -854,29 +864,49 @@ namespace AssetStudio
|
||||
"///////////////////////////////////////////\n";
|
||||
}
|
||||
|
||||
public class ShaderSubProgramEntry
|
||||
{
|
||||
public int Offset;
|
||||
public int Length;
|
||||
public int Segment;
|
||||
|
||||
public ShaderSubProgramEntry(BinaryReader reader, int[] version)
|
||||
{
|
||||
Offset = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
Segment = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ShaderProgram
|
||||
{
|
||||
public ShaderSubProgramEntry[] entries;
|
||||
public ShaderSubProgram[] m_SubPrograms;
|
||||
|
||||
public ShaderProgram(BinaryReader reader, int[] version)
|
||||
{
|
||||
var subProgramsCapacity = reader.ReadInt32();
|
||||
m_SubPrograms = new ShaderSubProgram[subProgramsCapacity];
|
||||
int entrySize;
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
entrySize = 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
entrySize = 8;
|
||||
}
|
||||
entries = new ShaderSubProgramEntry[subProgramsCapacity];
|
||||
for (int i = 0; i < subProgramsCapacity; i++)
|
||||
{
|
||||
reader.BaseStream.Position = 4 + i * entrySize;
|
||||
var offset = reader.ReadInt32();
|
||||
reader.BaseStream.Position = offset;
|
||||
m_SubPrograms[i] = new ShaderSubProgram(reader);
|
||||
entries[i] = new ShaderSubProgramEntry(reader, version);
|
||||
}
|
||||
m_SubPrograms = new ShaderSubProgram[subProgramsCapacity];
|
||||
}
|
||||
|
||||
public void Read(BinaryReader reader, int segment)
|
||||
{
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
var entry = entries[i];
|
||||
if (entry.Segment == segment)
|
||||
{
|
||||
reader.BaseStream.Position = entry.Offset;
|
||||
m_SubPrograms[i] = new ShaderSubProgram(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,32 +19,38 @@ namespace AssetStudio
|
||||
{
|
||||
if (m_SpriteAtlas.m_RenderDataMap.TryGetValue(m_Sprite.m_RenderDataKey, out var spriteAtlasData) && spriteAtlasData.texture.TryGet(out var m_Texture2D))
|
||||
{
|
||||
return CutImage(m_Texture2D, m_Sprite, spriteAtlasData.textureRect, spriteAtlasData.textureRectOffset, spriteAtlasData.settingsRaw);
|
||||
return CutImage(m_Sprite, m_Texture2D, spriteAtlasData.textureRect, spriteAtlasData.textureRectOffset, spriteAtlasData.downscaleMultiplier, spriteAtlasData.settingsRaw);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Sprite.m_RD.texture.TryGet(out var m_Texture2D))
|
||||
{
|
||||
return CutImage(m_Texture2D, m_Sprite, m_Sprite.m_RD.textureRect, m_Sprite.m_RD.textureRectOffset, m_Sprite.m_RD.settingsRaw);
|
||||
return CutImage(m_Sprite, m_Texture2D, m_Sprite.m_RD.textureRect, m_Sprite.m_RD.textureRectOffset, m_Sprite.m_RD.downscaleMultiplier, m_Sprite.m_RD.settingsRaw);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Image<Bgra32> CutImage(Texture2D m_Texture2D, Sprite m_Sprite, Rectf textureRect, Vector2 textureRectOffset, SpriteSettings settingsRaw)
|
||||
private static Image<Bgra32> CutImage(Sprite m_Sprite, Texture2D m_Texture2D, Rectf textureRect, Vector2 textureRectOffset, float downscaleMultiplier, SpriteSettings settingsRaw)
|
||||
{
|
||||
var originalImage = m_Texture2D.ConvertToImage(false);
|
||||
if (originalImage != null)
|
||||
{
|
||||
using (originalImage)
|
||||
{
|
||||
if (downscaleMultiplier > 0f && downscaleMultiplier != 1f)
|
||||
{
|
||||
var width = (int)(m_Texture2D.m_Width / downscaleMultiplier);
|
||||
var height = (int)(m_Texture2D.m_Height / downscaleMultiplier);
|
||||
originalImage.Mutate(x => x.Resize(width, height));
|
||||
}
|
||||
var rectX = (int)Math.Floor(textureRect.x);
|
||||
var rectY = (int)Math.Floor(textureRect.y);
|
||||
var rectRight = (int)Math.Ceiling(textureRect.x + textureRect.width);
|
||||
var rectBottom = (int)Math.Ceiling(textureRect.y + textureRect.height);
|
||||
rectRight = Math.Min(rectRight, m_Texture2D.m_Width);
|
||||
rectBottom = Math.Min(rectBottom, m_Texture2D.m_Height);
|
||||
rectRight = Math.Min(rectRight, originalImage.Width);
|
||||
rectBottom = Math.Min(rectBottom, originalImage.Height);
|
||||
var rect = new Rectangle(rectX, rectY, rectRight - rectX, rectBottom - rectY);
|
||||
var spriteImage = originalImage.Clone(x => x.Crop(rect));
|
||||
if (settingsRaw.packed == 1)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Texture2DDecoder;
|
||||
|
||||
namespace AssetStudio
|
||||
@@ -11,6 +12,7 @@ namespace AssetStudio
|
||||
private TextureFormat m_TextureFormat;
|
||||
private int[] version;
|
||||
private BuildTarget platform;
|
||||
private int outPutSize;
|
||||
|
||||
public Texture2DConverter(Texture2D m_Texture2D)
|
||||
{
|
||||
@@ -20,6 +22,7 @@ namespace AssetStudio
|
||||
m_TextureFormat = m_Texture2D.m_TextureFormat;
|
||||
version = m_Texture2D.version;
|
||||
platform = m_Texture2D.platform;
|
||||
outPutSize = m_Width * m_Height * 4;
|
||||
}
|
||||
|
||||
public bool DecodeTexture2D(byte[] bytes)
|
||||
@@ -60,6 +63,8 @@ namespace AssetStudio
|
||||
SwapBytesForXbox(buff);
|
||||
flag = DecodeDXT1(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.DXT3:
|
||||
break;
|
||||
case TextureFormat.DXT5: //test pass
|
||||
SwapBytesForXbox(buff);
|
||||
flag = DecodeDXT5(buff, bytes);
|
||||
@@ -94,18 +99,18 @@ namespace AssetStudio
|
||||
case TextureFormat.RGB9e5Float: //test pass
|
||||
flag = DecodeRGB9e5Float(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.BC4: //test pass
|
||||
flag = DecodeBC4(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.BC5: //test pass
|
||||
flag = DecodeBC5(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.BC6H: //test pass
|
||||
flag = DecodeBC6H(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.BC7: //test pass
|
||||
flag = DecodeBC7(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.BC4: //test pass
|
||||
flag = DecodeBC4(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.BC5: //test pass
|
||||
flag = DecodeBC5(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.DXT1Crunched: //test pass
|
||||
flag = DecodeDXT1Crunched(buff, bytes);
|
||||
break;
|
||||
@@ -194,6 +199,15 @@ namespace AssetStudio
|
||||
case TextureFormat.ETC2_RGBA8Crunched: //test pass
|
||||
flag = DecodeETC2A8Crunched(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.RG32: //test pass
|
||||
flag = DecodeRG32(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.RGB48: //test pass
|
||||
flag = DecodeRGB48(buff, bytes);
|
||||
break;
|
||||
case TextureFormat.RGBA64: //test pass
|
||||
flag = DecodeRGBA64(buff, bytes);
|
||||
break;
|
||||
}
|
||||
BigArrayPool<byte>.Shared.Return(buff);
|
||||
return flag;
|
||||
@@ -214,9 +228,10 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeAlpha8(byte[] image_data, byte[] buff)
|
||||
{
|
||||
var size = m_Width * m_Height;
|
||||
var span = new Span<byte>(buff);
|
||||
span.Fill(0xFF);
|
||||
for (var i = 0; i < m_Width * m_Height; i++)
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 4 + 3] = image_data[i];
|
||||
}
|
||||
@@ -225,8 +240,9 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeARGB4444(byte[] image_data, byte[] buff)
|
||||
{
|
||||
var size = m_Width * m_Height;
|
||||
var pixelNew = new byte[4];
|
||||
for (var i = 0; i < m_Width * m_Height; i++)
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
var pixelOldShort = BitConverter.ToUInt16(image_data, i * 2);
|
||||
pixelNew[0] = (byte)(pixelOldShort & 0x000f);
|
||||
@@ -242,7 +258,8 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGB24(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < m_Width * m_Height; i++)
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 4] = image_data[i * 3 + 2];
|
||||
buff[i * 4 + 1] = image_data[i * 3 + 1];
|
||||
@@ -254,7 +271,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGBA32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = image_data[i + 2];
|
||||
buff[i + 1] = image_data[i + 1];
|
||||
@@ -266,7 +283,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeARGB32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = image_data[i + 3];
|
||||
buff[i + 1] = image_data[i + 2];
|
||||
@@ -278,7 +295,8 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGB565(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < m_Width * m_Height; i++)
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
var p = BitConverter.ToUInt16(image_data, i * 2);
|
||||
buff[i * 4] = (byte)((p << 3) | (p >> 2 & 7));
|
||||
@@ -291,11 +309,12 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeR16(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < m_Width * m_Height; i++)
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 4] = 0; //b
|
||||
buff[i * 4 + 1] = 0; //g
|
||||
buff[i * 4 + 2] = image_data[i * 2 + 1]; //r
|
||||
buff[i * 4 + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2)); //r
|
||||
buff[i * 4 + 3] = 255; //a
|
||||
}
|
||||
return true;
|
||||
@@ -313,8 +332,9 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGBA4444(byte[] image_data, byte[] buff)
|
||||
{
|
||||
var size = m_Width * m_Height;
|
||||
var pixelNew = new byte[4];
|
||||
for (var i = 0; i < m_Width * m_Height; i++)
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
var pixelOldShort = BitConverter.ToUInt16(image_data, i * 2);
|
||||
pixelNew[0] = (byte)((pixelOldShort & 0x00f0) >> 4);
|
||||
@@ -330,7 +350,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeBGRA32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = image_data[i];
|
||||
buff[i + 1] = image_data[i + 1];
|
||||
@@ -342,7 +362,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRHalf(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0;
|
||||
buff[i + 1] = 0;
|
||||
@@ -354,7 +374,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGHalf(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0;
|
||||
buff[i + 1] = (byte)Math.Round(Half.ToHalf(image_data, i + 2) * 255f);
|
||||
@@ -366,7 +386,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGBAHalf(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = (byte)Math.Round(Half.ToHalf(image_data, i * 2 + 4) * 255f);
|
||||
buff[i + 1] = (byte)Math.Round(Half.ToHalf(image_data, i * 2 + 2) * 255f);
|
||||
@@ -378,7 +398,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRFloat(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0;
|
||||
buff[i + 1] = 0;
|
||||
@@ -390,7 +410,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGFloat(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0;
|
||||
buff[i + 1] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 2 + 4) * 255f);
|
||||
@@ -402,7 +422,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGBAFloat(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 4 + 8) * 255f);
|
||||
buff[i + 1] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 4 + 4) * 255f);
|
||||
@@ -412,6 +432,7 @@ namespace AssetStudio
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static byte ClampByte(int x)
|
||||
{
|
||||
return (byte)(byte.MaxValue < x ? byte.MaxValue : (x > byte.MinValue ? x : byte.MinValue));
|
||||
@@ -449,7 +470,7 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRGB9e5Float(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < buff.Length; i += 4)
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
var n = BitConverter.ToInt32(image_data, i);
|
||||
var scale = n >> 27 & 0x1f;
|
||||
@@ -571,19 +592,21 @@ namespace AssetStudio
|
||||
|
||||
private bool DecodeRG16(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < m_Width * m_Height; i += 2)
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 2] = 0; //B
|
||||
buff[i * 2 + 1] = image_data[i + 1];//G
|
||||
buff[i * 2 + 2] = image_data[i];//R
|
||||
buff[i * 2 + 3] = 255;//A
|
||||
buff[i * 4] = 0; //B
|
||||
buff[i * 4 + 1] = image_data[i * 2 + 1];//G
|
||||
buff[i * 4 + 2] = image_data[i * 2];//R
|
||||
buff[i * 4 + 3] = 255;//A
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DecodeR8(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < m_Width * m_Height; i++)
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 4] = 0; //B
|
||||
buff[i * 4 + 1] = 0; //G
|
||||
@@ -617,6 +640,49 @@ namespace AssetStudio
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte DownScaleFrom16BitTo8Bit(ushort component)
|
||||
{
|
||||
return (byte)(((component * 255) + 32895) >> 16);
|
||||
}
|
||||
|
||||
private bool DecodeRG32(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = 0; //b
|
||||
buff[i + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i + 2)); //g
|
||||
buff[i + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i)); //r
|
||||
buff[i + 3] = byte.MaxValue; //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DecodeRGB48(byte[] image_data, byte[] buff)
|
||||
{
|
||||
var size = m_Width * m_Height;
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
buff[i * 4] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6 + 4)); //b
|
||||
buff[i * 4 + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6 + 2)); //g
|
||||
buff[i * 4 + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6)); //r
|
||||
buff[i * 4 + 3] = byte.MaxValue; //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DecodeRGBA64(byte[] image_data, byte[] buff)
|
||||
{
|
||||
for (var i = 0; i < outPutSize; i += 4)
|
||||
{
|
||||
buff[i] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 4)); //b
|
||||
buff[i + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 2)); //g
|
||||
buff[i + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2)); //r
|
||||
buff[i + 3] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 6)); //a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool UnpackCrunch(byte[] image_data, out byte[] result)
|
||||
{
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3) //2017.3 and up
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
<Version>0.16.0.0</Version>
|
||||
<AssemblyVersion>0.16.0.0</AssemblyVersion>
|
||||
<FileVersion>0.16.0.0</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2020-2021; Copyright © hozuki 2020</Copyright>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user