Compare commits
175 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
571ea2da4a | ||
|
|
9cbe91decb | ||
|
|
19c6c5fe73 | ||
|
|
792850dbb2 | ||
|
|
2ce9cae957 | ||
|
|
af5e50cfa9 | ||
|
|
ce1172ca9a | ||
|
|
a7e6d91f5b | ||
|
|
34a0af683a | ||
|
|
91410a33b1 | ||
|
|
d08b78c2cf | ||
|
|
2ef52afe1e | ||
|
|
05a41d2f1e | ||
|
|
34c38e1415 | ||
|
|
c85873b729 | ||
|
|
b146d251a7 | ||
|
|
3129d67fc1 | ||
|
|
850ba63a10 | ||
|
|
17b91984d6 | ||
|
|
7ab2cda120 | ||
|
|
4345885cc9 | ||
|
|
53720e37ab | ||
|
|
7c3cb36630 | ||
|
|
c1cddce031 | ||
|
|
973a1076e4 | ||
|
|
089e164756 | ||
|
|
c2b6691fd9 | ||
|
|
8dec094304 | ||
|
|
bedee240be | ||
|
|
d963d71b12 | ||
|
|
77a0c9c40a | ||
|
|
f3e406983b | ||
|
|
08b7bfcf9a | ||
|
|
57e4f7cefd | ||
|
|
c9cf2d188e | ||
|
|
ab98585b6a | ||
|
|
075d53a455 | ||
|
|
432116d834 | ||
|
|
caa45216ef | ||
|
|
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 | ||
|
|
1766dcbdeb | ||
|
|
ef38471ff1 | ||
|
|
217a7993e9 | ||
|
|
0a41615763 | ||
|
|
9d34f668d5 | ||
|
|
9269a36725 | ||
|
|
813e8b10a6 | ||
|
|
84c75fadf5 | ||
|
|
c76e41b1ab | ||
|
|
fefeea5f35 | ||
|
|
4a81c461e8 | ||
|
|
b10d03d50d | ||
|
|
da98a0c5b8 | ||
|
|
76d17bacf5 | ||
|
|
6678ce082b | ||
|
|
07074b3deb | ||
|
|
df5d9f90d4 | ||
|
|
4f2d30552a | ||
|
|
d259c7a5cd | ||
|
|
c71ceb7ea6 | ||
|
|
85cf134a49 | ||
|
|
687b1d3a0d | ||
|
|
a30a0d0bc5 | ||
|
|
e1dc54d6d7 | ||
|
|
c4270e186d | ||
|
|
182a42ace2 | ||
|
|
06fbe69a97 | ||
|
|
a0bf4f9acd | ||
|
|
12568ba044 | ||
|
|
de95b02285 | ||
|
|
286edfe72c | ||
|
|
d717b223b7 | ||
|
|
9e195832ef | ||
|
|
c8d08b2793 | ||
|
|
2bcd9662be | ||
|
|
ea461ee3d2 | ||
|
|
fda821b441 | ||
|
|
5c193c761a | ||
|
|
14f47c6d30 | ||
|
|
e53eacef78 | ||
|
|
ada26db659 | ||
|
|
48ca96807f | ||
|
|
2018028853 | ||
|
|
6f138dcc05 | ||
|
|
69bcd2be67 | ||
|
|
45ad53b19a | ||
|
|
6230240ee3 | ||
|
|
73ec9f4bee | ||
|
|
f3a0bf505e | ||
|
|
290708876d | ||
|
|
5b96a29cca | ||
|
|
948e2c4d92 | ||
|
|
76da1c33ae | ||
|
|
72b84ee24d | ||
|
|
7b33d41172 | ||
|
|
c7043c1a83 | ||
|
|
d0baf26c61 | ||
|
|
60ac10b043 | ||
|
|
80dc24b487 | ||
|
|
9d32a9dd6a | ||
|
|
d96cc3c762 | ||
|
|
509df42730 | ||
|
|
4efa5b0507 | ||
|
|
cffe96b409 | ||
|
|
16dddc01e3 | ||
|
|
b5d2c2cadb | ||
|
|
1d2c0ab6cb | ||
|
|
c6b7e04c47 | ||
|
|
5704813b28 | ||
|
|
465c989e75 | ||
|
|
d335aaef9e | ||
|
|
495b48c783 | ||
|
|
05b55722fb | ||
|
|
de54257eef | ||
|
|
e62b6c3d77 | ||
|
|
dc05e5b5eb | ||
|
|
f377381e26 | ||
|
|
20f9fe493f | ||
|
|
0b462754a5 | ||
|
|
b1ea8dd346 | ||
|
|
4a46f897bd | ||
|
|
6a5ec80de7 | ||
|
|
4f2046d412 | ||
|
|
1cf59e8d67 | ||
|
|
e9e8390bbc | ||
|
|
738b084440 | ||
|
|
32cce894ac | ||
|
|
a6264b39d1 | ||
|
|
eb4981808b |
172
.gitignore
vendored
172
.gitignore
vendored
@@ -1,7 +1,10 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
@@ -15,13 +18,22 @@
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
build/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
@@ -36,18 +48,28 @@ TestResult.xml
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
@@ -57,6 +79,7 @@ artifacts/
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
@@ -72,14 +95,21 @@ _Chutzpah*
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
@@ -101,9 +131,18 @@ _TeamCity*
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
@@ -131,47 +170,68 @@ publish/
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
## TODO: Comment the next line if you want to checkin your
|
||||
## web deploy settings but do note that will include unencrypted
|
||||
## passwords
|
||||
#*.pubxml
|
||||
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Windows Azure Build Output
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
@@ -182,21 +242,30 @@ _UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- Backup*.rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
@@ -204,7 +273,68 @@ FakesAssemblies/
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# LightSwitch generated files
|
||||
GeneratedArtifacts/
|
||||
_Pvt_Extensions/
|
||||
ModelManifest.xml
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
17
AssetStudio.PInvoke/AssetStudio.PInvoke.csproj
Normal file
17
AssetStudio.PInvoke/AssetStudio.PInvoke.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>0.16.8.1</Version>
|
||||
<AssemblyVersion>0.16.8.1</AssemblyVersion>
|
||||
<FileVersion>0.16.8.1</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2020-2021; Copyright © hozuki 2020</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net472|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
124
AssetStudio.PInvoke/DllLoader.cs
Normal file
124
AssetStudio.PInvoke/DllLoader.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio.PInvoke
|
||||
{
|
||||
public static class DllLoader
|
||||
{
|
||||
|
||||
public static void PreloadDll(string dllName)
|
||||
{
|
||||
var dllDir = GetDirectedDllDirectory();
|
||||
|
||||
// Not using OperatingSystem.Platform.
|
||||
// See: https://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Win32.LoadDll(dllDir, dllName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Posix.LoadDll(dllDir, dllName);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDirectedDllDirectory()
|
||||
{
|
||||
var localPath = Process.GetCurrentProcess().MainModule.FileName;
|
||||
var localDir = Path.GetDirectoryName(localPath);
|
||||
|
||||
var subDir = Environment.Is64BitProcess ? "x64" : "x86";
|
||||
|
||||
var directedDllDir = Path.Combine(localDir, subDir);
|
||||
|
||||
return directedDllDir;
|
||||
}
|
||||
|
||||
private static class Win32
|
||||
{
|
||||
|
||||
internal static void LoadDll(string dllDir, string dllName)
|
||||
{
|
||||
var dllFileName = $"{dllName}.dll";
|
||||
var directedDllPath = Path.Combine(dllDir, dllFileName);
|
||||
|
||||
// Specify SEARCH_DLL_LOAD_DIR to load dependent libraries located in the same platform-specific directory.
|
||||
var hLibrary = LoadLibraryEx(directedDllPath, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
|
||||
if (hLibrary == IntPtr.Zero)
|
||||
{
|
||||
var errorCode = Marshal.GetLastWin32Error();
|
||||
var exception = new Win32Exception(errorCode);
|
||||
|
||||
throw new DllNotFoundException(exception.Message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
// HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
|
||||
// HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr LoadLibraryEx(string lpLibFileName, IntPtr hFile, uint dwFlags);
|
||||
|
||||
private const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x1000;
|
||||
private const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x100;
|
||||
|
||||
}
|
||||
|
||||
private static class Posix
|
||||
{
|
||||
|
||||
internal static void LoadDll(string dllDir, string dllName)
|
||||
{
|
||||
string dllExtension;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
dllExtension = ".so";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
dllExtension = ".dylib";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
var dllFileName = $"lib{dllName}{dllExtension}";
|
||||
var directedDllPath = Path.Combine(dllDir, dllFileName);
|
||||
|
||||
const int ldFlags = RTLD_NOW | RTLD_GLOBAL;
|
||||
var hLibrary = DlOpen(directedDllPath, ldFlags);
|
||||
|
||||
if (hLibrary == IntPtr.Zero)
|
||||
{
|
||||
var pErrStr = DlError();
|
||||
// `PtrToStringAnsi` always uses the specific constructor of `String` (see dotnet/core#2325),
|
||||
// which in turn interprets the byte sequence with system default codepage. On OSX and Linux
|
||||
// the codepage is UTF-8 so the error message should be handled correctly.
|
||||
var errorMessage = Marshal.PtrToStringAnsi(pErrStr);
|
||||
|
||||
throw new DllNotFoundException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// OSX and most Linux OS use LP64 so `int` is still 32-bit even on 64-bit platforms.
|
||||
// void *dlopen(const char *filename, int flag);
|
||||
[DllImport("libdl", EntryPoint = "dlopen")]
|
||||
private static extern IntPtr DlOpen([MarshalAs(UnmanagedType.LPStr)] string fileName, int flags);
|
||||
|
||||
// char *dlerror(void);
|
||||
[DllImport("libdl", EntryPoint = "dlerror")]
|
||||
private static extern IntPtr DlError();
|
||||
|
||||
private const int RTLD_LAZY = 0x1;
|
||||
private const int RTLD_NOW = 0x2;
|
||||
private const int RTLD_GLOBAL = 0x100;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
100
AssetStudio.PInvoke/Utf8StringHandle.cs
Normal file
100
AssetStudio.PInvoke/Utf8StringHandle.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace AssetStudio.PInvoke
|
||||
{
|
||||
// Generally the technique from Steamworks.NET
|
||||
public class Utf8StringHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
|
||||
static Utf8StringHandle()
|
||||
{
|
||||
Utf8 = new UTF8Encoding(false);
|
||||
}
|
||||
|
||||
public Utf8StringHandle(string str)
|
||||
: base(true)
|
||||
{
|
||||
IntPtr buffer;
|
||||
|
||||
if (str == null)
|
||||
{
|
||||
buffer = IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (str.Length == 0)
|
||||
{
|
||||
buffer = Marshal.AllocHGlobal(1);
|
||||
|
||||
unsafe
|
||||
{
|
||||
*(byte*)buffer = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var strlen = Utf8.GetByteCount(str);
|
||||
var strBuffer = new byte[strlen + 1];
|
||||
|
||||
Utf8.GetBytes(str, 0, str.Length, strBuffer, 0);
|
||||
|
||||
buffer = Marshal.AllocHGlobal(strBuffer.Length);
|
||||
|
||||
Marshal.Copy(strBuffer, 0, buffer, strBuffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
SetHandle(buffer);
|
||||
}
|
||||
|
||||
public static string ReadUtf8StringFromPointer(IntPtr lpstr)
|
||||
{
|
||||
if (lpstr == IntPtr.Zero || lpstr == new IntPtr(-1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var byteCount = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var p = (byte*)lpstr.ToPointer();
|
||||
|
||||
while (*p != 0)
|
||||
{
|
||||
byteCount += 1;
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (byteCount == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var strBuffer = new byte[byteCount];
|
||||
|
||||
Marshal.Copy(lpstr, strBuffer, 0, byteCount);
|
||||
|
||||
var str = Utf8.GetString(strBuffer);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
if (!IsInvalid)
|
||||
{
|
||||
Marshal.FreeHGlobal(handle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly UTF8Encoding Utf8;
|
||||
|
||||
}
|
||||
}
|
||||
158
AssetStudio.sln
158
AssetStudio.sln
@@ -1,61 +1,141 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2024
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31410.357
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{422FEC21-EF60-4F29-AA56-95DFDA23C913}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBX", "AssetStudioFBX\AssetStudioFBX.vcxproj", "{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio.PInvoke", "AssetStudio.PInvoke\AssetStudio.PInvoke.csproj", "{0B2BE613-3049-4021-85D1-21C325F729F4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioFBXWrapper", "AssetStudioFBXWrapper\AssetStudioFBXWrapper.csproj", "{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027} = {11EA25A3-ED68-40EE-A9D0-7FDE3B583027}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{AF56B63C-1764-41B7-9E60-8D485422AC3B}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{29EAD018-1C67-497A-AB8E-727D595AD756}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Texture2DDecoderWrapper", "Texture2DDecoderWrapper\Texture2DDecoderWrapper.csproj", "{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD} = {29356642-C46E-4144-83D8-22DC09D0D7FD}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBXNative", "AssetStudioFBXNative\AssetStudioFBXNative.vcxproj", "{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Texture2DDecoderNative", "Texture2DDecoderNative\Texture2DDecoderNative.vcxproj", "{29356642-C46E-4144-83D8-22DC09D0D7FD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x64.Build.0 = Debug|x64
|
||||
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x86.Build.0 = Debug|x86
|
||||
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x64.ActiveCfg = Release|x64
|
||||
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x64.Build.0 = Release|x64
|
||||
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x86.ActiveCfg = Release|x86
|
||||
{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x86.Build.0 = Release|x86
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|x64.Build.0 = Debug|x64
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Debug|x86.Build.0 = Debug|Win32
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|x64.ActiveCfg = Release|x64
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|x64.Build.0 = Release|x64
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|x86.ActiveCfg = Release|Win32
|
||||
{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}.Release|x86.Build.0 = Release|Win32
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|x64.Build.0 = Debug|x64
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Debug|x86.Build.0 = Debug|x86
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|x64.ActiveCfg = Release|x64
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|x64.Build.0 = Release|x64
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|x86.ActiveCfg = Release|x86
|
||||
{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}.Release|x86.Build.0 = Release|x86
|
||||
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AF56B63C-1764-41B7-9E60-8D485422AC3B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x64.Build.0 = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x64.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x86.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x64.Build.0 = Debug|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x86.Build.0 = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x64.ActiveCfg = Release|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x64.Build.0 = Release|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x86.ActiveCfg = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x86.Build.0 = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x64.Build.0 = Debug|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x86.Build.0 = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x64.ActiveCfg = Release|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x64.Build.0 = Release|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x86.ActiveCfg = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {F5C476A6-2B3B-416F-8BD5-6FE454FF3972}
|
||||
SolutionGuid = {3C074481-9CDD-4780-B9F6-57BBC5092EA2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,153 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{AF56B63C-1764-41B7-9E60-8D485422AC3B}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>AssetStudio</RootNamespace>
|
||||
<AssemblyName>AssetStudio</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
|
||||
<Version>0.16.8.1</Version>
|
||||
<AssemblyVersion>0.16.8.1</AssemblyVersion>
|
||||
<FileVersion>0.16.8.1</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2021</Copyright>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net472|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<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.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="7zip\Common\CommandLineParser.cs" />
|
||||
<Compile Include="7zip\Common\CRC.cs" />
|
||||
<Compile Include="7zip\Common\InBuffer.cs" />
|
||||
<Compile Include="7zip\Common\OutBuffer.cs" />
|
||||
<Compile Include="7zip\Compress\LZMA\LzmaBase.cs" />
|
||||
<Compile Include="7zip\Compress\LZMA\LzmaDecoder.cs" />
|
||||
<Compile Include="7zip\Compress\LZMA\LzmaEncoder.cs" />
|
||||
<Compile Include="7zip\Compress\LZ\IMatchFinder.cs" />
|
||||
<Compile Include="7zip\Compress\LZ\LzBinTree.cs" />
|
||||
<Compile Include="7zip\Compress\LZ\LzInWindow.cs" />
|
||||
<Compile Include="7zip\Compress\LZ\LzOutWindow.cs" />
|
||||
<Compile Include="7zip\Compress\RangeCoder\RangeCoder.cs" />
|
||||
<Compile Include="7zip\Compress\RangeCoder\RangeCoderBit.cs" />
|
||||
<Compile Include="7zip\Compress\RangeCoder\RangeCoderBitTree.cs" />
|
||||
<Compile Include="7zip\ICoder.cs" />
|
||||
<Compile Include="Classes\RuntimeAnimatorController.cs" />
|
||||
<Compile Include="Math\Color.cs" />
|
||||
<Compile Include="Math\Half.cs" />
|
||||
<Compile Include="Math\HalfHelper.cs" />
|
||||
<Compile Include="Math\Matrix4x4.cs" />
|
||||
<Compile Include="Math\Quaternion.cs" />
|
||||
<Compile Include="Math\Vector2.cs" />
|
||||
<Compile Include="Math\Vector3.cs" />
|
||||
<Compile Include="Math\Vector4.cs" />
|
||||
<Compile Include="UType.cs" />
|
||||
<Compile Include="ResourceReader.cs" />
|
||||
<Compile Include="IImported.cs" />
|
||||
<Compile Include="SerializedFile.cs" />
|
||||
<Compile Include="AssetsManager.cs" />
|
||||
<Compile Include="Extensions\BinaryReaderExtensions.cs" />
|
||||
<Compile Include="Extensions\BinaryWriterExtensions.cs" />
|
||||
<Compile Include="Brotli\BitReader.cs" />
|
||||
<Compile Include="Brotli\BrotliInputStream.cs" />
|
||||
<Compile Include="Brotli\BrotliRuntimeException.cs" />
|
||||
<Compile Include="Brotli\Context.cs" />
|
||||
<Compile Include="Brotli\Decode.cs" />
|
||||
<Compile Include="Brotli\Dictionary.cs" />
|
||||
<Compile Include="Brotli\Huffman.cs" />
|
||||
<Compile Include="Brotli\HuffmanTreeGroup.cs" />
|
||||
<Compile Include="Brotli\IntReader.cs" />
|
||||
<Compile Include="Brotli\Prefix.cs" />
|
||||
<Compile Include="Brotli\RunningState.cs" />
|
||||
<Compile Include="Brotli\State.cs" />
|
||||
<Compile Include="Brotli\Transform.cs" />
|
||||
<Compile Include="Brotli\Utils.cs" />
|
||||
<Compile Include="Brotli\WordTransformType.cs" />
|
||||
<Compile Include="BuildTarget.cs" />
|
||||
<Compile Include="BuildType.cs" />
|
||||
<Compile Include="BundleFile.cs" />
|
||||
<Compile Include="Classes\Animation.cs" />
|
||||
<Compile Include="Classes\AnimationClip.cs" />
|
||||
<Compile Include="Classes\Animator.cs" />
|
||||
<Compile Include="Classes\AnimatorController.cs" />
|
||||
<Compile Include="Classes\AnimatorOverrideController.cs" />
|
||||
<Compile Include="Classes\AssetBundle.cs" />
|
||||
<Compile Include="Classes\AudioClip.cs" />
|
||||
<Compile Include="Classes\Avatar.cs" />
|
||||
<Compile Include="Classes\Behaviour.cs" />
|
||||
<Compile Include="Classes\BuildSettings.cs" />
|
||||
<Compile Include="Classes\Component.cs" />
|
||||
<Compile Include="Classes\EditorExtension.cs" />
|
||||
<Compile Include="Classes\Font.cs" />
|
||||
<Compile Include="Classes\GameObject.cs" />
|
||||
<Compile Include="Classes\Material.cs" />
|
||||
<Compile Include="Classes\Mesh.cs" />
|
||||
<Compile Include="Classes\MeshFilter.cs" />
|
||||
<Compile Include="Classes\MeshRenderer.cs" />
|
||||
<Compile Include="Classes\MonoBehaviour.cs" />
|
||||
<Compile Include="Classes\MonoScript.cs" />
|
||||
<Compile Include="Classes\MovieTexture.cs" />
|
||||
<Compile Include="Classes\NamedObject.cs" />
|
||||
<Compile Include="Classes\Object.cs" />
|
||||
<Compile Include="Classes\PlayerSettings.cs" />
|
||||
<Compile Include="Classes\RectTransform.cs" />
|
||||
<Compile Include="Classes\Renderer.cs" />
|
||||
<Compile Include="Classes\Shader.cs" />
|
||||
<Compile Include="Classes\SkinnedMeshRenderer.cs" />
|
||||
<Compile Include="Classes\Sprite.cs" />
|
||||
<Compile Include="Classes\SpriteAtlas.cs" />
|
||||
<Compile Include="Classes\TextAsset.cs" />
|
||||
<Compile Include="Classes\Texture.cs" />
|
||||
<Compile Include="Classes\Texture2D.cs" />
|
||||
<Compile Include="Classes\Transform.cs" />
|
||||
<Compile Include="Classes\VideoClip.cs" />
|
||||
<Compile Include="ClassIDType.cs" />
|
||||
<Compile Include="CommonString.cs" />
|
||||
<Compile Include="EndianBinaryReader.cs" />
|
||||
<Compile Include="FileIdentifier.cs" />
|
||||
<Compile Include="ILogger.cs" />
|
||||
<Compile Include="ImportHelper.cs" />
|
||||
<Compile Include="IProgress.cs" />
|
||||
<Compile Include="LocalSerializedObjectIdentifier.cs" />
|
||||
<Compile Include="Logger.cs" />
|
||||
<Compile Include="Lz4DecoderStream.cs" />
|
||||
<Compile Include="ObjectInfo.cs" />
|
||||
<Compile Include="ObjectReader.cs" />
|
||||
<Compile Include="Classes\PPtr.cs" />
|
||||
<Compile Include="Progress.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SerializedFileHeader.cs" />
|
||||
<Compile Include="SerializedType.cs" />
|
||||
<Compile Include="SevenZipHelper.cs" />
|
||||
<Compile Include="Extensions\StreamExtensions.cs" />
|
||||
<Compile Include="TypeTreeHelper.cs" />
|
||||
<Compile Include="TypeTreeNode.cs" />
|
||||
<Compile Include="WebFile.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static AssetStudio.ImportHelper;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AssetsManager
|
||||
{
|
||||
public string SpecifyUnityVersion;
|
||||
public List<SerializedFile> assetsFileList = new List<SerializedFile>();
|
||||
internal Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>();
|
||||
internal Dictionary<string, EndianBinaryReader> resourceFileReaders = new Dictionary<string, EndianBinaryReader>();
|
||||
|
||||
internal Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
internal Dictionary<string, BinaryReader> resourceFileReaders = new Dictionary<string, BinaryReader>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private List<string> importFiles = new List<string>();
|
||||
private HashSet<string> importFilesHash = new HashSet<string>();
|
||||
private HashSet<string> assetsFileListHash = new HashSet<string>();
|
||||
private HashSet<string> importFilesHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
private HashSet<string> assetsFileListHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public void LoadFiles(params string[] files)
|
||||
{
|
||||
@@ -36,7 +40,7 @@ namespace AssetStudio
|
||||
foreach (var file in files)
|
||||
{
|
||||
importFiles.Add(file);
|
||||
importFilesHash.Add(Path.GetFileName(file).ToUpper());
|
||||
importFilesHash.Add(Path.GetFileName(file));
|
||||
}
|
||||
|
||||
Progress.Reset();
|
||||
@@ -52,47 +56,59 @@ namespace AssetStudio
|
||||
assetsFileListHash.Clear();
|
||||
|
||||
ReadAssets();
|
||||
ProcessGameObject();
|
||||
ProcessAssets();
|
||||
}
|
||||
|
||||
private void LoadFile(string fullName)
|
||||
{
|
||||
switch (CheckFileType(fullName, out var reader))
|
||||
var reader = new FileReader(fullName);
|
||||
LoadFile(reader);
|
||||
}
|
||||
|
||||
private void LoadFile(FileReader reader)
|
||||
{
|
||||
switch (reader.FileType)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFile(fullName, reader);
|
||||
LoadAssetsFile(reader);
|
||||
break;
|
||||
case FileType.BundleFile:
|
||||
LoadBundleFile(fullName, reader);
|
||||
LoadBundleFile(reader);
|
||||
break;
|
||||
case FileType.WebFile:
|
||||
LoadWebFile(fullName, reader);
|
||||
LoadWebFile(reader);
|
||||
break;
|
||||
case FileType.GZipFile:
|
||||
LoadFile(DecompressGZip(reader));
|
||||
break;
|
||||
case FileType.BrotliFile:
|
||||
LoadFile(DecompressBrotli(reader));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAssetsFile(string fullName, EndianBinaryReader reader)
|
||||
private void LoadAssetsFile(FileReader reader)
|
||||
{
|
||||
var fileName = Path.GetFileName(fullName);
|
||||
if (!assetsFileListHash.Contains(fileName.ToUpper()))
|
||||
if (!assetsFileListHash.Contains(reader.FileName))
|
||||
{
|
||||
Logger.Info($"Loading {fileName}");
|
||||
Logger.Info($"Loading {reader.FileName}");
|
||||
try
|
||||
{
|
||||
var assetsFile = new SerializedFile(this, fullName, reader);
|
||||
var assetsFile = new SerializedFile(reader, this);
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.upperFileName);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
|
||||
foreach (var sharedFile in assetsFile.m_Externals)
|
||||
{
|
||||
var sharedFilePath = Path.GetDirectoryName(fullName) + "\\" + sharedFile.fileName;
|
||||
var sharedFileName = sharedFile.fileName;
|
||||
|
||||
if (!importFilesHash.Contains(sharedFileName.ToUpper()))
|
||||
if (!importFilesHash.Contains(sharedFileName))
|
||||
{
|
||||
var sharedFilePath = Path.Combine(Path.GetDirectoryName(reader.FullPath), sharedFileName);
|
||||
if (!File.Exists(sharedFilePath))
|
||||
{
|
||||
var findFiles = Directory.GetFiles(Path.GetDirectoryName(fullName), sharedFileName, SearchOption.AllDirectories);
|
||||
var findFiles = Directory.GetFiles(Path.GetDirectoryName(reader.FullPath), sharedFileName, SearchOption.AllDirectories);
|
||||
if (findFiles.Length > 0)
|
||||
{
|
||||
sharedFilePath = findFiles[0];
|
||||
@@ -102,15 +118,15 @@ namespace AssetStudio
|
||||
if (File.Exists(sharedFilePath))
|
||||
{
|
||||
importFiles.Add(sharedFilePath);
|
||||
importFilesHash.Add(sharedFileName.ToUpper());
|
||||
importFilesHash.Add(sharedFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading assets file {reader.FileName}", e);
|
||||
reader.Dispose();
|
||||
//Logger.Error($"Unable to load assets file {fileName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -119,54 +135,58 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAssetsFromMemory(string fullName, EndianBinaryReader reader, string originalPath, string unityVersion = null)
|
||||
private void LoadAssetsFromMemory(FileReader reader, string originalPath, string unityVersion = null)
|
||||
{
|
||||
var upperFileName = Path.GetFileName(fullName).ToUpper();
|
||||
if (!assetsFileListHash.Contains(upperFileName))
|
||||
if (!assetsFileListHash.Contains(reader.FileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
var assetsFile = new SerializedFile(this, fullName, reader);
|
||||
var assetsFile = new SerializedFile(reader, this);
|
||||
assetsFile.originalPath = originalPath;
|
||||
if (assetsFile.header.m_Version < 7)
|
||||
if (!string.IsNullOrEmpty(unityVersion) && assetsFile.header.m_Version < SerializedFileFormatVersion.kUnknown_7)
|
||||
{
|
||||
assetsFile.SetVersion(unityVersion);
|
||||
}
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.upperFileName);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
//Logger.Error($"Unable to load assets file {fileName} from {Path.GetFileName(originalPath)}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
resourceFileReaders.Add(upperFileName, reader);
|
||||
Logger.Error($"Error while reading assets file {reader.FileName} from {Path.GetFileName(originalPath)}", e);
|
||||
resourceFileReaders.Add(reader.FileName, reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadBundleFile(string fullName, EndianBinaryReader reader, string parentPath = null)
|
||||
private void LoadBundleFile(FileReader reader, string originalPath = null)
|
||||
{
|
||||
var fileName = Path.GetFileName(fullName);
|
||||
Logger.Info("Loading " + fileName);
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
try
|
||||
{
|
||||
var bundleFile = new BundleFile(reader, fullName);
|
||||
var bundleFile = new BundleFile(reader);
|
||||
foreach (var file in bundleFile.fileList)
|
||||
{
|
||||
var dummyPath = Path.GetDirectoryName(fullName) + "\\" + file.fileName;
|
||||
LoadAssetsFromMemory(dummyPath, new EndianBinaryReader(file.stream), parentPath ?? fullName, bundleFile.versionEngine);
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
||||
var subReader = new FileReader(dummyPath, file.stream);
|
||||
if (subReader.FileType == FileType.AssetsFile)
|
||||
{
|
||||
LoadAssetsFromMemory(subReader, originalPath ?? reader.FullPath, bundleFile.m_Header.unityRevision);
|
||||
}
|
||||
else if (!resourceFileReaders.ContainsKey(file.fileName))
|
||||
{
|
||||
resourceFileReaders.Add(file.fileName, subReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
/*var str = $"Unable to load bundle file {fileName}";
|
||||
if (parentPath != null)
|
||||
var str = $"Error while reading bundle file {reader.FileName}";
|
||||
if (originalPath != null)
|
||||
{
|
||||
str += $" from {Path.GetFileName(parentPath)}";
|
||||
str += $" from {Path.GetFileName(originalPath)}";
|
||||
}
|
||||
Logger.Error(str);*/
|
||||
Logger.Error(str, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -174,33 +194,36 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadWebFile(string fullName, EndianBinaryReader reader)
|
||||
private void LoadWebFile(FileReader reader)
|
||||
{
|
||||
var fileName = Path.GetFileName(fullName);
|
||||
Logger.Info("Loading " + fileName);
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
try
|
||||
{
|
||||
var webFile = new WebFile(reader);
|
||||
foreach (var file in webFile.fileList)
|
||||
{
|
||||
var dummyPath = Path.GetDirectoryName(fullName) + "\\" + file.fileName;
|
||||
switch (CheckFileType(file.stream, out var fileReader))
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
||||
var subReader = new FileReader(dummyPath, file.stream);
|
||||
switch (subReader.FileType)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFromMemory(dummyPath, fileReader, fullName);
|
||||
LoadAssetsFromMemory(subReader, reader.FullPath);
|
||||
break;
|
||||
case FileType.BundleFile:
|
||||
LoadBundleFile(dummyPath, fileReader, fullName);
|
||||
LoadBundleFile(subReader, reader.FullPath);
|
||||
break;
|
||||
case FileType.WebFile:
|
||||
LoadWebFile(dummyPath, fileReader);
|
||||
LoadWebFile(subReader);
|
||||
break;
|
||||
case FileType.ResourceFile:
|
||||
resourceFileReaders[file.fileName] = subReader; //TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
//Logger.Error($"Unable to load web file {fileName}");
|
||||
Logger.Error($"Error while reading web file {reader.FileName}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -208,6 +231,18 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckStrippedVersion(SerializedFile assetsFile)
|
||||
{
|
||||
if (assetsFile.IsVersionStripped && string.IsNullOrEmpty(SpecifyUnityVersion))
|
||||
{
|
||||
throw new Exception("The Unity version has been stripped, please set the version in the options");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(SpecifyUnityVersion))
|
||||
{
|
||||
assetsFile.SetVersion(SpecifyUnityVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var assetsFile in assetsFileList)
|
||||
@@ -235,96 +270,113 @@ namespace AssetStudio
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsFileList)
|
||||
{
|
||||
assetsFile.Objects = new Dictionary<long, Object>(assetsFile.m_Objects.Count);
|
||||
foreach (var objectInfo in assetsFile.m_Objects)
|
||||
{
|
||||
var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo);
|
||||
switch (objectReader.type)
|
||||
try
|
||||
{
|
||||
case ClassIDType.Animation:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Animation(objectReader));
|
||||
break;
|
||||
case ClassIDType.AnimationClip:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new AnimationClip(objectReader));
|
||||
break;
|
||||
case ClassIDType.Animator:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Animator(objectReader));
|
||||
break;
|
||||
case ClassIDType.AnimatorController:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new AnimatorController(objectReader));
|
||||
break;
|
||||
case ClassIDType.AnimatorOverrideController:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new AnimatorOverrideController(objectReader));
|
||||
break;
|
||||
case ClassIDType.AssetBundle:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new AssetBundle(objectReader));
|
||||
break;
|
||||
case ClassIDType.AudioClip:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new AudioClip(objectReader));
|
||||
break;
|
||||
case ClassIDType.Avatar:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Avatar(objectReader));
|
||||
break;
|
||||
case ClassIDType.Font:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Font(objectReader));
|
||||
break;
|
||||
case ClassIDType.GameObject:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new GameObject(objectReader));
|
||||
break;
|
||||
case ClassIDType.Material:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Material(objectReader));
|
||||
break;
|
||||
case ClassIDType.Mesh:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Mesh(objectReader));
|
||||
break;
|
||||
case ClassIDType.MeshFilter:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new MeshFilter(objectReader));
|
||||
break;
|
||||
case ClassIDType.MeshRenderer:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new MeshRenderer(objectReader));
|
||||
break;
|
||||
case ClassIDType.MonoBehaviour:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new MonoBehaviour(objectReader));
|
||||
break;
|
||||
case ClassIDType.MonoScript:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new MonoScript(objectReader));
|
||||
break;
|
||||
case ClassIDType.MovieTexture:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new MovieTexture(objectReader));
|
||||
break;
|
||||
case ClassIDType.PlayerSettings:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new PlayerSettings(objectReader));
|
||||
break;
|
||||
case ClassIDType.RectTransform:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new RectTransform(objectReader));
|
||||
break;
|
||||
case ClassIDType.Shader:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Shader(objectReader));
|
||||
break;
|
||||
case ClassIDType.SkinnedMeshRenderer:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new SkinnedMeshRenderer(objectReader));
|
||||
break;
|
||||
case ClassIDType.Sprite:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Sprite(objectReader));
|
||||
break;
|
||||
case ClassIDType.SpriteAtlas:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new SpriteAtlas(objectReader));
|
||||
break;
|
||||
case ClassIDType.TextAsset:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new TextAsset(objectReader));
|
||||
break;
|
||||
case ClassIDType.Texture2D:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Texture2D(objectReader));
|
||||
break;
|
||||
case ClassIDType.Transform:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Transform(objectReader));
|
||||
break;
|
||||
case ClassIDType.VideoClip:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new VideoClip(objectReader));
|
||||
break;
|
||||
default:
|
||||
assetsFile.Objects.Add(objectInfo.m_PathID, new Object(objectReader));
|
||||
break;
|
||||
Object obj;
|
||||
switch (objectReader.type)
|
||||
{
|
||||
case ClassIDType.Animation:
|
||||
obj = new Animation(objectReader);
|
||||
break;
|
||||
case ClassIDType.AnimationClip:
|
||||
obj = new AnimationClip(objectReader);
|
||||
break;
|
||||
case ClassIDType.Animator:
|
||||
obj = new Animator(objectReader);
|
||||
break;
|
||||
case ClassIDType.AnimatorController:
|
||||
obj = new AnimatorController(objectReader);
|
||||
break;
|
||||
case ClassIDType.AnimatorOverrideController:
|
||||
obj = new AnimatorOverrideController(objectReader);
|
||||
break;
|
||||
case ClassIDType.AssetBundle:
|
||||
obj = new AssetBundle(objectReader);
|
||||
break;
|
||||
case ClassIDType.AudioClip:
|
||||
obj = new AudioClip(objectReader);
|
||||
break;
|
||||
case ClassIDType.Avatar:
|
||||
obj = new Avatar(objectReader);
|
||||
break;
|
||||
case ClassIDType.Font:
|
||||
obj = new Font(objectReader);
|
||||
break;
|
||||
case ClassIDType.GameObject:
|
||||
obj = new GameObject(objectReader);
|
||||
break;
|
||||
case ClassIDType.Material:
|
||||
obj = new Material(objectReader);
|
||||
break;
|
||||
case ClassIDType.Mesh:
|
||||
obj = new Mesh(objectReader);
|
||||
break;
|
||||
case ClassIDType.MeshFilter:
|
||||
obj = new MeshFilter(objectReader);
|
||||
break;
|
||||
case ClassIDType.MeshRenderer:
|
||||
obj = new MeshRenderer(objectReader);
|
||||
break;
|
||||
case ClassIDType.MonoBehaviour:
|
||||
obj = new MonoBehaviour(objectReader);
|
||||
break;
|
||||
case ClassIDType.MonoScript:
|
||||
obj = new MonoScript(objectReader);
|
||||
break;
|
||||
case ClassIDType.MovieTexture:
|
||||
obj = new MovieTexture(objectReader);
|
||||
break;
|
||||
case ClassIDType.PlayerSettings:
|
||||
obj = new PlayerSettings(objectReader);
|
||||
break;
|
||||
case ClassIDType.RectTransform:
|
||||
obj = new RectTransform(objectReader);
|
||||
break;
|
||||
case ClassIDType.Shader:
|
||||
obj = new Shader(objectReader);
|
||||
break;
|
||||
case ClassIDType.SkinnedMeshRenderer:
|
||||
obj = new SkinnedMeshRenderer(objectReader);
|
||||
break;
|
||||
case ClassIDType.Sprite:
|
||||
obj = new Sprite(objectReader);
|
||||
break;
|
||||
case ClassIDType.SpriteAtlas:
|
||||
obj = new SpriteAtlas(objectReader);
|
||||
break;
|
||||
case ClassIDType.TextAsset:
|
||||
obj = new TextAsset(objectReader);
|
||||
break;
|
||||
case ClassIDType.Texture2D:
|
||||
obj = new Texture2D(objectReader);
|
||||
break;
|
||||
case ClassIDType.Transform:
|
||||
obj = new Transform(objectReader);
|
||||
break;
|
||||
case ClassIDType.VideoClip:
|
||||
obj = new VideoClip(objectReader);
|
||||
break;
|
||||
case ClassIDType.ResourceManager:
|
||||
obj = new ResourceManager(objectReader);
|
||||
break;
|
||||
default:
|
||||
obj = new Object(objectReader);
|
||||
break;
|
||||
}
|
||||
assetsFile.AddObject(obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
Progress.Report(++i, progressCount);
|
||||
@@ -332,13 +384,13 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessGameObject()
|
||||
private void ProcessAssets()
|
||||
{
|
||||
Logger.Info("Process GameObject...");
|
||||
Logger.Info("Process Assets...");
|
||||
|
||||
foreach (var assetsFile in assetsFileList)
|
||||
{
|
||||
foreach (var obj in assetsFile.Objects.Values)
|
||||
foreach (var obj in assetsFile.Objects)
|
||||
{
|
||||
if (obj is GameObject m_GameObject)
|
||||
{
|
||||
@@ -370,6 +422,19 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (obj is SpriteAtlas m_SpriteAtlas)
|
||||
{
|
||||
foreach (var m_PackedSprite in m_SpriteAtlas.m_PackedSprites)
|
||||
{
|
||||
if (m_PackedSprite.TryGet(out var m_Sprite))
|
||||
{
|
||||
if (m_Sprite.m_SpriteAtlas.IsNull)
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,246 +1,314 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Lz4;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StreamFile
|
||||
{
|
||||
public string fileName;
|
||||
public Stream stream;
|
||||
}
|
||||
|
||||
public class BlockInfo
|
||||
{
|
||||
public uint compressedSize;
|
||||
public uint uncompressedSize;
|
||||
public short flag;
|
||||
}
|
||||
|
||||
public class BundleFile
|
||||
{
|
||||
private string path;
|
||||
public string versionPlayer;
|
||||
public string versionEngine;
|
||||
public List<StreamFile> fileList = new List<StreamFile>();
|
||||
|
||||
public BundleFile(EndianBinaryReader bundleReader, string path)
|
||||
public class Header
|
||||
{
|
||||
this.path = path;
|
||||
var signature = bundleReader.ReadStringToNull();
|
||||
switch (signature)
|
||||
public string signature;
|
||||
public uint version;
|
||||
public string unityVersion;
|
||||
public string unityRevision;
|
||||
public long size;
|
||||
public uint compressedBlocksInfoSize;
|
||||
public uint uncompressedBlocksInfoSize;
|
||||
public uint flags;
|
||||
}
|
||||
|
||||
public class StorageBlock
|
||||
{
|
||||
public uint compressedSize;
|
||||
public uint uncompressedSize;
|
||||
public ushort flags;
|
||||
}
|
||||
|
||||
public class Node
|
||||
{
|
||||
public long offset;
|
||||
public long size;
|
||||
public uint flags;
|
||||
public string path;
|
||||
}
|
||||
|
||||
public Header m_Header;
|
||||
private StorageBlock[] m_BlocksInfo;
|
||||
private Node[] m_DirectoryInfo;
|
||||
|
||||
public StreamFile[] fileList;
|
||||
|
||||
public BundleFile(FileReader reader)
|
||||
{
|
||||
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":
|
||||
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA":
|
||||
if (m_Header.version == 6)
|
||||
{
|
||||
var format = bundleReader.ReadInt32();
|
||||
versionPlayer = bundleReader.ReadStringToNull();
|
||||
versionEngine = bundleReader.ReadStringToNull();
|
||||
if (format < 6)
|
||||
{
|
||||
int bundleSize = bundleReader.ReadInt32();
|
||||
}
|
||||
else if (format == 6)
|
||||
{
|
||||
ReadFormat6(bundleReader, true);
|
||||
return;
|
||||
}
|
||||
short dummy2 = bundleReader.ReadInt16();
|
||||
int offset = bundleReader.ReadInt16();
|
||||
int dummy3 = bundleReader.ReadInt32();
|
||||
int lzmaChunks = bundleReader.ReadInt32();
|
||||
|
||||
int lzmaSize = 0;
|
||||
long streamSize = 0;
|
||||
|
||||
for (int i = 0; i < lzmaChunks; i++)
|
||||
{
|
||||
lzmaSize = bundleReader.ReadInt32();
|
||||
streamSize = bundleReader.ReadInt32();
|
||||
}
|
||||
|
||||
bundleReader.Position = offset;
|
||||
switch (signature)
|
||||
{
|
||||
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA": //.bytes
|
||||
case "UnityWeb":
|
||||
{
|
||||
var lzmaBuffer = bundleReader.ReadBytes(lzmaSize);
|
||||
using (var lzmaStream = new EndianBinaryReader(SevenZipHelper.StreamDecompress(new MemoryStream(lzmaBuffer))))
|
||||
{
|
||||
GetAssetsFiles(lzmaStream, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "UnityRaw":
|
||||
{
|
||||
GetAssetsFiles(bundleReader, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
goto case "UnityFS";
|
||||
}
|
||||
ReadHeaderAndBlocksInfo(reader);
|
||||
using (var blocksStream = CreateBlocksStream(reader.FullPath))
|
||||
{
|
||||
ReadBlocksAndDirectory(reader, blocksStream);
|
||||
ReadFiles(blocksStream, reader.FullPath);
|
||||
}
|
||||
break;
|
||||
case "UnityFS":
|
||||
ReadHeader(reader);
|
||||
ReadBlocksInfoAndDirectory(reader);
|
||||
using (var blocksStream = CreateBlocksStream(reader.FullPath))
|
||||
{
|
||||
var format = bundleReader.ReadInt32();
|
||||
versionPlayer = bundleReader.ReadStringToNull();
|
||||
versionEngine = bundleReader.ReadStringToNull();
|
||||
if (format == 6)
|
||||
{
|
||||
ReadFormat6(bundleReader);
|
||||
}
|
||||
break;
|
||||
ReadBlocks(reader, blocksStream);
|
||||
ReadFiles(blocksStream, reader.FullPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void GetAssetsFiles(EndianBinaryReader reader, int offset)
|
||||
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
|
||||
{
|
||||
int fileCount = reader.ReadInt32();
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
var isCompressed = m_Header.signature == "UnityWeb";
|
||||
if (m_Header.version >= 4)
|
||||
{
|
||||
var file = new StreamFile();
|
||||
file.fileName = Path.GetFileName(reader.ReadStringToNull());
|
||||
int fileOffset = reader.ReadInt32();
|
||||
fileOffset += offset;
|
||||
int fileSize = reader.ReadInt32();
|
||||
long nextFile = reader.Position;
|
||||
reader.Position = fileOffset;
|
||||
var buffer = reader.ReadBytes(fileSize);
|
||||
file.stream = new MemoryStream(buffer);
|
||||
fileList.Add(file);
|
||||
reader.Position = nextFile;
|
||||
var hash = reader.ReadBytes(16);
|
||||
var crc = reader.ReadUInt32();
|
||||
}
|
||||
var minimumStreamedBytes = reader.ReadUInt32();
|
||||
m_Header.size = reader.ReadUInt32();
|
||||
var numberOfLevelsToDownloadBeforeStreaming = reader.ReadUInt32();
|
||||
var levelCount = reader.ReadInt32();
|
||||
m_BlocksInfo = new StorageBlock[1];
|
||||
for (int i = 0; i < levelCount; i++)
|
||||
{
|
||||
var storageBlock = new StorageBlock()
|
||||
{
|
||||
compressedSize = reader.ReadUInt32(),
|
||||
uncompressedSize = reader.ReadUInt32(),
|
||||
flags = (ushort)(isCompressed ? 1 : 0)
|
||||
};
|
||||
if (i == levelCount - 1)
|
||||
{
|
||||
m_BlocksInfo[0] = storageBlock;
|
||||
}
|
||||
}
|
||||
if (m_Header.version >= 2)
|
||||
{
|
||||
var completeFileSize = reader.ReadUInt32();
|
||||
}
|
||||
if (m_Header.version >= 3)
|
||||
{
|
||||
var fileInfoHeaderSize = reader.ReadUInt32();
|
||||
}
|
||||
reader.Position = m_Header.size;
|
||||
}
|
||||
|
||||
private void ReadFormat6(EndianBinaryReader bundleReader, bool padding = false)
|
||||
private Stream CreateBlocksStream(string path)
|
||||
{
|
||||
var bundleSize = bundleReader.ReadInt64();
|
||||
int compressedSize = bundleReader.ReadInt32();
|
||||
int uncompressedSize = bundleReader.ReadInt32();
|
||||
int flag = bundleReader.ReadInt32();
|
||||
if (padding)
|
||||
bundleReader.ReadByte();
|
||||
byte[] blocksInfoBytes;
|
||||
if ((flag & 0x80) != 0)//at end of file
|
||||
Stream blocksStream;
|
||||
var uncompressedSizeSum = m_BlocksInfo.Sum(x => x.uncompressedSize);
|
||||
if (uncompressedSizeSum >= int.MaxValue)
|
||||
{
|
||||
var position = bundleReader.Position;
|
||||
bundleReader.Position = bundleReader.BaseStream.Length - compressedSize;
|
||||
blocksInfoBytes = bundleReader.ReadBytes(compressedSize);
|
||||
bundleReader.Position = position;
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(null, uncompressedSizeSum);
|
||||
assetsDataStream = memoryMappedFile.CreateViewStream();*/
|
||||
blocksStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
|
||||
}
|
||||
else
|
||||
{
|
||||
blocksInfoBytes = bundleReader.ReadBytes(compressedSize);
|
||||
blocksStream = new MemoryStream((int)uncompressedSizeSum);
|
||||
}
|
||||
MemoryStream blocksInfoStream;
|
||||
switch (flag & 0x3F)
|
||||
return blocksStream;
|
||||
}
|
||||
|
||||
private void ReadBlocksAndDirectory(EndianBinaryReader reader, Stream blocksStream)
|
||||
{
|
||||
foreach (var blockInfo in m_BlocksInfo)
|
||||
{
|
||||
default://None
|
||||
var uncompressedBytes = reader.ReadBytes((int)blockInfo.compressedSize);
|
||||
if (blockInfo.flags == 1)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream(uncompressedBytes))
|
||||
{
|
||||
blocksInfoStream = new MemoryStream(blocksInfoBytes);
|
||||
break;
|
||||
}
|
||||
case 1://LZMA
|
||||
{
|
||||
blocksInfoStream = SevenZipHelper.StreamDecompress(new MemoryStream(blocksInfoBytes));
|
||||
break;
|
||||
}
|
||||
case 2://LZ4
|
||||
case 3://LZ4HC
|
||||
{
|
||||
byte[] uncompressedBytes = new byte[uncompressedSize];
|
||||
using (var decoder = new Lz4DecoderStream(new MemoryStream(blocksInfoBytes)))
|
||||
using (var decompressStream = SevenZipHelper.StreamDecompress(memoryStream))
|
||||
{
|
||||
decoder.Read(uncompressedBytes, 0, uncompressedSize);
|
||||
uncompressedBytes = decompressStream.ToArray();
|
||||
}
|
||||
blocksInfoStream = new MemoryStream(uncompressedBytes);
|
||||
break;
|
||||
}
|
||||
//case 4:LZHAM?
|
||||
}
|
||||
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoStream))
|
||||
{
|
||||
blocksInfoReader.Position = 0x10;
|
||||
int blockcount = blocksInfoReader.ReadInt32();
|
||||
var blockInfos = new BlockInfo[blockcount];
|
||||
for (int i = 0; i < blockcount; i++)
|
||||
{
|
||||
blockInfos[i] = new BlockInfo
|
||||
{
|
||||
uncompressedSize = blocksInfoReader.ReadUInt32(),
|
||||
compressedSize = blocksInfoReader.ReadUInt32(),
|
||||
flag = blocksInfoReader.ReadInt16()
|
||||
};
|
||||
}
|
||||
Stream dataStream;
|
||||
var uncompressedSizeSum = blockInfos.Sum(x => x.uncompressedSize);
|
||||
if (uncompressedSizeSum > int.MaxValue)
|
||||
blocksStream.Write(uncompressedBytes, 0, uncompressedBytes.Length);
|
||||
}
|
||||
blocksStream.Position = 0;
|
||||
var blocksReader = new EndianBinaryReader(blocksStream);
|
||||
var nodesCount = blocksReader.ReadInt32();
|
||||
m_DirectoryInfo = new Node[nodesCount];
|
||||
for (int i = 0; i < nodesCount; i++)
|
||||
{
|
||||
m_DirectoryInfo[i] = new Node
|
||||
{
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(Path.GetFileName(path), uncompressedSizeSum);
|
||||
assetsDataStream = memoryMappedFile.CreateViewStream();*/
|
||||
dataStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
|
||||
path = blocksReader.ReadStringToNull(),
|
||||
offset = blocksReader.ReadUInt32(),
|
||||
size = blocksReader.ReadUInt32()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void ReadFiles(Stream blocksStream, string path)
|
||||
{
|
||||
fileList = new StreamFile[m_DirectoryInfo.Length];
|
||||
for (int i = 0; i < m_DirectoryInfo.Length; i++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(null, entryinfo_size);
|
||||
file.stream = memoryMappedFile.CreateViewStream();*/
|
||||
var extractPath = path + "_unpacked" + Path.DirectorySeparatorChar;
|
||||
Directory.CreateDirectory(extractPath);
|
||||
file.stream = new FileStream(extractPath + file.fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataStream = new MemoryStream();
|
||||
file.stream = new MemoryStream((int)node.size);
|
||||
}
|
||||
foreach (var blockInfo in blockInfos)
|
||||
{
|
||||
switch (blockInfo.flag & 0x3F)
|
||||
blocksStream.Position = node.offset;
|
||||
blocksStream.CopyTo(file.stream, node.size);
|
||||
file.stream.Position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadHeader(EndianBinaryReader reader)
|
||||
{
|
||||
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;
|
||||
reader.Position = reader.BaseStream.Length - m_Header.compressedBlocksInfoSize;
|
||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||
reader.Position = position;
|
||||
}
|
||||
else //0x40 kArchiveBlocksAndDirectoryInfoCombined
|
||||
{
|
||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||
}
|
||||
var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes);
|
||||
MemoryStream blocksInfoUncompresseddStream;
|
||||
switch (m_Header.flags & 0x3F) //kArchiveCompressionTypeMask
|
||||
{
|
||||
default: //None
|
||||
{
|
||||
default://None
|
||||
{
|
||||
bundleReader.BaseStream.CopyTo(dataStream, blockInfo.compressedSize);
|
||||
break;
|
||||
}
|
||||
case 1://LZMA
|
||||
{
|
||||
SevenZipHelper.StreamDecompress(bundleReader.BaseStream, dataStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
|
||||
break;
|
||||
}
|
||||
case 2://LZ4
|
||||
case 3://LZ4HC
|
||||
{
|
||||
var lz4Stream = new Lz4DecoderStream(bundleReader.BaseStream, blockInfo.compressedSize);
|
||||
lz4Stream.CopyTo(dataStream, blockInfo.uncompressedSize);
|
||||
break;
|
||||
}
|
||||
//case 4:LZHAM?
|
||||
blocksInfoUncompresseddStream = blocksInfoCompressedStream;
|
||||
break;
|
||||
}
|
||||
case 1: //LZMA
|
||||
{
|
||||
blocksInfoUncompresseddStream = new MemoryStream((int)(m_Header.uncompressedBlocksInfoSize));
|
||||
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
|
||||
blocksInfoUncompresseddStream.Position = 0;
|
||||
blocksInfoCompressedStream.Close();
|
||||
break;
|
||||
}
|
||||
case 2: //LZ4
|
||||
case 3: //LZ4HC
|
||||
{
|
||||
var uncompressedBytes = new byte[m_Header.uncompressedBlocksInfoSize];
|
||||
using (var decoder = new Lz4DecoderStream(blocksInfoCompressedStream))
|
||||
{
|
||||
decoder.Read(uncompressedBytes, 0, uncompressedBytes.Length);
|
||||
}
|
||||
blocksInfoUncompresseddStream = new MemoryStream(uncompressedBytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompresseddStream))
|
||||
{
|
||||
var uncompressedDataHash = blocksInfoReader.ReadBytes(16);
|
||||
var blocksInfoCount = blocksInfoReader.ReadInt32();
|
||||
m_BlocksInfo = new StorageBlock[blocksInfoCount];
|
||||
for (int i = 0; i < blocksInfoCount; i++)
|
||||
{
|
||||
m_BlocksInfo[i] = new StorageBlock
|
||||
{
|
||||
uncompressedSize = blocksInfoReader.ReadUInt32(),
|
||||
compressedSize = blocksInfoReader.ReadUInt32(),
|
||||
flags = blocksInfoReader.ReadUInt16()
|
||||
};
|
||||
}
|
||||
dataStream.Position = 0;
|
||||
using (dataStream)
|
||||
|
||||
var nodesCount = blocksInfoReader.ReadInt32();
|
||||
m_DirectoryInfo = new Node[nodesCount];
|
||||
for (int i = 0; i < nodesCount; i++)
|
||||
{
|
||||
var entryinfo_count = blocksInfoReader.ReadInt32();
|
||||
for (int i = 0; i < entryinfo_count; i++)
|
||||
m_DirectoryInfo[i] = new Node
|
||||
{
|
||||
var file = new StreamFile();
|
||||
var entryinfo_offset = blocksInfoReader.ReadInt64();
|
||||
var entryinfo_size = blocksInfoReader.ReadInt64();
|
||||
flag = blocksInfoReader.ReadInt32();
|
||||
file.fileName = Path.GetFileName(blocksInfoReader.ReadStringToNull());
|
||||
if (entryinfo_size > int.MaxValue)
|
||||
{
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(file.fileName, entryinfo_size);
|
||||
file.stream = memoryMappedFile.CreateViewStream();*/
|
||||
var extractPath = path + "_unpacked\\";
|
||||
Directory.CreateDirectory(extractPath);
|
||||
file.stream = File.Create(extractPath + file.fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.stream = new MemoryStream();
|
||||
}
|
||||
dataStream.Position = entryinfo_offset;
|
||||
dataStream.CopyTo(file.stream, entryinfo_size);
|
||||
file.stream.Position = 0;
|
||||
fileList.Add(file);
|
||||
}
|
||||
offset = blocksInfoReader.ReadInt64(),
|
||||
size = blocksInfoReader.ReadInt64(),
|
||||
flags = blocksInfoReader.ReadUInt32(),
|
||||
path = blocksInfoReader.ReadStringToNull(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadBlocks(EndianBinaryReader reader, Stream blocksStream)
|
||||
{
|
||||
foreach (var blockInfo in m_BlocksInfo)
|
||||
{
|
||||
switch (blockInfo.flags & 0x3F) //kStorageBlockCompressionTypeMask
|
||||
{
|
||||
default: //None
|
||||
{
|
||||
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
|
||||
break;
|
||||
}
|
||||
case 1: //LZMA
|
||||
{
|
||||
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
|
||||
break;
|
||||
}
|
||||
case 2: //LZ4
|
||||
case 3: //LZ4HC
|
||||
{
|
||||
var compressedStream = new MemoryStream(reader.ReadBytes((int)blockInfo.compressedSize));
|
||||
using (var lz4Stream = new Lz4DecoderStream(compressedStream))
|
||||
{
|
||||
lz4Stream.CopyTo(blocksStream, blockInfo.uncompressedSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
blocksStream.Position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ namespace AssetStudio
|
||||
public AnimationCurve<float> curve;
|
||||
public string attribute;
|
||||
public string path;
|
||||
public int classID;
|
||||
public ClassIDType classID;
|
||||
public PPtr<MonoScript> script;
|
||||
|
||||
|
||||
@@ -301,7 +301,7 @@ namespace AssetStudio
|
||||
curve = new AnimationCurve<float>(reader, reader.ReadSingle);
|
||||
attribute = reader.ReadAlignedString();
|
||||
path = reader.ReadAlignedString();
|
||||
classID = reader.ReadInt32();
|
||||
classID = (ClassIDType)reader.ReadInt32();
|
||||
script = new PPtr<MonoScript>(reader);
|
||||
}
|
||||
}
|
||||
@@ -637,6 +637,50 @@ namespace AssetStudio
|
||||
m_Binding = new ValueArrayConstant(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public AnimationClipBindingConstant ConvertValueArrayToGenericBinding()
|
||||
{
|
||||
var bindings = new AnimationClipBindingConstant();
|
||||
var genericBindings = new List<GenericBinding>();
|
||||
var values = m_Binding;
|
||||
for (int i = 0; i < values.m_ValueArray.Length;)
|
||||
{
|
||||
var curveID = values.m_ValueArray[i].m_ID;
|
||||
var curveTypeID = values.m_ValueArray[i].m_TypeID;
|
||||
var binding = new GenericBinding();
|
||||
genericBindings.Add(binding);
|
||||
if (curveTypeID == 4174552735) //CRC(PositionX))
|
||||
{
|
||||
binding.path = curveID;
|
||||
binding.attribute = 1; //kBindTransformPosition
|
||||
binding.typeID = ClassIDType.Transform;
|
||||
i += 3;
|
||||
}
|
||||
else if (curveTypeID == 2211994246) //CRC(QuaternionX))
|
||||
{
|
||||
binding.path = curveID;
|
||||
binding.attribute = 2; //kBindTransformRotation
|
||||
binding.typeID = ClassIDType.Transform;
|
||||
i += 4;
|
||||
}
|
||||
else if (curveTypeID == 1512518241) //CRC(ScaleX))
|
||||
{
|
||||
binding.path = curveID;
|
||||
binding.attribute = 3; //kBindTransformScale
|
||||
binding.typeID = ClassIDType.Transform;
|
||||
i += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
binding.typeID = ClassIDType.Animator;
|
||||
binding.path = 0;
|
||||
binding.attribute = curveID;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
bindings.genericBindings = genericBindings.ToArray();
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
|
||||
public class ValueDelta
|
||||
@@ -754,6 +798,8 @@ namespace AssetStudio
|
||||
public byte customType;
|
||||
public byte isPPtrCurve;
|
||||
|
||||
public GenericBinding() { }
|
||||
|
||||
public GenericBinding(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
@@ -779,6 +825,8 @@ namespace AssetStudio
|
||||
public GenericBinding[] genericBindings;
|
||||
public PPtr<Object>[] pptrCurveMapping;
|
||||
|
||||
public AnimationClipBindingConstant() { }
|
||||
|
||||
public AnimationClipBindingConstant(ObjectReader reader)
|
||||
{
|
||||
int numBindings = reader.ReadInt32();
|
||||
|
||||
@@ -31,6 +31,10 @@ namespace AssetStudio
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_LinearVelocityBlending = reader.ReadBoolean();
|
||||
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 2)) //2021.2 and up
|
||||
{
|
||||
var m_StabilizeFeet = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace AssetStudio
|
||||
public AudioCompressionFormat m_CompressionFormat;
|
||||
|
||||
public string m_Source;
|
||||
public long m_Offset;
|
||||
public long m_Size;
|
||||
public Lazy<byte[]> m_AudioData;
|
||||
public long m_Offset; //ulong
|
||||
public long m_Size; //ulong
|
||||
public ResourceReader m_AudioData;
|
||||
|
||||
public AudioClip(ObjectReader reader) : base(reader)
|
||||
{
|
||||
@@ -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,6 +72,7 @@ namespace AssetStudio
|
||||
m_Legacy3D = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
|
||||
//StreamedResource m_Resource
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadInt64();
|
||||
m_Size = reader.ReadInt64();
|
||||
@@ -81,13 +82,13 @@ namespace AssetStudio
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_Source))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_Source, assetsFile, m_Offset, (int)m_Size);
|
||||
resourceReader = new ResourceReader(m_Source, assetsFile, m_Offset, m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size);
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_Size);
|
||||
}
|
||||
m_AudioData = new Lazy<byte[]>(resourceReader.GetData);
|
||||
m_AudioData = resourceReader;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,19 +166,19 @@ namespace AssetStudio
|
||||
|
||||
if (version[0] < 4) //4.0 down
|
||||
{
|
||||
GetChannels();
|
||||
GetChannels(version);
|
||||
}
|
||||
}
|
||||
else //5.0 and up
|
||||
{
|
||||
GetStreams();
|
||||
GetStreams(version);
|
||||
}
|
||||
|
||||
m_DataSize = reader.ReadBytes(reader.ReadInt32());
|
||||
m_DataSize = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
private void GetStreams()
|
||||
private void GetStreams(int[] version)
|
||||
{
|
||||
var streamCount = m_Channels.Max(x => x.stream) + 1;
|
||||
m_Streams = new StreamInfo[streamCount];
|
||||
@@ -195,7 +195,7 @@ namespace AssetStudio
|
||||
if (m_Channel.dimension > 0)
|
||||
{
|
||||
chnMask |= 1u << chn;
|
||||
stride += m_Channel.dimension * MeshHelper.GetChannelFormatSize(m_Channel.format);
|
||||
stride += m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,7 +213,7 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private void GetChannels()
|
||||
private void GetChannels(int[] version)
|
||||
{
|
||||
m_Channels = new ChannelInfo[6];
|
||||
for (int i = 0; i < 6; i++)
|
||||
@@ -253,7 +253,7 @@ namespace AssetStudio
|
||||
m_Channel.dimension = 4;
|
||||
break;
|
||||
}
|
||||
offset += (byte)(m_Channel.dimension * MeshHelper.GetChannelFormatSize(m_Channel.format));
|
||||
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,11 +396,21 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
public enum GfxPrimitiveType : int
|
||||
{
|
||||
kPrimitiveTriangles = 0,
|
||||
kPrimitiveTriangleStrip = 1,
|
||||
kPrimitiveQuads = 2,
|
||||
kPrimitiveLines = 3,
|
||||
kPrimitiveLineStrip = 4,
|
||||
kPrimitivePoints = 5,
|
||||
};
|
||||
|
||||
public class SubMesh
|
||||
{
|
||||
public uint firstByte;
|
||||
public uint indexCount;
|
||||
public int topology;
|
||||
public GfxPrimitiveType topology;
|
||||
public uint triangleCount;
|
||||
public uint baseVertex;
|
||||
public uint firstVertex;
|
||||
@@ -413,7 +423,7 @@ namespace AssetStudio
|
||||
|
||||
firstByte = reader.ReadUInt32();
|
||||
indexCount = reader.ReadUInt32();
|
||||
topology = reader.ReadInt32();
|
||||
topology = (GfxPrimitiveType)reader.ReadInt32();
|
||||
|
||||
if (version[0] < 4) //4.0 down
|
||||
{
|
||||
@@ -436,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;
|
||||
@@ -451,12 +461,16 @@ namespace AssetStudio
|
||||
public float[] m_UV1;
|
||||
public float[] m_UV2;
|
||||
public float[] m_UV3;
|
||||
public float[] m_UV4;
|
||||
public float[] m_UV5;
|
||||
public float[] m_UV6;
|
||||
public float[] m_UV7;
|
||||
public float[] m_Tangents;
|
||||
private VertexData m_VertexData;
|
||||
private CompressedMesh m_CompressedMesh;
|
||||
private StreamingInfo m_StreamData;
|
||||
|
||||
public List<uint> m_Indices = new List<uint>(); //use a list because I don't always know the facecount for triangle strips
|
||||
public List<uint> m_Indices = new List<uint>();
|
||||
|
||||
public Mesh(ObjectReader reader) : base(reader)
|
||||
{
|
||||
@@ -536,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();
|
||||
@@ -638,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();
|
||||
}
|
||||
|
||||
@@ -666,7 +681,7 @@ namespace AssetStudio
|
||||
{
|
||||
if (m_VertexData.m_VertexCount > 0)
|
||||
{
|
||||
var resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, (int)m_StreamData.size);
|
||||
var resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size);
|
||||
m_VertexData.m_DataSize = resourceReader.GetData();
|
||||
}
|
||||
}
|
||||
@@ -680,7 +695,7 @@ namespace AssetStudio
|
||||
DecompressCompressedMesh();
|
||||
}
|
||||
|
||||
BuildFaces();
|
||||
GetTriangles();
|
||||
}
|
||||
|
||||
private void ReadVertexData()
|
||||
@@ -696,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.GetChannelFormatSize(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++)
|
||||
{
|
||||
@@ -726,10 +742,10 @@ namespace AssetStudio
|
||||
|
||||
int[] componentsIntArray = null;
|
||||
float[] componentsFloatArray = null;
|
||||
if (m_Channel.format == 10 || m_Channel.format == 11)
|
||||
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes);
|
||||
if (MeshHelper.IsIntFormat(vertexFormat))
|
||||
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, vertexFormat);
|
||||
else
|
||||
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, componentByteSize);
|
||||
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
|
||||
|
||||
if (version[0] >= 2018)
|
||||
{
|
||||
@@ -759,10 +775,18 @@ namespace AssetStudio
|
||||
case 7: //kShaderChannelTexCoord3
|
||||
m_UV3 = componentsFloatArray;
|
||||
break;
|
||||
//kShaderChannelTexCoord4 8
|
||||
//kShaderChannelTexCoord5 9
|
||||
//kShaderChannelTexCoord6 10
|
||||
//kShaderChannelTexCoord7 11
|
||||
case 8: //kShaderChannelTexCoord4
|
||||
m_UV4 = componentsFloatArray;
|
||||
break;
|
||||
case 9: //kShaderChannelTexCoord5
|
||||
m_UV5 = componentsFloatArray;
|
||||
break;
|
||||
case 10: //kShaderChannelTexCoord6
|
||||
m_UV6 = componentsFloatArray;
|
||||
break;
|
||||
case 11: //kShaderChannelTexCoord7
|
||||
m_UV7 = componentsFloatArray;
|
||||
break;
|
||||
//2018.2 and up
|
||||
case 12: //kShaderChannelBlendWeight
|
||||
if (m_Skin == null)
|
||||
@@ -840,23 +864,40 @@ namespace AssetStudio
|
||||
if (m_CompressedMesh.m_Vertices.m_NumItems > 0)
|
||||
{
|
||||
m_VertexCount = (int)m_CompressedMesh.m_Vertices.m_NumItems / 3;
|
||||
m_Vertices = m_CompressedMesh.m_Vertices.UnpackFloats(3, 4);
|
||||
m_Vertices = m_CompressedMesh.m_Vertices.UnpackFloats(3, 3 * 4);
|
||||
}
|
||||
//UV
|
||||
if (m_CompressedMesh.m_UV.m_NumItems > 0)
|
||||
{
|
||||
m_UV0 = m_CompressedMesh.m_UV.UnpackFloats(2, 4, 0, m_VertexCount);
|
||||
if (m_CompressedMesh.m_UV.m_NumItems >= m_VertexCount * 4)
|
||||
var m_UVInfo = m_CompressedMesh.m_UVInfo;
|
||||
if (m_UVInfo != 0)
|
||||
{
|
||||
m_UV1 = m_CompressedMesh.m_UV.UnpackFloats(2, 4, m_VertexCount * 2, m_VertexCount);
|
||||
const int kInfoBitsPerUV = 4;
|
||||
const int kUVDimensionMask = 3;
|
||||
const int kUVChannelExists = 4;
|
||||
const int kMaxTexCoordShaderChannels = 8;
|
||||
|
||||
int uvSrcOffset = 0;
|
||||
for (int uv = 0; uv < kMaxTexCoordShaderChannels; uv++)
|
||||
{
|
||||
var texCoordBits = m_UVInfo >> (uv * kInfoBitsPerUV);
|
||||
texCoordBits &= (1u << kInfoBitsPerUV) - 1u;
|
||||
if ((texCoordBits & kUVChannelExists) != 0)
|
||||
{
|
||||
var uvDim = 1 + (int)(texCoordBits & kUVDimensionMask);
|
||||
var m_UV = m_CompressedMesh.m_UV.UnpackFloats(uvDim, uvDim * 4, uvSrcOffset, m_VertexCount);
|
||||
SetUV(uv, m_UV);
|
||||
uvSrcOffset += uvDim * m_VertexCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_CompressedMesh.m_UV.m_NumItems >= m_VertexCount * 6)
|
||||
else
|
||||
{
|
||||
m_UV2 = m_CompressedMesh.m_UV.UnpackFloats(2, 4, m_VertexCount * 4, m_VertexCount);
|
||||
}
|
||||
if (m_CompressedMesh.m_UV.m_NumItems >= m_VertexCount * 8)
|
||||
{
|
||||
m_UV3 = m_CompressedMesh.m_UV.UnpackFloats(2, 4, m_VertexCount * 6, m_VertexCount);
|
||||
m_UV0 = m_CompressedMesh.m_UV.UnpackFloats(2, 2 * 4, 0, m_VertexCount);
|
||||
if (m_CompressedMesh.m_UV.m_NumItems >= m_VertexCount * 4)
|
||||
{
|
||||
m_UV1 = m_CompressedMesh.m_UV.UnpackFloats(2, 2 * 4, m_VertexCount * 2, m_VertexCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
//BindPose
|
||||
@@ -1008,7 +1049,7 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildFaces()
|
||||
private void GetTriangles()
|
||||
{
|
||||
foreach (var m_SubMesh in m_SubMeshes)
|
||||
{
|
||||
@@ -1017,43 +1058,65 @@ namespace AssetStudio
|
||||
{
|
||||
firstIndex /= 2;
|
||||
}
|
||||
|
||||
if (m_SubMesh.topology == 0)
|
||||
var indexCount = m_SubMesh.indexCount;
|
||||
var topology = m_SubMesh.topology;
|
||||
if (topology == GfxPrimitiveType.kPrimitiveTriangles)
|
||||
{
|
||||
for (int i = 0; i < m_SubMesh.indexCount / 3; i++)
|
||||
for (int i = 0; i < indexCount; i += 3)
|
||||
{
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + i * 3]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 1]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 2]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + i]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + i + 1]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + i + 2]);
|
||||
}
|
||||
}
|
||||
else if (version[0] < 4 || topology == GfxPrimitiveType.kPrimitiveTriangleStrip)
|
||||
{
|
||||
// de-stripify :
|
||||
uint triIndex = 0;
|
||||
for (int i = 0; i < indexCount - 2; i++)
|
||||
{
|
||||
var a = m_IndexBuffer[firstIndex + i];
|
||||
var b = m_IndexBuffer[firstIndex + i + 1];
|
||||
var c = m_IndexBuffer[firstIndex + i + 2];
|
||||
|
||||
// skip degenerates
|
||||
if (a == b || a == c || b == c)
|
||||
continue;
|
||||
|
||||
// do the winding flip-flop of strips :
|
||||
if ((i & 1) == 1)
|
||||
{
|
||||
m_Indices.Add(b);
|
||||
m_Indices.Add(a);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Indices.Add(a);
|
||||
m_Indices.Add(b);
|
||||
}
|
||||
m_Indices.Add(c);
|
||||
triIndex += 3;
|
||||
}
|
||||
//fix indexCount
|
||||
m_SubMesh.indexCount = triIndex;
|
||||
}
|
||||
else if (topology == GfxPrimitiveType.kPrimitiveQuads)
|
||||
{
|
||||
for (int q = 0; q < indexCount; q += 4)
|
||||
{
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + q]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + q + 1]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + q + 2]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + q]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + q + 2]);
|
||||
m_Indices.Add(m_IndexBuffer[firstIndex + q + 3]);
|
||||
}
|
||||
//fix indexCount
|
||||
m_SubMesh.indexCount = indexCount / 2 * 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint j = 0;
|
||||
for (int i = 0; i < m_SubMesh.indexCount - 2; i++)
|
||||
{
|
||||
uint fa = m_IndexBuffer[firstIndex + i];
|
||||
uint fb = m_IndexBuffer[firstIndex + i + 1];
|
||||
uint fc = m_IndexBuffer[firstIndex + i + 2];
|
||||
|
||||
if ((fa != fb) && (fa != fc) && (fc != fb))
|
||||
{
|
||||
m_Indices.Add(fa);
|
||||
if ((i % 2) == 0)
|
||||
{
|
||||
m_Indices.Add(fb);
|
||||
m_Indices.Add(fc);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Indices.Add(fc);
|
||||
m_Indices.Add(fb);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
//fix indexCount
|
||||
m_SubMesh.indexCount = j * 3;
|
||||
throw new NotSupportedException("Failed getting triangles. Submesh topology is lines or points.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1066,62 +1129,253 @@ namespace AssetStudio
|
||||
m_Skin[i] = new BoneWeights4();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetUV(int uv, float[] m_UV)
|
||||
{
|
||||
switch (uv)
|
||||
{
|
||||
case 0:
|
||||
m_UV0 = m_UV;
|
||||
break;
|
||||
case 1:
|
||||
m_UV1 = m_UV;
|
||||
break;
|
||||
case 2:
|
||||
m_UV2 = m_UV;
|
||||
break;
|
||||
case 3:
|
||||
m_UV3 = m_UV;
|
||||
break;
|
||||
case 4:
|
||||
m_UV4 = m_UV;
|
||||
break;
|
||||
case 5:
|
||||
m_UV5 = m_UV;
|
||||
break;
|
||||
case 6:
|
||||
m_UV6 = m_UV;
|
||||
break;
|
||||
case 7:
|
||||
m_UV7 = m_UV;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public float[] GetUV(int uv)
|
||||
{
|
||||
switch (uv)
|
||||
{
|
||||
case 0:
|
||||
return m_UV0;
|
||||
case 1:
|
||||
return m_UV1;
|
||||
case 2:
|
||||
return m_UV2;
|
||||
case 3:
|
||||
return m_UV3;
|
||||
case 4:
|
||||
return m_UV4;
|
||||
case 5:
|
||||
return m_UV5;
|
||||
case 6:
|
||||
return m_UV6;
|
||||
case 7:
|
||||
return m_UV7;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class MeshHelper
|
||||
{
|
||||
public static uint GetChannelFormatSize(int format)
|
||||
public enum VertexChannelFormat
|
||||
{
|
||||
switch (format)
|
||||
kChannelFormatFloat,
|
||||
kChannelFormatFloat16,
|
||||
kChannelFormatColor,
|
||||
kChannelFormatByte,
|
||||
kChannelFormatUInt32
|
||||
}
|
||||
|
||||
public enum VertexFormat2017
|
||||
{
|
||||
kVertexFormatFloat,
|
||||
kVertexFormatFloat16,
|
||||
kVertexFormatColor,
|
||||
kVertexFormatUNorm8,
|
||||
kVertexFormatSNorm8,
|
||||
kVertexFormatUNorm16,
|
||||
kVertexFormatSNorm16,
|
||||
kVertexFormatUInt8,
|
||||
kVertexFormatSInt8,
|
||||
kVertexFormatUInt16,
|
||||
kVertexFormatSInt16,
|
||||
kVertexFormatUInt32,
|
||||
kVertexFormatSInt32
|
||||
}
|
||||
|
||||
public enum VertexFormat
|
||||
{
|
||||
kVertexFormatFloat,
|
||||
kVertexFormatFloat16,
|
||||
kVertexFormatUNorm8,
|
||||
kVertexFormatSNorm8,
|
||||
kVertexFormatUNorm16,
|
||||
kVertexFormatSNorm16,
|
||||
kVertexFormatUInt8,
|
||||
kVertexFormatSInt8,
|
||||
kVertexFormatUInt16,
|
||||
kVertexFormatSInt16,
|
||||
kVertexFormatUInt32,
|
||||
kVertexFormatSInt32
|
||||
}
|
||||
|
||||
public static VertexFormat ToVertexFormat(int format, int[] version)
|
||||
{
|
||||
if (version[0] < 2017)
|
||||
{
|
||||
case 0: //kChannelFormatFloat
|
||||
return 4u;
|
||||
case 1: //kChannelFormatFloat16
|
||||
return 2u;
|
||||
case 2: //kChannelFormatColor
|
||||
return 1u;
|
||||
case 3: //kChannelFormatByte
|
||||
return 1u;
|
||||
case 4: //kChannelFormatUInt32
|
||||
return 4u;
|
||||
case 10: //kChannelFormatInt32
|
||||
return 4u;
|
||||
case 11: //kChannelFormatInt32
|
||||
return 4u;
|
||||
default:
|
||||
return 0;
|
||||
switch ((VertexChannelFormat)format)
|
||||
{
|
||||
case VertexChannelFormat.kChannelFormatFloat:
|
||||
return VertexFormat.kVertexFormatFloat;
|
||||
case VertexChannelFormat.kChannelFormatFloat16:
|
||||
return VertexFormat.kVertexFormatFloat16;
|
||||
case VertexChannelFormat.kChannelFormatColor: //in 4.x is size 4
|
||||
return VertexFormat.kVertexFormatUNorm8;
|
||||
case VertexChannelFormat.kChannelFormatByte:
|
||||
return VertexFormat.kVertexFormatUInt8;
|
||||
case VertexChannelFormat.kChannelFormatUInt32: //in 5.x
|
||||
return VertexFormat.kVertexFormatUInt32;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
else if (version[0] < 2019)
|
||||
{
|
||||
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 float[] BytesToFloatArray(byte[] inputBytes, int size)
|
||||
|
||||
public static uint GetFormatSize(VertexFormat format)
|
||||
{
|
||||
var result = new float[inputBytes.Length / size];
|
||||
for (int i = 0; i < inputBytes.Length / size; i++)
|
||||
switch (format)
|
||||
{
|
||||
var value = 0f;
|
||||
switch (size)
|
||||
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 1:
|
||||
value = inputBytes[i] / 255.0f;
|
||||
case VertexFormat.kVertexFormatFloat:
|
||||
result[i] = BitConverter.ToSingle(inputBytes, i * 4);
|
||||
break;
|
||||
case 2:
|
||||
value = Half.ToHalf(inputBytes, i * 2);
|
||||
case VertexFormat.kVertexFormatFloat16:
|
||||
result[i] = Half.ToHalf(inputBytes, i * 2);
|
||||
break;
|
||||
case 4:
|
||||
value = BitConverter.ToSingle(inputBytes, i * 4);
|
||||
case VertexFormat.kVertexFormatUNorm8:
|
||||
result[i] = inputBytes[i] / 255f;
|
||||
break;
|
||||
case VertexFormat.kVertexFormatSNorm8:
|
||||
result[i] = Math.Max((sbyte)inputBytes[i] / 127f, -1f);
|
||||
break;
|
||||
case VertexFormat.kVertexFormatUNorm16:
|
||||
result[i] = BitConverter.ToUInt16(inputBytes, i * 2) / 65535f;
|
||||
break;
|
||||
case VertexFormat.kVertexFormatSNorm16:
|
||||
result[i] = Math.Max(BitConverter.ToInt16(inputBytes, i * 2) / 32767f, -1f);
|
||||
break;
|
||||
}
|
||||
result[i] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int[] BytesToIntArray(byte[] inputBytes)
|
||||
public static int[] BytesToIntArray(byte[] inputBytes, VertexFormat format)
|
||||
{
|
||||
var result = new int[inputBytes.Length / 4];
|
||||
for (int i = 0; i < inputBytes.Length / 4; i++)
|
||||
var size = GetFormatSize(format);
|
||||
var len = inputBytes.Length / size;
|
||||
var result = new int[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
|
||||
switch (format)
|
||||
{
|
||||
case VertexFormat.kVertexFormatUInt8:
|
||||
case VertexFormat.kVertexFormatSInt8:
|
||||
result[i] = inputBytes[i];
|
||||
break;
|
||||
case VertexFormat.kVertexFormatUInt16:
|
||||
case VertexFormat.kVertexFormatSInt16:
|
||||
result[i] = BitConverter.ToInt16(inputBytes, i * 2);
|
||||
break;
|
||||
case VertexFormat.kVertexFormatUInt32:
|
||||
case VertexFormat.kVertexFormatSInt32:
|
||||
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -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,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
@@ -36,19 +33,38 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
protected bool HasStructMember(string name)
|
||||
{
|
||||
return serializedType?.m_Nodes != null && serializedType.m_Nodes.Any(x => x.m_Name == name);
|
||||
}
|
||||
|
||||
public string Dump()
|
||||
{
|
||||
reader.Reset();
|
||||
if (serializedType?.m_Nodes != null)
|
||||
if (serializedType?.m_Type != null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
TypeTreeHelper.ReadTypeString(sb, serializedType.m_Nodes, reader);
|
||||
return sb.ToString();
|
||||
return TypeTreeHelper.ReadTypeString(serializedType.m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string Dump(TypeTree m_Type)
|
||||
{
|
||||
if (m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadTypeString(m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OrderedDictionary ToType()
|
||||
{
|
||||
if (serializedType?.m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadType(serializedType.m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OrderedDictionary ToType(TypeTree m_Type)
|
||||
{
|
||||
if (m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadType(m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace AssetStudio
|
||||
public PPtr(ObjectReader reader)
|
||||
{
|
||||
m_FileID = reader.ReadInt32();
|
||||
m_PathID = reader.m_Version < 14 ? reader.ReadInt32() : reader.ReadInt64();
|
||||
m_PathID = reader.m_Version < SerializedFileFormatVersion.kUnknown_14 ? reader.ReadInt32() : reader.ReadInt64();
|
||||
assetsFile = reader.assetsFile;
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ namespace AssetStudio
|
||||
if (index == -2)
|
||||
{
|
||||
var m_External = assetsFile.m_Externals[m_FileID - 1];
|
||||
var name = m_External.fileName.ToUpper();
|
||||
var name = m_External.fileName;
|
||||
if (!assetsFileIndexCache.TryGetValue(name, out index))
|
||||
{
|
||||
index = assetsFileList.FindIndex(x => x.upperFileName == name);
|
||||
index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
assetsFileIndexCache.Add(name, index);
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ namespace AssetStudio
|
||||
{
|
||||
if (TryGetAssetsFile(out var sourceFile))
|
||||
{
|
||||
if (sourceFile.Objects.TryGetValue(m_PathID, out var obj))
|
||||
if (sourceFile.ObjectsDic.TryGetValue(m_PathID, out var obj))
|
||||
{
|
||||
if (obj is T variable)
|
||||
{
|
||||
@@ -75,7 +75,7 @@ namespace AssetStudio
|
||||
{
|
||||
if (TryGetAssetsFile(out var sourceFile))
|
||||
{
|
||||
if (sourceFile.Objects.TryGetValue(m_PathID, out var obj))
|
||||
if (sourceFile.ObjectsDic.TryGetValue(m_PathID, out var obj))
|
||||
{
|
||||
if (obj is T2 variable)
|
||||
{
|
||||
@@ -91,8 +91,8 @@ namespace AssetStudio
|
||||
|
||||
public void Set(T m_Object)
|
||||
{
|
||||
var name = m_Object.assetsFile.upperFileName;
|
||||
if (string.Equals(assetsFile.upperFileName, name, StringComparison.Ordinal))
|
||||
var name = m_Object.assetsFile.fileName;
|
||||
if (string.Equals(assetsFile.fileName, name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
m_FileID = 0;
|
||||
}
|
||||
@@ -119,13 +119,13 @@ namespace AssetStudio
|
||||
|
||||
if (!assetsFileIndexCache.TryGetValue(name, out index))
|
||||
{
|
||||
index = assetsFileList.FindIndex(x => x.upperFileName == name);
|
||||
index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
assetsFileIndexCache.Add(name, index);
|
||||
}
|
||||
|
||||
m_PathID = m_Object.m_PathID;
|
||||
}
|
||||
|
||||
public bool IsNull() => m_PathID == 0 || m_FileID < 0;
|
||||
public bool IsNull => m_PathID == 0 || m_FileID < 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,25 @@ namespace AssetStudio
|
||||
var m_Enabled = reader.ReadBoolean();
|
||||
var m_CastShadows = reader.ReadByte();
|
||||
var m_ReceiveShadows = reader.ReadByte();
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[0] >= 2)) //2017.2 and up
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
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();
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
var m_RayTracingMode = reader.ReadByte();
|
||||
}
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_RayTraceProcedural = reader.ReadByte();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
|
||||
19
AssetStudio/Classes/ResourceManager.cs
Normal file
19
AssetStudio/Classes/ResourceManager.cs
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +394,7 @@ namespace AssetStudio
|
||||
public VectorParameter[] m_VectorParams;
|
||||
public StructParameter[] m_StructParams;
|
||||
public int m_Size;
|
||||
public bool m_IsPartialCB;
|
||||
|
||||
public ConstantBuffer(ObjectReader reader)
|
||||
{
|
||||
@@ -402,6 +425,15 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
m_Size = reader.ReadInt32();
|
||||
|
||||
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
|
||||
{
|
||||
m_IsPartialCB = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,16 +479,16 @@ 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
|
||||
public class SerializedProgramParameters
|
||||
{
|
||||
public uint m_BlobIndex;
|
||||
public ParserBindChannels m_Channels;
|
||||
public ushort[] m_KeywordIndices;
|
||||
public sbyte m_ShaderHardwareTier;
|
||||
public ShaderGpuProgramType m_GpuProgramType;
|
||||
public VectorParameter[] m_VectorParams;
|
||||
public MatrixParameter[] m_MatrixParams;
|
||||
public TextureParameter[] m_TextureParams;
|
||||
@@ -466,33 +498,8 @@ namespace AssetStudio
|
||||
public UAVParameter[] m_UAVParams;
|
||||
public SamplerParameter[] m_Samplers;
|
||||
|
||||
public SerializedSubProgram(ObjectReader reader)
|
||||
public SerializedProgramParameters(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_BlobIndex = reader.ReadUInt32();
|
||||
m_Channels = new ParserBindChannels(reader);
|
||||
|
||||
if (version[0] >= 2019) //2019 and up
|
||||
{
|
||||
var m_GlobalKeywordIndices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
var m_LocalKeywordIndices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_KeywordIndices = reader.ReadUInt16Array();
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
m_ShaderHardwareTier = reader.ReadSByte();
|
||||
m_GpuProgramType = (ShaderGpuProgramType)reader.ReadSByte();
|
||||
reader.AlignStream();
|
||||
|
||||
int numVectorParams = reader.ReadInt32();
|
||||
m_VectorParams = new VectorParameter[numVectorParams];
|
||||
for (int i = 0; i < numVectorParams; i++)
|
||||
@@ -542,18 +549,138 @@ namespace AssetStudio
|
||||
m_UAVParams[i] = new UAVParameter(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
int numSamplers = reader.ReadInt32();
|
||||
m_Samplers = new SamplerParameter[numSamplers];
|
||||
for (int i = 0; i < numSamplers; i++)
|
||||
{
|
||||
int numSamplers = reader.ReadInt32();
|
||||
m_Samplers = new SamplerParameter[numSamplers];
|
||||
for (int i = 0; i < numSamplers; i++)
|
||||
m_Samplers[i] = new SamplerParameter(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SerializedSubProgram
|
||||
{
|
||||
public uint m_BlobIndex;
|
||||
public ParserBindChannels m_Channels;
|
||||
public ushort[] m_KeywordIndices;
|
||||
public sbyte m_ShaderHardwareTier;
|
||||
public ShaderGpuProgramType m_GpuProgramType;
|
||||
public SerializedProgramParameters m_Parameters;
|
||||
public VectorParameter[] m_VectorParams;
|
||||
public MatrixParameter[] m_MatrixParams;
|
||||
public TextureParameter[] m_TextureParams;
|
||||
public BufferBinding[] m_BufferParams;
|
||||
public ConstantBuffer[] m_ConstantBuffers;
|
||||
public BufferBinding[] m_ConstantBufferBindings;
|
||||
public UAVParameter[] m_UAVParams;
|
||||
public SamplerParameter[] m_Samplers;
|
||||
|
||||
public SerializedSubProgram(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_BlobIndex = reader.ReadUInt32();
|
||||
m_Channels = new ParserBindChannels(reader);
|
||||
|
||||
if ((version[0] >= 2019 && version[0] < 2021) || (version[0] == 2021 && version[1] < 2)) //2019 ~2021.1
|
||||
{
|
||||
var m_GlobalKeywordIndices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
var m_LocalKeywordIndices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_KeywordIndices = reader.ReadUInt16Array();
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
m_Samplers[i] = new SamplerParameter(reader);
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
m_ShaderHardwareTier = reader.ReadSByte();
|
||||
m_GpuProgramType = (ShaderGpuProgramType)reader.ReadSByte();
|
||||
reader.AlignStream();
|
||||
|
||||
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
|
||||
{
|
||||
m_Parameters = new SerializedProgramParameters(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
int numVectorParams = reader.ReadInt32();
|
||||
m_VectorParams = new VectorParameter[numVectorParams];
|
||||
for (int i = 0; i < numVectorParams; i++)
|
||||
{
|
||||
m_VectorParams[i] = new VectorParameter(reader);
|
||||
}
|
||||
|
||||
int numMatrixParams = reader.ReadInt32();
|
||||
m_MatrixParams = new MatrixParameter[numMatrixParams];
|
||||
for (int i = 0; i < numMatrixParams; i++)
|
||||
{
|
||||
m_MatrixParams[i] = new MatrixParameter(reader);
|
||||
}
|
||||
|
||||
int numTextureParams = reader.ReadInt32();
|
||||
m_TextureParams = new TextureParameter[numTextureParams];
|
||||
for (int i = 0; i < numTextureParams; i++)
|
||||
{
|
||||
m_TextureParams[i] = new TextureParameter(reader);
|
||||
}
|
||||
|
||||
int numBufferParams = reader.ReadInt32();
|
||||
m_BufferParams = new BufferBinding[numBufferParams];
|
||||
for (int i = 0; i < numBufferParams; i++)
|
||||
{
|
||||
m_BufferParams[i] = new BufferBinding(reader);
|
||||
}
|
||||
|
||||
int numConstantBuffers = reader.ReadInt32();
|
||||
m_ConstantBuffers = new ConstantBuffer[numConstantBuffers];
|
||||
for (int i = 0; i < numConstantBuffers; i++)
|
||||
{
|
||||
m_ConstantBuffers[i] = new ConstantBuffer(reader);
|
||||
}
|
||||
|
||||
int numConstantBufferBindings = reader.ReadInt32();
|
||||
m_ConstantBufferBindings = new BufferBinding[numConstantBufferBindings];
|
||||
for (int i = 0; i < numConstantBufferBindings; i++)
|
||||
{
|
||||
m_ConstantBufferBindings[i] = new BufferBinding(reader);
|
||||
}
|
||||
|
||||
int numUAVParams = reader.ReadInt32();
|
||||
m_UAVParams = new UAVParameter[numUAVParams];
|
||||
for (int i = 0; i < numUAVParams; i++)
|
||||
{
|
||||
m_UAVParams[i] = new UAVParameter(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
int numSamplers = reader.ReadInt32();
|
||||
m_Samplers = new SamplerParameter[numSamplers];
|
||||
for (int i = 0; i < numSamplers; i++)
|
||||
{
|
||||
m_Samplers[i] = new SamplerParameter(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -561,15 +688,26 @@ namespace AssetStudio
|
||||
public class SerializedProgram
|
||||
{
|
||||
public SerializedSubProgram[] m_SubPrograms;
|
||||
public SerializedProgramParameters m_CommonParameters;
|
||||
|
||||
public SerializedProgram(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int numSubPrograms = reader.ReadInt32();
|
||||
m_SubPrograms = new SerializedSubProgram[numSubPrograms];
|
||||
for (int i = 0; i < numSubPrograms; i++)
|
||||
{
|
||||
m_SubPrograms[i] = new SerializedSubProgram(reader);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
m_CommonParameters = new SerializedProgramParameters(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,6 +720,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;
|
||||
@@ -591,16 +733,38 @@ namespace AssetStudio
|
||||
public SerializedProgram progGeometry;
|
||||
public SerializedProgram progHull;
|
||||
public SerializedProgram progDomain;
|
||||
public SerializedProgram progRayTracing;
|
||||
public bool m_HasInstancingVariant;
|
||||
public string m_UseName;
|
||||
public string m_Name;
|
||||
public string m_TextureName;
|
||||
public SerializedTagMap m_Tags;
|
||||
public ushort[] m_SerializedKeywordStateMask;
|
||||
|
||||
public SerializedPass(ObjectReader reader)
|
||||
{
|
||||
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();
|
||||
if (version[0] < 2021 || (version[0] == 2021 && version[1] < 2)) //2021.1 and down
|
||||
{
|
||||
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++)
|
||||
@@ -616,6 +780,10 @@ namespace AssetStudio
|
||||
progGeometry = new SerializedProgram(reader);
|
||||
progHull = new SerializedProgram(reader);
|
||||
progDomain = new SerializedProgram(reader);
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
progRayTracing = new SerializedProgram(reader);
|
||||
}
|
||||
m_HasInstancingVariant = reader.ReadBoolean();
|
||||
if (version[0] >= 2018) //2018 and up
|
||||
{
|
||||
@@ -626,6 +794,11 @@ namespace AssetStudio
|
||||
m_Name = reader.ReadAlignedString();
|
||||
m_TextureName = reader.ReadAlignedString();
|
||||
m_Tags = new SerializedTagMap(reader);
|
||||
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 2)) //2021.2 and up
|
||||
{
|
||||
m_SerializedKeywordStateMask = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,18 +849,35 @@ 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;
|
||||
public SerializedSubShader[] m_SubShaders;
|
||||
public string[] m_KeywordNames;
|
||||
public byte[] m_KeywordFlags;
|
||||
public string m_Name;
|
||||
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();
|
||||
@@ -697,6 +887,13 @@ namespace AssetStudio
|
||||
m_SubShaders[i] = new SerializedSubShader(reader);
|
||||
}
|
||||
|
||||
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 2)) //2021.2 and up
|
||||
{
|
||||
m_KeywordNames = reader.ReadStringArray();
|
||||
m_KeywordFlags = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
m_Name = reader.ReadAlignedString();
|
||||
m_CustomEditorName = reader.ReadAlignedString();
|
||||
m_FallbackName = reader.ReadAlignedString();
|
||||
@@ -708,6 +905,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();
|
||||
}
|
||||
@@ -736,7 +943,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
|
||||
@@ -759,20 +970,49 @@ namespace AssetStudio
|
||||
{
|
||||
m_ParsedForm = new SerializedShader(reader);
|
||||
platforms = reader.ReadUInt32Array().Select(x => (ShaderCompilerPlatform)x).ToArray();
|
||||
offsets = reader.ReadUInt32Array();
|
||||
compressedLengths = reader.ReadUInt32Array();
|
||||
decompressedLengths = reader.ReadUInt32Array();
|
||||
compressedBlob = reader.ReadBytes(reader.ReadInt32());
|
||||
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();
|
||||
}
|
||||
else
|
||||
{
|
||||
offsets = reader.ReadUInt32Array();
|
||||
compressedLengths = reader.ReadUInt32Array();
|
||||
decompressedLengths = reader.ReadUInt32Array();
|
||||
}
|
||||
compressedBlob = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
|
||||
var m_DependenciesCount = reader.ReadInt32();
|
||||
for (int i = 0; i < m_DependenciesCount; i++)
|
||||
{
|
||||
new PPtr<Shader>(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2018)
|
||||
{
|
||||
var m_NonModifiableTexturesCount = reader.ReadInt32();
|
||||
for (int i = 0; i < m_NonModifiableTexturesCount; i++)
|
||||
{
|
||||
var first = reader.ReadAlignedString();
|
||||
new PPtr<Texture>(reader);
|
||||
}
|
||||
}
|
||||
|
||||
var m_ShaderIsBaked = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
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
|
||||
@@ -32,6 +31,12 @@ namespace AssetStudio
|
||||
kSPMRectangle
|
||||
};
|
||||
|
||||
public enum SpriteMeshType
|
||||
{
|
||||
kSpriteMeshTypeFullRect,
|
||||
kSpriteMeshTypeTight
|
||||
};
|
||||
|
||||
public class SpriteSettings
|
||||
{
|
||||
public uint settingsRaw;
|
||||
@@ -39,6 +44,7 @@ namespace AssetStudio
|
||||
public uint packed;
|
||||
public SpritePackingMode packingMode;
|
||||
public SpritePackingRotation packingRotation;
|
||||
public SpriteMeshType meshType;
|
||||
|
||||
public SpriteSettings(BinaryReader reader)
|
||||
{
|
||||
@@ -47,8 +53,7 @@ namespace AssetStudio
|
||||
packed = settingsRaw & 1; //1
|
||||
packingMode = (SpritePackingMode)((settingsRaw >> 1) & 1); //1
|
||||
packingRotation = (SpritePackingRotation)((settingsRaw >> 2) & 0xf); //4
|
||||
|
||||
//meshType = (settingsRaw >> 6) & 1; //1
|
||||
meshType = (SpriteMeshType)((settingsRaw >> 6) & 1); //1
|
||||
//reserved
|
||||
}
|
||||
}
|
||||
@@ -82,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;
|
||||
@@ -118,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);
|
||||
@@ -150,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
|
||||
{
|
||||
@@ -170,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;
|
||||
@@ -187,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StreamingInfo
|
||||
{
|
||||
public uint offset;
|
||||
public long offset; //ulong
|
||||
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.ReadInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = reader.ReadUInt32();
|
||||
}
|
||||
size = reader.ReadUInt32();
|
||||
path = reader.ReadAlignedString();
|
||||
}
|
||||
@@ -56,7 +60,7 @@ namespace AssetStudio
|
||||
public bool m_MipMap;
|
||||
public int m_MipCount;
|
||||
public GLTextureSettings m_TextureSettings;
|
||||
public Lazy<byte[]> image_data;
|
||||
public ResourceReader image_data;
|
||||
public StreamingInfo m_StreamData;
|
||||
|
||||
public Texture2D(ObjectReader reader) : base(reader)
|
||||
@@ -64,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
|
||||
{
|
||||
@@ -73,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
|
||||
{
|
||||
@@ -92,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
|
||||
{
|
||||
@@ -101,13 +134,13 @@ namespace AssetStudio
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_StreamData?.path))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, (int)m_StreamData.size);
|
||||
resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, image_data_size);
|
||||
}
|
||||
image_data = new Lazy<byte[]>(resourceReader.GetData);
|
||||
image_data = resourceReader;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,5 +203,14 @@ namespace AssetStudio
|
||||
R8,
|
||||
ETC_RGB4Crunched,
|
||||
ETC2_RGBA8Crunched,
|
||||
ASTC_HDR_4x4,
|
||||
ASTC_HDR_5x5,
|
||||
ASTC_HDR_6x6,
|
||||
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 long m_Offset; //ulong
|
||||
public long m_Size; //ulong
|
||||
|
||||
public StreamedResource(BinaryReader reader)
|
||||
{
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadInt64();
|
||||
m_Size = reader.ReadInt64();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VideoClip : NamedObject
|
||||
{
|
||||
public Lazy<byte[]> m_VideoData;
|
||||
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,22 +41,32 @@ 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, m_ExternalResources.m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size);
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_ExternalResources.m_Size);
|
||||
}
|
||||
m_VideoData = new Lazy<byte[]>(resourceReader.GetData);
|
||||
m_VideoData = resourceReader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,9 @@ namespace AssetStudio
|
||||
{1083, "BoundsInt"},
|
||||
{1093, "m_CorrespondingSourceObject"},
|
||||
{1121, "m_PrefabInstance"},
|
||||
{1138, "m_PrefabAsset"}
|
||||
{1138, "m_PrefabAsset"},
|
||||
{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());
|
||||
@@ -122,6 +122,11 @@ namespace AssetStudio
|
||||
return ReadArray(reader.ReadUInt32, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static uint[][] ReadUInt32ArrayArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt32Array, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static uint[] ReadUInt32Array(this BinaryReader reader, int length)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt32, length);
|
||||
|
||||
100
AssetStudio/FileReader.cs
Normal file
100
AssetStudio/FileReader.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class FileReader : EndianBinaryReader
|
||||
{
|
||||
public string FullPath;
|
||||
public string FileName;
|
||||
public FileType FileType;
|
||||
|
||||
private static readonly byte[] gzipMagic = { 0x1f, 0x8b };
|
||||
private static readonly byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
|
||||
|
||||
public FileReader(string path) : this(path, File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { }
|
||||
|
||||
public FileReader(string path, Stream stream) : base(stream, EndianType.BigEndian)
|
||||
{
|
||||
FullPath = Path.GetFullPath(path);
|
||||
FileName = Path.GetFileName(path);
|
||||
FileType = CheckFileType();
|
||||
}
|
||||
|
||||
private FileType CheckFileType()
|
||||
{
|
||||
var signature = this.ReadStringToNull(20);
|
||||
Position = 0;
|
||||
switch (signature)
|
||||
{
|
||||
case "UnityWeb":
|
||||
case "UnityRaw":
|
||||
case "UnityArchive":
|
||||
case "UnityFS":
|
||||
return FileType.BundleFile;
|
||||
case "UnityWebData1.0":
|
||||
return FileType.WebFile;
|
||||
default:
|
||||
{
|
||||
var magic = ReadBytes(2);
|
||||
Position = 0;
|
||||
if (gzipMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.GZipFile;
|
||||
}
|
||||
Position = 0x20;
|
||||
magic = ReadBytes(6);
|
||||
Position = 0;
|
||||
if (brotliMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.BrotliFile;
|
||||
}
|
||||
if (IsSerializedFile())
|
||||
{
|
||||
return FileType.AssetsFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FileType.ResourceFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSerializedFile()
|
||||
{
|
||||
var fileSize = BaseStream.Length;
|
||||
if (fileSize < 20)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var m_MetadataSize = ReadUInt32();
|
||||
long m_FileSize = ReadUInt32();
|
||||
var m_Version = ReadUInt32();
|
||||
long m_DataOffset = ReadUInt32();
|
||||
var m_Endianess = ReadByte();
|
||||
var m_Reserved = ReadBytes(3);
|
||||
if (m_Version >= 22)
|
||||
{
|
||||
if (fileSize < 48)
|
||||
{
|
||||
Position = 0;
|
||||
return false;
|
||||
}
|
||||
m_MetadataSize = ReadUInt32();
|
||||
m_FileSize = ReadInt64();
|
||||
m_DataOffset = ReadInt64();
|
||||
}
|
||||
Position = 0;
|
||||
if (m_FileSize != fileSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_DataOffset > fileSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
AssetStudio/FileType.cs
Normal file
18
AssetStudio/FileType.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum FileType
|
||||
{
|
||||
AssetsFile,
|
||||
BundleFile,
|
||||
WebFile,
|
||||
ResourceFile,
|
||||
GZipFile,
|
||||
BrotliFile
|
||||
}
|
||||
}
|
||||
@@ -132,30 +132,31 @@ namespace AssetStudio
|
||||
public class ImportedMesh
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public List<ImportedVertex> VertexList { get; set; }
|
||||
public List<ImportedSubmesh> SubmeshList { get; set; }
|
||||
public List<ImportedBone> BoneList { get; set; }
|
||||
public bool hasNormal { get; set; }
|
||||
public bool[] hasUV { get; set; }
|
||||
public bool hasTangent { get; set; }
|
||||
public bool hasColor { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedSubmesh
|
||||
{
|
||||
public List<ImportedVertex> VertexList { get; set; }
|
||||
public List<ImportedFace> FaceList { get; set; }
|
||||
public string Material { get; set; }
|
||||
public int BaseVertex { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedVertex
|
||||
{
|
||||
public Vector3 Position { get; set; }
|
||||
public Vector3 Vertex { get; set; }
|
||||
public Vector3 Normal { get; set; }
|
||||
public float[][] UV { get; set; }
|
||||
public Vector4 Tangent { get; set; }
|
||||
public Color Color { get; set; }
|
||||
public float[] Weights { get; set; }
|
||||
public int[] BoneIndices { get; set; }
|
||||
public Vector3 Normal { get; set; }
|
||||
public float[] UV { get; set; }
|
||||
public Vector4 Tangent { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedVertexWithColour : ImportedVertex
|
||||
{
|
||||
public Color Colour { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedFace
|
||||
@@ -205,7 +206,7 @@ namespace AssetStudio
|
||||
public class ImportedKeyframedAnimation
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public float SampleRate { get; set; }
|
||||
public List<ImportedAnimationKeyframedTrack> TrackList { get; set; }
|
||||
|
||||
public ImportedAnimationKeyframedTrack FindTrack(string path)
|
||||
@@ -227,14 +228,13 @@ namespace AssetStudio
|
||||
public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>();
|
||||
public List<ImportedKeyframe<Vector3>> Rotations = new List<ImportedKeyframe<Vector3>>();
|
||||
public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>();
|
||||
public ImportedBlendShape BlendShape;
|
||||
}
|
||||
|
||||
public class ImportedKeyframe<T>
|
||||
{
|
||||
public float time { get; set; }
|
||||
public T value { get; set; }
|
||||
public T inSlope { get; set; }
|
||||
public T outSlope { get; set; }
|
||||
|
||||
public ImportedKeyframe(float time, T value)
|
||||
{
|
||||
@@ -243,21 +243,36 @@ namespace AssetStudio
|
||||
}
|
||||
}
|
||||
|
||||
public class ImportedBlendShape
|
||||
{
|
||||
public string ChannelName;
|
||||
public List<ImportedKeyframe<float>> Keyframes = new List<ImportedKeyframe<float>>();
|
||||
}
|
||||
|
||||
public class ImportedMorph
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string ClipName { get; set; }
|
||||
public List<Tuple<float, int, int>> Channels { get; set; }
|
||||
public List<ImportedMorphChannel> Channels { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMorphChannel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<ImportedMorphKeyframe> KeyframeList { get; set; }
|
||||
public List<ushort> MorphedVertexIndices { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMorphKeyframe
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<ImportedVertex> VertexList { get; set; }
|
||||
public List<ushort> MorphedVertexIndices { get; set; }
|
||||
public bool hasNormals { get; set; }
|
||||
public bool hasTangents { get; set; }
|
||||
public float Weight { get; set; }
|
||||
public List<ImportedMorphVertex> VertexList { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMorphVertex
|
||||
{
|
||||
public uint Index { get; set; }
|
||||
public ImportedVertex Vertex { get; set; }
|
||||
}
|
||||
|
||||
public static class ImportedHelpers
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using Org.Brotli.Dec;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum FileType
|
||||
{
|
||||
AssetsFile,
|
||||
BundleFile,
|
||||
WebFile
|
||||
}
|
||||
|
||||
public static class ImportHelper
|
||||
{
|
||||
public static void MergeSplitAssets(string path, bool allDirectories = false)
|
||||
@@ -19,8 +14,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*");
|
||||
@@ -42,7 +37,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"));
|
||||
@@ -56,48 +51,31 @@ namespace AssetStudio
|
||||
return selectFile.Distinct().ToArray();
|
||||
}
|
||||
|
||||
public static FileType CheckFileType(Stream stream, out EndianBinaryReader reader)
|
||||
public static FileReader DecompressGZip(FileReader reader)
|
||||
{
|
||||
reader = new EndianBinaryReader(stream);
|
||||
return CheckFileType(reader);
|
||||
}
|
||||
|
||||
public static FileType CheckFileType(string fileName, out EndianBinaryReader reader)
|
||||
{
|
||||
reader = new EndianBinaryReader(File.OpenRead(fileName));
|
||||
return CheckFileType(reader);
|
||||
}
|
||||
|
||||
private static FileType CheckFileType(EndianBinaryReader reader)
|
||||
{
|
||||
var signature = reader.ReadStringToNull(20);
|
||||
reader.Position = 0;
|
||||
switch (signature)
|
||||
using (reader)
|
||||
{
|
||||
case "UnityWeb":
|
||||
case "UnityRaw":
|
||||
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA":
|
||||
case "UnityFS":
|
||||
return FileType.BundleFile;
|
||||
case "UnityWebData1.0":
|
||||
return FileType.WebFile;
|
||||
default:
|
||||
{
|
||||
var magic = reader.ReadBytes(2);
|
||||
reader.Position = 0;
|
||||
if (WebFile.gzipMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.WebFile;
|
||||
}
|
||||
reader.Position = 0x20;
|
||||
magic = reader.ReadBytes(6);
|
||||
reader.Position = 0;
|
||||
if (WebFile.brotliMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.WebFile;
|
||||
}
|
||||
return FileType.AssetsFile;
|
||||
}
|
||||
var stream = new MemoryStream();
|
||||
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
|
||||
{
|
||||
gs.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
return new FileReader(reader.FullPath, stream);
|
||||
}
|
||||
}
|
||||
|
||||
public static FileReader DecompressBrotli(FileReader reader)
|
||||
{
|
||||
using (reader)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using (var brotliStream = new BrotliInputStream(reader.BaseStream))
|
||||
{
|
||||
brotliStream.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
return new FileReader(reader.FullPath, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System
|
||||
namespace AssetStudio
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a half-precision floating point number.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System
|
||||
namespace AssetStudio
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for Half conversions and some low level operations.
|
||||
|
||||
@@ -89,6 +89,8 @@ namespace AssetStudio
|
||||
|
||||
public static Vector3 Zero => new Vector3();
|
||||
|
||||
public static Vector3 One => new Vector3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
public static Vector3 operator +(Vector3 a, Vector3 b)
|
||||
{
|
||||
return new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
|
||||
|
||||
@@ -7,10 +7,12 @@ namespace AssetStudio
|
||||
{
|
||||
public class ObjectInfo
|
||||
{
|
||||
public uint byteStart;
|
||||
public long byteStart;
|
||||
public uint byteSize;
|
||||
public int typeID;
|
||||
public int classID;
|
||||
public ushort isDestroyed;
|
||||
public byte stripped;
|
||||
|
||||
public long m_PathID;
|
||||
public SerializedType serializedType;
|
||||
|
||||
@@ -10,12 +10,12 @@ namespace AssetStudio
|
||||
{
|
||||
public SerializedFile assetsFile;
|
||||
public long m_PathID;
|
||||
public uint byteStart;
|
||||
public long byteStart;
|
||||
public uint byteSize;
|
||||
public ClassIDType type;
|
||||
public SerializedType serializedType;
|
||||
public BuildTarget platform;
|
||||
public uint m_Version;
|
||||
public SerializedFileFormatVersion m_Version;
|
||||
|
||||
public int[] version => assetsFile.version;
|
||||
public BuildType buildType => assetsFile.buildType;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("AssetStudio")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("AssetStudio")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("af56b63c-1764-41b7-9e60-8d485422ac3b")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -8,11 +8,10 @@ namespace AssetStudio
|
||||
private string path;
|
||||
private SerializedFile assetsFile;
|
||||
private long offset;
|
||||
private int size;
|
||||
private long size;
|
||||
private BinaryReader reader;
|
||||
|
||||
|
||||
public ResourceReader(string path, SerializedFile assetsFile, long offset, int size)
|
||||
public ResourceReader(string path, SerializedFile assetsFile, long offset, long size)
|
||||
{
|
||||
needSearch = true;
|
||||
this.path = path;
|
||||
@@ -21,30 +20,28 @@ namespace AssetStudio
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public ResourceReader(BinaryReader reader, long offset, int size)
|
||||
public ResourceReader(BinaryReader reader, long offset, long size)
|
||||
{
|
||||
this.reader = reader;
|
||||
this.offset = offset;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public byte[] GetData()
|
||||
private BinaryReader GetReader()
|
||||
{
|
||||
if (needSearch)
|
||||
{
|
||||
var resourceFileName = Path.GetFileName(path);
|
||||
|
||||
if (assetsFile.assetsManager.resourceFileReaders.TryGetValue(resourceFileName.ToUpper(), out var reader))
|
||||
if (assetsFile.assetsManager.resourceFileReaders.TryGetValue(resourceFileName, out reader))
|
||||
{
|
||||
reader.Position = offset;
|
||||
return reader.ReadBytes(size);
|
||||
needSearch = false;
|
||||
return reader;
|
||||
}
|
||||
|
||||
var currentDirectory = Path.GetDirectoryName(assetsFile.fullName);
|
||||
var resourceFilePath = currentDirectory + "\\" + resourceFileName;
|
||||
var assetsFileDirectory = Path.GetDirectoryName(assetsFile.fullName);
|
||||
var resourceFilePath = Path.Combine(assetsFileDirectory, resourceFileName);
|
||||
if (!File.Exists(resourceFilePath))
|
||||
{
|
||||
var findFiles = Directory.GetFiles(currentDirectory, resourceFileName, SearchOption.AllDirectories);
|
||||
var findFiles = Directory.GetFiles(assetsFileDirectory, resourceFileName, SearchOption.AllDirectories);
|
||||
if (findFiles.Length > 0)
|
||||
{
|
||||
resourceFilePath = findFiles[0];
|
||||
@@ -52,18 +49,34 @@ namespace AssetStudio
|
||||
}
|
||||
if (File.Exists(resourceFilePath))
|
||||
{
|
||||
using (var resourceReader = new BinaryReader(File.OpenRead(resourceFilePath)))
|
||||
{
|
||||
resourceReader.BaseStream.Position = offset;
|
||||
return resourceReader.ReadBytes(size);
|
||||
}
|
||||
needSearch = false;
|
||||
reader = new BinaryReader(File.OpenRead(resourceFilePath));
|
||||
assetsFile.assetsManager.resourceFileReaders.Add(resourceFileName, reader);
|
||||
return reader;
|
||||
}
|
||||
|
||||
throw new FileNotFoundException($"Can't find the resource file {resourceFileName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
|
||||
reader.BaseStream.Position = offset;
|
||||
return reader.ReadBytes(size);
|
||||
public byte[] GetData()
|
||||
{
|
||||
var binaryReader = GetReader();
|
||||
binaryReader.BaseStream.Position = offset;
|
||||
return binaryReader.ReadBytes((int)size);
|
||||
}
|
||||
|
||||
public void WriteData(string path)
|
||||
{
|
||||
var binaryReader = GetReader();
|
||||
binaryReader.BaseStream.Position = offset;
|
||||
using (var writer = File.OpenWrite(path))
|
||||
{
|
||||
binaryReader.BaseStream.CopyTo(writer, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,63 +9,73 @@ namespace AssetStudio
|
||||
public class SerializedFile
|
||||
{
|
||||
public AssetsManager assetsManager;
|
||||
public EndianBinaryReader reader;
|
||||
public FileReader reader;
|
||||
public string fullName;
|
||||
public string originalPath;
|
||||
public string fileName;
|
||||
public string upperFileName;
|
||||
public int[] version = { 0, 0, 0, 0 };
|
||||
public BuildType buildType;
|
||||
public Dictionary<long, Object> Objects;
|
||||
public List<Object> Objects;
|
||||
public Dictionary<long, Object> ObjectsDic;
|
||||
|
||||
public SerializedFileHeader header;
|
||||
private EndianType m_FileEndianess;
|
||||
private byte m_FileEndianess;
|
||||
public string unityVersion = "2.5.0f5";
|
||||
public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform;
|
||||
private bool m_EnableTypeTree = true;
|
||||
public List<SerializedType> m_Types;
|
||||
public int bigIDEnabled = 0;
|
||||
public List<ObjectInfo> m_Objects;
|
||||
private List<LocalSerializedObjectIdentifier> m_ScriptTypes;
|
||||
public List<FileIdentifier> m_Externals;
|
||||
public List<SerializedType> m_RefTypes;
|
||||
public string userInformation;
|
||||
|
||||
public SerializedFile(AssetsManager assetsManager, string fullName, EndianBinaryReader reader)
|
||||
public SerializedFile(FileReader reader, AssetsManager assetsManager)
|
||||
{
|
||||
this.assetsManager = assetsManager;
|
||||
this.reader = reader;
|
||||
this.fullName = fullName;
|
||||
fileName = Path.GetFileName(fullName);
|
||||
upperFileName = fileName.ToUpper();
|
||||
fullName = reader.FullPath;
|
||||
fileName = reader.FileName;
|
||||
|
||||
//ReadHeader
|
||||
// ReadHeader
|
||||
header = new SerializedFileHeader();
|
||||
header.m_MetadataSize = reader.ReadUInt32();
|
||||
header.m_FileSize = reader.ReadUInt32();
|
||||
header.m_Version = reader.ReadUInt32();
|
||||
header.m_Version = (SerializedFileFormatVersion)reader.ReadUInt32();
|
||||
header.m_DataOffset = reader.ReadUInt32();
|
||||
|
||||
if (header.m_Version >= 9)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_9)
|
||||
{
|
||||
header.m_Endianess = reader.ReadByte();
|
||||
header.m_Reserved = reader.ReadBytes(3);
|
||||
m_FileEndianess = (EndianType)header.m_Endianess;
|
||||
m_FileEndianess = header.m_Endianess;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Position = header.m_FileSize - header.m_MetadataSize;
|
||||
m_FileEndianess = (EndianType)reader.ReadByte();
|
||||
m_FileEndianess = reader.ReadByte();
|
||||
}
|
||||
|
||||
//ReadMetadata
|
||||
if (m_FileEndianess == EndianType.LittleEndian)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kLargeFilesSupport)
|
||||
{
|
||||
header.m_MetadataSize = reader.ReadUInt32();
|
||||
header.m_FileSize = reader.ReadInt64();
|
||||
header.m_DataOffset = reader.ReadInt64();
|
||||
reader.ReadInt64(); // unknown
|
||||
}
|
||||
|
||||
// ReadMetadata
|
||||
if (m_FileEndianess == 0)
|
||||
{
|
||||
reader.endian = EndianType.LittleEndian;
|
||||
}
|
||||
if (header.m_Version >= 7)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_7)
|
||||
{
|
||||
unityVersion = reader.ReadStringToNull();
|
||||
SetVersion(unityVersion);
|
||||
}
|
||||
if (header.m_Version >= 8)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_8)
|
||||
{
|
||||
m_TargetPlatform = (BuildTarget)reader.ReadInt32();
|
||||
if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform))
|
||||
@@ -73,31 +83,37 @@ namespace AssetStudio
|
||||
m_TargetPlatform = BuildTarget.UnknownPlatform;
|
||||
}
|
||||
}
|
||||
if (header.m_Version >= 13)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kHasTypeTreeHashes)
|
||||
{
|
||||
m_EnableTypeTree = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
//ReadTypes
|
||||
// Read Types
|
||||
int typeCount = reader.ReadInt32();
|
||||
m_Types = new List<SerializedType>(typeCount);
|
||||
for (int i = 0; i < typeCount; i++)
|
||||
{
|
||||
m_Types.Add(ReadSerializedType());
|
||||
m_Types.Add(ReadSerializedType(false));
|
||||
}
|
||||
|
||||
if (header.m_Version >= 7 && header.m_Version < 14)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_7 && header.m_Version < SerializedFileFormatVersion.kUnknown_14)
|
||||
{
|
||||
var bigIDEnabled = reader.ReadInt32();
|
||||
bigIDEnabled = reader.ReadInt32();
|
||||
}
|
||||
|
||||
//ReadObjects
|
||||
// Read Objects
|
||||
int objectCount = reader.ReadInt32();
|
||||
m_Objects = new List<ObjectInfo>(objectCount);
|
||||
Objects = new List<Object>(objectCount);
|
||||
ObjectsDic = new Dictionary<long, Object>(objectCount);
|
||||
for (int i = 0; i < objectCount; i++)
|
||||
{
|
||||
var objectInfo = new ObjectInfo();
|
||||
if (header.m_Version < 14)
|
||||
if (bigIDEnabled != 0)
|
||||
{
|
||||
objectInfo.m_PathID = reader.ReadInt64();
|
||||
}
|
||||
else if (header.m_Version < SerializedFileFormatVersion.kUnknown_14)
|
||||
{
|
||||
objectInfo.m_PathID = reader.ReadInt32();
|
||||
}
|
||||
@@ -106,15 +122,19 @@ namespace AssetStudio
|
||||
reader.AlignStream();
|
||||
objectInfo.m_PathID = reader.ReadInt64();
|
||||
}
|
||||
objectInfo.byteStart = reader.ReadUInt32();
|
||||
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kLargeFilesSupport)
|
||||
objectInfo.byteStart = reader.ReadInt64();
|
||||
else
|
||||
objectInfo.byteStart = reader.ReadUInt32();
|
||||
|
||||
objectInfo.byteStart += header.m_DataOffset;
|
||||
objectInfo.byteSize = reader.ReadUInt32();
|
||||
objectInfo.typeID = reader.ReadInt32();
|
||||
if (header.m_Version < 16)
|
||||
if (header.m_Version < SerializedFileFormatVersion.kRefactoredClassId)
|
||||
{
|
||||
objectInfo.classID = reader.ReadUInt16();
|
||||
objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID);
|
||||
var isDestroyed = reader.ReadUInt16();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -122,14 +142,24 @@ namespace AssetStudio
|
||||
objectInfo.serializedType = type;
|
||||
objectInfo.classID = type.classID;
|
||||
}
|
||||
if (header.m_Version == 15 || header.m_Version == 16)
|
||||
if (header.m_Version < SerializedFileFormatVersion.kHasScriptTypeIndex)
|
||||
{
|
||||
var stripped = reader.ReadByte();
|
||||
objectInfo.isDestroyed = reader.ReadUInt16();
|
||||
}
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kHasScriptTypeIndex && header.m_Version < SerializedFileFormatVersion.kRefactorTypeData)
|
||||
{
|
||||
var m_ScriptTypeIndex = reader.ReadInt16();
|
||||
if (objectInfo.serializedType != null)
|
||||
objectInfo.serializedType.m_ScriptTypeIndex = m_ScriptTypeIndex;
|
||||
}
|
||||
if (header.m_Version == SerializedFileFormatVersion.kSupportsStrippedObject || header.m_Version == SerializedFileFormatVersion.kRefactoredClassId)
|
||||
{
|
||||
objectInfo.stripped = reader.ReadByte();
|
||||
}
|
||||
m_Objects.Add(objectInfo);
|
||||
}
|
||||
|
||||
if (header.m_Version >= 11)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kHasScriptTypeIndex)
|
||||
{
|
||||
int scriptCount = reader.ReadInt32();
|
||||
m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount);
|
||||
@@ -137,7 +167,7 @@ namespace AssetStudio
|
||||
{
|
||||
var m_ScriptType = new LocalSerializedObjectIdentifier();
|
||||
m_ScriptType.localSerializedFileIndex = reader.ReadInt32();
|
||||
if (header.m_Version < 14)
|
||||
if (header.m_Version < SerializedFileFormatVersion.kUnknown_14)
|
||||
{
|
||||
m_ScriptType.localIdentifierInFile = reader.ReadInt32();
|
||||
}
|
||||
@@ -155,11 +185,11 @@ namespace AssetStudio
|
||||
for (int i = 0; i < externalsCount; i++)
|
||||
{
|
||||
var m_External = new FileIdentifier();
|
||||
if (header.m_Version >= 6)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_6)
|
||||
{
|
||||
var tempEmpty = reader.ReadStringToNull();
|
||||
}
|
||||
if (header.m_Version >= 5)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_5)
|
||||
{
|
||||
m_External.guid = new Guid(reader.ReadBytes(16));
|
||||
m_External.type = reader.ReadInt32();
|
||||
@@ -169,83 +199,114 @@ namespace AssetStudio
|
||||
m_Externals.Add(m_External);
|
||||
}
|
||||
|
||||
if (header.m_Version >= 5)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kSupportsRefObject)
|
||||
{
|
||||
//var userInformation = reader.ReadStringToNull();
|
||||
int refTypesCount = reader.ReadInt32();
|
||||
m_RefTypes = new List<SerializedType>(refTypesCount);
|
||||
for (int i = 0; i < refTypesCount; i++)
|
||||
{
|
||||
m_RefTypes.Add(ReadSerializedType(true));
|
||||
}
|
||||
}
|
||||
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_5)
|
||||
{
|
||||
userInformation = reader.ReadStringToNull();
|
||||
}
|
||||
|
||||
//reader.AlignStream(16);
|
||||
}
|
||||
|
||||
public void SetVersion(string stringVersion)
|
||||
{
|
||||
unityVersion = stringVersion;
|
||||
var buildSplit = Regex.Replace(stringVersion, @"\d", "").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
|
||||
buildType = new BuildType(buildSplit[0]);
|
||||
var versionSplit = Regex.Replace(stringVersion, @"\D", ".").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
|
||||
version = versionSplit.Select(int.Parse).ToArray();
|
||||
if (stringVersion != strippedVersion)
|
||||
{
|
||||
unityVersion = stringVersion;
|
||||
var buildSplit = Regex.Replace(stringVersion, @"\d", "").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
|
||||
buildType = new BuildType(buildSplit[0]);
|
||||
var versionSplit = Regex.Replace(stringVersion, @"\D", ".").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
|
||||
version = versionSplit.Select(int.Parse).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private SerializedType ReadSerializedType()
|
||||
private SerializedType ReadSerializedType(bool isRefType)
|
||||
{
|
||||
var type = new SerializedType();
|
||||
|
||||
type.classID = reader.ReadInt32();
|
||||
|
||||
if (header.m_Version >= 16)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kRefactoredClassId)
|
||||
{
|
||||
type.m_IsStrippedType = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
if (header.m_Version >= 17)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kRefactorTypeData)
|
||||
{
|
||||
type.m_ScriptTypeIndex = reader.ReadInt16();
|
||||
}
|
||||
|
||||
if (header.m_Version >= 13)
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kHasTypeTreeHashes)
|
||||
{
|
||||
if ((header.m_Version < 16 && type.classID < 0) || (header.m_Version >= 16 && type.classID == 114))
|
||||
if (isRefType && type.m_ScriptTypeIndex >= 0)
|
||||
{
|
||||
type.m_ScriptID = reader.ReadBytes(16); //Hash128
|
||||
type.m_ScriptID = reader.ReadBytes(16);
|
||||
}
|
||||
type.m_OldTypeHash = reader.ReadBytes(16); //Hash128
|
||||
else if ((header.m_Version < SerializedFileFormatVersion.kRefactoredClassId && type.classID < 0) || (header.m_Version >= SerializedFileFormatVersion.kRefactoredClassId && type.classID == 114))
|
||||
{
|
||||
type.m_ScriptID = reader.ReadBytes(16);
|
||||
}
|
||||
type.m_OldTypeHash = reader.ReadBytes(16);
|
||||
}
|
||||
|
||||
if (m_EnableTypeTree)
|
||||
{
|
||||
var typeTree = new List<TypeTreeNode>();
|
||||
if (header.m_Version >= 12 || header.m_Version == 10)
|
||||
type.m_Type = new TypeTree();
|
||||
type.m_Type.m_Nodes = new List<TypeTreeNode>();
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_12 || header.m_Version == SerializedFileFormatVersion.kUnknown_10)
|
||||
{
|
||||
ReadTypeTree5(typeTree);
|
||||
TypeTreeBlobRead(type.m_Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadTypeTree(typeTree);
|
||||
ReadTypeTree(type.m_Type);
|
||||
}
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kStoresTypeDependencies)
|
||||
{
|
||||
if (isRefType)
|
||||
{
|
||||
type.m_KlassName = reader.ReadStringToNull();
|
||||
type.m_NameSpace = reader.ReadStringToNull();
|
||||
type.m_AsmName = reader.ReadStringToNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
type.m_TypeDependencies = reader.ReadInt32Array();
|
||||
}
|
||||
}
|
||||
|
||||
type.m_Nodes = typeTree;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private void ReadTypeTree(List<TypeTreeNode> typeTree, int level = 0)
|
||||
private void ReadTypeTree(TypeTree m_Type, int level = 0)
|
||||
{
|
||||
var typeTreeNode = new TypeTreeNode();
|
||||
typeTree.Add(typeTreeNode);
|
||||
m_Type.m_Nodes.Add(typeTreeNode);
|
||||
typeTreeNode.m_Level = level;
|
||||
typeTreeNode.m_Type = reader.ReadStringToNull();
|
||||
typeTreeNode.m_Name = reader.ReadStringToNull();
|
||||
typeTreeNode.m_ByteSize = reader.ReadInt32();
|
||||
if (header.m_Version == 2)
|
||||
if (header.m_Version == SerializedFileFormatVersion.kUnknown_2)
|
||||
{
|
||||
var variableCount = reader.ReadInt32();
|
||||
}
|
||||
if (header.m_Version != 3)
|
||||
if (header.m_Version != SerializedFileFormatVersion.kUnknown_3)
|
||||
{
|
||||
typeTreeNode.m_Index = reader.ReadInt32();
|
||||
}
|
||||
typeTreeNode.m_IsArray = reader.ReadInt32();
|
||||
typeTreeNode.m_TypeFlags = reader.ReadInt32();
|
||||
typeTreeNode.m_Version = reader.ReadInt32();
|
||||
if (header.m_Version != 3)
|
||||
if (header.m_Version != SerializedFileFormatVersion.kUnknown_3)
|
||||
{
|
||||
typeTreeNode.m_MetaFlag = reader.ReadInt32();
|
||||
}
|
||||
@@ -253,46 +314,41 @@ namespace AssetStudio
|
||||
int childrenCount = reader.ReadInt32();
|
||||
for (int i = 0; i < childrenCount; i++)
|
||||
{
|
||||
ReadTypeTree(typeTree, level + 1);
|
||||
ReadTypeTree(m_Type, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadTypeTree5(List<TypeTreeNode> typeTree)
|
||||
private void TypeTreeBlobRead(TypeTree m_Type)
|
||||
{
|
||||
int numberOfNodes = reader.ReadInt32();
|
||||
int stringBufferSize = reader.ReadInt32();
|
||||
|
||||
var nodeSize = 24;
|
||||
if (header.m_Version > 17)
|
||||
for (int i = 0; i < numberOfNodes; i++)
|
||||
{
|
||||
nodeSize = 32;
|
||||
var typeTreeNode = new TypeTreeNode();
|
||||
m_Type.m_Nodes.Add(typeTreeNode);
|
||||
typeTreeNode.m_Version = reader.ReadUInt16();
|
||||
typeTreeNode.m_Level = reader.ReadByte();
|
||||
typeTreeNode.m_TypeFlags = reader.ReadByte();
|
||||
typeTreeNode.m_TypeStrOffset = reader.ReadUInt32();
|
||||
typeTreeNode.m_NameStrOffset = reader.ReadUInt32();
|
||||
typeTreeNode.m_ByteSize = reader.ReadInt32();
|
||||
typeTreeNode.m_Index = reader.ReadInt32();
|
||||
typeTreeNode.m_MetaFlag = reader.ReadInt32();
|
||||
if (header.m_Version >= SerializedFileFormatVersion.kTypeTreeNodeWithTypeFlags)
|
||||
{
|
||||
typeTreeNode.m_RefTypeHash = reader.ReadUInt64();
|
||||
}
|
||||
}
|
||||
reader.Position += numberOfNodes * nodeSize;
|
||||
using (var stringBufferReader = new BinaryReader(new MemoryStream(reader.ReadBytes(stringBufferSize))))
|
||||
m_Type.m_StringBuffer = reader.ReadBytes(stringBufferSize);
|
||||
|
||||
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_Type.m_StringBuffer)))
|
||||
{
|
||||
reader.Position -= numberOfNodes * nodeSize + stringBufferSize;
|
||||
for (int i = 0; i < numberOfNodes; i++)
|
||||
{
|
||||
var typeTreeNode = new TypeTreeNode();
|
||||
typeTree.Add(typeTreeNode);
|
||||
typeTreeNode.m_Version = reader.ReadUInt16();
|
||||
typeTreeNode.m_Level = reader.ReadByte();
|
||||
typeTreeNode.m_IsArray = reader.ReadBoolean() ? 1 : 0;
|
||||
typeTreeNode.m_TypeStrOffset = reader.ReadUInt32();
|
||||
typeTreeNode.m_NameStrOffset = reader.ReadUInt32();
|
||||
typeTreeNode.m_ByteSize = reader.ReadInt32();
|
||||
typeTreeNode.m_Index = reader.ReadInt32();
|
||||
typeTreeNode.m_MetaFlag = reader.ReadInt32();
|
||||
|
||||
if (header.m_Version > 17)
|
||||
{
|
||||
reader.Position += 8;
|
||||
}
|
||||
|
||||
typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset);
|
||||
typeTreeNode.m_Name = ReadString(stringBufferReader, typeTreeNode.m_NameStrOffset);
|
||||
var m_Node = m_Type.m_Nodes[i];
|
||||
m_Node.m_Type = ReadString(stringBufferReader, m_Node.m_TypeStrOffset);
|
||||
m_Node.m_Name = ReadString(stringBufferReader, m_Node.m_NameStrOffset);
|
||||
}
|
||||
reader.Position += stringBufferSize;
|
||||
}
|
||||
|
||||
string ReadString(BinaryReader stringBufferReader, uint value)
|
||||
@@ -311,5 +367,15 @@ namespace AssetStudio
|
||||
return offset.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddObject(Object obj)
|
||||
{
|
||||
Objects.Add(obj);
|
||||
ObjectsDic.Add(obj.m_PathID, obj);
|
||||
}
|
||||
|
||||
public bool IsVersionStripped => unityVersion == strippedVersion;
|
||||
|
||||
private const string strippedVersion = "0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
87
AssetStudio/SerializedFileFormatVersion.cs
Normal file
87
AssetStudio/SerializedFileFormatVersion.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum SerializedFileFormatVersion
|
||||
{
|
||||
kUnsupported = 1,
|
||||
kUnknown_2 = 2,
|
||||
kUnknown_3 = 3,
|
||||
/// <summary>
|
||||
/// 1.2.0 to 2.0.0
|
||||
/// </summary>
|
||||
kUnknown_5 = 5,
|
||||
/// <summary>
|
||||
/// 2.1.0 to 2.6.1
|
||||
/// </summary>
|
||||
kUnknown_6 = 6,
|
||||
/// <summary>
|
||||
/// 3.0.0b
|
||||
/// </summary>
|
||||
kUnknown_7 = 7,
|
||||
/// <summary>
|
||||
/// 3.0.0 to 3.4.2
|
||||
/// </summary>
|
||||
kUnknown_8 = 8,
|
||||
/// <summary>
|
||||
/// 3.5.0 to 4.7.2
|
||||
/// </summary>
|
||||
kUnknown_9 = 9,
|
||||
/// <summary>
|
||||
/// 5.0.0aunk1
|
||||
/// </summary>
|
||||
kUnknown_10 = 10,
|
||||
/// <summary>
|
||||
/// 5.0.0aunk2
|
||||
/// </summary>
|
||||
kHasScriptTypeIndex = 11,
|
||||
/// <summary>
|
||||
/// 5.0.0aunk3
|
||||
/// </summary>
|
||||
kUnknown_12 = 12,
|
||||
/// <summary>
|
||||
/// 5.0.0aunk4
|
||||
/// </summary>
|
||||
kHasTypeTreeHashes = 13,
|
||||
/// <summary>
|
||||
/// 5.0.0unk
|
||||
/// </summary>
|
||||
kUnknown_14 = 14,
|
||||
/// <summary>
|
||||
/// 5.0.1 to 5.4.0
|
||||
/// </summary>
|
||||
kSupportsStrippedObject = 15,
|
||||
/// <summary>
|
||||
/// 5.5.0a
|
||||
/// </summary>
|
||||
kRefactoredClassId = 16,
|
||||
/// <summary>
|
||||
/// 5.5.0unk to 2018.4
|
||||
/// </summary>
|
||||
kRefactorTypeData = 17,
|
||||
/// <summary>
|
||||
/// 2019.1a
|
||||
/// </summary>
|
||||
kRefactorShareableTypeTreeData = 18,
|
||||
/// <summary>
|
||||
/// 2019.1unk
|
||||
/// </summary>
|
||||
kTypeTreeNodeWithTypeFlags = 19,
|
||||
/// <summary>
|
||||
/// 2019.2
|
||||
/// </summary>
|
||||
kSupportsRefObject = 20,
|
||||
/// <summary>
|
||||
/// 2019.3 to 2019.4
|
||||
/// </summary>
|
||||
kStoresTypeDependencies = 21,
|
||||
/// <summary>
|
||||
/// 2020.1 to x
|
||||
/// </summary>
|
||||
kLargeFilesSupport = 22
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ namespace AssetStudio
|
||||
public class SerializedFileHeader
|
||||
{
|
||||
public uint m_MetadataSize;
|
||||
public uint m_FileSize;
|
||||
public uint m_Version;
|
||||
public uint m_DataOffset;
|
||||
public long m_FileSize;
|
||||
public SerializedFileFormatVersion m_Version;
|
||||
public long m_DataOffset;
|
||||
public byte m_Endianess;
|
||||
public byte[] m_Reserved;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,12 @@ namespace AssetStudio
|
||||
public int classID;
|
||||
public bool m_IsStrippedType;
|
||||
public short m_ScriptTypeIndex = -1;
|
||||
public List<TypeTreeNode> m_Nodes;
|
||||
public TypeTree m_Type;
|
||||
public byte[] m_ScriptID; //Hash128
|
||||
public byte[] m_OldTypeHash; //Hash128
|
||||
public int[] m_TypeDependencies;
|
||||
public string m_KlassName;
|
||||
public string m_NameSpace;
|
||||
public string m_AsmName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
AssetStudio/StreamFile.cs
Normal file
11
AssetStudio/StreamFile.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StreamFile
|
||||
{
|
||||
public string path;
|
||||
public string fileName;
|
||||
public Stream stream;
|
||||
}
|
||||
}
|
||||
14
AssetStudio/TypeTree.cs
Normal file
14
AssetStudio/TypeTree.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class TypeTree
|
||||
{
|
||||
public List<TypeTreeNode> m_Nodes;
|
||||
public byte[] m_StringBuffer;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,45 @@
|
||||
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 string ReadTypeString(TypeTree m_Type, ObjectReader reader)
|
||||
{
|
||||
for (int i = 0; i < members.Count; i++)
|
||||
reader.Reset();
|
||||
var sb = new StringBuilder();
|
||||
var m_Nodes = m_Type.m_Nodes;
|
||||
for (int i = 0; i < m_Nodes.Count; i++)
|
||||
{
|
||||
ReadStringValue(sb, members, reader, ref i);
|
||||
ReadStringValue(sb, m_Nodes, 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 sb.ToString();
|
||||
}
|
||||
|
||||
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader, ref int i)
|
||||
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> m_Nodes, BinaryReader reader, ref int i)
|
||||
{
|
||||
var member = members[i];
|
||||
var level = member.m_Level;
|
||||
var varTypeStr = member.m_Type;
|
||||
var varNameStr = member.m_Name;
|
||||
var m_Node = m_Nodes[i];
|
||||
var level = m_Node.m_Level;
|
||||
var varTypeStr = m_Node.m_Type;
|
||||
var varNameStr = m_Node.m_Name;
|
||||
object value = null;
|
||||
var append = true;
|
||||
var align = (member.m_MetaFlag & 0x4000) != 0;
|
||||
var align = (m_Node.m_MetaFlag & 0x4000) != 0;
|
||||
switch (varTypeStr)
|
||||
{
|
||||
case "SInt8":
|
||||
value = reader.ReadSByte();
|
||||
break;
|
||||
case "UInt8":
|
||||
case "char":
|
||||
value = reader.ReadByte();
|
||||
break;
|
||||
case "short":
|
||||
@@ -56,6 +65,7 @@ namespace AssetStudio
|
||||
break;
|
||||
case "UInt64":
|
||||
case "unsigned long long":
|
||||
case "FileSize":
|
||||
value = reader.ReadUInt64();
|
||||
break;
|
||||
case "float":
|
||||
@@ -73,41 +83,20 @@ namespace AssetStudio
|
||||
sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str);
|
||||
i += 3;
|
||||
break;
|
||||
case "vector":
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
append = false;
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
|
||||
var size = reader.ReadInt32();
|
||||
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
|
||||
var vector = GetMembers(members, level, i);
|
||||
i += vector.Count - 1;
|
||||
vector.RemoveRange(0, 3);
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
|
||||
int tmp = 0;
|
||||
ReadStringValue(sb, vector, reader, ref tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "map":
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
append = false;
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
|
||||
var size = reader.ReadInt32();
|
||||
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
|
||||
var map = GetMembers(members, level, i);
|
||||
var map = GetNodes(m_Nodes, i);
|
||||
i += map.Count - 1;
|
||||
map.RemoveRange(0, 4);
|
||||
var first = GetMembers(map, map[0].m_Level, 0);
|
||||
map.RemoveRange(0, first.Count);
|
||||
var second = map;
|
||||
var first = GetNodes(map, 4);
|
||||
var next = 4 + first.Count;
|
||||
var second = GetNodes(map, next);
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
|
||||
@@ -131,20 +120,37 @@ namespace AssetStudio
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (i != members.Count && members[i + 1].m_Type == "Array")
|
||||
if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
|
||||
{
|
||||
goto case "vector";
|
||||
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
append = false;
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
|
||||
var size = reader.ReadInt32();
|
||||
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
|
||||
var vector = GetNodes(m_Nodes, i);
|
||||
i += vector.Count - 1;
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
|
||||
int tmp = 3;
|
||||
ReadStringValue(sb, vector, reader, ref tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
append = false;
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
|
||||
var @class = GetMembers(members, level, i);
|
||||
@class.RemoveAt(0);
|
||||
i += @class.Count;
|
||||
for (int j = 0; j < @class.Count; j++)
|
||||
else //Class
|
||||
{
|
||||
ReadStringValue(sb, @class, reader, ref j);
|
||||
append = false;
|
||||
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
|
||||
var @class = GetNodes(m_Nodes, i);
|
||||
i += @class.Count - 1;
|
||||
for (int j = 1; j < @class.Count; j++)
|
||||
{
|
||||
ReadStringValue(sb, @class, reader, ref j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (append)
|
||||
@@ -153,31 +159,38 @@ namespace AssetStudio
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
public static UType ReadUType(List<TypeTreeNode> members, BinaryReader reader)
|
||||
public static OrderedDictionary ReadType(TypeTree m_Types, ObjectReader reader)
|
||||
{
|
||||
var obj = new UType();
|
||||
for (int i = 1; i < members.Count; i++)
|
||||
reader.Reset();
|
||||
var obj = new OrderedDictionary();
|
||||
var m_Nodes = m_Types.m_Nodes;
|
||||
for (int i = 1; i < m_Nodes.Count; i++)
|
||||
{
|
||||
var member = members[i];
|
||||
var varNameStr = member.m_Name;
|
||||
obj[varNameStr] = ReadValue(members, reader, ref i);
|
||||
var m_Node = m_Nodes[i];
|
||||
var varNameStr = m_Node.m_Name;
|
||||
obj[varNameStr] = ReadValue(m_Nodes, 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;
|
||||
}
|
||||
|
||||
private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i)
|
||||
private static object ReadValue(List<TypeTreeNode> m_Nodes, BinaryReader reader, ref int i)
|
||||
{
|
||||
var member = members[i];
|
||||
var level = member.m_Level;
|
||||
var varTypeStr = member.m_Type;
|
||||
var m_Node = m_Nodes[i];
|
||||
var varTypeStr = m_Node.m_Type;
|
||||
object value;
|
||||
var align = (member.m_MetaFlag & 0x4000) != 0;
|
||||
var align = (m_Node.m_MetaFlag & 0x4000) != 0;
|
||||
switch (varTypeStr)
|
||||
{
|
||||
case "SInt8":
|
||||
value = reader.ReadSByte();
|
||||
break;
|
||||
case "UInt8":
|
||||
case "char":
|
||||
value = reader.ReadByte();
|
||||
break;
|
||||
case "short":
|
||||
@@ -203,6 +216,7 @@ namespace AssetStudio
|
||||
break;
|
||||
case "UInt64":
|
||||
case "unsigned long long":
|
||||
case "FileSize":
|
||||
value = reader.ReadUInt64();
|
||||
break;
|
||||
case "float":
|
||||
@@ -220,16 +234,15 @@ namespace AssetStudio
|
||||
break;
|
||||
case "map":
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
var map = GetNodes(m_Nodes, i);
|
||||
i += map.Count - 1;
|
||||
var first = GetNodes(map, 4);
|
||||
var next = 4 + first.Count;
|
||||
var second = GetNodes(map, next);
|
||||
var size = reader.ReadInt32();
|
||||
var dic = new List<KeyValuePair<object, object>>(size);
|
||||
var map = GetMembers(members, level, i);
|
||||
i += map.Count - 1;
|
||||
map.RemoveRange(0, 4);
|
||||
var first = GetMembers(map, map[0].m_Level, 0);
|
||||
map.RemoveRange(0, first.Count);
|
||||
var second = map;
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
int tmp1 = 0;
|
||||
@@ -248,18 +261,17 @@ namespace AssetStudio
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (i != members.Count && members[i + 1].m_Type == "Array") //Array
|
||||
if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
var vector = GetNodes(m_Nodes, i);
|
||||
i += vector.Count - 1;
|
||||
var size = reader.ReadInt32();
|
||||
var list = new List<object>(size);
|
||||
var vector = GetMembers(members, level, i);
|
||||
i += vector.Count - 1;
|
||||
vector.RemoveRange(0, 3);
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
int tmp = 0;
|
||||
int tmp = 3;
|
||||
list.Add(ReadValue(vector, reader, ref tmp));
|
||||
}
|
||||
value = list;
|
||||
@@ -267,11 +279,10 @@ namespace AssetStudio
|
||||
}
|
||||
else //Class
|
||||
{
|
||||
var @class = GetMembers(members, level, i);
|
||||
@class.RemoveAt(0);
|
||||
i += @class.Count;
|
||||
var obj = new UType();
|
||||
for (int j = 0; j < @class.Count; j++)
|
||||
var @class = GetNodes(m_Nodes, i);
|
||||
i += @class.Count - 1;
|
||||
var obj = new OrderedDictionary();
|
||||
for (int j = 1; j < @class.Count; j++)
|
||||
{
|
||||
var classmember = @class[j];
|
||||
var name = classmember.m_Name;
|
||||
@@ -287,156 +298,22 @@ namespace AssetStudio
|
||||
return value;
|
||||
}
|
||||
|
||||
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int level, int index)
|
||||
private static List<TypeTreeNode> GetNodes(List<TypeTreeNode> m_Nodes, int index)
|
||||
{
|
||||
var member2 = new List<TypeTreeNode>();
|
||||
member2.Add(members[0]);
|
||||
for (int i = index + 1; i < members.Count; i++)
|
||||
var nodes = new List<TypeTreeNode>();
|
||||
nodes.Add(m_Nodes[index]);
|
||||
var level = m_Nodes[index].m_Level;
|
||||
for (int i = index + 1; i < m_Nodes.Count; i++)
|
||||
{
|
||||
var member = members[i];
|
||||
var member = m_Nodes[i];
|
||||
var level2 = member.m_Level;
|
||||
if (level2 <= level)
|
||||
{
|
||||
return member2;
|
||||
return nodes;
|
||||
}
|
||||
member2.Add(member);
|
||||
nodes.Add(member);
|
||||
}
|
||||
return member2;
|
||||
}
|
||||
|
||||
public static byte[] WriteUType(UType obj, List<TypeTreeNode> members)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var write = new BinaryWriter(stream);
|
||||
for (int i = 0; i < members.Count; i++)
|
||||
{
|
||||
var member = members[i];
|
||||
var varNameStr = member.m_Name;
|
||||
WriteValue(obj[varNameStr], members, write, ref i);
|
||||
}
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private static void WriteValue(object value, List<TypeTreeNode> members, BinaryWriter write, ref int i)
|
||||
{
|
||||
var member = members[i];
|
||||
var level = member.m_Level;
|
||||
var varTypeStr = member.m_Type;
|
||||
var align = (member.m_MetaFlag & 0x4000) != 0;
|
||||
switch (varTypeStr)
|
||||
{
|
||||
case "SInt8":
|
||||
write.Write((sbyte)value);
|
||||
break;
|
||||
case "UInt8":
|
||||
write.Write((byte)value);
|
||||
break;
|
||||
case "short":
|
||||
case "SInt16":
|
||||
write.Write((short)value);
|
||||
break;
|
||||
case "UInt16":
|
||||
case "unsigned short":
|
||||
write.Write((ushort)value);
|
||||
break;
|
||||
case "int":
|
||||
case "SInt32":
|
||||
write.Write((int)value);
|
||||
break;
|
||||
case "UInt32":
|
||||
case "unsigned int":
|
||||
case "Type*":
|
||||
write.Write((uint)value);
|
||||
break;
|
||||
case "long long":
|
||||
case "SInt64":
|
||||
write.Write((long)value);
|
||||
break;
|
||||
case "UInt64":
|
||||
case "unsigned long long":
|
||||
write.Write((ulong)value);
|
||||
break;
|
||||
case "float":
|
||||
write.Write((float)value);
|
||||
break;
|
||||
case "double":
|
||||
write.Write((double)value);
|
||||
break;
|
||||
case "bool":
|
||||
write.Write((bool)value);
|
||||
break;
|
||||
case "string":
|
||||
write.WriteAlignedString((string)value);
|
||||
i += 3;
|
||||
break;
|
||||
case "map":
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
var dic = (List<KeyValuePair<object, object>>)value;
|
||||
var size = dic.Count;
|
||||
write.Write(size);
|
||||
var map = GetMembers(members, level, i);
|
||||
i += map.Count - 1;
|
||||
map.RemoveRange(0, 4);
|
||||
var first = GetMembers(map, map[0].m_Level, 0);
|
||||
map.RemoveRange(0, first.Count);
|
||||
var second = map;
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
int tmp1 = 0;
|
||||
int tmp2 = 0;
|
||||
WriteValue(dic[j].Key, first, write, ref tmp1);
|
||||
WriteValue(dic[j].Value, second, write, ref tmp2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "TypelessData":
|
||||
{
|
||||
var bytes = ((object[])value).Cast<byte>().ToArray();
|
||||
var size = bytes.Length;
|
||||
write.Write(size);
|
||||
write.Write(bytes);
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (i != members.Count && members[i + 1].m_Type == "Array") //Array
|
||||
{
|
||||
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
|
||||
align = true;
|
||||
var list = (List<object>)value;
|
||||
var size = list.Count;
|
||||
write.Write(size);
|
||||
var vector = GetMembers(members, level, i);
|
||||
i += vector.Count - 1;
|
||||
vector.RemoveRange(0, 3);
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
int tmp = 0;
|
||||
WriteValue(list[j], vector, write, ref tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else //Class
|
||||
{
|
||||
var @class = GetMembers(members, level, i);
|
||||
@class.RemoveAt(0);
|
||||
i += @class.Count;
|
||||
var obj = (UType)value;
|
||||
for (int j = 0; j < @class.Count; j++)
|
||||
{
|
||||
var classmember = @class[j];
|
||||
var name = classmember.m_Name;
|
||||
WriteValue(obj[name], @class, write, ref j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (align)
|
||||
write.AlignStream(4);
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,22 @@ namespace AssetStudio
|
||||
public string m_Name;
|
||||
public int m_ByteSize;
|
||||
public int m_Index;
|
||||
public int m_IsArray;
|
||||
public int m_TypeFlags; //m_IsArray
|
||||
public int m_Version;
|
||||
public int m_MetaFlag;
|
||||
public int m_Level;
|
||||
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,155 +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 List<object> values;
|
||||
|
||||
public UType()
|
||||
{
|
||||
keys = new List<string>();
|
||||
values = new List<object>();
|
||||
}
|
||||
|
||||
private int GetValueIndex(string name)
|
||||
{
|
||||
for (int i = 0, n = keys.Count; i < n; i++)
|
||||
{
|
||||
if (string.Equals(keys[i], name, StringComparison.Ordinal))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool TryGetValue<T>(string key, out T value)
|
||||
{
|
||||
var index = GetValueIndex(key);
|
||||
if (index != -1)
|
||||
{
|
||||
value = (T)values[index];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = default(T);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public object this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
var index = GetValueIndex(key);
|
||||
if (index != -1)
|
||||
{
|
||||
return values[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
var index = GetValueIndex(key);
|
||||
if (index == -1)
|
||||
{
|
||||
keys.Add(key);
|
||||
values.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
values[index] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<string> Keys => keys;
|
||||
|
||||
public ICollection<object> Values => values;
|
||||
|
||||
public int Count => keys.Count;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public void Add(string key, object value)
|
||||
{
|
||||
keys.Add(key);
|
||||
values.Add(value);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, object> item)
|
||||
{
|
||||
keys.Add(item.Key);
|
||||
values.Add(item.Value);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
keys.Clear();
|
||||
values.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<string, object> item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return GetValueIndex(key) != -1;
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||
{
|
||||
for (int i = 0, n = keys.Count; i < n; i++)
|
||||
{
|
||||
yield return new KeyValuePair<string, object>(keys[i], values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<string, object> item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out object value)
|
||||
{
|
||||
var index = GetValueIndex(key);
|
||||
if (index != -1)
|
||||
{
|
||||
value = values[index];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Org.Brotli.Dec;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class WebFile
|
||||
{
|
||||
public static byte[] gzipMagic = { 0x1f, 0x8b };
|
||||
public static byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
|
||||
public List<StreamFile> fileList = new List<StreamFile>();
|
||||
public StreamFile[] fileList;
|
||||
|
||||
private class WebData
|
||||
{
|
||||
@@ -23,50 +17,8 @@ namespace AssetStudio
|
||||
|
||||
public WebFile(EndianBinaryReader reader)
|
||||
{
|
||||
var magic = reader.ReadBytes(2);
|
||||
reader.Position = 0;
|
||||
if (gzipMagic.SequenceEqual(magic))
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
|
||||
{
|
||||
gs.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
using (var binaryReader = new BinaryReader(stream))
|
||||
{
|
||||
ReadWebData(binaryReader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Position = 0x20;
|
||||
magic = reader.ReadBytes(6);
|
||||
reader.Position = 0;
|
||||
if (brotliMagic.SequenceEqual(magic))
|
||||
{
|
||||
var brotliStream = new BrotliInputStream(reader.BaseStream);
|
||||
var stream = new MemoryStream();
|
||||
brotliStream.CopyTo(stream);
|
||||
stream.Position = 0;
|
||||
using (var binaryReader = new BinaryReader(stream))
|
||||
{
|
||||
ReadWebData(binaryReader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.endian = EndianType.LittleEndian;
|
||||
ReadWebData(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadWebData(BinaryReader reader)
|
||||
{
|
||||
reader.endian = EndianType.LittleEndian;
|
||||
var signature = reader.ReadStringToNull();
|
||||
if (signature != "UnityWebData1.0")
|
||||
return;
|
||||
var headLength = reader.ReadInt32();
|
||||
var dataList = new List<WebData>();
|
||||
while (reader.BaseStream.Position < headLength)
|
||||
@@ -78,14 +30,16 @@ namespace AssetStudio
|
||||
data.path = Encoding.UTF8.GetString(reader.ReadBytes(pathLength));
|
||||
dataList.Add(data);
|
||||
}
|
||||
|
||||
foreach (var data in dataList)
|
||||
fileList = new StreamFile[dataList.Count];
|
||||
for (int i = 0; i < dataList.Count; i++)
|
||||
{
|
||||
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));
|
||||
fileList.Add(file);
|
||||
fileList[i] = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using namespace System;
|
||||
using namespace System::Reflection;
|
||||
using namespace System::Runtime::CompilerServices;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace System::Security::Permissions;
|
||||
|
||||
[assembly:AssemblyTitleAttribute(L"AssetStudioFBX")];
|
||||
[assembly:AssemblyDescriptionAttribute(L"")];
|
||||
[assembly:AssemblyConfigurationAttribute(L"")];
|
||||
[assembly:AssemblyCompanyAttribute(L"")];
|
||||
[assembly:AssemblyProductAttribute(L"AssetStudioFBX")];
|
||||
[assembly:AssemblyCopyrightAttribute(L"Copyright © Perfare 2018")];
|
||||
[assembly:AssemblyTrademarkAttribute(L"")];
|
||||
[assembly:AssemblyCultureAttribute(L"")];
|
||||
|
||||
[assembly:AssemblyVersionAttribute("1.0.*")];
|
||||
|
||||
[assembly:ComVisible(false)];
|
||||
|
||||
[assembly:CLSCompliantAttribute(true)];
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "AssetStudioFBX.h"
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
char* Fbx::StringToCharArray(String^ s)
|
||||
{
|
||||
return (char*)(void*)Marshal::StringToHGlobalAnsi(s);
|
||||
}
|
||||
|
||||
void Fbx::Init(FbxManager** pSdkManager, FbxScene** pScene)
|
||||
{
|
||||
*pSdkManager = FbxManager::Create();
|
||||
if (!pSdkManager)
|
||||
{
|
||||
throw gcnew Exception(gcnew String("Unable to create the FBX SDK manager"));
|
||||
}
|
||||
|
||||
FbxIOSettings* ios = FbxIOSettings::Create(*pSdkManager, IOSROOT);
|
||||
(*pSdkManager)->SetIOSettings(ios);
|
||||
*pScene = FbxScene::Create(*pSdkManager, "");
|
||||
}
|
||||
|
||||
Vector3 Fbx::QuaternionToEuler(Quaternion q)
|
||||
{
|
||||
FbxAMatrix lMatrixRot;
|
||||
lMatrixRot.SetQ(FbxQuaternion(q.X, q.Y, q.Z, q.W));
|
||||
FbxVector4 lEuler = lMatrixRot.GetR();
|
||||
return Vector3((float)lEuler[0], (float)lEuler[1], (float)lEuler[2]);
|
||||
}
|
||||
|
||||
Quaternion Fbx::EulerToQuaternion(Vector3 v)
|
||||
{
|
||||
FbxAMatrix lMatrixRot;
|
||||
lMatrixRot.SetR(FbxVector4(v.X, v.Y, v.Z));
|
||||
FbxQuaternion lQuaternion = lMatrixRot.GetQ();
|
||||
return Quaternion((float)lQuaternion[0], (float)lQuaternion[1], (float)lQuaternion[2], (float)lQuaternion[3]);
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
#ifdef IOS_REF
|
||||
#undef IOS_REF
|
||||
#define IOS_REF (*(pSdkManager->GetIOSettings()))
|
||||
#endif
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Collections::Generic;
|
||||
using namespace System::IO;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
|
||||
#define WITH_MARSHALLED_STRING(name,str,block)\
|
||||
{ \
|
||||
char* name; \
|
||||
try \
|
||||
{ \
|
||||
name = StringToCharArray(str); \
|
||||
block \
|
||||
} \
|
||||
finally \
|
||||
{ \
|
||||
Marshal::FreeHGlobal((IntPtr)name); \
|
||||
} \
|
||||
}
|
||||
|
||||
static char* FBXVersion[] =
|
||||
{
|
||||
FBX_2010_00_COMPATIBLE,
|
||||
FBX_2011_00_COMPATIBLE,
|
||||
FBX_2012_00_COMPATIBLE,
|
||||
FBX_2013_00_COMPATIBLE,
|
||||
FBX_2014_00_COMPATIBLE,
|
||||
FBX_2016_00_COMPATIBLE
|
||||
};
|
||||
|
||||
namespace AssetStudio {
|
||||
|
||||
public ref class Fbx
|
||||
{
|
||||
public:
|
||||
static Vector3 QuaternionToEuler(Quaternion q);
|
||||
static Quaternion EulerToQuaternion(Vector3 v);
|
||||
static char* StringToCharArray(String^ s);
|
||||
static void Init(FbxManager** pSdkManager, FbxScene** pScene);
|
||||
|
||||
ref class Exporter
|
||||
{
|
||||
public:
|
||||
static void Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, bool flatInbetween, int versionIndex, bool isAscii);
|
||||
|
||||
private:
|
||||
bool exportSkins;
|
||||
float boneSize;
|
||||
IImported^ imported;
|
||||
HashSet<String^>^ framePaths;
|
||||
Dictionary<ImportedFrame^, size_t>^ frameToNode;
|
||||
List<ImportedFrame^>^ meshFrames;
|
||||
|
||||
char* cDest;
|
||||
FbxManager* pSdkManager;
|
||||
FbxScene* pScene;
|
||||
FbxExporter* pExporter;
|
||||
FbxArray<FbxSurfacePhong*>* pMaterials;
|
||||
FbxArray<FbxFileTexture*>* pTextures;
|
||||
FbxPose* pBindPose;
|
||||
|
||||
Exporter(String^ path, IImported^ imported, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, int versionIndex, bool isAscii);
|
||||
~Exporter();
|
||||
|
||||
void Exporter::LinkTexture(ImportedMaterialTexture^ texture, FbxFileTexture* pTexture, FbxProperty& prop);
|
||||
void SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool allBones);
|
||||
HashSet<String^>^ SearchHierarchy();
|
||||
void SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames);
|
||||
void SetJointsFromImportedMeshes(bool allBones);
|
||||
void ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame);
|
||||
void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList);
|
||||
FbxFileTexture* ExportTexture(ImportedTexture^ matTex);
|
||||
void ExportAnimations(bool eulerFilter, float filterValue, bool flatInbetween);
|
||||
void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision, bool flatInbetween);
|
||||
void ExportMorphs(bool morphMask, bool flatInbetween);
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}</ProjectGuid>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>AssetStudioFBX</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>FBXSDK_SHARED;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\x86\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AssemblyInfo.cpp" />
|
||||
<ClCompile Include="AssetStudioFBX.cpp" />
|
||||
<ClCompile Include="AssetStudioFBXExporter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AssetStudioFBX.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj">
|
||||
<Project>{af56b63c-1764-41b7-9e60-8d485422ac3b}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AssemblyInfo.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AssetStudioFBX.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AssetStudioFBXExporter.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AssetStudioFBX.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,969 +0,0 @@
|
||||
#include "AssetStudioFBX.h"
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
void Fbx::Exporter::Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, bool flatInbetween, int versionIndex, bool isAscii)
|
||||
{
|
||||
FileInfo^ file = gcnew FileInfo(path);
|
||||
DirectoryInfo^ dir = file->Directory;
|
||||
if (!dir->Exists)
|
||||
{
|
||||
dir->Create();
|
||||
}
|
||||
String^ currentDir = Directory::GetCurrentDirectory();
|
||||
Directory::SetCurrentDirectory(dir->FullName);
|
||||
path = Path::GetFileName(path);
|
||||
|
||||
Exporter^ exporter = gcnew Exporter(path, imported, allFrames, allBones, skins, boneSize, scaleFactor, versionIndex, isAscii);
|
||||
//TODO exporter->ExportMorphs(false, flatInbetween);
|
||||
exporter->ExportAnimations(eulerFilter, filterPrecision, flatInbetween);
|
||||
exporter->pExporter->Export(exporter->pScene);
|
||||
delete exporter;
|
||||
|
||||
Directory::SetCurrentDirectory(currentDir);
|
||||
}
|
||||
|
||||
Fbx::Exporter::Exporter(String^ path, IImported^ imported, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, int versionIndex, bool isAscii)
|
||||
{
|
||||
this->imported = imported;
|
||||
exportSkins = skins;
|
||||
this->boneSize = boneSize;
|
||||
|
||||
cDest = NULL;
|
||||
pSdkManager = NULL;
|
||||
pScene = NULL;
|
||||
pExporter = NULL;
|
||||
pMaterials = NULL;
|
||||
pTextures = NULL;
|
||||
|
||||
pin_ptr<FbxManager*> pSdkManagerPin = &pSdkManager;
|
||||
pin_ptr<FbxScene*> pScenePin = &pScene;
|
||||
Init(pSdkManagerPin, pScenePin);
|
||||
|
||||
IOS_REF.SetBoolProp(EXP_FBX_MATERIAL, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_TEXTURE, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_EMBEDDED, false);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_SHAPE, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_GOBO, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_ANIMATION, true);
|
||||
IOS_REF.SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true);
|
||||
|
||||
FbxGlobalSettings& globalSettings = pScene->GetGlobalSettings();
|
||||
globalSettings.SetSystemUnit(FbxSystemUnit(scaleFactor));
|
||||
|
||||
cDest = StringToCharArray(path);
|
||||
pExporter = FbxExporter::Create(pScene, "");
|
||||
|
||||
int pFileFormat = 0;
|
||||
if (versionIndex == 0)
|
||||
{
|
||||
pFileFormat = 3;
|
||||
if (isAscii)
|
||||
{
|
||||
pFileFormat = 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pExporter->SetFileExportVersion(FBXVersion[versionIndex]);
|
||||
if (isAscii)
|
||||
{
|
||||
pFileFormat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pExporter->Initialize(cDest, pFileFormat, pSdkManager->GetIOSettings()))
|
||||
{
|
||||
throw gcnew Exception(gcnew String("Failed to initialize FbxExporter: ") + gcnew String(pExporter->GetStatus().GetErrorString()));
|
||||
}
|
||||
|
||||
framePaths = nullptr;
|
||||
if (!allFrames)
|
||||
{
|
||||
framePaths = SearchHierarchy();
|
||||
if (!framePaths)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pBindPose = FbxPose::Create(pScene, "BindPose");
|
||||
pBindPose->SetIsBindPose(true);
|
||||
|
||||
frameToNode = gcnew Dictionary<ImportedFrame^, size_t>();
|
||||
meshFrames = imported->MeshList != nullptr ? gcnew List<ImportedFrame^>() : nullptr;
|
||||
ExportFrame(pScene->GetRootNode(), imported->RootFrame);
|
||||
|
||||
if (imported->MeshList != nullptr)
|
||||
{
|
||||
SetJointsFromImportedMeshes(allBones);
|
||||
|
||||
pMaterials = new FbxArray<FbxSurfacePhong*>();
|
||||
pTextures = new FbxArray<FbxFileTexture*>();
|
||||
pMaterials->Reserve(imported->MaterialList->Count);
|
||||
pTextures->Reserve(imported->TextureList->Count);
|
||||
|
||||
for (int i = 0; i < meshFrames->Count; i++)
|
||||
{
|
||||
auto meshFram = meshFrames[i];
|
||||
FbxNode* meshNode = (FbxNode*)frameToNode[meshFram];
|
||||
ImportedMesh^ mesh = ImportedHelpers::FindMesh(meshFram->Path, imported->MeshList);
|
||||
ExportMesh(meshNode, mesh);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetJointsNode(imported->RootFrame, nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
Fbx::Exporter::~Exporter()
|
||||
{
|
||||
imported = nullptr;
|
||||
if (framePaths != nullptr)
|
||||
{
|
||||
framePaths->Clear();
|
||||
}
|
||||
if (frameToNode != nullptr)
|
||||
{
|
||||
frameToNode->Clear();
|
||||
}
|
||||
if (meshFrames != nullptr)
|
||||
{
|
||||
meshFrames->Clear();
|
||||
}
|
||||
|
||||
if (pMaterials != NULL)
|
||||
{
|
||||
delete pMaterials;
|
||||
}
|
||||
if (pTextures != NULL)
|
||||
{
|
||||
delete pTextures;
|
||||
}
|
||||
if (pExporter != NULL)
|
||||
{
|
||||
pExporter->Destroy();
|
||||
}
|
||||
if (pScene != NULL)
|
||||
{
|
||||
pScene->Destroy();
|
||||
}
|
||||
if (pSdkManager != NULL)
|
||||
{
|
||||
pSdkManager->Destroy();
|
||||
}
|
||||
if (cDest != NULL)
|
||||
{
|
||||
Marshal::FreeHGlobal((IntPtr)cDest);
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool allBones)
|
||||
{
|
||||
size_t pointer;
|
||||
if (frameToNode->TryGetValue(frame, pointer))
|
||||
{
|
||||
auto pNode = (FbxNode*)pointer;
|
||||
if (allBones || bonePaths->Contains(frame->Path))
|
||||
{
|
||||
FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
|
||||
pJoint->Size.Set(FbxDouble(boneSize));
|
||||
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
|
||||
pNode->SetNodeAttribute(pJoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
FbxNull* pNull = FbxNull::Create(pScene, "");
|
||||
if (pNode->GetChildCount() > 0)
|
||||
{
|
||||
pNull->Look.Set(FbxNull::eNone);
|
||||
}
|
||||
|
||||
pNode->SetNodeAttribute(pNull);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < frame->Count; i++)
|
||||
{
|
||||
SetJointsNode(frame[i], bonePaths, allBones);
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<String^>^ Fbx::Exporter::SearchHierarchy()
|
||||
{
|
||||
if (imported->MeshList == nullptr || imported->MeshList->Count == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
HashSet<String^>^ exportFrames = gcnew HashSet<String^>();
|
||||
SearchHierarchy(imported->RootFrame, exportFrames);
|
||||
return exportFrames;
|
||||
}
|
||||
|
||||
void Fbx::Exporter::SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames)
|
||||
{
|
||||
ImportedMesh^ meshListSome = ImportedHelpers::FindMesh(frame->Path, imported->MeshList);
|
||||
if (meshListSome != nullptr)
|
||||
{
|
||||
ImportedFrame^ parent = frame;
|
||||
while (parent != nullptr)
|
||||
{
|
||||
exportFrames->Add(parent->Path);
|
||||
parent = parent->Parent;
|
||||
}
|
||||
|
||||
List<ImportedBone^>^ boneList = meshListSome->BoneList;
|
||||
if (boneList != nullptr)
|
||||
{
|
||||
for (int i = 0; i < boneList->Count; i++)
|
||||
{
|
||||
if (!exportFrames->Contains(boneList[i]->Path))
|
||||
{
|
||||
ImportedFrame^ boneParent = imported->RootFrame->FindFrameByPath(boneList[i]->Path);
|
||||
while (boneParent != nullptr)
|
||||
{
|
||||
exportFrames->Add(boneParent->Path);
|
||||
boneParent = boneParent->Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < frame->Count; i++)
|
||||
{
|
||||
SearchHierarchy(frame[i], exportFrames);
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::SetJointsFromImportedMeshes(bool allBones)
|
||||
{
|
||||
if (!exportSkins)
|
||||
{
|
||||
return;
|
||||
}
|
||||
HashSet<String^>^ bonePaths = gcnew HashSet<String^>();
|
||||
for (int i = 0; i < imported->MeshList->Count; i++)
|
||||
{
|
||||
ImportedMesh^ meshList = imported->MeshList[i];
|
||||
List<ImportedBone^>^ boneList = meshList->BoneList;
|
||||
if (boneList != nullptr)
|
||||
{
|
||||
for (int j = 0; j < boneList->Count; j++)
|
||||
{
|
||||
ImportedBone^ bone = boneList[j];
|
||||
bonePaths->Add(bone->Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetJointsNode(imported->RootFrame, bonePaths, allBones);
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame)
|
||||
{
|
||||
if (framePaths == nullptr || framePaths->Contains(frame->Path))
|
||||
{
|
||||
FbxNode* pFrameNode;
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pName,
|
||||
frame->Name,
|
||||
pFrameNode = FbxNode::Create(pScene, pName);
|
||||
);
|
||||
|
||||
pFrameNode->LclScaling.Set(FbxDouble3(frame->LocalScale.X, frame->LocalScale.Y, frame->LocalScale.Z));
|
||||
pFrameNode->LclRotation.Set(FbxDouble3(frame->LocalRotation.X, frame->LocalRotation.Y, frame->LocalRotation.Z));
|
||||
pFrameNode->LclTranslation.Set(FbxDouble3(frame->LocalPosition.X, frame->LocalPosition.Y, frame->LocalPosition.Z));
|
||||
pFrameNode->SetPreferedAngle(pFrameNode->LclRotation.Get());
|
||||
pParentNode->AddChild(pFrameNode);
|
||||
pBindPose->Add(pFrameNode, pFrameNode->EvaluateGlobalTransform());
|
||||
|
||||
if (imported->MeshList != nullptr && ImportedHelpers::FindMesh(frame->Path, imported->MeshList) != nullptr)
|
||||
{
|
||||
meshFrames->Add(frame);
|
||||
}
|
||||
|
||||
frameToNode->Add(frame, (size_t)pFrameNode);
|
||||
|
||||
for (int i = 0; i < frame->Count; i++)
|
||||
{
|
||||
ExportFrame(pFrameNode, frame[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList)
|
||||
{
|
||||
List<ImportedBone^>^ boneList = meshList->BoneList;
|
||||
bool hasBones;
|
||||
if (exportSkins && boneList != nullptr)
|
||||
{
|
||||
hasBones = boneList->Count > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasBones = false;
|
||||
}
|
||||
|
||||
FbxArray<FbxNode*>* pBoneNodeList = nullptr;
|
||||
FbxArray<FbxCluster*>* pClusterArray = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
if (hasBones)
|
||||
{
|
||||
pBoneNodeList = new FbxArray<FbxNode*>();
|
||||
pBoneNodeList->Reserve(boneList->Count);
|
||||
for (int i = 0; i < boneList->Count; i++)
|
||||
{
|
||||
auto bone = boneList[i];
|
||||
auto frame = imported->RootFrame->FindFrameByPath(bone->Path);
|
||||
auto frameNode = (FbxNode*)frameToNode[frame];
|
||||
pBoneNodeList->Add(frameNode);
|
||||
}
|
||||
|
||||
pClusterArray = new FbxArray<FbxCluster*>();
|
||||
pClusterArray->Reserve(boneList->Count);
|
||||
for (int i = 0; i < boneList->Count; i++)
|
||||
{
|
||||
FbxNode* pNode = pBoneNodeList->GetAt(i);
|
||||
FbxString lClusterName = pNode->GetNameOnly() + FbxString("Cluster");
|
||||
FbxCluster* pCluster = FbxCluster::Create(pScene, lClusterName.Buffer());
|
||||
pCluster->SetLink(pNode);
|
||||
pCluster->SetLinkMode(FbxCluster::eTotalOne);
|
||||
pClusterArray->Add(pCluster);
|
||||
}
|
||||
}
|
||||
|
||||
FbxMesh* pMesh = FbxMesh::Create(pScene, "");
|
||||
pFrameNode->SetNodeAttribute(pMesh);
|
||||
|
||||
int vertexCount = 0;
|
||||
for (int i = 0; i < meshList->SubmeshList->Count; i++)
|
||||
{
|
||||
vertexCount += meshList->SubmeshList[i]->VertexList->Count;
|
||||
}
|
||||
|
||||
pMesh->InitControlPoints(vertexCount);
|
||||
FbxVector4* pControlPoints = pMesh->GetControlPoints();
|
||||
|
||||
FbxGeometryElementNormal* lGeometryElementNormal = pMesh->CreateElementNormal();
|
||||
lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
|
||||
FbxGeometryElementUV* lGeometryElementUV = pMesh->CreateElementUV("UV0");
|
||||
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
|
||||
FbxGeometryElementTangent* lGeometryElementTangent = pMesh->CreateElementTangent();
|
||||
lGeometryElementTangent->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementTangent->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
|
||||
FbxGeometryElementVertexColor* lGeometryElementVertexColor = nullptr;
|
||||
bool vertexColours = vertexCount > 0 && dynamic_cast<ImportedVertexWithColour^>(meshList->SubmeshList[0]->VertexList[0]) != nullptr;
|
||||
if (vertexColours)
|
||||
{
|
||||
lGeometryElementVertexColor = pMesh->CreateElementVertexColor();
|
||||
lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
}
|
||||
|
||||
FbxGeometryElementMaterial* lGeometryElementMaterial = pMesh->CreateElementMaterial();
|
||||
lGeometryElementMaterial->SetMappingMode(FbxGeometryElement::eByPolygon);
|
||||
lGeometryElementMaterial->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
|
||||
|
||||
int firstVertex = 0;
|
||||
for (int i = 0; i < meshList->SubmeshList->Count; i++)
|
||||
{
|
||||
ImportedSubmesh^ meshObj = meshList->SubmeshList[i];
|
||||
List<ImportedVertex^>^ vertexList = meshObj->VertexList;
|
||||
List<ImportedFace^>^ faceList = meshObj->FaceList;
|
||||
|
||||
int materialIndex = 0;
|
||||
ImportedMaterial^ mat = ImportedHelpers::FindMaterial(meshObj->Material, imported->MaterialList);
|
||||
if (mat != nullptr)
|
||||
{
|
||||
char* pMatName = NULL;
|
||||
try
|
||||
{
|
||||
pMatName = StringToCharArray(mat->Name);
|
||||
int foundMat = -1;
|
||||
for (int j = 0; j < pMaterials->GetCount(); j++)
|
||||
{
|
||||
FbxSurfacePhong* pMatTemp = pMaterials->GetAt(j);
|
||||
if (strcmp(pMatTemp->GetName(), pMatName) == 0)
|
||||
{
|
||||
foundMat = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FbxSurfacePhong* pMat;
|
||||
if (foundMat >= 0)
|
||||
{
|
||||
pMat = pMaterials->GetAt(foundMat);
|
||||
}
|
||||
else
|
||||
{
|
||||
FbxString lShadingName = "Phong";
|
||||
Color diffuse = mat->Diffuse;
|
||||
Color ambient = mat->Ambient;
|
||||
Color emissive = mat->Emissive;
|
||||
Color specular = mat->Specular;
|
||||
Color reflection = mat->Reflection;
|
||||
pMat = FbxSurfacePhong::Create(pScene, pMatName);
|
||||
pMat->Diffuse.Set(FbxDouble3(diffuse.R, diffuse.G, diffuse.B));
|
||||
pMat->DiffuseFactor.Set(FbxDouble(diffuse.A));
|
||||
pMat->Ambient.Set(FbxDouble3(ambient.R, ambient.G, ambient.B));
|
||||
pMat->AmbientFactor.Set(FbxDouble(ambient.A));
|
||||
pMat->Emissive.Set(FbxDouble3(emissive.R, emissive.G, emissive.B));
|
||||
pMat->EmissiveFactor.Set(FbxDouble(emissive.A));
|
||||
pMat->Specular.Set(FbxDouble3(specular.R, specular.G, specular.B));
|
||||
pMat->SpecularFactor.Set(FbxDouble(specular.A));
|
||||
pMat->Reflection.Set(FbxDouble3(reflection.R, reflection.G, reflection.B));
|
||||
pMat->ReflectionFactor.Set(FbxDouble(reflection.A));
|
||||
pMat->Shininess.Set(FbxDouble(mat->Shininess));
|
||||
pMat->TransparencyFactor.Set(FbxDouble(mat->Transparency));
|
||||
pMat->ShadingModel.Set(lShadingName);
|
||||
pMaterials->Add(pMat);
|
||||
}
|
||||
materialIndex = pFrameNode->AddMaterial(pMat);
|
||||
|
||||
bool hasTexture = false;
|
||||
|
||||
for each (ImportedMaterialTexture^ texture in mat->Textures)
|
||||
{
|
||||
auto pTexture = ExportTexture(ImportedHelpers::FindTexture(texture->Name, imported->TextureList));
|
||||
if (pTexture != NULL)
|
||||
{
|
||||
if (texture->Dest == 0)
|
||||
{
|
||||
LinkTexture(texture, pTexture, pMat->Diffuse);
|
||||
hasTexture = true;
|
||||
}
|
||||
else if (texture->Dest == 1)
|
||||
{
|
||||
LinkTexture(texture, pTexture, pMat->NormalMap);
|
||||
hasTexture = true;
|
||||
}
|
||||
else if (texture->Dest == 2)
|
||||
{
|
||||
LinkTexture(texture, pTexture, pMat->Specular);
|
||||
hasTexture = true;
|
||||
}
|
||||
else if (texture->Dest == 3)
|
||||
{
|
||||
LinkTexture(texture, pTexture, pMat->Bump);
|
||||
hasTexture = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTexture)
|
||||
{
|
||||
pFrameNode->SetShadingMode(FbxNode::eTextureShading);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal::FreeHGlobal((IntPtr)pMatName);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < vertexList->Count; j++)
|
||||
{
|
||||
ImportedVertex^ vertex = vertexList[j];
|
||||
|
||||
Vector3 coords = vertex->Position;
|
||||
pControlPoints[j + firstVertex] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
|
||||
|
||||
Vector3 normal = vertex->Normal;
|
||||
lGeometryElementNormal->GetDirectArray().Add(FbxVector4(normal.X, normal.Y, normal.Z, 0));
|
||||
|
||||
array<float>^ uv = vertex->UV;
|
||||
if (uv != nullptr)
|
||||
{
|
||||
lGeometryElementUV->GetDirectArray().Add(FbxVector2(uv[0], uv[1]));
|
||||
}
|
||||
|
||||
Vector4 tangent = vertex->Tangent;
|
||||
lGeometryElementTangent->GetDirectArray().Add(FbxVector4(tangent.X, tangent.Y, tangent.Z, tangent.W));
|
||||
|
||||
if (vertexColours)
|
||||
{
|
||||
ImportedVertexWithColour^ vert = (ImportedVertexWithColour^)vertexList[j];
|
||||
lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(vert->Colour.R, vert->Colour.G, vert->Colour.B, vert->Colour.A));
|
||||
}
|
||||
|
||||
if (hasBones && vertex->BoneIndices != nullptr)
|
||||
{
|
||||
auto boneIndices = vertex->BoneIndices;
|
||||
auto weights4 = vertex->Weights;
|
||||
for (int k = 0; k < 4; k++)
|
||||
{
|
||||
if (boneIndices[k] < boneList->Count && weights4[k] > 0)
|
||||
{
|
||||
FbxCluster* pCluster = pClusterArray->GetAt(boneIndices[k]);
|
||||
pCluster->AddControlPointIndex(j + firstVertex, weights4[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < faceList->Count; j++)
|
||||
{
|
||||
ImportedFace^ face = faceList[j];
|
||||
pMesh->BeginPolygon(materialIndex);
|
||||
pMesh->AddPolygon(face->VertexIndices[0] + firstVertex);
|
||||
pMesh->AddPolygon(face->VertexIndices[1] + firstVertex);
|
||||
pMesh->AddPolygon(face->VertexIndices[2] + firstVertex);
|
||||
pMesh->EndPolygon();
|
||||
}
|
||||
|
||||
firstVertex += vertexList->Count;
|
||||
}
|
||||
|
||||
if (hasBones)
|
||||
{
|
||||
FbxSkin* pSkin = FbxSkin::Create(pScene, "");
|
||||
FbxAMatrix lMeshMatrix = pFrameNode->EvaluateGlobalTransform();
|
||||
for (int j = 0; j < boneList->Count; j++)
|
||||
{
|
||||
FbxCluster* pCluster = pClusterArray->GetAt(j);
|
||||
if (pCluster->GetControlPointIndicesCount() > 0)
|
||||
{
|
||||
auto boneMatrix = boneList[j]->Matrix;
|
||||
FbxAMatrix lBoneMatrix;
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
for (int n = 0; n < 4; n++)
|
||||
{
|
||||
lBoneMatrix.mData[m][n] = boneMatrix[m, n];
|
||||
}
|
||||
}
|
||||
|
||||
pCluster->SetTransformMatrix(lMeshMatrix);
|
||||
pCluster->SetTransformLinkMatrix(lMeshMatrix * lBoneMatrix.Inverse());
|
||||
|
||||
pSkin->AddCluster(pCluster);
|
||||
}
|
||||
}
|
||||
|
||||
if (pSkin->GetClusterCount() > 0)
|
||||
{
|
||||
pMesh->AddDeformer(pSkin);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pBoneNodeList != NULL)
|
||||
{
|
||||
delete pBoneNodeList;
|
||||
}
|
||||
if (pClusterArray != NULL)
|
||||
{
|
||||
delete pClusterArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FbxFileTexture* Fbx::Exporter::ExportTexture(ImportedTexture^ matTex)
|
||||
{
|
||||
FbxFileTexture* pTex = NULL;
|
||||
|
||||
if (matTex != nullptr)
|
||||
{
|
||||
String^ matTexName = matTex->Name;
|
||||
char* pTexName = NULL;
|
||||
try
|
||||
{
|
||||
pTexName = StringToCharArray(matTexName);
|
||||
int foundTex = -1;
|
||||
for (int i = 0; i < pTextures->GetCount(); i++)
|
||||
{
|
||||
FbxFileTexture* pTexTemp = pTextures->GetAt(i);
|
||||
if (strcmp(pTexTemp->GetName(), pTexName) == 0)
|
||||
{
|
||||
foundTex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundTex >= 0)
|
||||
{
|
||||
pTex = pTextures->GetAt(foundTex);
|
||||
}
|
||||
else
|
||||
{
|
||||
pTex = FbxFileTexture::Create(pScene, pTexName);
|
||||
pTex->SetFileName(pTexName);
|
||||
pTex->SetTextureUse(FbxTexture::eStandard);
|
||||
pTex->SetMappingType(FbxTexture::eUV);
|
||||
pTex->SetMaterialUse(FbxFileTexture::eModelMaterial);
|
||||
pTex->SetSwapUV(false);
|
||||
pTex->SetTranslation(0.0, 0.0);
|
||||
pTex->SetScale(1.0, 1.0);
|
||||
pTex->SetRotation(0.0, 0.0);
|
||||
pTextures->Add(pTex);
|
||||
|
||||
String^ path = Path::GetDirectoryName(gcnew String(pExporter->GetFileName().Buffer()));
|
||||
if (path == String::Empty)
|
||||
{
|
||||
path = ".";
|
||||
}
|
||||
FileInfo^ file = gcnew FileInfo(path + Path::DirectorySeparatorChar + Path::GetFileName(matTex->Name));
|
||||
DirectoryInfo^ dir = file->Directory;
|
||||
if (!dir->Exists)
|
||||
{
|
||||
dir->Create();
|
||||
}
|
||||
BinaryWriter^ writer = gcnew BinaryWriter(file->Create());
|
||||
writer->Write(matTex->Data);
|
||||
writer->Close();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal::FreeHGlobal((IntPtr)pTexName);
|
||||
}
|
||||
}
|
||||
|
||||
return pTex;
|
||||
}
|
||||
|
||||
void Fbx::Exporter::LinkTexture(ImportedMaterialTexture^ texture, FbxFileTexture* pTexture, FbxProperty& prop)
|
||||
{
|
||||
pTexture->SetTranslation(texture->Offset.X, texture->Offset.Y);
|
||||
pTexture->SetScale(texture->Scale.X, texture->Scale.Y);
|
||||
prop.ConnectSrcObject(pTexture);
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportAnimations(bool eulerFilter, float filterPrecision, bool flatInbetween)
|
||||
{
|
||||
auto importedAnimationList = imported->AnimationList;
|
||||
if (importedAnimationList == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FbxAnimCurveFilterUnroll* lFilter = eulerFilter ? new FbxAnimCurveFilterUnroll() : NULL;
|
||||
|
||||
for (int i = 0; i < importedAnimationList->Count; i++)
|
||||
{
|
||||
auto importedAnimation = importedAnimationList[i];
|
||||
FbxString kTakeName;
|
||||
if (importedAnimation->Name)
|
||||
{
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pClipName,
|
||||
importedAnimation->Name,
|
||||
kTakeName = FbxString(pClipName);
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
kTakeName = FbxString("Take") + FbxString(i);
|
||||
}
|
||||
ExportKeyframedAnimation(importedAnimation, kTakeName, lFilter, filterPrecision, flatInbetween);
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision, bool flatInbetween)
|
||||
{
|
||||
List<ImportedAnimationKeyframedTrack^>^ pAnimationList = parser->TrackList;
|
||||
|
||||
char* lTakeName = kTakeName.Buffer();
|
||||
|
||||
FbxAnimStack* lAnimStack = FbxAnimStack::Create(pScene, lTakeName);
|
||||
FbxAnimLayer* lAnimLayer = FbxAnimLayer::Create(pScene, "Base Layer");
|
||||
lAnimStack->AddMember(lAnimLayer);
|
||||
|
||||
for (int j = 0; j < pAnimationList->Count; j++)
|
||||
{
|
||||
ImportedAnimationKeyframedTrack^ keyframeList = pAnimationList[j];
|
||||
if (keyframeList->Path == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto frame = imported->RootFrame->FindFrameByPath(keyframeList->Path);
|
||||
if (frame != nullptr)
|
||||
{
|
||||
FbxNode* pNode = (FbxNode*)frameToNode[frame];
|
||||
|
||||
FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
||||
FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
||||
FbxAnimCurve* lCurveSZ = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
||||
FbxAnimCurve* lCurveRX = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
||||
FbxAnimCurve* lCurveRY = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
||||
FbxAnimCurve* lCurveRZ = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
||||
FbxAnimCurve* lCurveTX = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
||||
FbxAnimCurve* lCurveTY = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
||||
FbxAnimCurve* lCurveTZ = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
||||
|
||||
lCurveSX->KeyModifyBegin();
|
||||
lCurveSY->KeyModifyBegin();
|
||||
lCurveSZ->KeyModifyBegin();
|
||||
lCurveRX->KeyModifyBegin();
|
||||
lCurveRY->KeyModifyBegin();
|
||||
lCurveRZ->KeyModifyBegin();
|
||||
lCurveTX->KeyModifyBegin();
|
||||
lCurveTY->KeyModifyBegin();
|
||||
lCurveTZ->KeyModifyBegin();
|
||||
|
||||
FbxTime lTime;
|
||||
|
||||
for each (auto Scaling in keyframeList->Scalings)
|
||||
{
|
||||
lTime.SetSecondDouble(Scaling->time);
|
||||
|
||||
lCurveSX->KeySet(lCurveSX->KeyAdd(lTime), lTime, Scaling->value.X);
|
||||
lCurveSY->KeySet(lCurveSY->KeyAdd(lTime), lTime, Scaling->value.Y);
|
||||
lCurveSZ->KeySet(lCurveSZ->KeyAdd(lTime), lTime, Scaling->value.Z);
|
||||
}
|
||||
for each (auto Rotation in keyframeList->Rotations)
|
||||
{
|
||||
lTime.SetSecondDouble(Rotation->time);
|
||||
|
||||
lCurveRX->KeySet(lCurveRX->KeyAdd(lTime), lTime, Rotation->value.X);
|
||||
lCurveRY->KeySet(lCurveRY->KeyAdd(lTime), lTime, Rotation->value.Y);
|
||||
lCurveRZ->KeySet(lCurveRZ->KeyAdd(lTime), lTime, Rotation->value.Z);
|
||||
}
|
||||
for each (auto Translation in keyframeList->Translations)
|
||||
{
|
||||
lTime.SetSecondDouble(Translation->time);
|
||||
|
||||
lCurveTX->KeySet(lCurveTX->KeyAdd(lTime), lTime, Translation->value.X);
|
||||
lCurveTY->KeySet(lCurveTY->KeyAdd(lTime), lTime, Translation->value.Y);
|
||||
lCurveTZ->KeySet(lCurveTZ->KeyAdd(lTime), lTime, Translation->value.Z);
|
||||
}
|
||||
|
||||
lCurveSX->KeyModifyEnd();
|
||||
lCurveSY->KeyModifyEnd();
|
||||
lCurveSZ->KeyModifyEnd();
|
||||
lCurveRX->KeyModifyEnd();
|
||||
lCurveRY->KeyModifyEnd();
|
||||
lCurveRZ->KeyModifyEnd();
|
||||
lCurveTX->KeyModifyEnd();
|
||||
lCurveTY->KeyModifyEnd();
|
||||
lCurveTZ->KeyModifyEnd();
|
||||
|
||||
if (eulerFilter)
|
||||
{
|
||||
FbxAnimCurve* lCurve[3];
|
||||
lCurve[0] = lCurveRX;
|
||||
lCurve[1] = lCurveRY;
|
||||
lCurve[2] = lCurveRZ;
|
||||
eulerFilter->Reset();
|
||||
eulerFilter->SetQualityTolerance(filterPrecision);
|
||||
eulerFilter->Apply(lCurve, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fbx::Exporter::ExportMorphs(bool morphMask, bool flatInbetween)
|
||||
{
|
||||
/*if (imported->MeshList == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int meshIdx = 0; meshIdx < imported->MeshList->Count; meshIdx++)
|
||||
{
|
||||
ImportedMesh^ meshList = imported->MeshList[meshIdx];
|
||||
FbxNode* pBaseNode = NULL;
|
||||
for (int nodeIdx = 0; nodeIdx < pMeshNodes->GetCount(); nodeIdx++)
|
||||
{
|
||||
FbxNode* pMeshNode = pMeshNodes->GetAt(nodeIdx);
|
||||
String^ framePath = gcnew String(pMeshNode->GetName());
|
||||
FbxNode* rootNode = pMeshNode;
|
||||
while ((rootNode = rootNode->GetParent()) != pScene->GetRootNode())
|
||||
{
|
||||
framePath = gcnew String(rootNode->GetName()) + "/" + framePath;
|
||||
}
|
||||
if (framePath == meshList->Path)
|
||||
{
|
||||
pBaseNode = pMeshNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pBaseNode == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for each (ImportedMorph^ morph in imported->MorphList)
|
||||
{
|
||||
if (morph->Path != meshList->Path)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int meshVertexIndex = 0;
|
||||
for (int meshObjIdx = pBaseNode->GetChildCount() - meshList->SubmeshList->Count; meshObjIdx < meshList->SubmeshList->Count; meshObjIdx++)
|
||||
{
|
||||
List<ImportedVertex^>^ vertList = meshList->SubmeshList[meshObjIdx]->VertexList;
|
||||
FbxNode* pBaseMeshNode = pBaseNode->GetChild(meshObjIdx);
|
||||
FbxMesh* pBaseMesh = pBaseMeshNode->GetMesh();
|
||||
int numColourSets = pBaseMesh->GetElementVertexColorCount();
|
||||
|
||||
FbxBlendShape* lBlendShape;
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pShapeName,
|
||||
morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty),
|
||||
lBlendShape = FbxBlendShape::Create(pScene, pShapeName);
|
||||
);
|
||||
FbxProperty rootGroupProp = FbxProperty::Create(lBlendShape, FbxStringDT, "RootGroup");
|
||||
pBaseMesh->AddDeformer(lBlendShape);
|
||||
List<ImportedMorphKeyframe^>^ keyframes = morph->KeyframeList;
|
||||
for (int i = 0; i < morph->Channels->Count; i++)
|
||||
{
|
||||
FbxBlendShapeChannel* lBlendShapeChannel;
|
||||
if (!flatInbetween)
|
||||
{
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pChannelName,
|
||||
gcnew String(lBlendShape->GetName()) + "." + keyframes[morph->Channels[i]->Item2]->Name->Substring(0, keyframes[morph->Channels[i]->Item2]->Name->LastIndexOf("_")),
|
||||
lBlendShapeChannel = FbxBlendShapeChannel::Create(pScene, pChannelName);
|
||||
);
|
||||
lBlendShapeChannel->DeformPercent = morph->Channels[i]->Item1;
|
||||
lBlendShape->AddBlendShapeChannel(lBlendShapeChannel);
|
||||
}
|
||||
|
||||
for (int frameIdx = 0; frameIdx < morph->Channels[i]->Item3; frameIdx++)
|
||||
{
|
||||
int shapeIdx = morph->Channels[i]->Item2 + frameIdx;
|
||||
ImportedMorphKeyframe^ keyframe = keyframes[shapeIdx];
|
||||
|
||||
FbxShape* pShape;
|
||||
if (!flatInbetween)
|
||||
{
|
||||
char* pMorphShapeName;
|
||||
try
|
||||
{
|
||||
pMorphShapeName = StringToCharArray(keyframe->Name);
|
||||
if (pScene->FindMember<FbxShape>(pMorphShapeName))
|
||||
{
|
||||
Marshal::FreeHGlobal((IntPtr)pMorphShapeName);
|
||||
pMorphShapeName = StringToCharArray(morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty) + "__" + keyframe->Name);
|
||||
}
|
||||
pShape = FbxShape::Create(pScene, pMorphShapeName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal::FreeHGlobal((IntPtr)pMorphShapeName);
|
||||
}
|
||||
if (frameIdx == morph->Channels[i]->Item3 - 1)
|
||||
{
|
||||
FbxProperty::Create(lBlendShape, FbxStringDT, rootGroupProp.GetName() + "|" + pShape->GetName());
|
||||
}
|
||||
lBlendShapeChannel->AddTargetShape(pShape, keyframe->Weight);
|
||||
}
|
||||
else
|
||||
{
|
||||
lBlendShapeChannel = FbxBlendShapeChannel::Create(pScene, "");
|
||||
lBlendShapeChannel->DeformPercent = morph->Channels[i]->Item1;
|
||||
lBlendShape->AddBlendShapeChannel(lBlendShapeChannel);
|
||||
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pMorphShapeName,
|
||||
morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty) + "." + keyframe->Name,
|
||||
pShape = FbxShape::Create(pScene, pMorphShapeName);
|
||||
);
|
||||
lBlendShapeChannel->AddTargetShape(pShape, 100);
|
||||
|
||||
FbxProperty weightProp;
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pWeightName,
|
||||
gcnew String(pShape->GetName()) + ".Weight",
|
||||
weightProp = FbxProperty::Create(pBaseMesh, FbxDoubleDT, pWeightName);
|
||||
);
|
||||
weightProp.ModifyFlag(FbxPropertyFlags::eUserDefined, true);
|
||||
weightProp.Set<double>(keyframe->Weight);
|
||||
}
|
||||
|
||||
pShape->InitControlPoints(vertList->Count);
|
||||
FbxVector4* pControlPoints = pShape->GetControlPoints();
|
||||
|
||||
for (int j = 0; j < vertList->Count; j++)
|
||||
{
|
||||
ImportedVertex^ vertex = vertList[j];
|
||||
Vector3 coords = vertex->Position;
|
||||
pControlPoints[j] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
|
||||
}
|
||||
List<unsigned short>^ meshIndices = keyframe->MorphedVertexIndices;
|
||||
for (int j = 0; j < meshIndices->Count; j++)
|
||||
{
|
||||
int controlPointIndex = meshIndices[j] - meshVertexIndex;
|
||||
if (controlPointIndex >= 0 && controlPointIndex < vertList->Count)
|
||||
{
|
||||
Vector3 coords = keyframe->VertexList[j]->Position;
|
||||
pControlPoints[controlPointIndex] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
|
||||
}
|
||||
}
|
||||
if (flatInbetween && meshIndices->Count == 0)
|
||||
{
|
||||
Vector3 coords = vertList[0]->Position;
|
||||
pControlPoints[0] = FbxVector4(coords.X - 1.0e-6, coords.Y, coords.Z, 0);
|
||||
}
|
||||
|
||||
if (flatInbetween && frameIdx > 0)
|
||||
{
|
||||
int shapeIdx = morph->Channels[i]->Item2 + frameIdx - 1;
|
||||
ImportedMorphKeyframe^ keyframe = keyframes[shapeIdx];
|
||||
|
||||
List<unsigned short>^ meshIndices = keyframe->MorphedVertexIndices;
|
||||
for (int j = 0; j < meshIndices->Count; j++)
|
||||
{
|
||||
int controlPointIndex = meshIndices[j] - meshVertexIndex;
|
||||
if (controlPointIndex >= 0 && controlPointIndex < vertList->Count)
|
||||
{
|
||||
Vector3 coords = keyframe->VertexList[j]->Position - vertList[controlPointIndex]->Position;
|
||||
pControlPoints[controlPointIndex] -= FbxVector4(coords.X, coords.Y, coords.Z, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (morphMask && frameIdx == 0)
|
||||
{
|
||||
int colourSetIdx = numColourSets + shapeIdx;
|
||||
FbxGeometryElementVertexColor* lGeometryElementVertexColor = pBaseMesh->GetElementVertexColor(colourSetIdx);
|
||||
if (lGeometryElementVertexColor == NULL)
|
||||
{
|
||||
lGeometryElementVertexColor = pBaseMesh->CreateElementVertexColor();
|
||||
}
|
||||
lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint);
|
||||
lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect);
|
||||
WITH_MARSHALLED_STRING
|
||||
(
|
||||
pColourLayerName, morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty) + "." + keyframe->Name,
|
||||
lGeometryElementVertexColor->SetName(pColourLayerName);
|
||||
);
|
||||
for (int j = 0; j < vertList->Count; j++)
|
||||
{
|
||||
lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(1, 1, 1));
|
||||
}
|
||||
for (int j = 0; j < meshIndices->Count; j++)
|
||||
{
|
||||
int controlPointIndex = meshIndices[j] - meshVertexIndex;
|
||||
if (controlPointIndex >= 0 && controlPointIndex < vertList->Count)
|
||||
{
|
||||
lGeometryElementVertexColor->GetDirectArray().SetAt(controlPointIndex, FbxColor(0, 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
meshVertexIndex += meshList->SubmeshList[meshObjIdx]->VertexList->Count;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
99
AssetStudioFBXNative/AssetStudioFBXNative.rc
Normal file
99
AssetStudioFBXNative/AssetStudioFBXNative.rc
Normal file
@@ -0,0 +1,99 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Language neutral resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||
#pragma code_page(65001)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "000004b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "AssetStudioFBXNative"
|
||||
VALUE "FileVersion", "1.0.0.1"
|
||||
VALUE "InternalName", "AssetStudioFBXNative.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) Perfare 2018-2020; Copyright (C) hozuki 2020"
|
||||
VALUE "OriginalFilename", "AssetStudioFBXNative.dll"
|
||||
VALUE "ProductName", "AssetStudioFBXNative"
|
||||
VALUE "ProductVersion", "1.0.0.1"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // Language neutral resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
204
AssetStudioFBXNative/AssetStudioFBXNative.vcxproj
Normal file
204
AssetStudioFBXNative/AssetStudioFBXNative.vcxproj
Normal file
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{11ea25a3-ed68-40ee-a9d0-7fde3b583027}</ProjectGuid>
|
||||
<RootNamespace>AssetStudioFBXNative</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<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-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'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<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>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<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>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<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-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'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<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>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<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>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="asfbx_anim_context.cpp" />
|
||||
<ClCompile Include="asfbx_context.cpp" />
|
||||
<ClCompile Include="api.cpp" />
|
||||
<ClCompile Include="asfbx_morph_context.cpp" />
|
||||
<ClCompile Include="asfbx_skin_context.cpp" />
|
||||
<ClCompile Include="utils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api.h" />
|
||||
<ClInclude Include="asfbx_anim_context.h" />
|
||||
<ClInclude Include="asfbx_context.h" />
|
||||
<ClInclude Include="asfbx_morph_context.h" />
|
||||
<ClInclude Include="asfbx_skin_context.h" />
|
||||
<ClInclude Include="bool32_t.h" />
|
||||
<ClInclude Include="dllexport.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="utils.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="AssetStudioFBXNative.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<Target Name="AfterBuild">
|
||||
<MSBuild Condition=" '$(Platform)' == 'Win32' " Projects="$(MSBuildProjectFile)" Properties="Platform=x64;PlatFormTarget=x64" RunEachTargetSeparately="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
74
AssetStudioFBXNative/AssetStudioFBXNative.vcxproj.filters
Normal file
74
AssetStudioFBXNative/AssetStudioFBXNative.vcxproj.filters
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="utils.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="api.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asfbx_context.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asfbx_skin_context.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asfbx_anim_context.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asfbx_morph_context.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dllexport.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="api.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utils.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="bool32_t.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asfbx_context.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asfbx_skin_context.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asfbx_anim_context.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="asfbx_morph_context.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="AssetStudioFBXNative.rc">
|
||||
<Filter>资源文件</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
1163
AssetStudioFBXNative/api.cpp
Normal file
1163
AssetStudioFBXNative/api.cpp
Normal file
File diff suppressed because it is too large
Load Diff
161
AssetStudioFBXNative/api.h
Normal file
161
AssetStudioFBXNative/api.h
Normal file
@@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
|
||||
#include "dllexport.h"
|
||||
#include "bool32_t.h"
|
||||
|
||||
namespace fbxsdk
|
||||
{
|
||||
class FbxNode;
|
||||
class FbxFileTexture;
|
||||
template<typename T, const int Alignment = 16>
|
||||
class FbxArray;
|
||||
class FbxCluster;
|
||||
class FbxMesh;
|
||||
class FbxSurfacePhong;
|
||||
}
|
||||
|
||||
struct AsFbxContext;
|
||||
struct AsFbxSkinContext;
|
||||
struct AsFbxAnimContext;
|
||||
struct AsFbxMorphContext;
|
||||
|
||||
AS_API(void) AsUtilQuaternionToEuler(float qx, float qy, float qz, float qw, float* vx, float* vy, float* vz);
|
||||
|
||||
AS_API(void) AsUtilEulerToQuaternion(float vx, float vy, float vz, float* qx, float* qy, float* qz, float* qw);
|
||||
|
||||
// All strings ([const] char *) in this header are UTF-8 strings.
|
||||
|
||||
AS_API(AsFbxContext*) AsFbxCreateContext();
|
||||
|
||||
// Do not free pErrMsg
|
||||
AS_API(bool32_t) AsFbxInitializeContext(AsFbxContext* pContext, const char* pFileName, float scaleFactor, int32_t versionIndex, bool32_t isAscii, bool32_t is60Fps, const char** pErrMsg);
|
||||
|
||||
AS_API(void) AsFbxDisposeContext(AsFbxContext** ppContext);
|
||||
|
||||
AS_API(void) AsFbxSetFramePaths(AsFbxContext* pContext, const char* ppPaths[], int32_t count);
|
||||
|
||||
AS_API(void) AsFbxExportScene(AsFbxContext* pContext);
|
||||
|
||||
AS_API(fbxsdk::FbxNode*) AsFbxGetSceneRootNode(AsFbxContext* pContext);
|
||||
|
||||
AS_API(fbxsdk::FbxNode*) AsFbxExportSingleFrame(AsFbxContext* pContext, fbxsdk::FbxNode* pParentNode, const char* pFramePath, const char* pFrameName, float localPositionX, float localPositionY, float localPositionZ, float localRotationX, float localRotationY, float localRotationZ, float localScaleX, float localScaleY, float localScaleZ);
|
||||
|
||||
AS_API(void) AsFbxSetJointsNode_CastToBone(AsFbxContext* pContext, fbxsdk::FbxNode* pNode, float boneSize);
|
||||
|
||||
AS_API(void) AsFbxSetJointsNode_BoneInPath(AsFbxContext* pContext, fbxsdk::FbxNode* pNode, float boneSize);
|
||||
|
||||
AS_API(void) AsFbxSetJointsNode_Generic(AsFbxContext* pContext, fbxsdk::FbxNode* pNode);
|
||||
|
||||
AS_API(void) AsFbxPrepareMaterials(AsFbxContext* pContext, int32_t materialCount, int32_t textureCount);
|
||||
|
||||
AS_API(fbxsdk::FbxFileTexture*) AsFbxCreateTexture(AsFbxContext* pContext, const char* pMatTexName);
|
||||
|
||||
AS_API(void) AsFbxLinkTexture(int32_t dest, fbxsdk::FbxFileTexture* pTexture, fbxsdk::FbxSurfacePhong* pMaterial, float offsetX, float offsetY, float scaleX, float scaleY);
|
||||
|
||||
AS_API(fbxsdk::FbxArray<fbxsdk::FbxCluster*>*) AsFbxMeshCreateClusterArray(int32_t boneCount);
|
||||
|
||||
AS_API(void) AsFbxMeshDisposeClusterArray(fbxsdk::FbxArray<fbxsdk::FbxCluster*>** ppArray);
|
||||
|
||||
AS_API(fbxsdk::FbxCluster*) AsFbxMeshCreateCluster(AsFbxContext* pContext, fbxsdk::FbxNode* pBoneNode);
|
||||
|
||||
AS_API(void) AsFbxMeshAddCluster(fbxsdk::FbxArray<fbxsdk::FbxCluster*>* pArray, /* CanBeNull */ fbxsdk::FbxCluster* pCluster);
|
||||
|
||||
AS_API(fbxsdk::FbxMesh*) AsFbxMeshCreateMesh(AsFbxContext* pContext, fbxsdk::FbxNode* pFrameNode);
|
||||
|
||||
AS_API(void) AsFbxMeshInitControlPoints(fbxsdk::FbxMesh* pMesh, int32_t vertexCount);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateElementNormal(fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateDiffuseUV(fbxsdk::FbxMesh* pMesh, int32_t uv);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateNormalMapUV(fbxsdk::FbxMesh* pMesh, int32_t uv);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateElementTangent(fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateElementVertexColor(fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(void) AsFbxMeshCreateElementMaterial(fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(fbxsdk::FbxSurfacePhong*) AsFbxCreateMaterial(AsFbxContext* pContext, const char* pMatName,
|
||||
float diffuseR, float diffuseG, float diffuseB,
|
||||
float ambientR, float ambientG, float ambientB,
|
||||
float emissiveR, float emissiveG, float emissiveB,
|
||||
float specularR, float specularG, float specularB,
|
||||
float reflectR, float reflectG, float reflectB,
|
||||
float shininess, float transparency);
|
||||
|
||||
AS_API(int32_t) AsFbxAddMaterialToFrame(fbxsdk::FbxNode* pFrameNode, fbxsdk::FbxSurfacePhong* pMaterial);
|
||||
|
||||
AS_API(void) AsFbxSetFrameShadingModeToTextureShading(fbxsdk::FbxNode* pFrameNode);
|
||||
|
||||
AS_API(void) AsFbxMeshSetControlPoint(fbxsdk::FbxMesh* pMesh, int32_t index, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxMeshAddPolygon(fbxsdk::FbxMesh* pMesh, int32_t materialIndex, int32_t index0, int32_t index1, int32_t index2);
|
||||
|
||||
AS_API(void) AsFbxMeshElementNormalAdd(fbxsdk::FbxMesh* pMesh, int32_t elementIndex, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxMeshElementUVAdd(fbxsdk::FbxMesh* pMesh, int32_t elementIndex, float u, float v);
|
||||
|
||||
AS_API(void) AsFbxMeshElementTangentAdd(fbxsdk::FbxMesh* pMesh, int32_t elementIndex, float x, float y, float z, float w);
|
||||
|
||||
AS_API(void) AsFbxMeshElementVertexColorAdd(fbxsdk::FbxMesh* pMesh, int32_t elementIndex, float r, float g, float b, float a);
|
||||
|
||||
AS_API(void) AsFbxMeshSetBoneWeight(fbxsdk::FbxArray<fbxsdk::FbxCluster*>* pClusterArray, int32_t boneIndex, int32_t vertexIndex, float weight);
|
||||
|
||||
AS_API(AsFbxSkinContext*) AsFbxMeshCreateSkinContext(AsFbxContext* pContext, fbxsdk::FbxNode* pFrameNode);
|
||||
|
||||
AS_API(void) AsFbxMeshDisposeSkinContext(AsFbxSkinContext** ppSkinContext);
|
||||
|
||||
AS_API(bool32_t) FbxClusterArray_HasItemAt(fbxsdk::FbxArray<fbxsdk::FbxCluster*>* pClusterArray, int32_t index);
|
||||
|
||||
AS_API(void) AsFbxMeshSkinAddCluster(AsFbxSkinContext* pSkinContext, fbxsdk::FbxArray<fbxsdk::FbxCluster*>* pClusterArray, int32_t index, float pBoneMatrix[16]);
|
||||
|
||||
AS_API(void) AsFbxMeshAddDeformer(AsFbxSkinContext* pSkinContext, fbxsdk::FbxMesh* pMesh);
|
||||
|
||||
AS_API(AsFbxAnimContext*) AsFbxAnimCreateContext(bool32_t eulerFilter);
|
||||
|
||||
AS_API(void) AsFbxAnimDisposeContext(AsFbxAnimContext** ppAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimPrepareStackAndLayer(AsFbxContext* pContext, AsFbxAnimContext* pAnimContext, const char* pTakeName);
|
||||
|
||||
AS_API(void) AsFbxAnimLoadCurves(fbxsdk::FbxNode* pNode, AsFbxAnimContext* pAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimBeginKeyModify(AsFbxAnimContext* pAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimEndKeyModify(AsFbxAnimContext* pAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimAddScalingKey(AsFbxAnimContext* pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxAnimAddRotationKey(AsFbxAnimContext* pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxAnimAddTranslationKey(AsFbxAnimContext* pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
AS_API(void) AsFbxAnimApplyEulerFilter(AsFbxAnimContext* pAnimContext, float filterPrecision);
|
||||
|
||||
AS_API(int32_t) AsFbxAnimGetCurrentBlendShapeChannelCount(AsFbxAnimContext* pAnimContext, fbxsdk::FbxNode* pNode);
|
||||
|
||||
AS_API(bool32_t) AsFbxAnimIsBlendShapeChannelMatch(AsFbxAnimContext* pAnimContext, int32_t channelIndex, const char* channelName);
|
||||
|
||||
AS_API(void) AsFbxAnimBeginBlendShapeAnimCurve(AsFbxAnimContext* pAnimContext, int32_t channelIndex);
|
||||
|
||||
AS_API(void) AsFbxAnimEndBlendShapeAnimCurve(AsFbxAnimContext* pAnimContext);
|
||||
|
||||
AS_API(void) AsFbxAnimAddBlendShapeKeyframe(AsFbxAnimContext* pAnimContext, float time, float value);
|
||||
|
||||
AS_API(AsFbxMorphContext*) AsFbxMorphCreateContext();
|
||||
|
||||
AS_API(void) AsFbxMorphInitializeContext(AsFbxContext* pContext, AsFbxMorphContext* pMorphContext, fbxsdk::FbxNode* pNode);
|
||||
|
||||
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, 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);
|
||||
27
AssetStudioFBXNative/asfbx_anim_context.cpp
Normal file
27
AssetStudioFBXNative/asfbx_anim_context.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "asfbx_anim_context.h"
|
||||
|
||||
AsFbxAnimContext::AsFbxAnimContext(bool32_t eulerFilter)
|
||||
: lFilter(nullptr)
|
||||
{
|
||||
if (eulerFilter)
|
||||
{
|
||||
lFilter = new FbxAnimCurveFilterUnroll();
|
||||
}
|
||||
|
||||
lAnimStack = nullptr;
|
||||
lAnimLayer = nullptr;
|
||||
|
||||
lCurveSX = nullptr;
|
||||
lCurveSY = nullptr;
|
||||
lCurveSZ = nullptr;
|
||||
lCurveRX = nullptr;
|
||||
lCurveRY = nullptr;
|
||||
lCurveRZ = nullptr;
|
||||
lCurveTX = nullptr;
|
||||
lCurveTY = nullptr;
|
||||
lCurveTZ = nullptr;
|
||||
|
||||
pMesh = nullptr;
|
||||
lBlendShape = nullptr;
|
||||
lAnimCurve = nullptr;
|
||||
}
|
||||
32
AssetStudioFBXNative/asfbx_anim_context.h
Normal file
32
AssetStudioFBXNative/asfbx_anim_context.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
#include "bool32_t.h"
|
||||
|
||||
struct AsFbxAnimContext
|
||||
{
|
||||
|
||||
FbxAnimCurveFilterUnroll* lFilter;
|
||||
|
||||
FbxAnimStack* lAnimStack;
|
||||
FbxAnimLayer* lAnimLayer;
|
||||
|
||||
FbxAnimCurve* lCurveSX;
|
||||
FbxAnimCurve* lCurveSY;
|
||||
FbxAnimCurve* lCurveSZ;
|
||||
FbxAnimCurve* lCurveRX;
|
||||
FbxAnimCurve* lCurveRY;
|
||||
FbxAnimCurve* lCurveRZ;
|
||||
FbxAnimCurve* lCurveTX;
|
||||
FbxAnimCurve* lCurveTY;
|
||||
FbxAnimCurve* lCurveTZ;
|
||||
|
||||
FbxMesh* pMesh;
|
||||
FbxBlendShape* lBlendShape;
|
||||
FbxAnimCurve* lAnimCurve;
|
||||
|
||||
AsFbxAnimContext(bool32_t eulerFilter);
|
||||
~AsFbxAnimContext() = default;
|
||||
|
||||
};
|
||||
33
AssetStudioFBXNative/asfbx_context.cpp
Normal file
33
AssetStudioFBXNative/asfbx_context.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <fbxsdk.h>
|
||||
|
||||
#include "asfbx_context.h"
|
||||
|
||||
AsFbxContext::AsFbxContext()
|
||||
{
|
||||
pSdkManager = nullptr;
|
||||
pScene = nullptr;
|
||||
pTextures = nullptr;
|
||||
pMaterials = nullptr;
|
||||
pExporter = nullptr;
|
||||
pBindPose = nullptr;
|
||||
}
|
||||
|
||||
AsFbxContext::~AsFbxContext()
|
||||
{
|
||||
framePaths.clear();
|
||||
|
||||
delete pMaterials;
|
||||
delete pTextures;
|
||||
|
||||
if (pExporter != nullptr) {
|
||||
pExporter->Destroy();
|
||||
}
|
||||
|
||||
if (pScene != nullptr) {
|
||||
pScene->Destroy();
|
||||
}
|
||||
|
||||
if (pSdkManager != nullptr) {
|
||||
pSdkManager->Destroy();
|
||||
}
|
||||
}
|
||||
21
AssetStudioFBXNative/asfbx_context.h
Normal file
21
AssetStudioFBXNative/asfbx_context.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
struct AsFbxContext
|
||||
{
|
||||
|
||||
fbxsdk::FbxManager* pSdkManager;
|
||||
fbxsdk::FbxScene* pScene;
|
||||
fbxsdk::FbxArray<fbxsdk::FbxFileTexture*>* pTextures;
|
||||
fbxsdk::FbxArray<fbxsdk::FbxSurfacePhong*>* pMaterials;
|
||||
fbxsdk::FbxExporter* pExporter;
|
||||
fbxsdk::FbxPose* pBindPose;
|
||||
|
||||
std::unordered_set<std::string> framePaths;
|
||||
|
||||
AsFbxContext();
|
||||
~AsFbxContext();
|
||||
};
|
||||
9
AssetStudioFBXNative/asfbx_morph_context.cpp
Normal file
9
AssetStudioFBXNative/asfbx_morph_context.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "asfbx_morph_context.h"
|
||||
|
||||
AsFbxMorphContext::AsFbxMorphContext()
|
||||
{
|
||||
pMesh = nullptr;
|
||||
lBlendShape = nullptr;
|
||||
lBlendShapeChannel = nullptr;
|
||||
lShape = nullptr;
|
||||
}
|
||||
16
AssetStudioFBXNative/asfbx_morph_context.h
Normal file
16
AssetStudioFBXNative/asfbx_morph_context.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
struct AsFbxMorphContext
|
||||
{
|
||||
|
||||
FbxMesh* pMesh;
|
||||
FbxBlendShape* lBlendShape;
|
||||
FbxBlendShapeChannel* lBlendShapeChannel;
|
||||
FbxShape* lShape;
|
||||
|
||||
AsFbxMorphContext();
|
||||
~AsFbxMorphContext() = default;
|
||||
|
||||
};
|
||||
16
AssetStudioFBXNative/asfbx_skin_context.cpp
Normal file
16
AssetStudioFBXNative/asfbx_skin_context.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "asfbx_skin_context.h"
|
||||
#include "asfbx_context.h"
|
||||
|
||||
AsFbxSkinContext::AsFbxSkinContext(AsFbxContext* pContext, FbxNode* pFrameNode)
|
||||
: pSkin(nullptr)
|
||||
{
|
||||
if (pContext != nullptr && pContext->pScene != nullptr)
|
||||
{
|
||||
pSkin = FbxSkin::Create(pContext->pScene, "");
|
||||
}
|
||||
|
||||
if (pFrameNode != nullptr)
|
||||
{
|
||||
lMeshMatrix = pFrameNode->EvaluateGlobalTransform();
|
||||
}
|
||||
}
|
||||
16
AssetStudioFBXNative/asfbx_skin_context.h
Normal file
16
AssetStudioFBXNative/asfbx_skin_context.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
struct AsFbxContext;
|
||||
|
||||
struct AsFbxSkinContext
|
||||
{
|
||||
|
||||
FbxSkin* pSkin;
|
||||
FbxAMatrix lMeshMatrix;
|
||||
|
||||
AsFbxSkinContext(AsFbxContext* pContext, FbxNode* pFrameNode);
|
||||
~AsFbxSkinContext() = default;
|
||||
|
||||
};
|
||||
5
AssetStudioFBXNative/bool32_t.h
Normal file
5
AssetStudioFBXNative/bool32_t.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
typedef uint32_t bool32_t;
|
||||
1
AssetStudioFBXNative/cpp.hint
Normal file
1
AssetStudioFBXNative/cpp.hint
Normal file
@@ -0,0 +1 @@
|
||||
#define AS_API(ret_type)
|
||||
56
AssetStudioFBXNative/dllexport.h
Normal file
56
AssetStudioFBXNative/dllexport.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if _MSC_VER < 1910 // MSVC 2017-
|
||||
#error MSVC 2017 or later is required.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW__)
|
||||
#ifdef _AS_DLL
|
||||
#ifdef __GNUC__
|
||||
#define _AS_EXPORT __attribute__ ((dllexport))
|
||||
#else
|
||||
#define _AS_EXPORT __declspec(dllexport)
|
||||
#endif
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
#define _AS_EXPORT __attribute__ ((dllimport))
|
||||
#else
|
||||
#define _AS_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#define _AS_LOCAL
|
||||
#else
|
||||
#if __GNUC__ >= 4
|
||||
#define _AS_EXPORT __attribute__ ((visibility ("default")))
|
||||
#define _AS_LOCAL __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define _AS_EXPORT
|
||||
#define _AS_LOCAL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifndef _EXTERN_C_STMT
|
||||
#define _EXTERN_C_STMT extern "C"
|
||||
#endif
|
||||
#else
|
||||
#ifndef _EXTERN_C_STMT
|
||||
#define _EXTERN_C_STMT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _AS_CALL
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define _AS_CALL __stdcall
|
||||
#else
|
||||
#define _AS_CALL /* __cdecl */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define AS_API(ret_type) _EXTERN_C_STMT _AS_EXPORT ret_type _AS_CALL
|
||||
#else
|
||||
#define AS_API(ret_type) _EXTERN_C_STMT _AS_EXPORT _AS_CALL ret_type
|
||||
#endif
|
||||
14
AssetStudioFBXNative/resource.h
Normal file
14
AssetStudioFBXNative/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by AssetStudioFBXNative.rc
|
||||
|
||||
// <20>¶<EFBFBD><C2B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>Ĭ<EFBFBD><C4AC>ֵ
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
43
AssetStudioFBXNative/utils.cpp
Normal file
43
AssetStudioFBXNative/utils.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <fbxsdk.h>
|
||||
#include <cassert>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
Vector3::Vector3()
|
||||
: X(0), Y(0), Z(0)
|
||||
{
|
||||
}
|
||||
|
||||
Vector3::Vector3(float x, float y, float z)
|
||||
: X(x), Y(y), Z(z)
|
||||
{
|
||||
}
|
||||
|
||||
Quaternion::Quaternion()
|
||||
: X(0), Y(0), Z(0), W(1)
|
||||
{
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(float x, float y, float z)
|
||||
: X(x), Y(y), Z(z), W(1)
|
||||
{
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(float x, float y, float z, float w)
|
||||
: X(x), Y(y), Z(z), W(w)
|
||||
{
|
||||
}
|
||||
|
||||
Vector3 QuaternionToEuler(Quaternion q) {
|
||||
FbxAMatrix lMatrixRot;
|
||||
lMatrixRot.SetQ(FbxQuaternion(q.X, q.Y, q.Z, q.W));
|
||||
FbxVector4 lEuler = lMatrixRot.GetR();
|
||||
return Vector3((float)lEuler[0], (float)lEuler[1], (float)lEuler[2]);
|
||||
}
|
||||
|
||||
Quaternion EulerToQuaternion(Vector3 v) {
|
||||
FbxAMatrix lMatrixRot;
|
||||
lMatrixRot.SetR(FbxVector4(v.X, v.Y, v.Z));
|
||||
FbxQuaternion lQuaternion = lMatrixRot.GetQ();
|
||||
return Quaternion((float)lQuaternion[0], (float)lQuaternion[1], (float)lQuaternion[2], (float)lQuaternion[3]);
|
||||
}
|
||||
29
AssetStudioFBXNative/utils.h
Normal file
29
AssetStudioFBXNative/utils.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
struct Vector3 {
|
||||
|
||||
float X;
|
||||
float Y;
|
||||
float Z;
|
||||
|
||||
Vector3();
|
||||
Vector3(float x, float y, float z);
|
||||
|
||||
};
|
||||
|
||||
struct Quaternion {
|
||||
|
||||
float X;
|
||||
float Y;
|
||||
float Z;
|
||||
float W;
|
||||
|
||||
Quaternion();
|
||||
Quaternion(float x, float y, float z);
|
||||
Quaternion(float x, float y, float z, float w);
|
||||
|
||||
};
|
||||
|
||||
Vector3 QuaternionToEuler(Quaternion q);
|
||||
|
||||
Quaternion EulerToQuaternion(Vector3 v);
|
||||
22
AssetStudioFBXWrapper/AssetStudioFBXWrapper.csproj
Normal file
22
AssetStudioFBXWrapper/AssetStudioFBXWrapper.csproj
Normal file
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>0.16.8.1</Version>
|
||||
<AssemblyVersion>0.16.8.1</AssemblyVersion>
|
||||
<FileVersion>0.16.8.1</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2021; Copyright © hozuki 2020</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net472|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudio.PInvoke\AssetStudio.PInvoke.csproj" />
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
AssetStudioFBXWrapper/Fbx.PInvoke.cs
Normal file
16
AssetStudioFBXWrapper/Fbx.PInvoke.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using AssetStudio.FbxInterop;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
partial class Fbx
|
||||
{
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsUtilQuaternionToEuler(float qx, float qy, float qz, float qw, out float vx, out float vy, out float vz);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsUtilEulerToQuaternion(float vx, float vy, float vz, out float qx, out float qy, out float qz, out float qw);
|
||||
|
||||
}
|
||||
}
|
||||
58
AssetStudioFBXWrapper/Fbx.cs
Normal file
58
AssetStudioFBXWrapper/Fbx.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using AssetStudio.FbxInterop;
|
||||
using AssetStudio.PInvoke;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static partial class Fbx
|
||||
{
|
||||
|
||||
static Fbx()
|
||||
{
|
||||
DllLoader.PreloadDll(FbxDll.DllName);
|
||||
}
|
||||
|
||||
public static Vector3 QuaternionToEuler(Quaternion q)
|
||||
{
|
||||
AsUtilQuaternionToEuler(q.X, q.Y, q.Z, q.W, out var x, out var y, out var z);
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
public static Quaternion EulerToQuaternion(Vector3 v)
|
||||
{
|
||||
AsUtilEulerToQuaternion(v.X, v.Y, v.Z, out var x, out var y, out var z, out var w);
|
||||
return new Quaternion(x, y, z, w);
|
||||
}
|
||||
|
||||
public static class Exporter
|
||||
{
|
||||
|
||||
public static void Export(string path, IImported imported, bool eulerFilter, float filterPrecision,
|
||||
bool allNodes, bool skins, bool animation, bool blendShape, bool castToBone, float boneSize, bool exportAllUvsAsDiffuseMaps, float scaleFactor, int versionIndex, bool isAscii)
|
||||
{
|
||||
var file = new FileInfo(path);
|
||||
var dir = file.Directory;
|
||||
|
||||
if (!dir.Exists)
|
||||
{
|
||||
dir.Create();
|
||||
}
|
||||
|
||||
var currentDir = Directory.GetCurrentDirectory();
|
||||
Directory.SetCurrentDirectory(dir.FullName);
|
||||
|
||||
var name = Path.GetFileName(path);
|
||||
|
||||
using (var exporter = new FbxExporter(name, imported, allNodes, skins, castToBone, boneSize, exportAllUvsAsDiffuseMaps, scaleFactor, versionIndex, isAscii))
|
||||
{
|
||||
exporter.Initialize();
|
||||
exporter.ExportAll(blendShape, animation, eulerFilter, filterPrecision);
|
||||
}
|
||||
|
||||
Directory.SetCurrentDirectory(currentDir);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
10
AssetStudioFBXWrapper/FbxDll.cs
Normal file
10
AssetStudioFBXWrapper/FbxDll.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace AssetStudio.FbxInterop
|
||||
{
|
||||
internal static class FbxDll
|
||||
{
|
||||
|
||||
internal const string DllName = "AssetStudioFBXNative";
|
||||
internal const string FbxsdkDllName = "libfbxsdk";
|
||||
|
||||
}
|
||||
}
|
||||
244
AssetStudioFBXWrapper/FbxExporter.cs
Normal file
244
AssetStudioFBXWrapper/FbxExporter.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace AssetStudio.FbxInterop
|
||||
{
|
||||
internal sealed class FbxExporter : IDisposable
|
||||
{
|
||||
|
||||
private FbxExporterContext _context;
|
||||
|
||||
private readonly string _fileName;
|
||||
private readonly IImported _imported;
|
||||
private readonly bool _allNodes;
|
||||
private readonly bool _exportSkins;
|
||||
private readonly bool _castToBone;
|
||||
private readonly float _boneSize;
|
||||
private readonly bool _exportAllUvsAsDiffuseMaps;
|
||||
private readonly float _scaleFactor;
|
||||
private readonly int _versionIndex;
|
||||
private readonly bool _isAscii;
|
||||
|
||||
internal FbxExporter(string fileName, IImported imported, bool allNodes, bool exportSkins, bool castToBone, float boneSize, bool exportAllUvsAsDiffuseMaps, float scaleFactor, int versionIndex, bool isAscii)
|
||||
{
|
||||
_context = new FbxExporterContext();
|
||||
|
||||
_fileName = fileName;
|
||||
_imported = imported;
|
||||
_allNodes = allNodes;
|
||||
_exportSkins = exportSkins;
|
||||
_castToBone = castToBone;
|
||||
_boneSize = boneSize;
|
||||
_exportAllUvsAsDiffuseMaps = exportAllUvsAsDiffuseMaps;
|
||||
_scaleFactor = scaleFactor;
|
||||
_versionIndex = versionIndex;
|
||||
_isAscii = isAscii;
|
||||
}
|
||||
|
||||
~FbxExporter()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_context.Dispose();
|
||||
}
|
||||
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
internal void Initialize()
|
||||
{
|
||||
var is60Fps = _imported.AnimationList.Count > 0 && _imported.AnimationList[0].SampleRate.Equals(60.0f);
|
||||
|
||||
_context.Initialize(_fileName, _scaleFactor, _versionIndex, _isAscii, is60Fps);
|
||||
|
||||
if (!_allNodes)
|
||||
{
|
||||
var framePaths = SearchHierarchy();
|
||||
|
||||
_context.SetFramePaths(framePaths);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ExportAll(bool blendShape, bool animation, bool eulerFilter, float filterPrecision)
|
||||
{
|
||||
var meshFrames = new List<ImportedFrame>();
|
||||
|
||||
ExportRootFrame(meshFrames);
|
||||
|
||||
if (_imported.MeshList != null)
|
||||
{
|
||||
SetJointsFromImportedMeshes();
|
||||
|
||||
PrepareMaterials();
|
||||
|
||||
ExportMeshFrames(_imported.RootFrame, meshFrames);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetJointsNode(_imported.RootFrame, null, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (blendShape)
|
||||
{
|
||||
ExportMorphs();
|
||||
}
|
||||
|
||||
if (animation)
|
||||
{
|
||||
ExportAnimations(eulerFilter, filterPrecision);
|
||||
}
|
||||
|
||||
ExportScene();
|
||||
}
|
||||
|
||||
private void ExportMorphs()
|
||||
{
|
||||
_context.ExportMorphs(_imported.RootFrame, _imported.MorphList);
|
||||
}
|
||||
|
||||
private void ExportAnimations(bool eulerFilter, float filterPrecision)
|
||||
{
|
||||
_context.ExportAnimations(_imported.RootFrame, _imported.AnimationList, eulerFilter, filterPrecision);
|
||||
}
|
||||
|
||||
private void ExportRootFrame(List<ImportedFrame> meshFrames)
|
||||
{
|
||||
_context.ExportFrame(_imported.MeshList, meshFrames, _imported.RootFrame);
|
||||
}
|
||||
|
||||
private void ExportScene()
|
||||
{
|
||||
_context.ExportScene();
|
||||
}
|
||||
|
||||
private void SetJointsFromImportedMeshes()
|
||||
{
|
||||
if (!_exportSkins)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Assert(_imported.MeshList != null);
|
||||
|
||||
var bonePaths = new HashSet<string>();
|
||||
|
||||
foreach (var mesh in _imported.MeshList)
|
||||
{
|
||||
var boneList = mesh.BoneList;
|
||||
|
||||
if (boneList != null)
|
||||
{
|
||||
foreach (var bone in boneList)
|
||||
{
|
||||
bonePaths.Add(bone.Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetJointsNode(_imported.RootFrame, bonePaths, _castToBone);
|
||||
}
|
||||
|
||||
private void SetJointsNode(ImportedFrame rootFrame, HashSet<string> bonePaths, bool castToBone)
|
||||
{
|
||||
_context.SetJointsNode(rootFrame, bonePaths, castToBone, _boneSize);
|
||||
}
|
||||
|
||||
private void PrepareMaterials()
|
||||
{
|
||||
_context.PrepareMaterials(_imported.MaterialList.Count, _imported.TextureList.Count);
|
||||
}
|
||||
|
||||
private void ExportMeshFrames(ImportedFrame rootFrame, List<ImportedFrame> meshFrames)
|
||||
{
|
||||
foreach (var meshFrame in meshFrames)
|
||||
{
|
||||
_context.ExportMeshFromFrame(rootFrame, meshFrame, _imported.MeshList, _imported.MaterialList, _imported.TextureList, _exportSkins, _exportAllUvsAsDiffuseMaps);
|
||||
}
|
||||
}
|
||||
|
||||
private HashSet<string> SearchHierarchy()
|
||||
{
|
||||
if (_imported.MeshList == null || _imported.MeshList.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var exportFrames = new HashSet<string>();
|
||||
|
||||
SearchHierarchy(_imported.RootFrame, _imported.MeshList, exportFrames);
|
||||
|
||||
return exportFrames;
|
||||
}
|
||||
|
||||
private static void SearchHierarchy(ImportedFrame rootFrame, List<ImportedMesh> meshList, HashSet<string> exportFrames)
|
||||
{
|
||||
var frameStack = new Stack<ImportedFrame>();
|
||||
|
||||
frameStack.Push(rootFrame);
|
||||
|
||||
while (frameStack.Count > 0)
|
||||
{
|
||||
var frame = frameStack.Pop();
|
||||
|
||||
var meshListSome = ImportedHelpers.FindMesh(frame.Path, meshList);
|
||||
|
||||
if (meshListSome != null)
|
||||
{
|
||||
var parent = frame;
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
exportFrames.Add(parent.Path);
|
||||
parent = parent.Parent;
|
||||
}
|
||||
|
||||
var boneList = meshListSome.BoneList;
|
||||
|
||||
if (boneList != null)
|
||||
{
|
||||
foreach (var bone in boneList)
|
||||
{
|
||||
if (!exportFrames.Contains(bone.Path))
|
||||
{
|
||||
var boneParent = rootFrame.FindFrameByPath(bone.Path);
|
||||
|
||||
while (boneParent != null)
|
||||
{
|
||||
exportFrames.Add(boneParent.Path);
|
||||
boneParent = boneParent.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = frame.Count - 1; i >= 0; i -= 1)
|
||||
{
|
||||
frameStack.Push(frame[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
325
AssetStudioFBXWrapper/FbxExporterContext.PInvoke.cs
Normal file
325
AssetStudioFBXWrapper/FbxExporterContext.PInvoke.cs
Normal file
@@ -0,0 +1,325 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using AssetStudio.PInvoke;
|
||||
|
||||
namespace AssetStudio.FbxInterop
|
||||
{
|
||||
partial class FbxExporterContext
|
||||
{
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxCreateContext();
|
||||
|
||||
private static bool AsFbxInitializeContext(IntPtr context, string fileName, float scaleFactor, int versionIndex, bool isAscii, bool is60Fps, out string errorMessage)
|
||||
{
|
||||
bool b;
|
||||
IntPtr pErrMsg;
|
||||
|
||||
using (var fileNameUtf8 = new Utf8StringHandle(fileName))
|
||||
{
|
||||
b = AsFbxInitializeContext(context, fileNameUtf8.DangerousGetHandle(), scaleFactor, versionIndex, isAscii, is60Fps, out pErrMsg);
|
||||
}
|
||||
|
||||
errorMessage = Utf8StringHandle.ReadUtf8StringFromPointer(pErrMsg);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
// Do not free the pointer strErrorMessage
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool AsFbxInitializeContext(IntPtr context, IntPtr strFileName, float scaleFactor, int versionIndex, [MarshalAs(UnmanagedType.Bool)] bool isAscii, [MarshalAs(UnmanagedType.Bool)] bool is60Fps, out IntPtr strErrorMessage);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxDisposeContext(ref IntPtr ppContext);
|
||||
|
||||
private static void AsFbxSetFramePaths(IntPtr context, string[] framePaths)
|
||||
{
|
||||
var framePathCount = framePaths.Length;
|
||||
|
||||
if (framePathCount == 0)
|
||||
{
|
||||
AsFbxSetFramePaths(context, Array.Empty<IntPtr>(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var utf8Paths = new Utf8StringHandle[framePathCount];
|
||||
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < framePathCount; i += 1)
|
||||
{
|
||||
utf8Paths[i] = new Utf8StringHandle(framePaths[i]);
|
||||
}
|
||||
|
||||
var pathPointers = new IntPtr[framePathCount];
|
||||
|
||||
for (var i = 0; i < framePathCount; i += 1)
|
||||
{
|
||||
pathPointers[i] = utf8Paths[i].DangerousGetHandle();
|
||||
}
|
||||
|
||||
AsFbxSetFramePaths(context, pathPointers, framePathCount);
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var path in utf8Paths)
|
||||
{
|
||||
path?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxSetFramePaths(IntPtr context, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] strFramePaths, int count);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxExportScene(IntPtr context);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxGetSceneRootNode(IntPtr context);
|
||||
|
||||
private static IntPtr AsFbxExportSingleFrame(IntPtr context, IntPtr parentNode, string framePath, string frameName, in Vector3 localPosition, in Vector3 localRotation, in Vector3 localScale)
|
||||
{
|
||||
using (var framePathUtf8 = new Utf8StringHandle(framePath))
|
||||
{
|
||||
using (var frameNameUtf8 = new Utf8StringHandle(frameName))
|
||||
{
|
||||
return AsFbxExportSingleFrame(context, parentNode, framePathUtf8.DangerousGetHandle(), frameNameUtf8.DangerousGetHandle(), localPosition.X, localPosition.Y, localPosition.Z, localRotation.X, localRotation.Y, localRotation.Z, localScale.X, localScale.Y, localScale.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxExportSingleFrame(IntPtr context, IntPtr parentNode, IntPtr strFramePath, IntPtr strFrameName, float localPositionX, float localPositionY, float localPositionZ, float localRotationX, float localRotationY, float localRotationZ, float localScaleX, float localScaleY, float localScaleZ);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxSetJointsNode_CastToBone(IntPtr context, IntPtr node, float boneSize);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxSetJointsNode_BoneInPath(IntPtr context, IntPtr node, float boneSize);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxSetJointsNode_Generic(IntPtr context, IntPtr node);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxPrepareMaterials(IntPtr context, int materialCount, int textureCount);
|
||||
|
||||
private static IntPtr AsFbxCreateTexture(IntPtr context, string matTexName)
|
||||
{
|
||||
using (var matTexNameUtf8 = new Utf8StringHandle(matTexName))
|
||||
{
|
||||
return AsFbxCreateTexture(context, matTexNameUtf8.DangerousGetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxCreateTexture(IntPtr context, IntPtr strMatTexName);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxLinkTexture(int dest, IntPtr texture, IntPtr material, float offsetX, float offsetY, float scaleX, float scaleY);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxMeshCreateClusterArray(int boneCount);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshDisposeClusterArray(ref IntPtr ppArray);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxMeshCreateCluster(IntPtr context, IntPtr boneNode);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshAddCluster(IntPtr array, IntPtr cluster);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxMeshCreateMesh(IntPtr context, IntPtr frameNode);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshInitControlPoints(IntPtr mesh, int vertexCount);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshCreateElementNormal(IntPtr mesh);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshCreateDiffuseUV(IntPtr mesh, int uv);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshCreateNormalMapUV(IntPtr mesh, int uv);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshCreateElementTangent(IntPtr mesh);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshCreateElementVertexColor(IntPtr mesh);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshCreateElementMaterial(IntPtr mesh);
|
||||
|
||||
private static IntPtr AsFbxCreateMaterial(IntPtr pContext, string matName, in Color diffuse, in Color ambient, in Color emissive, in Color specular, in Color reflection, float shininess, float transparency)
|
||||
{
|
||||
using (var matNameUtf8 = new Utf8StringHandle(matName))
|
||||
{
|
||||
return AsFbxCreateMaterial(pContext, matNameUtf8.DangerousGetHandle(), diffuse.R, diffuse.G, diffuse.B, ambient.R, ambient.G, ambient.B, emissive.R, emissive.G, emissive.B, specular.R, specular.G, specular.B, reflection.R, reflection.G, reflection.B, shininess, transparency);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxCreateMaterial(IntPtr pContext, IntPtr pMatName,
|
||||
float diffuseR, float diffuseG, float diffuseB,
|
||||
float ambientR, float ambientG, float ambientB,
|
||||
float emissiveR, float emissiveG, float emissiveB,
|
||||
float specularR, float specularG, float specularB,
|
||||
float reflectR, float reflectG, float reflectB,
|
||||
float shininess, float transparency);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern int AsFbxAddMaterialToFrame(IntPtr frameNode, IntPtr material);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxSetFrameShadingModeToTextureShading(IntPtr frameNode);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshSetControlPoint(IntPtr mesh, int index, float x, float y, float z);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshAddPolygon(IntPtr mesh, int materialIndex, int index0, int index1, int index2);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshElementNormalAdd(IntPtr mesh, int elementIndex, float x, float y, float z);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshElementUVAdd(IntPtr mesh, int elementIndex, float u, float v);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshElementTangentAdd(IntPtr mesh, int elementIndex, float x, float y, float z, float w);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshElementVertexColorAdd(IntPtr mesh, int elementIndex, float r, float g, float b, float a);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshSetBoneWeight(IntPtr pClusterArray, int boneIndex, int vertexIndex, float weight);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxMeshCreateSkinContext(IntPtr context, IntPtr frameNode);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshDisposeSkinContext(ref IntPtr ppSkinContext);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool FbxClusterArray_HasItemAt(IntPtr pClusterArray, int index);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private unsafe static extern void AsFbxMeshSkinAddCluster(IntPtr pSkinContext, IntPtr pClusterArray, int index, float* pBoneMatrix);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMeshAddDeformer(IntPtr pSkinContext, IntPtr pMesh);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxAnimCreateContext([MarshalAs(UnmanagedType.Bool)] bool eulerFilter);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimDisposeContext(ref IntPtr ppAnimContext);
|
||||
|
||||
private static void AsFbxAnimPrepareStackAndLayer(IntPtr pContext, IntPtr pAnimContext, string takeName)
|
||||
{
|
||||
using (var takeNameUtf8 = new Utf8StringHandle(takeName))
|
||||
{
|
||||
AsFbxAnimPrepareStackAndLayer(pContext, pAnimContext, takeNameUtf8.DangerousGetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimPrepareStackAndLayer(IntPtr pContext, IntPtr pAnimContext, IntPtr strTakeName);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimLoadCurves(IntPtr pNode, IntPtr pAnimContext);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimBeginKeyModify(IntPtr pAnimContext);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimEndKeyModify(IntPtr pAnimContext);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimAddScalingKey(IntPtr pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimAddRotationKey(IntPtr pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimAddTranslationKey(IntPtr pAnimContext, float time, float x, float y, float z);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimApplyEulerFilter(IntPtr pAnimContext, float filterPrecision);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern int AsFbxAnimGetCurrentBlendShapeChannelCount(IntPtr pAnimContext, IntPtr pNode);
|
||||
|
||||
private static bool AsFbxAnimIsBlendShapeChannelMatch(IntPtr pAnimContext, int channelIndex, string channelName)
|
||||
{
|
||||
using (var channelNameUtf8 = new Utf8StringHandle(channelName))
|
||||
{
|
||||
return AsFbxAnimIsBlendShapeChannelMatch(pAnimContext, channelIndex, channelNameUtf8.DangerousGetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool AsFbxAnimIsBlendShapeChannelMatch(IntPtr pAnimContext, int channelIndex, IntPtr strChannelName);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimBeginBlendShapeAnimCurve(IntPtr pAnimContext, int channelIndex);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimEndBlendShapeAnimCurve(IntPtr pAnimContext);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxAnimAddBlendShapeKeyframe(IntPtr pAnimContext, float time, float value);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern IntPtr AsFbxMorphCreateContext();
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphInitializeContext(IntPtr pContext, IntPtr pMorphContext, IntPtr pNode);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphDisposeContext(ref IntPtr ppMorphContext);
|
||||
|
||||
private static void AsFbxMorphAddBlendShapeChannel(IntPtr pContext, IntPtr pMorphContext, string channelName)
|
||||
{
|
||||
using (var channelNameUtf8 = new Utf8StringHandle(channelName))
|
||||
{
|
||||
AsFbxMorphAddBlendShapeChannel(pContext, pMorphContext, channelNameUtf8.DangerousGetHandle());
|
||||
}
|
||||
}
|
||||
|
||||
[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, IntPtr strShapeName);
|
||||
|
||||
[DllImport(FbxDll.DllName, CallingConvention = CallingConvention.Winapi)]
|
||||
private static extern void AsFbxMorphCopyBlendShapeControlPoints(IntPtr pMorphContext);
|
||||
|
||||
[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);
|
||||
|
||||
}
|
||||
}
|
||||
643
AssetStudioFBXWrapper/FbxExporterContext.cs
Normal file
643
AssetStudioFBXWrapper/FbxExporterContext.cs
Normal file
@@ -0,0 +1,643 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AssetStudio.FbxInterop
|
||||
{
|
||||
internal sealed partial class FbxExporterContext : IDisposable
|
||||
{
|
||||
|
||||
private IntPtr _pContext;
|
||||
private readonly Dictionary<ImportedFrame, IntPtr> _frameToNode;
|
||||
private readonly List<KeyValuePair<string, IntPtr>> _createdMaterials;
|
||||
private readonly Dictionary<string, IntPtr> _createdTextures;
|
||||
|
||||
public FbxExporterContext()
|
||||
{
|
||||
_pContext = AsFbxCreateContext();
|
||||
_frameToNode = new Dictionary<ImportedFrame, IntPtr>();
|
||||
_createdMaterials = new List<KeyValuePair<string, IntPtr>>();
|
||||
_createdTextures = new Dictionary<string, IntPtr>();
|
||||
}
|
||||
|
||||
~FbxExporterContext()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
IsDisposed = true;
|
||||
|
||||
_frameToNode.Clear();
|
||||
_createdMaterials.Clear();
|
||||
_createdTextures.Clear();
|
||||
|
||||
AsFbxDisposeContext(ref _pContext);
|
||||
}
|
||||
|
||||
private void EnsureNotDisposed()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(FbxExporterContext));
|
||||
}
|
||||
}
|
||||
|
||||
internal void Initialize(string fileName, float scaleFactor, int versionIndex, bool isAscii, bool is60Fps)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
var b = AsFbxInitializeContext(_pContext, fileName, scaleFactor, versionIndex, isAscii, is60Fps, out var errorMessage);
|
||||
|
||||
if (!b)
|
||||
{
|
||||
var fullMessage = $"Failed to initialize FbxExporter: {errorMessage}";
|
||||
throw new ApplicationException(fullMessage);
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetFramePaths(HashSet<string> framePaths)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
if (framePaths == null || framePaths.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var framePathList = new List<string>(framePaths);
|
||||
var framePathArray = framePathList.ToArray();
|
||||
|
||||
AsFbxSetFramePaths(_pContext, framePathArray);
|
||||
}
|
||||
|
||||
internal void ExportScene()
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
AsFbxExportScene(_pContext);
|
||||
}
|
||||
|
||||
internal void ExportFrame(List<ImportedMesh> meshList, List<ImportedFrame> meshFrames, ImportedFrame rootFrame)
|
||||
{
|
||||
var rootNode = AsFbxGetSceneRootNode(_pContext);
|
||||
|
||||
Debug.Assert(rootNode != IntPtr.Zero);
|
||||
|
||||
var nodeStack = new Stack<IntPtr>();
|
||||
var frameStack = new Stack<ImportedFrame>();
|
||||
|
||||
nodeStack.Push(rootNode);
|
||||
frameStack.Push(rootFrame);
|
||||
|
||||
while (nodeStack.Count > 0)
|
||||
{
|
||||
var parentNode = nodeStack.Pop();
|
||||
var frame = frameStack.Pop();
|
||||
|
||||
var childNode = AsFbxExportSingleFrame(_pContext, parentNode, frame.Path, frame.Name, frame.LocalPosition, frame.LocalRotation, frame.LocalScale);
|
||||
|
||||
if (meshList != null && ImportedHelpers.FindMesh(frame.Path, meshList) != null)
|
||||
{
|
||||
meshFrames.Add(frame);
|
||||
}
|
||||
|
||||
_frameToNode.Add(frame, childNode);
|
||||
|
||||
for (var i = frame.Count - 1; i >= 0; i -= 1)
|
||||
{
|
||||
nodeStack.Push(childNode);
|
||||
frameStack.Push(frame[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetJointsNode(ImportedFrame rootFrame, HashSet<string> bonePaths, bool castToBone, float boneSize)
|
||||
{
|
||||
var frameStack = new Stack<ImportedFrame>();
|
||||
|
||||
frameStack.Push(rootFrame);
|
||||
|
||||
while (frameStack.Count > 0)
|
||||
{
|
||||
var frame = frameStack.Pop();
|
||||
|
||||
if (_frameToNode.TryGetValue(frame, out var node))
|
||||
{
|
||||
Debug.Assert(node != IntPtr.Zero);
|
||||
|
||||
if (castToBone)
|
||||
{
|
||||
AsFbxSetJointsNode_CastToBone(_pContext, node, boneSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(bonePaths != null);
|
||||
|
||||
if (bonePaths.Contains(frame.Path))
|
||||
{
|
||||
AsFbxSetJointsNode_BoneInPath(_pContext, node, boneSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
AsFbxSetJointsNode_Generic(_pContext, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = frame.Count - 1; i >= 0; i -= 1)
|
||||
{
|
||||
frameStack.Push(frame[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void PrepareMaterials(int materialCount, int textureCount)
|
||||
{
|
||||
AsFbxPrepareMaterials(_pContext, materialCount, textureCount);
|
||||
}
|
||||
|
||||
internal void ExportMeshFromFrame(ImportedFrame rootFrame, ImportedFrame meshFrame, List<ImportedMesh> meshList, List<ImportedMaterial> materialList, List<ImportedTexture> textureList, bool exportSkins, bool exportAllUvsAsDiffuseMaps)
|
||||
{
|
||||
var meshNode = _frameToNode[meshFrame];
|
||||
var mesh = ImportedHelpers.FindMesh(meshFrame.Path, meshList);
|
||||
|
||||
ExportMesh(rootFrame, materialList, textureList, meshNode, mesh, exportSkins, exportAllUvsAsDiffuseMaps);
|
||||
}
|
||||
|
||||
private IntPtr ExportTexture(ImportedTexture texture)
|
||||
{
|
||||
if (texture == null)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (_createdTextures.ContainsKey(texture.Name))
|
||||
{
|
||||
return _createdTextures[texture.Name];
|
||||
}
|
||||
|
||||
var pTex = AsFbxCreateTexture(_pContext, texture.Name);
|
||||
|
||||
_createdTextures.Add(texture.Name, pTex);
|
||||
|
||||
var file = new FileInfo(texture.Name);
|
||||
|
||||
using (var writer = new BinaryWriter(file.Create()))
|
||||
{
|
||||
writer.Write(texture.Data);
|
||||
}
|
||||
|
||||
return pTex;
|
||||
}
|
||||
|
||||
private void ExportMesh(ImportedFrame rootFrame, List<ImportedMaterial> materialList, List<ImportedTexture> textureList, IntPtr frameNode, ImportedMesh importedMesh, bool exportSkins, bool exportAllUvsAsDiffuseMaps)
|
||||
{
|
||||
var boneList = importedMesh.BoneList;
|
||||
var totalBoneCount = 0;
|
||||
var hasBones = false;
|
||||
if (exportSkins && boneList?.Count > 0)
|
||||
{
|
||||
totalBoneCount = boneList.Count;
|
||||
hasBones = true;
|
||||
}
|
||||
|
||||
var pClusterArray = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
if (hasBones)
|
||||
{
|
||||
pClusterArray = AsFbxMeshCreateClusterArray(totalBoneCount);
|
||||
|
||||
foreach (var bone in boneList)
|
||||
{
|
||||
if (bone.Path != null)
|
||||
{
|
||||
var frame = rootFrame.FindFrameByPath(bone.Path);
|
||||
var boneNode = _frameToNode[frame];
|
||||
|
||||
var cluster = AsFbxMeshCreateCluster(_pContext, boneNode);
|
||||
|
||||
AsFbxMeshAddCluster(pClusterArray, cluster);
|
||||
}
|
||||
else
|
||||
{
|
||||
AsFbxMeshAddCluster(pClusterArray, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mesh = AsFbxMeshCreateMesh(_pContext, frameNode);
|
||||
|
||||
AsFbxMeshInitControlPoints(mesh, importedMesh.VertexList.Count);
|
||||
|
||||
if (importedMesh.hasNormal)
|
||||
{
|
||||
AsFbxMeshCreateElementNormal(mesh);
|
||||
}
|
||||
|
||||
for (int i = 0; i < importedMesh.hasUV.Length; i++)
|
||||
{
|
||||
if (!importedMesh.hasUV[i]) { continue; }
|
||||
|
||||
if (i == 1 && !exportAllUvsAsDiffuseMaps)
|
||||
{
|
||||
AsFbxMeshCreateNormalMapUV(mesh, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
AsFbxMeshCreateDiffuseUV(mesh, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (importedMesh.hasTangent)
|
||||
{
|
||||
AsFbxMeshCreateElementTangent(mesh);
|
||||
}
|
||||
|
||||
if (importedMesh.hasColor)
|
||||
{
|
||||
AsFbxMeshCreateElementVertexColor(mesh);
|
||||
}
|
||||
|
||||
AsFbxMeshCreateElementMaterial(mesh);
|
||||
|
||||
foreach (var meshObj in importedMesh.SubmeshList)
|
||||
{
|
||||
var materialIndex = 0;
|
||||
var mat = ImportedHelpers.FindMaterial(meshObj.Material, materialList);
|
||||
|
||||
if (mat != null)
|
||||
{
|
||||
var foundMat = _createdMaterials.FindIndex(kv => kv.Key == mat.Name);
|
||||
IntPtr pMat;
|
||||
|
||||
if (foundMat >= 0)
|
||||
{
|
||||
pMat = _createdMaterials[foundMat].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var diffuse = mat.Diffuse;
|
||||
var ambient = mat.Ambient;
|
||||
var emissive = mat.Emissive;
|
||||
var specular = mat.Specular;
|
||||
var reflection = mat.Reflection;
|
||||
|
||||
pMat = AsFbxCreateMaterial(_pContext, mat.Name, in diffuse, in ambient, in emissive, in specular, in reflection, mat.Shininess, mat.Transparency);
|
||||
|
||||
_createdMaterials.Add(new KeyValuePair<string, IntPtr>(mat.Name, pMat));
|
||||
}
|
||||
|
||||
materialIndex = AsFbxAddMaterialToFrame(frameNode, pMat);
|
||||
|
||||
var hasTexture = false;
|
||||
|
||||
foreach (var texture in mat.Textures)
|
||||
{
|
||||
var tex = ImportedHelpers.FindTexture(texture.Name, textureList);
|
||||
var pTexture = ExportTexture(tex);
|
||||
|
||||
if (pTexture != IntPtr.Zero)
|
||||
{
|
||||
switch (texture.Dest)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
AsFbxLinkTexture(texture.Dest, pTexture, pMat, texture.Offset.X, texture.Offset.Y, texture.Scale.X, texture.Scale.Y);
|
||||
hasTexture = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTexture)
|
||||
{
|
||||
AsFbxSetFrameShadingModeToTextureShading(frameNode);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var face in meshObj.FaceList)
|
||||
{
|
||||
var index0 = face.VertexIndices[0] + meshObj.BaseVertex;
|
||||
var index1 = face.VertexIndices[1] + meshObj.BaseVertex;
|
||||
var index2 = face.VertexIndices[2] + meshObj.BaseVertex;
|
||||
|
||||
AsFbxMeshAddPolygon(mesh, materialIndex, index0, index1, index2);
|
||||
}
|
||||
}
|
||||
|
||||
var vertexList = importedMesh.VertexList;
|
||||
|
||||
var vertexCount = vertexList.Count;
|
||||
|
||||
for (var j = 0; j < vertexCount; j += 1)
|
||||
{
|
||||
var importedVertex = vertexList[j];
|
||||
|
||||
var vertex = importedVertex.Vertex;
|
||||
AsFbxMeshSetControlPoint(mesh, j, vertex.X, vertex.Y, vertex.Z);
|
||||
|
||||
if (importedMesh.hasNormal)
|
||||
{
|
||||
var normal = importedVertex.Normal;
|
||||
AsFbxMeshElementNormalAdd(mesh, 0, normal.X, normal.Y, normal.Z);
|
||||
}
|
||||
|
||||
for (var uvIndex = 0; uvIndex < importedMesh.hasUV.Length; uvIndex += 1)
|
||||
{
|
||||
if (importedMesh.hasUV[uvIndex])
|
||||
{
|
||||
var uv = importedVertex.UV[uvIndex];
|
||||
AsFbxMeshElementUVAdd(mesh, uvIndex, uv[0], uv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (importedMesh.hasTangent)
|
||||
{
|
||||
var tangent = importedVertex.Tangent;
|
||||
AsFbxMeshElementTangentAdd(mesh, 0, tangent.X, tangent.Y, tangent.Z, tangent.W);
|
||||
}
|
||||
|
||||
if (importedMesh.hasColor)
|
||||
{
|
||||
var color = importedVertex.Color;
|
||||
AsFbxMeshElementVertexColorAdd(mesh, 0, color.R, color.G, color.B, color.A);
|
||||
}
|
||||
|
||||
if (hasBones && importedVertex.BoneIndices != null)
|
||||
{
|
||||
var boneIndices = importedVertex.BoneIndices;
|
||||
var boneWeights = importedVertex.Weights;
|
||||
|
||||
for (var k = 0; k < 4; k += 1)
|
||||
{
|
||||
if (boneIndices[k] < totalBoneCount && boneWeights[k] > 0)
|
||||
{
|
||||
AsFbxMeshSetBoneWeight(pClusterArray, boneIndices[k], j, boneWeights[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (hasBones)
|
||||
{
|
||||
IntPtr pSkinContext = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
pSkinContext = AsFbxMeshCreateSkinContext(_pContext, frameNode);
|
||||
|
||||
unsafe
|
||||
{
|
||||
var boneMatrix = stackalloc float[16];
|
||||
|
||||
for (var j = 0; j < totalBoneCount; j += 1)
|
||||
{
|
||||
if (!FbxClusterArray_HasItemAt(pClusterArray, j))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var m = boneList[j].Matrix;
|
||||
|
||||
CopyMatrix4x4(in m, boneMatrix);
|
||||
|
||||
AsFbxMeshSkinAddCluster(pSkinContext, pClusterArray, j, boneMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
AsFbxMeshAddDeformer(pSkinContext, mesh);
|
||||
}
|
||||
finally
|
||||
{
|
||||
AsFbxMeshDisposeSkinContext(ref pSkinContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
AsFbxMeshDisposeClusterArray(ref pClusterArray);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe void CopyMatrix4x4(in Matrix4x4 matrix, float* buffer)
|
||||
{
|
||||
for (var m = 0; m < 4; m += 1)
|
||||
{
|
||||
for (var n = 0; n < 4; n += 1)
|
||||
{
|
||||
var index = IndexFrom4x4(m, n);
|
||||
buffer[index] = matrix[m, n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int IndexFrom4x4(int m, int n)
|
||||
{
|
||||
return 4 * m + n;
|
||||
}
|
||||
|
||||
internal void ExportAnimations(ImportedFrame rootFrame, List<ImportedKeyframedAnimation> animationList, bool eulerFilter, float filterPrecision)
|
||||
{
|
||||
if (animationList == null || animationList.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var pAnimContext = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
pAnimContext = AsFbxAnimCreateContext(eulerFilter);
|
||||
|
||||
for (int i = 0; i < animationList.Count; i++)
|
||||
{
|
||||
var importedAnimation = animationList[i];
|
||||
string takeName;
|
||||
|
||||
if (importedAnimation.Name != null)
|
||||
{
|
||||
takeName = importedAnimation.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
takeName = $"Take{i.ToString()}";
|
||||
}
|
||||
|
||||
AsFbxAnimPrepareStackAndLayer(_pContext, pAnimContext, takeName);
|
||||
|
||||
ExportKeyframedAnimation(rootFrame, importedAnimation, pAnimContext, filterPrecision);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
AsFbxAnimDisposeContext(ref pAnimContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExportKeyframedAnimation(ImportedFrame rootFrame, ImportedKeyframedAnimation parser, IntPtr pAnimContext, float filterPrecision)
|
||||
{
|
||||
foreach (var track in parser.TrackList)
|
||||
{
|
||||
if (track.Path == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var frame = rootFrame.FindFrameByPath(track.Path);
|
||||
|
||||
if (frame == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var pNode = _frameToNode[frame];
|
||||
|
||||
AsFbxAnimLoadCurves(pNode, pAnimContext);
|
||||
|
||||
AsFbxAnimBeginKeyModify(pAnimContext);
|
||||
|
||||
foreach (var scaling in track.Scalings)
|
||||
{
|
||||
var value = scaling.value;
|
||||
AsFbxAnimAddScalingKey(pAnimContext, scaling.time, value.X, value.Y, value.Z);
|
||||
}
|
||||
|
||||
foreach (var rotation in track.Rotations)
|
||||
{
|
||||
var value = rotation.value;
|
||||
AsFbxAnimAddRotationKey(pAnimContext, rotation.time, value.X, value.Y, value.Z);
|
||||
}
|
||||
|
||||
foreach (var translation in track.Translations)
|
||||
{
|
||||
var value = translation.value;
|
||||
AsFbxAnimAddTranslationKey(pAnimContext, translation.time, value.X, value.Y, value.Z);
|
||||
}
|
||||
|
||||
AsFbxAnimEndKeyModify(pAnimContext);
|
||||
|
||||
AsFbxAnimApplyEulerFilter(pAnimContext, filterPrecision);
|
||||
|
||||
var blendShape = track.BlendShape;
|
||||
|
||||
if (blendShape != null)
|
||||
{
|
||||
var channelCount = AsFbxAnimGetCurrentBlendShapeChannelCount(pAnimContext, pNode);
|
||||
|
||||
if (channelCount > 0)
|
||||
{
|
||||
for (var channelIndex = 0; channelIndex < channelCount; channelIndex += 1)
|
||||
{
|
||||
if (!AsFbxAnimIsBlendShapeChannelMatch(pAnimContext, channelIndex, blendShape.ChannelName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AsFbxAnimBeginBlendShapeAnimCurve(pAnimContext, channelIndex);
|
||||
|
||||
foreach (var keyframe in blendShape.Keyframes)
|
||||
{
|
||||
AsFbxAnimAddBlendShapeKeyframe(pAnimContext, keyframe.time, keyframe.value);
|
||||
}
|
||||
|
||||
AsFbxAnimEndBlendShapeAnimCurve(pAnimContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void ExportMorphs(ImportedFrame rootFrame, List<ImportedMorph> morphList)
|
||||
{
|
||||
if (morphList == null || morphList.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var morph in morphList)
|
||||
{
|
||||
var frame = rootFrame.FindFrameByPath(morph.Path);
|
||||
|
||||
if (frame == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var pNode = _frameToNode[frame];
|
||||
|
||||
var pMorphContext = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
pMorphContext = AsFbxMorphCreateContext();
|
||||
|
||||
AsFbxMorphInitializeContext(_pContext, pMorphContext, pNode);
|
||||
|
||||
foreach (var channel in morph.Channels)
|
||||
{
|
||||
AsFbxMorphAddBlendShapeChannel(_pContext, pMorphContext, channel.Name);
|
||||
|
||||
for (var i = 0; i < channel.KeyframeList.Count; i++)
|
||||
{
|
||||
var keyframe = channel.KeyframeList[i];
|
||||
|
||||
AsFbxMorphAddBlendShapeChannelShape(_pContext, pMorphContext, keyframe.Weight, i == 0 ? channel.Name : $"{channel.Name}_{i + 1}");
|
||||
|
||||
AsFbxMorphCopyBlendShapeControlPoints(pMorphContext);
|
||||
|
||||
foreach (var vertex in keyframe.VertexList)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
AsFbxMorphDisposeContext(ref pMorphContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,192 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>AssetStudioGUI</RootNamespace>
|
||||
<AssemblyName>AssetStudioGUI</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="OpenTK">
|
||||
<HintPath>Libraries\OpenTK.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK.GLControl">
|
||||
<HintPath>Libraries\OpenTK.GLControl.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="GUILogger.cs" />
|
||||
<Compile Include="GUIProgress.cs" />
|
||||
<Compile Include="Components\GameObjectTreeNode.cs" />
|
||||
<Compile Include="Components\OpenFolderDialog.cs" />
|
||||
<Compile Include="Components\AssetItem.cs" />
|
||||
<Compile Include="Exporter.cs" />
|
||||
<Compile Include="Studio.cs" />
|
||||
<Compile Include="ExportOptions.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ExportOptions.Designer.cs">
|
||||
<DependentUpon>ExportOptions.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Components\GOHierarchy.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="AssetStudioGUIForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="AssetStudioGUIForm.Designer.cs">
|
||||
<DependentUpon>AssetStudioGUIForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Components\TypeTreeItem.cs" />
|
||||
<Compile Include="Components\TreeViewExtensions.cs" />
|
||||
<EmbeddedResource Include="ExportOptions.resx">
|
||||
<DependentUpon>ExportOptions.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="AssetStudioGUIForm.resx">
|
||||
<DependentUpon>AssetStudioGUIForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4 Client Profile %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 4.5</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\preview.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\as.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
|
||||
<Project>{9131c403-7fe8-444d-9af5-5fe5df76ff24}</Project>
|
||||
<Name>AssetStudioUtility</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj">
|
||||
<Project>{af56b63c-1764-41b7-9e60-8d485422ac3b}</Project>
|
||||
<Name>AssetStudio</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy /y "$(ProjectDir)Libraries" "$(TargetDir)"
|
||||
xcopy /y "$(ProjectDir)Libraries\$(PlatformName)" "$(TargetDir)"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
|
||||
<AssemblyTitle>AssetStudio Mod by VaDiM</AssemblyTitle>
|
||||
<Version>0.16.8.1</Version>
|
||||
<AssemblyVersion>0.16.8.1</AssemblyVersion>
|
||||
<FileVersion>0.16.8.1</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2021</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj" />
|
||||
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Update="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="Libraries\x86\fmod.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>x86\fmod.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="Libraries\x64\fmod.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<TargetPath>x64\fmod.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="OpenTK" Version="3.1.0" />
|
||||
<PackageReference Include="OpenTK.GLControl" Version="3.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CustomAfterBuild" AfterTargets="AfterBuild">
|
||||
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\Win32\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(SolutionDir)AssetStudioFBXNative\bin\x64\$(Configuration)\AssetStudioFBXNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\Win32\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)x86" ContinueOnError="true" />
|
||||
<Copy SourceFiles="$(SolutionDir)Texture2DDecoderNative\bin\x64\$(Configuration)\Texture2DDecoderNative.dll" DestinationFolder="$(TargetDir)x64" ContinueOnError="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
715
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
715
AssetStudioGUI/AssetStudioGUIForm.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -147,9 +147,6 @@ The quick brown fox jumps over the lazy dog. 1234567890</value>
|
||||
<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>
|
||||
|
||||
96
AssetStudioGUI/Components/AlphanumComparatorFast.cs
Normal file
96
AssetStudioGUI/Components/AlphanumComparatorFast.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
// This code developed by Dot Net Perls
|
||||
using System.Collections;
|
||||
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
internal class AlphanumComparatorFast : IComparer
|
||||
{
|
||||
public int Compare(object x, object y)
|
||||
{
|
||||
if (!(x is string s1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!(y is string s2))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int len1 = s1.Length;
|
||||
int len2 = s2.Length;
|
||||
int marker1 = 0;
|
||||
int marker2 = 0;
|
||||
|
||||
// Walk through two the strings with two markers.
|
||||
while (marker1 < len1 && marker2 < len2)
|
||||
{
|
||||
char ch1 = s1[marker1];
|
||||
char ch2 = s2[marker2];
|
||||
|
||||
// Some buffers we can build up characters in for each chunk.
|
||||
char[] space1 = new char[len1];
|
||||
int loc1 = 0;
|
||||
char[] space2 = new char[len2];
|
||||
int loc2 = 0;
|
||||
|
||||
// Walk through all following characters that are digits or
|
||||
// characters in BOTH strings starting at the appropriate marker.
|
||||
// Collect char arrays.
|
||||
do
|
||||
{
|
||||
space1[loc1++] = ch1;
|
||||
marker1++;
|
||||
|
||||
if (marker1 < len1)
|
||||
{
|
||||
ch1 = s1[marker1];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
|
||||
|
||||
do
|
||||
{
|
||||
space2[loc2++] = ch2;
|
||||
marker2++;
|
||||
|
||||
if (marker2 < len2)
|
||||
{
|
||||
ch2 = s2[marker2];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
|
||||
|
||||
// If we have collected numbers, compare them numerically.
|
||||
// Otherwise, if we have strings, compare them alphabetically.
|
||||
string str1 = new string(space1);
|
||||
string str2 = new string(space2);
|
||||
|
||||
int result;
|
||||
|
||||
if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
|
||||
{
|
||||
int thisNumericChunk = int.Parse(str1);
|
||||
int thatNumericChunk = int.Parse(str2);
|
||||
result = thisNumericChunk.CompareTo(thatNumericChunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = str1.CompareTo(str2);
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return len1 - len2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,11 @@ namespace AssetStudioGUI
|
||||
{
|
||||
public Object Asset;
|
||||
public SerializedFile SourceFile;
|
||||
public string Container = string.Empty;
|
||||
public string TypeString;
|
||||
public long m_PathID;
|
||||
public long FullSize;
|
||||
public ClassIDType Type;
|
||||
public string TypeString;
|
||||
|
||||
public string Extension;
|
||||
public string InfoText;
|
||||
public string UniqueID;
|
||||
public GameObjectTreeNode TreeNode;
|
||||
@@ -20,9 +20,21 @@ namespace AssetStudioGUI
|
||||
{
|
||||
Asset = asset;
|
||||
SourceFile = asset.assetsFile;
|
||||
FullSize = asset.byteSize;
|
||||
Type = asset.type;
|
||||
TypeString = Type.ToString();
|
||||
m_PathID = asset.m_PathID;
|
||||
FullSize = asset.byteSize;
|
||||
}
|
||||
|
||||
public void SetSubItems()
|
||||
{
|
||||
SubItems.AddRange(new[]
|
||||
{
|
||||
Container, //Container
|
||||
TypeString, //Type
|
||||
m_PathID.ToString(), //PathID
|
||||
FullSize.ToString(), //Size
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,11 @@ namespace AssetStudioGUI
|
||||
frm.GetOptions(out var options);
|
||||
options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT;
|
||||
frm.SetOptions(options);
|
||||
if (Title != null)
|
||||
if (!string.IsNullOrEmpty(Title))
|
||||
{
|
||||
frm.SetTitle(Title);
|
||||
if (InitialFolder != null)
|
||||
}
|
||||
if (!string.IsNullOrEmpty(InitialFolder))
|
||||
{
|
||||
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
|
||||
if (NativeMethods.SHCreateItemFromParsingName(InitialFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
|
||||
@@ -39,7 +41,7 @@ namespace AssetStudioGUI
|
||||
frm.SetFolder(directoryShellItem);
|
||||
}
|
||||
}
|
||||
if (DefaultFolder != null)
|
||||
if (!string.IsNullOrEmpty(DefaultFolder))
|
||||
{
|
||||
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
|
||||
if (NativeMethods.SHCreateItemFromParsingName(DefaultFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace AssetStudioGUI
|
||||
hItem = node.Handle,
|
||||
mask = TVIF_STATE,
|
||||
stateMask = TVIS_STATEIMAGEMASK,
|
||||
state = 0
|
||||
state = TVIS_STATEIMAGEMASK //temp bugfix for an issue with getting stuck during the "Building tree structure" step
|
||||
};
|
||||
SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
|
||||
}
|
||||
|
||||
@@ -7,19 +7,19 @@ namespace AssetStudioGUI
|
||||
{
|
||||
internal class TypeTreeItem : ListViewItem
|
||||
{
|
||||
private List<TypeTreeNode> m_Nodes;
|
||||
private TypeTree m_Type;
|
||||
|
||||
public TypeTreeItem(int typeID, List<TypeTreeNode> m_Nodes)
|
||||
public TypeTreeItem(int typeID, TypeTree m_Type)
|
||||
{
|
||||
this.m_Nodes = m_Nodes;
|
||||
Text = m_Nodes[0].m_Type + " " + m_Nodes[0].m_Name;
|
||||
this.m_Type = m_Type;
|
||||
Text = m_Type.m_Nodes[0].m_Type + " " + m_Type.m_Nodes[0].m_Name;
|
||||
SubItems.Add(typeID.ToString());
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var i in m_Nodes)
|
||||
foreach (var i in m_Type.m_Nodes)
|
||||
{
|
||||
sb.AppendFormat("{0}{1} {2} {3} {4}\r\n", new string('\t', i.m_Level), i.m_Type, i.m_Name, i.m_ByteSize, (i.m_MetaFlag & 0x4000) != 0);
|
||||
}
|
||||
|
||||
308
AssetStudioGUI/ExportOptions.Designer.cs
generated
308
AssetStudioGUI/ExportOptions.Designer.cs
generated
@@ -28,31 +28,40 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.OKbutton = new System.Windows.Forms.Button();
|
||||
this.Cancel = new System.Windows.Forms.Button();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.openAfterExport = new System.Windows.Forms.CheckBox();
|
||||
this.restoreExtensionName = new System.Windows.Forms.CheckBox();
|
||||
this.assetGroupOptions = new System.Windows.Forms.ComboBox();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.convertAudio = new System.Windows.Forms.CheckBox();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.totga = new System.Windows.Forms.RadioButton();
|
||||
this.tojpg = new System.Windows.Forms.RadioButton();
|
||||
this.topng = new System.Windows.Forms.RadioButton();
|
||||
this.tobmp = new System.Windows.Forms.RadioButton();
|
||||
this.converttexture = new System.Windows.Forms.CheckBox();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.exportAllUvsAsDiffuseMaps = new System.Windows.Forms.CheckBox();
|
||||
this.exportBlendShape = new System.Windows.Forms.CheckBox();
|
||||
this.exportAnimations = new System.Windows.Forms.CheckBox();
|
||||
this.scaleFactor = new System.Windows.Forms.NumericUpDown();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
this.fbxFormat = new System.Windows.Forms.ComboBox();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.fbxVersion = new System.Windows.Forms.ComboBox();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.flatInbetween = new System.Windows.Forms.CheckBox();
|
||||
this.boneSize = new System.Windows.Forms.NumericUpDown();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.skins = new System.Windows.Forms.CheckBox();
|
||||
this.exportSkins = new System.Windows.Forms.CheckBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.filterPrecision = new System.Windows.Forms.NumericUpDown();
|
||||
this.allBones = new System.Windows.Forms.CheckBox();
|
||||
this.allFrames = new System.Windows.Forms.CheckBox();
|
||||
this.castToBone = new System.Windows.Forms.CheckBox();
|
||||
this.exportAllNodes = new System.Windows.Forms.CheckBox();
|
||||
this.eulerFilter = new System.Windows.Forms.CheckBox();
|
||||
this.exportUvsTooltip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
@@ -63,20 +72,20 @@
|
||||
//
|
||||
// OKbutton
|
||||
//
|
||||
this.OKbutton.Location = new System.Drawing.Point(321, 267);
|
||||
this.OKbutton.Location = new System.Drawing.Point(318, 380);
|
||||
this.OKbutton.Name = "OKbutton";
|
||||
this.OKbutton.Size = new System.Drawing.Size(75, 21);
|
||||
this.OKbutton.Size = new System.Drawing.Size(75, 23);
|
||||
this.OKbutton.TabIndex = 6;
|
||||
this.OKbutton.Text = "OK";
|
||||
this.OKbutton.UseVisualStyleBackColor = true;
|
||||
this.OKbutton.Click += new System.EventHandler(this.fbxOKbutton_Click);
|
||||
this.OKbutton.Click += new System.EventHandler(this.OKbutton_Click);
|
||||
//
|
||||
// Cancel
|
||||
//
|
||||
this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.Cancel.Location = new System.Drawing.Point(402, 267);
|
||||
this.Cancel.Location = new System.Drawing.Point(399, 380);
|
||||
this.Cancel.Name = "Cancel";
|
||||
this.Cancel.Size = new System.Drawing.Size(75, 21);
|
||||
this.Cancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.Cancel.TabIndex = 7;
|
||||
this.Cancel.Text = "Cancel";
|
||||
this.Cancel.UseVisualStyleBackColor = true;
|
||||
@@ -85,68 +94,130 @@
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.AutoSize = true;
|
||||
this.groupBox1.Controls.Add(this.openAfterExport);
|
||||
this.groupBox1.Controls.Add(this.restoreExtensionName);
|
||||
this.groupBox1.Controls.Add(this.assetGroupOptions);
|
||||
this.groupBox1.Controls.Add(this.label6);
|
||||
this.groupBox1.Controls.Add(this.convertAudio);
|
||||
this.groupBox1.Controls.Add(this.panel1);
|
||||
this.groupBox1.Controls.Add(this.converttexture);
|
||||
this.groupBox1.Location = new System.Drawing.Point(232, 12);
|
||||
this.groupBox1.Location = new System.Drawing.Point(12, 13);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(245, 114);
|
||||
this.groupBox1.Size = new System.Drawing.Size(232, 362);
|
||||
this.groupBox1.TabIndex = 9;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Convert";
|
||||
this.groupBox1.Text = "Export";
|
||||
//
|
||||
// openAfterExport
|
||||
//
|
||||
this.openAfterExport.AutoSize = true;
|
||||
this.openAfterExport.Checked = true;
|
||||
this.openAfterExport.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.openAfterExport.Location = new System.Drawing.Point(6, 173);
|
||||
this.openAfterExport.Name = "openAfterExport";
|
||||
this.openAfterExport.Size = new System.Drawing.Size(137, 17);
|
||||
this.openAfterExport.TabIndex = 10;
|
||||
this.openAfterExport.Text = "Open folder after export";
|
||||
this.openAfterExport.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// restoreExtensionName
|
||||
//
|
||||
this.restoreExtensionName.AutoSize = true;
|
||||
this.restoreExtensionName.Checked = true;
|
||||
this.restoreExtensionName.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.restoreExtensionName.Location = new System.Drawing.Point(6, 63);
|
||||
this.restoreExtensionName.Name = "restoreExtensionName";
|
||||
this.restoreExtensionName.Size = new System.Drawing.Size(190, 17);
|
||||
this.restoreExtensionName.TabIndex = 9;
|
||||
this.restoreExtensionName.Text = "Restore TextAsset extension name";
|
||||
this.restoreExtensionName.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// assetGroupOptions
|
||||
//
|
||||
this.assetGroupOptions.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.assetGroupOptions.FormattingEnabled = true;
|
||||
this.assetGroupOptions.Items.AddRange(new object[] {
|
||||
"type name",
|
||||
"container path",
|
||||
"source file name",
|
||||
"do not group"});
|
||||
this.assetGroupOptions.Location = new System.Drawing.Point(6, 35);
|
||||
this.assetGroupOptions.Name = "assetGroupOptions";
|
||||
this.assetGroupOptions.Size = new System.Drawing.Size(149, 21);
|
||||
this.assetGroupOptions.TabIndex = 8;
|
||||
//
|
||||
// label6
|
||||
//
|
||||
this.label6.AutoSize = true;
|
||||
this.label6.Location = new System.Drawing.Point(6, 18);
|
||||
this.label6.Name = "label6";
|
||||
this.label6.Size = new System.Drawing.Size(127, 13);
|
||||
this.label6.TabIndex = 7;
|
||||
this.label6.Text = "Group exported assets by";
|
||||
//
|
||||
// convertAudio
|
||||
//
|
||||
this.convertAudio.AutoSize = true;
|
||||
this.convertAudio.Checked = true;
|
||||
this.convertAudio.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.convertAudio.Location = new System.Drawing.Point(6, 78);
|
||||
this.convertAudio.Location = new System.Drawing.Point(6, 150);
|
||||
this.convertAudio.Name = "convertAudio";
|
||||
this.convertAudio.Size = new System.Drawing.Size(198, 16);
|
||||
this.convertAudio.Size = new System.Drawing.Size(179, 17);
|
||||
this.convertAudio.TabIndex = 6;
|
||||
this.convertAudio.Text = "Convert AudioClip to WAV(PCM)";
|
||||
this.convertAudio.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.Controls.Add(this.totga);
|
||||
this.panel1.Controls.Add(this.tojpg);
|
||||
this.panel1.Controls.Add(this.topng);
|
||||
this.panel1.Controls.Add(this.tobmp);
|
||||
this.panel1.Location = new System.Drawing.Point(30, 42);
|
||||
this.panel1.Location = new System.Drawing.Point(20, 111);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(146, 30);
|
||||
this.panel1.Size = new System.Drawing.Size(202, 33);
|
||||
this.panel1.TabIndex = 5;
|
||||
//
|
||||
// totga
|
||||
//
|
||||
this.totga.AutoSize = true;
|
||||
this.totga.Location = new System.Drawing.Point(150, 7);
|
||||
this.totga.Name = "totga";
|
||||
this.totga.Size = new System.Drawing.Size(44, 17);
|
||||
this.totga.TabIndex = 2;
|
||||
this.totga.Text = "Tga";
|
||||
this.totga.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tojpg
|
||||
//
|
||||
this.tojpg.AutoSize = true;
|
||||
this.tojpg.Location = new System.Drawing.Point(97, 6);
|
||||
this.tojpg.Location = new System.Drawing.Point(97, 7);
|
||||
this.tojpg.Name = "tojpg";
|
||||
this.tojpg.Size = new System.Drawing.Size(47, 16);
|
||||
this.tojpg.Size = new System.Drawing.Size(48, 17);
|
||||
this.tojpg.TabIndex = 4;
|
||||
this.tojpg.Text = "JPEG";
|
||||
this.tojpg.Text = "Jpeg";
|
||||
this.tojpg.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// topng
|
||||
//
|
||||
this.topng.AutoSize = true;
|
||||
this.topng.Checked = true;
|
||||
this.topng.Location = new System.Drawing.Point(50, 6);
|
||||
this.topng.Location = new System.Drawing.Point(50, 7);
|
||||
this.topng.Name = "topng";
|
||||
this.topng.Size = new System.Drawing.Size(41, 16);
|
||||
this.topng.Size = new System.Drawing.Size(44, 17);
|
||||
this.topng.TabIndex = 3;
|
||||
this.topng.TabStop = true;
|
||||
this.topng.Text = "PNG";
|
||||
this.topng.Text = "Png";
|
||||
this.topng.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tobmp
|
||||
//
|
||||
this.tobmp.AutoSize = true;
|
||||
this.tobmp.Location = new System.Drawing.Point(3, 6);
|
||||
this.tobmp.Location = new System.Drawing.Point(3, 7);
|
||||
this.tobmp.Name = "tobmp";
|
||||
this.tobmp.Size = new System.Drawing.Size(41, 16);
|
||||
this.tobmp.Size = new System.Drawing.Size(46, 17);
|
||||
this.tobmp.TabIndex = 2;
|
||||
this.tobmp.Text = "BMP";
|
||||
this.tobmp.Text = "Bmp";
|
||||
this.tobmp.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// converttexture
|
||||
@@ -154,9 +225,9 @@
|
||||
this.converttexture.AutoSize = true;
|
||||
this.converttexture.Checked = true;
|
||||
this.converttexture.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.converttexture.Location = new System.Drawing.Point(6, 20);
|
||||
this.converttexture.Location = new System.Drawing.Point(6, 87);
|
||||
this.converttexture.Name = "converttexture";
|
||||
this.converttexture.Size = new System.Drawing.Size(126, 16);
|
||||
this.converttexture.Size = new System.Drawing.Size(116, 17);
|
||||
this.converttexture.TabIndex = 1;
|
||||
this.converttexture.Text = "Convert Texture2D";
|
||||
this.converttexture.UseVisualStyleBackColor = true;
|
||||
@@ -164,28 +235,67 @@
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.AutoSize = true;
|
||||
this.groupBox2.Controls.Add(this.exportAllUvsAsDiffuseMaps);
|
||||
this.groupBox2.Controls.Add(this.exportBlendShape);
|
||||
this.groupBox2.Controls.Add(this.exportAnimations);
|
||||
this.groupBox2.Controls.Add(this.scaleFactor);
|
||||
this.groupBox2.Controls.Add(this.label5);
|
||||
this.groupBox2.Controls.Add(this.fbxFormat);
|
||||
this.groupBox2.Controls.Add(this.label4);
|
||||
this.groupBox2.Controls.Add(this.fbxVersion);
|
||||
this.groupBox2.Controls.Add(this.label3);
|
||||
this.groupBox2.Controls.Add(this.flatInbetween);
|
||||
this.groupBox2.Controls.Add(this.boneSize);
|
||||
this.groupBox2.Controls.Add(this.label2);
|
||||
this.groupBox2.Controls.Add(this.skins);
|
||||
this.groupBox2.Controls.Add(this.exportSkins);
|
||||
this.groupBox2.Controls.Add(this.label1);
|
||||
this.groupBox2.Controls.Add(this.filterPrecision);
|
||||
this.groupBox2.Controls.Add(this.allBones);
|
||||
this.groupBox2.Controls.Add(this.allFrames);
|
||||
this.groupBox2.Controls.Add(this.castToBone);
|
||||
this.groupBox2.Controls.Add(this.exportAllNodes);
|
||||
this.groupBox2.Controls.Add(this.eulerFilter);
|
||||
this.groupBox2.Location = new System.Drawing.Point(12, 12);
|
||||
this.groupBox2.Location = new System.Drawing.Point(250, 13);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(214, 276);
|
||||
this.groupBox2.Size = new System.Drawing.Size(224, 362);
|
||||
this.groupBox2.TabIndex = 11;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Fbx";
|
||||
//
|
||||
// exportAllUvsAsDiffuseMaps
|
||||
//
|
||||
this.exportAllUvsAsDiffuseMaps.AccessibleDescription = "";
|
||||
this.exportAllUvsAsDiffuseMaps.AutoSize = true;
|
||||
this.exportAllUvsAsDiffuseMaps.Location = new System.Drawing.Point(6, 185);
|
||||
this.exportAllUvsAsDiffuseMaps.Name = "exportAllUvsAsDiffuseMaps";
|
||||
this.exportAllUvsAsDiffuseMaps.Size = new System.Drawing.Size(168, 17);
|
||||
this.exportAllUvsAsDiffuseMaps.TabIndex = 23;
|
||||
this.exportAllUvsAsDiffuseMaps.Text = "Export all UVs as diffuse maps";
|
||||
this.exportUvsTooltip.SetToolTip(this.exportAllUvsAsDiffuseMaps, "Unchecked: UV1 exported as normal map. Check this if your export is missing a UV " +
|
||||
"map.");
|
||||
this.exportAllUvsAsDiffuseMaps.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// exportBlendShape
|
||||
//
|
||||
this.exportBlendShape.AutoSize = true;
|
||||
this.exportBlendShape.Checked = true;
|
||||
this.exportBlendShape.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.exportBlendShape.Location = new System.Drawing.Point(6, 138);
|
||||
this.exportBlendShape.Name = "exportBlendShape";
|
||||
this.exportBlendShape.Size = new System.Drawing.Size(114, 17);
|
||||
this.exportBlendShape.TabIndex = 22;
|
||||
this.exportBlendShape.Text = "Export blendshape";
|
||||
this.exportBlendShape.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// exportAnimations
|
||||
//
|
||||
this.exportAnimations.AutoSize = true;
|
||||
this.exportAnimations.Checked = true;
|
||||
this.exportAnimations.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.exportAnimations.Location = new System.Drawing.Point(6, 114);
|
||||
this.exportAnimations.Name = "exportAnimations";
|
||||
this.exportAnimations.Size = new System.Drawing.Size(109, 17);
|
||||
this.exportAnimations.TabIndex = 21;
|
||||
this.exportAnimations.Text = "Export animations";
|
||||
this.exportAnimations.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// scaleFactor
|
||||
//
|
||||
this.scaleFactor.DecimalPlaces = 2;
|
||||
@@ -194,9 +304,9 @@
|
||||
0,
|
||||
0,
|
||||
131072});
|
||||
this.scaleFactor.Location = new System.Drawing.Point(83, 155);
|
||||
this.scaleFactor.Location = new System.Drawing.Point(83, 243);
|
||||
this.scaleFactor.Name = "scaleFactor";
|
||||
this.scaleFactor.Size = new System.Drawing.Size(60, 21);
|
||||
this.scaleFactor.Size = new System.Drawing.Size(60, 20);
|
||||
this.scaleFactor.TabIndex = 20;
|
||||
this.scaleFactor.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.scaleFactor.Value = new decimal(new int[] {
|
||||
@@ -208,9 +318,9 @@
|
||||
// label5
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.label5.Location = new System.Drawing.Point(6, 157);
|
||||
this.label5.Location = new System.Drawing.Point(6, 245);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(71, 12);
|
||||
this.label5.Size = new System.Drawing.Size(64, 13);
|
||||
this.label5.TabIndex = 19;
|
||||
this.label5.Text = "ScaleFactor";
|
||||
//
|
||||
@@ -221,17 +331,17 @@
|
||||
this.fbxFormat.Items.AddRange(new object[] {
|
||||
"Binary",
|
||||
"Ascii"});
|
||||
this.fbxFormat.Location = new System.Drawing.Point(75, 207);
|
||||
this.fbxFormat.Location = new System.Drawing.Point(77, 275);
|
||||
this.fbxFormat.Name = "fbxFormat";
|
||||
this.fbxFormat.Size = new System.Drawing.Size(61, 20);
|
||||
this.fbxFormat.Size = new System.Drawing.Size(61, 21);
|
||||
this.fbxFormat.TabIndex = 18;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(4, 210);
|
||||
this.label4.Location = new System.Drawing.Point(6, 280);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(59, 12);
|
||||
this.label4.Size = new System.Drawing.Size(59, 13);
|
||||
this.label4.TabIndex = 17;
|
||||
this.label4.Text = "FBXFormat";
|
||||
//
|
||||
@@ -246,35 +356,25 @@
|
||||
"7.3",
|
||||
"7.4",
|
||||
"7.5"});
|
||||
this.fbxVersion.Location = new System.Drawing.Point(75, 236);
|
||||
this.fbxVersion.Location = new System.Drawing.Point(77, 308);
|
||||
this.fbxVersion.Name = "fbxVersion";
|
||||
this.fbxVersion.Size = new System.Drawing.Size(47, 20);
|
||||
this.fbxVersion.Size = new System.Drawing.Size(47, 21);
|
||||
this.fbxVersion.TabIndex = 16;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(4, 239);
|
||||
this.label3.Location = new System.Drawing.Point(6, 311);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(65, 12);
|
||||
this.label3.Size = new System.Drawing.Size(62, 13);
|
||||
this.label3.TabIndex = 15;
|
||||
this.label3.Text = "FBXVersion";
|
||||
//
|
||||
// flatInbetween
|
||||
//
|
||||
this.flatInbetween.AutoSize = true;
|
||||
this.flatInbetween.Location = new System.Drawing.Point(6, 182);
|
||||
this.flatInbetween.Name = "flatInbetween";
|
||||
this.flatInbetween.Size = new System.Drawing.Size(102, 16);
|
||||
this.flatInbetween.TabIndex = 12;
|
||||
this.flatInbetween.Text = "FlatInbetween";
|
||||
this.flatInbetween.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// boneSize
|
||||
//
|
||||
this.boneSize.Location = new System.Drawing.Point(65, 128);
|
||||
this.boneSize.Location = new System.Drawing.Point(65, 213);
|
||||
this.boneSize.Name = "boneSize";
|
||||
this.boneSize.Size = new System.Drawing.Size(46, 21);
|
||||
this.boneSize.Size = new System.Drawing.Size(46, 20);
|
||||
this.boneSize.TabIndex = 11;
|
||||
this.boneSize.Value = new decimal(new int[] {
|
||||
10,
|
||||
@@ -285,30 +385,30 @@
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(6, 130);
|
||||
this.label2.Location = new System.Drawing.Point(6, 216);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(53, 12);
|
||||
this.label2.Size = new System.Drawing.Size(52, 13);
|
||||
this.label2.TabIndex = 10;
|
||||
this.label2.Text = "BoneSize";
|
||||
//
|
||||
// skins
|
||||
// exportSkins
|
||||
//
|
||||
this.skins.AutoSize = true;
|
||||
this.skins.Checked = true;
|
||||
this.skins.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.skins.Location = new System.Drawing.Point(6, 105);
|
||||
this.skins.Name = "skins";
|
||||
this.skins.Size = new System.Drawing.Size(54, 16);
|
||||
this.skins.TabIndex = 8;
|
||||
this.skins.Text = "Skins";
|
||||
this.skins.UseVisualStyleBackColor = true;
|
||||
this.exportSkins.AutoSize = true;
|
||||
this.exportSkins.Checked = true;
|
||||
this.exportSkins.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.exportSkins.Location = new System.Drawing.Point(6, 90);
|
||||
this.exportSkins.Name = "exportSkins";
|
||||
this.exportSkins.Size = new System.Drawing.Size(83, 17);
|
||||
this.exportSkins.TabIndex = 8;
|
||||
this.exportSkins.Text = "Export skins";
|
||||
this.exportSkins.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(26, 39);
|
||||
this.label1.Location = new System.Drawing.Point(26, 42);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(95, 12);
|
||||
this.label1.Size = new System.Drawing.Size(72, 13);
|
||||
this.label1.TabIndex = 7;
|
||||
this.label1.Text = "FilterPrecision";
|
||||
//
|
||||
@@ -320,9 +420,9 @@
|
||||
0,
|
||||
0,
|
||||
131072});
|
||||
this.filterPrecision.Location = new System.Drawing.Point(127, 37);
|
||||
this.filterPrecision.Location = new System.Drawing.Point(127, 40);
|
||||
this.filterPrecision.Name = "filterPrecision";
|
||||
this.filterPrecision.Size = new System.Drawing.Size(51, 21);
|
||||
this.filterPrecision.Size = new System.Drawing.Size(51, 20);
|
||||
this.filterPrecision.TabIndex = 6;
|
||||
this.filterPrecision.Value = new decimal(new int[] {
|
||||
25,
|
||||
@@ -330,36 +430,36 @@
|
||||
0,
|
||||
131072});
|
||||
//
|
||||
// allBones
|
||||
// castToBone
|
||||
//
|
||||
this.allBones.AutoSize = true;
|
||||
this.allBones.Checked = true;
|
||||
this.allBones.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.allBones.Location = new System.Drawing.Point(6, 83);
|
||||
this.allBones.Name = "allBones";
|
||||
this.allBones.Size = new System.Drawing.Size(72, 16);
|
||||
this.allBones.TabIndex = 5;
|
||||
this.allBones.Text = "AllBones";
|
||||
this.allBones.UseVisualStyleBackColor = true;
|
||||
this.castToBone.AutoSize = true;
|
||||
this.castToBone.Location = new System.Drawing.Point(6, 161);
|
||||
this.castToBone.Name = "castToBone";
|
||||
this.castToBone.Size = new System.Drawing.Size(131, 17);
|
||||
this.castToBone.TabIndex = 5;
|
||||
this.castToBone.Text = "All nodes cast to bone";
|
||||
this.castToBone.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// allFrames
|
||||
// exportAllNodes
|
||||
//
|
||||
this.allFrames.AutoSize = true;
|
||||
this.allFrames.Location = new System.Drawing.Point(6, 61);
|
||||
this.allFrames.Name = "allFrames";
|
||||
this.allFrames.Size = new System.Drawing.Size(78, 16);
|
||||
this.allFrames.TabIndex = 4;
|
||||
this.allFrames.Text = "AllFrames";
|
||||
this.allFrames.UseVisualStyleBackColor = true;
|
||||
this.exportAllNodes.AutoSize = true;
|
||||
this.exportAllNodes.Checked = true;
|
||||
this.exportAllNodes.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.exportAllNodes.Location = new System.Drawing.Point(6, 66);
|
||||
this.exportAllNodes.Name = "exportAllNodes";
|
||||
this.exportAllNodes.Size = new System.Drawing.Size(101, 17);
|
||||
this.exportAllNodes.TabIndex = 4;
|
||||
this.exportAllNodes.Text = "Export all nodes";
|
||||
this.exportAllNodes.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// eulerFilter
|
||||
//
|
||||
this.eulerFilter.AutoSize = true;
|
||||
this.eulerFilter.Checked = true;
|
||||
this.eulerFilter.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.eulerFilter.Location = new System.Drawing.Point(6, 20);
|
||||
this.eulerFilter.Location = new System.Drawing.Point(6, 22);
|
||||
this.eulerFilter.Name = "eulerFilter";
|
||||
this.eulerFilter.Size = new System.Drawing.Size(90, 16);
|
||||
this.eulerFilter.Size = new System.Drawing.Size(72, 17);
|
||||
this.eulerFilter.TabIndex = 3;
|
||||
this.eulerFilter.Text = "EulerFilter";
|
||||
this.eulerFilter.UseVisualStyleBackColor = true;
|
||||
@@ -367,19 +467,19 @@
|
||||
// ExportOptions
|
||||
//
|
||||
this.AcceptButton = this.OKbutton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.Cancel;
|
||||
this.ClientSize = new System.Drawing.Size(490, 301);
|
||||
this.ClientSize = new System.Drawing.Size(486, 416);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.Cancel);
|
||||
this.Controls.Add(this.OKbutton);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "ExportOptions";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Export options";
|
||||
this.TopMost = true;
|
||||
@@ -405,17 +505,17 @@
|
||||
private System.Windows.Forms.RadioButton tojpg;
|
||||
private System.Windows.Forms.RadioButton topng;
|
||||
private System.Windows.Forms.RadioButton tobmp;
|
||||
private System.Windows.Forms.RadioButton totga;
|
||||
private System.Windows.Forms.CheckBox convertAudio;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.CheckBox flatInbetween;
|
||||
private System.Windows.Forms.NumericUpDown boneSize;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.CheckBox skins;
|
||||
private System.Windows.Forms.CheckBox exportSkins;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.NumericUpDown filterPrecision;
|
||||
private System.Windows.Forms.CheckBox allBones;
|
||||
private System.Windows.Forms.CheckBox allFrames;
|
||||
private System.Windows.Forms.CheckBox castToBone;
|
||||
private System.Windows.Forms.CheckBox exportAllNodes;
|
||||
private System.Windows.Forms.CheckBox eulerFilter;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.ComboBox fbxVersion;
|
||||
@@ -423,5 +523,13 @@
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.NumericUpDown scaleFactor;
|
||||
private System.Windows.Forms.Label label5;
|
||||
private System.Windows.Forms.CheckBox exportBlendShape;
|
||||
private System.Windows.Forms.CheckBox exportAnimations;
|
||||
private System.Windows.Forms.ComboBox assetGroupOptions;
|
||||
private System.Windows.Forms.Label label6;
|
||||
private System.Windows.Forms.CheckBox restoreExtensionName;
|
||||
private System.Windows.Forms.CheckBox openAfterExport;
|
||||
private System.Windows.Forms.CheckBox exportAllUvsAsDiffuseMaps;
|
||||
private System.Windows.Forms.ToolTip exportUvsTooltip;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
@@ -15,9 +9,11 @@ namespace AssetStudioGUI
|
||||
public ExportOptions()
|
||||
{
|
||||
InitializeComponent();
|
||||
converttexture.Checked = (bool)Properties.Settings.Default["convertTexture"];
|
||||
convertAudio.Checked = (bool)Properties.Settings.Default["convertAudio"];
|
||||
var str = (string)Properties.Settings.Default["convertType"];
|
||||
assetGroupOptions.SelectedIndex = Properties.Settings.Default.assetGroupOption;
|
||||
restoreExtensionName.Checked = Properties.Settings.Default.restoreExtensionName;
|
||||
converttexture.Checked = Properties.Settings.Default.convertTexture;
|
||||
convertAudio.Checked = Properties.Settings.Default.convertAudio;
|
||||
var str = Properties.Settings.Default.convertType.ToString();
|
||||
foreach (Control c in panel1.Controls)
|
||||
{
|
||||
if (c.Text == str)
|
||||
@@ -26,46 +22,49 @@ namespace AssetStudioGUI
|
||||
break;
|
||||
}
|
||||
}
|
||||
eulerFilter.Checked = (bool)Properties.Settings.Default["eulerFilter"];
|
||||
filterPrecision.Value = (decimal)Properties.Settings.Default["filterPrecision"];
|
||||
allFrames.Checked = (bool)Properties.Settings.Default["allFrames"];
|
||||
allBones.Checked = (bool)Properties.Settings.Default["allBones"];
|
||||
skins.Checked = (bool)Properties.Settings.Default["skins"];
|
||||
boneSize.Value = (decimal)Properties.Settings.Default["boneSize"];
|
||||
scaleFactor.Value = (decimal)Properties.Settings.Default["scaleFactor"];
|
||||
flatInbetween.Checked = (bool)Properties.Settings.Default["flatInbetween"];
|
||||
fbxVersion.SelectedIndex = (int)Properties.Settings.Default["fbxVersion"];
|
||||
fbxFormat.SelectedIndex = (int)Properties.Settings.Default["fbxFormat"];
|
||||
openAfterExport.Checked = Properties.Settings.Default.openAfterExport;
|
||||
eulerFilter.Checked = Properties.Settings.Default.eulerFilter;
|
||||
filterPrecision.Value = Properties.Settings.Default.filterPrecision;
|
||||
exportAllNodes.Checked = Properties.Settings.Default.exportAllNodes;
|
||||
exportSkins.Checked = Properties.Settings.Default.exportSkins;
|
||||
exportAnimations.Checked = Properties.Settings.Default.exportAnimations;
|
||||
exportBlendShape.Checked = Properties.Settings.Default.exportBlendShape;
|
||||
castToBone.Checked = Properties.Settings.Default.castToBone;
|
||||
exportAllUvsAsDiffuseMaps.Checked = Properties.Settings.Default.exportAllUvsAsDiffuseMaps;
|
||||
boneSize.Value = Properties.Settings.Default.boneSize;
|
||||
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
|
||||
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
|
||||
fbxFormat.SelectedIndex = Properties.Settings.Default.fbxFormat;
|
||||
|
||||
}
|
||||
|
||||
private void exportOpnions_CheckedChanged(object sender, EventArgs e)
|
||||
private void OKbutton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default[((CheckBox)sender).Name] = ((CheckBox)sender).Checked;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void fbxOKbutton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default["convertTexture"] = converttexture.Checked;
|
||||
Properties.Settings.Default["convertAudio"] = convertAudio.Checked;
|
||||
Properties.Settings.Default.assetGroupOption = assetGroupOptions.SelectedIndex;
|
||||
Properties.Settings.Default.restoreExtensionName = restoreExtensionName.Checked;
|
||||
Properties.Settings.Default.convertTexture = converttexture.Checked;
|
||||
Properties.Settings.Default.convertAudio = convertAudio.Checked;
|
||||
foreach (Control c in panel1.Controls)
|
||||
{
|
||||
if (((RadioButton)c).Checked)
|
||||
{
|
||||
Properties.Settings.Default["convertType"] = c.Text;
|
||||
Properties.Settings.Default.convertType = (ImageFormat)Enum.Parse(typeof(ImageFormat), c.Text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Properties.Settings.Default["eulerFilter"] = eulerFilter.Checked;
|
||||
Properties.Settings.Default["filterPrecision"] = filterPrecision.Value;
|
||||
Properties.Settings.Default["allFrames"] = allFrames.Checked;
|
||||
Properties.Settings.Default["allBones"] = allBones.Checked;
|
||||
Properties.Settings.Default["skins"] = skins.Checked;
|
||||
Properties.Settings.Default["boneSize"] = boneSize.Value;
|
||||
Properties.Settings.Default["scaleFactor"] = scaleFactor.Value;
|
||||
Properties.Settings.Default["flatInbetween"] = flatInbetween.Checked;
|
||||
Properties.Settings.Default["fbxVersion"] = fbxVersion.SelectedIndex;
|
||||
Properties.Settings.Default["fbxFormat"] = fbxFormat.SelectedIndex;
|
||||
Properties.Settings.Default.openAfterExport = openAfterExport.Checked;
|
||||
Properties.Settings.Default.eulerFilter = eulerFilter.Checked;
|
||||
Properties.Settings.Default.filterPrecision = filterPrecision.Value;
|
||||
Properties.Settings.Default.exportAllNodes = exportAllNodes.Checked;
|
||||
Properties.Settings.Default.exportSkins = exportSkins.Checked;
|
||||
Properties.Settings.Default.exportAnimations = exportAnimations.Checked;
|
||||
Properties.Settings.Default.exportBlendShape = exportBlendShape.Checked;
|
||||
Properties.Settings.Default.castToBone = castToBone.Checked;
|
||||
Properties.Settings.Default.exportAllUvsAsDiffuseMaps = exportAllUvsAsDiffuseMaps.Checked;
|
||||
Properties.Settings.Default.boneSize = boneSize.Value;
|
||||
Properties.Settings.Default.scaleFactor = scaleFactor.Value;
|
||||
Properties.Settings.Default.fbxVersion = fbxVersion.SelectedIndex;
|
||||
Properties.Settings.Default.fbxFormat = fbxFormat.SelectedIndex;
|
||||
Properties.Settings.Default.Save();
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
@@ -76,5 +75,6 @@ namespace AssetStudioGUI
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,4 +117,10 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="exportUvsTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="exportUvsTooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -1,50 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Imaging;
|
||||
using AssetStudio;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AssetStudio;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
internal static class Exporter
|
||||
{
|
||||
public static bool ExportTexture2D(AssetItem item, string exportPathName)
|
||||
public static bool ExportTexture2D(AssetItem item, string exportPath)
|
||||
{
|
||||
var converter = new Texture2DConverter((Texture2D)item.Asset);
|
||||
var convertTexture = (bool)Properties.Settings.Default["convertTexture"];
|
||||
if (convertTexture)
|
||||
var m_Texture2D = (Texture2D)item.Asset;
|
||||
if (Properties.Settings.Default.convertTexture)
|
||||
{
|
||||
var bitmap = converter.ConvertToBitmap(true);
|
||||
if (bitmap == null)
|
||||
var type = Properties.Settings.Default.convertType;
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
ImageFormat format = null;
|
||||
var ext = (string)Properties.Settings.Default["convertType"];
|
||||
switch (ext)
|
||||
var stream = m_Texture2D.ConvertToStream(type, true);
|
||||
if (stream == null)
|
||||
return false;
|
||||
using (stream)
|
||||
{
|
||||
case "BMP":
|
||||
format = ImageFormat.Bmp;
|
||||
break;
|
||||
case "PNG":
|
||||
format = ImageFormat.Png;
|
||||
break;
|
||||
case "JPEG":
|
||||
format = ImageFormat.Jpeg;
|
||||
break;
|
||||
File.WriteAllBytes(exportFullPath, stream.ToArray());
|
||||
return true;
|
||||
}
|
||||
var exportFullName = exportPathName + item.Text + "." + ext.ToLower();
|
||||
if (ExportFileExists(exportFullName))
|
||||
return false;
|
||||
bitmap.Save(exportFullName, format);
|
||||
bitmap.Dispose();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var exportFullName = exportPathName + item.Text + converter.GetExtensionName();
|
||||
if (ExportFileExists(exportFullName))
|
||||
if (!TryExportFile(exportPath, item, ".tex", out var exportFullPath))
|
||||
return false;
|
||||
File.WriteAllBytes(exportFullName, converter.ConvertToContainer());
|
||||
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -52,72 +38,68 @@ namespace AssetStudioGUI
|
||||
public static bool ExportAudioClip(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_AudioClip = (AudioClip)item.Asset;
|
||||
var m_AudioData = m_AudioClip.m_AudioData.Value;
|
||||
var m_AudioData = m_AudioClip.m_AudioData.GetData();
|
||||
if (m_AudioData == null || m_AudioData.Length == 0)
|
||||
return false;
|
||||
var convertAudio = (bool)Properties.Settings.Default["convertAudio"];
|
||||
var converter = new AudioClipConverter(m_AudioClip);
|
||||
if (convertAudio && converter.IsFMODSupport)
|
||||
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 m_Shader = (Shader)item.Asset;
|
||||
var str = m_Shader.Convert();
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportTextAsset(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_TextAsset = (TextAsset)(item.Asset);
|
||||
var exportFullName = exportPath + item.Text + (item.Extension ?? ".txt");
|
||||
if (ExportFileExists(exportFullName))
|
||||
var extension = ".txt";
|
||||
if (Properties.Settings.Default.restoreExtensionName)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(item.Container))
|
||||
{
|
||||
extension = Path.GetExtension(item.Container);
|
||||
}
|
||||
}
|
||||
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 m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
|
||||
type = m_MonoBehaviour.ToType(m_Type);
|
||||
}
|
||||
var str = JsonConvert.SerializeObject(type, Formatting.Indented);
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -131,10 +113,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;
|
||||
@@ -145,8 +126,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);
|
||||
@@ -167,24 +147,25 @@ namespace AssetStudioGUI
|
||||
#endregion
|
||||
|
||||
#region UV
|
||||
if (m_Mesh.m_UV0 != null && m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 2)
|
||||
if (m_Mesh.m_UV0?.Length > 0)
|
||||
{
|
||||
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
|
||||
if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 2)
|
||||
{
|
||||
sb.AppendFormat("vt {0} {1}\r\n", m_Mesh.m_UV0[v * 2], m_Mesh.m_UV0[v * 2 + 1]);
|
||||
c = 2;
|
||||
}
|
||||
else if (m_Mesh.m_UV0.Length == m_Mesh.m_VertexCount * 3)
|
||||
{
|
||||
c = 3;
|
||||
}
|
||||
}
|
||||
else if (m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length == m_Mesh.m_VertexCount * 2)
|
||||
{
|
||||
for (int v = 0; v < m_Mesh.m_VertexCount; v++)
|
||||
{
|
||||
sb.AppendFormat("vt {0} {1}\r\n", m_Mesh.m_UV1[v * 2], m_Mesh.m_UV1[v * 2 + 1]);
|
||||
sb.AppendFormat("vt {0} {1}\r\n", m_Mesh.m_UV0[v * c], m_Mesh.m_UV0[v * c + 1]);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Normals
|
||||
if (m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0)
|
||||
if (m_Mesh.m_Normals?.Length > 0)
|
||||
{
|
||||
if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3)
|
||||
{
|
||||
@@ -217,20 +198,18 @@ namespace AssetStudioGUI
|
||||
#endregion
|
||||
|
||||
sb.Replace("NaN", "0");
|
||||
File.WriteAllText(exportFullName, sb.ToString());
|
||||
File.WriteAllText(exportFullPath, sb.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool ExportVideoClip(AssetItem item, string exportPath)
|
||||
{
|
||||
var m_VideoClip = (VideoClip)item.Asset;
|
||||
var m_VideoData = m_VideoClip.m_VideoData.Value;
|
||||
if (m_VideoData != null && m_VideoData.Length != 0)
|
||||
if (m_VideoClip.m_ExternalResources.m_Size > 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);
|
||||
m_VideoClip.m_VideoData.WriteData(exportFullPath);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -239,90 +218,161 @@ 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;
|
||||
}
|
||||
|
||||
public static bool ExportSprite(AssetItem item, string exportPath)
|
||||
{
|
||||
ImageFormat format = null;
|
||||
var type = (string)Properties.Settings.Default["convertType"];
|
||||
switch (type)
|
||||
{
|
||||
case "BMP":
|
||||
format = ImageFormat.Bmp;
|
||||
break;
|
||||
case "PNG":
|
||||
format = ImageFormat.Png;
|
||||
break;
|
||||
case "JPEG":
|
||||
format = ImageFormat.Jpeg;
|
||||
break;
|
||||
}
|
||||
var exportFullName = exportPath + item.Text + "." + type.ToLower();
|
||||
if (ExportFileExists(exportFullName))
|
||||
var type = Properties.Settings.Default.convertType;
|
||||
if (!TryExportFile(exportPath, item, "." + type.ToString().ToLower(), out var exportFullPath))
|
||||
return false;
|
||||
var bitmap = SpriteHelper.GetImageFromSprite((Sprite)item.Asset);
|
||||
if (bitmap != null)
|
||||
var stream = ((Sprite)item.Asset).GetImage(type);
|
||||
if (stream != null)
|
||||
{
|
||||
bitmap.Save(exportFullName, format);
|
||||
bitmap.Dispose();
|
||||
return true;
|
||||
using (stream)
|
||||
{
|
||||
File.WriteAllBytes(exportFullPath, stream.ToArray());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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";
|
||||
return ExportFbx(convert, exportPath);
|
||||
}
|
||||
|
||||
public static bool 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";
|
||||
return ExportFbx(convert, exportPath);
|
||||
}
|
||||
|
||||
private static bool ExportFbx(IImported convert, string exportPath)
|
||||
{
|
||||
var eulerFilter = (bool)Properties.Settings.Default["eulerFilter"];
|
||||
var filterPrecision = (float)(decimal)Properties.Settings.Default["filterPrecision"];
|
||||
var allFrames = (bool)Properties.Settings.Default["allFrames"];
|
||||
var allBones = (bool)Properties.Settings.Default["allBones"];
|
||||
var skins = (bool)Properties.Settings.Default["skins"];
|
||||
var boneSize = (int)(decimal)Properties.Settings.Default["boneSize"];
|
||||
var scaleFactor = (float)(decimal)Properties.Settings.Default["scaleFactor"];
|
||||
var flatInbetween = (bool)Properties.Settings.Default["flatInbetween"];
|
||||
var fbxVersion = (int)Properties.Settings.Default["fbxVersion"];
|
||||
var fbxFormat = (int)Properties.Settings.Default["fbxFormat"];
|
||||
ModelExporter.ExportFbx(exportPath, convert, eulerFilter, filterPrecision, allFrames, allBones, skins, boneSize, scaleFactor, flatInbetween, fbxVersion, fbxFormat == 1);
|
||||
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, 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, Properties.Settings.Default.convertType, animationList.Select(x => (AnimationClip)x.Asset).ToArray())
|
||||
: new ModelConverter(rootName, gameObject, Properties.Settings.Default.convertType);
|
||||
ExportFbx(convert, exportPath);
|
||||
}
|
||||
|
||||
private static void ExportFbx(IImported convert, string exportPath)
|
||||
{
|
||||
var eulerFilter = Properties.Settings.Default.eulerFilter;
|
||||
var filterPrecision = (float)Properties.Settings.Default.filterPrecision;
|
||||
var exportAllNodes = Properties.Settings.Default.exportAllNodes;
|
||||
var exportSkins = Properties.Settings.Default.exportSkins;
|
||||
var exportAnimations = Properties.Settings.Default.exportAnimations;
|
||||
var exportBlendShape = Properties.Settings.Default.exportBlendShape;
|
||||
var castToBone = Properties.Settings.Default.castToBone;
|
||||
var boneSize = (int)Properties.Settings.Default.boneSize;
|
||||
var exportAllUvsAsDiffuseMaps = Properties.Settings.Default.exportAllUvsAsDiffuseMaps;
|
||||
var scaleFactor = (float)Properties.Settings.Default.scaleFactor;
|
||||
var fbxVersion = Properties.Settings.Default.fbxVersion;
|
||||
var fbxFormat = Properties.Settings.Default.fbxFormat;
|
||||
ModelExporter.ExportFbx(exportPath, convert, eulerFilter, filterPrecision,
|
||||
exportAllNodes, exportSkins, exportAnimations, exportBlendShape, castToBone, boneSize, exportAllUvsAsDiffuseMaps, scaleFactor, fbxVersion, fbxFormat == 1);
|
||||
}
|
||||
|
||||
public static bool ExportDumpFile(AssetItem item, string exportPath)
|
||||
{
|
||||
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 m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
|
||||
str = m_MonoBehaviour.Dump(m_Type);
|
||||
}
|
||||
if (str != null)
|
||||
{
|
||||
File.WriteAllText(exportFullPath, str);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ExportConvertFile(AssetItem item, string exportPath)
|
||||
{
|
||||
switch (item.Type)
|
||||
{
|
||||
case ClassIDType.Texture2D:
|
||||
return ExportTexture2D(item, exportPath);
|
||||
case ClassIDType.AudioClip:
|
||||
return ExportAudioClip(item, exportPath);
|
||||
case ClassIDType.Shader:
|
||||
return ExportShader(item, exportPath);
|
||||
case ClassIDType.TextAsset:
|
||||
return ExportTextAsset(item, exportPath);
|
||||
case ClassIDType.MonoBehaviour:
|
||||
return ExportMonoBehaviour(item, exportPath);
|
||||
case ClassIDType.Font:
|
||||
return ExportFont(item, exportPath);
|
||||
case ClassIDType.Mesh:
|
||||
return ExportMesh(item, exportPath);
|
||||
case ClassIDType.VideoClip:
|
||||
return ExportVideoClip(item, exportPath);
|
||||
case ClassIDType.MovieTexture:
|
||||
return ExportMovieTexture(item, exportPath);
|
||||
case ClassIDType.Sprite:
|
||||
return ExportSprite(item, exportPath);
|
||||
case ClassIDType.Animator:
|
||||
return ExportAnimator(item, exportPath);
|
||||
case ClassIDType.AnimationClip:
|
||||
return false;
|
||||
default:
|
||||
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,13 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AssetStudio;
|
||||
using AssetStudio;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AssetStudioGUI
|
||||
{
|
||||
class GUILogger : ILogger
|
||||
{
|
||||
public bool ShowErrorMessage = false;
|
||||
private Action<string> action;
|
||||
|
||||
public GUILogger(Action<string> action)
|
||||
@@ -17,7 +16,19 @@ namespace AssetStudioGUI
|
||||
|
||||
public void Log(LoggerEvent loggerEvent, string message)
|
||||
{
|
||||
action(message);
|
||||
switch (loggerEvent)
|
||||
{
|
||||
case LoggerEvent.Error:
|
||||
if (ShowErrorMessage)
|
||||
{
|
||||
MessageBox.Show(message);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
action(message);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
FMOD, FMOD Ex, FMOD Designer and FMOD Studio are
|
||||
Copyright <20> 2005-2016 Firelight Technologies Pty, Ltd.
|
||||
|
||||
GRANT OF LICENSE
|
||||
----------------
|
||||
THIS END USER LICENSE AGREEMENT GRANTS THE USER, THE RIGHT TO USE FMOD,
|
||||
IN ITS LIBRARY AND TOOL FORM, IN THEIR OWN PRODUCTS, BE THEY FOR PERSONAL,
|
||||
EDUCATIONAL OR COMMERCIAL USE.
|
||||
THE USER MUST ADHERE TO THE LICENSING MODEL PROVIDED BY FIRELIGHT
|
||||
TECHNOLOGIES, AND MUST APPLY FOR A LICENSE IF NECESSARY. THE FOLLOWING
|
||||
LICENSES ARE AVAILABLE.
|
||||
|
||||
FMOD NON-COMMERCIAL LICENSE
|
||||
------------------------------------
|
||||
IF YOUR PRODUCT IS NOT INTENDED FOR COMMERCIAL GAIN AND DOES NOT
|
||||
INCLUDE THE FMOD LIBRARY FOR RESALE, LICENSE OR OTHER COMMERCIAL
|
||||
DISTRIBUTION, THEN USE OF FMOD IS FREE OF CHARGE. THERE ARE NO
|
||||
LICENSE FEES FOR NON-COMMERCIAL APPLICATIONS.
|
||||
THE USER MAY USE THIS EULA AS EVIDENCE OF THEIR LICENSE WITHOUT
|
||||
CONTACTING FIRELIGHT TECHNOLOGIES.
|
||||
|
||||
CONDITIONS/LIMITATIONS:
|
||||
- WHEN USING THIS LICENSE, THE FMOD LIBRARY CANNOT BE USED FOR
|
||||
RESALE OR OTHER COMMERCIAL DISTRIBUTION
|
||||
- THIS LICENSE CANNOT BE USED FOR PRODUCTS WHICH DO NOT MAKE
|
||||
PROFIT BUT ARE STILL COMMERCIALLY RELEASED
|
||||
- THIS LICENSE CANNOT BE USED FOR COMMERCIAL SERVICES, WHERE THE
|
||||
EXECUTABLE CONTAINING FMOD IS NOT SOLD, BUT THE DATA IS.
|
||||
- WHEN USING FMOD, A CREDIT LINE IS REQUIRED IN EITHER DOCUMENTATION,
|
||||
OR 'ON SCREEN' FORMAT (IF POSSIBLE). IT SHOULD CONTAIN AT LEAST
|
||||
THE WORDS "FMOD" (OR "FMOD STUDIO" IF APPLICABLE) AND
|
||||
"FIRELIGHT TECHNOLOGIES."
|
||||
LOGOS ARE AVAILABLE FOR BOX OR MANUAL ART, BUT ARE NOT MANDATORY.
|
||||
AN EXAMPLE CREDIT COULD BE:
|
||||
|
||||
FMOD Sound System, copyright <20> Firelight Technologies Pty, Ltd., 1994-2016.
|
||||
OR
|
||||
FMOD Studio, copyright <20> Firelight Technologies Pty, Ltd., 1994-2016.
|
||||
OR
|
||||
Audio Engine supplied by FMOD by Firelight Technologies.
|
||||
|
||||
NOTE THIS IN ADVANCE, AS IT MUST BE DONE BEFORE SHIPPING YOUR
|
||||
PRODUCT WITH FMOD.
|
||||
|
||||
FMOD FREE FOR INDIES LICENSE (FMOD STUDIO ONLY)
|
||||
------------------------------------------------
|
||||
INDIE DEVELOPERS ARE CONSIDERED BY OUR LICENSING MODEL, DEVELOPERS THAT DEVELOP
|
||||
A TITLE FOR UNDER $100K USD (TYPICALLY CONSIDERED AN 'INDIE' TITLE) TOTAL
|
||||
BUDGET, MEANING YOUR TOTAL COSTS ARE LESS THAN $100K USD AT TIME OF SHIPPING,
|
||||
YOU CAN USE FMOD FOR FREE.
|
||||
|
||||
CONDITIONS/LIMITATIONS
|
||||
- PLEASE WRITE TO SALES@FMOD.COM WITH THE NAME OF YOUR TITLE, RELEASE DATE
|
||||
AND PLATFORMS SO WE CAN REGISTER YOU IN OUR SYSTEM.
|
||||
- THERE IS NO RESTRICTION ON PLATFORM, ANY PLATFORM COMBINATION MAY BE USED.
|
||||
- INCOME IS NOT RELEVANT TO THE BUDGET LEVEL, IT MUST BE EXPENSE RELATED.
|
||||
- WHEN USING FMOD, A CREDIT LINE IS REQUIRED IN EITHER DOCUMENTATION,
|
||||
OR 'ON SCREEN' FORMAT (IF POSSIBLE). IT SHOULD CONTAIN AT LEAST
|
||||
THE WORDS FMOD STUDIO AND FIRELIGHT TECHNOLOGIES.
|
||||
LOGOS ARE AVAILABLE FOR BOX OR MANUAL ART, BUT ARE NOT MANDATORY.
|
||||
AN EXAMPLE CREDIT COULD BE:
|
||||
|
||||
FMOD STUDIO, COPYRIGHT <20> FIRELIGHT TECHNOLOGIES PTY, LTD., 1994-2016.
|
||||
|
||||
COMMERCIAL USAGE (FMOD EX AND FMOD STUDIO)
|
||||
------------------------------------------
|
||||
IF THE PRODUCT THAT USES FMOD IS INTENDED TO GENERATE INCOME, VIA DIRECT SALES
|
||||
OR INDIRECT REVENUE (SUCH AS ADVERTISING, DONATIONS, CONTRACT FEE) THEN THE
|
||||
DEVELOPER MUST APPLY TO FIRELIGHT TECHNOLOGIES FOR A COMMERCIAL LICENSE (UNLESS
|
||||
THE USER QUALIFIES FOR AN FMOD STUDIO 'INDIE LICENSE').
|
||||
TO APPLY FOR THIS LICENSE WRITE TO SALES@FMOD.COM WITH THE RELEVANT DETAILS.
|
||||
|
||||
REDISTRIBUTION LICENSE (FMOD EX AND FMOD STUDIO)
|
||||
------------------------------------------------
|
||||
IF THE USER WISHES TO REDISTRIBUTE FMOD AS PART OF AN ENGINE OR TOOL SOLUTION,
|
||||
THE USER MUST APPLY TO FIRELIGHT TECHNOLOGIES TO BE GRANTED A 'REDISTRIBUTION
|
||||
LICENSE'.
|
||||
TO APPLY FOR THIS LICENSE WRITE TO SALES@FMOD.COM WITH THE RELEVANT DETAILS.
|
||||
|
||||
WARRANTY AND LIMITATION OF LIABILITY
|
||||
------------------------------------
|
||||
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 FOUNDATION
|
||||
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.
|
||||
|
||||
FMOD Uses Ogg Vorbis codec. BSD license.
|
||||
-----------------------------------------
|
||||
Copyright (c) 2002, Xiph.org Foundation
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of the Xiph.org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 FOUNDATION
|
||||
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.
|
||||
|
||||
For Android platform code.
|
||||
--------------------------
|
||||
Copyright (C) 2010 The Android Open Source Project
|
||||
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 OWNER 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.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user