82 Commits

Author SHA1 Message Date
VaDiM
eab789939d listSearh fix 2020-08-01 21:14:42 +03:00
VaDiM
04266251aa add "Dump with PathID as filename" feature 2020-07-27 23:22:53 +03:00
VaDiM
c5f7ef6e91 add some features
- Export tex2D/sprites with PathID as a filename
- Dump selected assets from the context menu strip
- Drag&Drop support by Jayatubi
- Sort by PathID by Tahvohck
2020-07-26 23:40:19 +03:00
Perfare
4a81c461e8 Modify Sprite processing function as an extension function 2020-04-10 18:57:04 +08:00
Perfare
b10d03d50d fixed bug 2020-04-10 18:51:43 +08:00
Perfare
da98a0c5b8 fixed bug 2020-04-10 18:20:45 +08:00
Perfare
76d17bacf5 improve type read 2020-04-10 18:11:56 +08:00
Perfare
6678ce082b refactor BundleFile read 2020-04-07 16:13:04 +08:00
Perfare
07074b3deb improve SerializedFile read 2020-04-07 08:59:04 +08:00
Perfare
df5d9f90d4 Add copy function to assetListView 2020-04-07 08:55:51 +08:00
Perfare
4f2d30552a set UV1 to NormalMap channel 2020-04-07 08:23:13 +08:00
Perfare
d259c7a5cd multiple uv export 2020-04-06 19:29:15 +08:00
Perfare
c71ceb7ea6 improve SerializedType read 2020-04-06 19:21:48 +08:00
Perfare
85cf134a49 Fixed if the container has the same key 2020-03-30 09:01:25 +08:00
Perfare
687b1d3a0d Fixed get triangles of mesh #510 2020-03-30 08:52:16 +08:00
Perfare
a30a0d0bc5 Update README.md 2020-03-28 15:52:15 +08:00
Perfare
e1dc54d6d7 use list to store objects in their original order 2020-03-28 14:13:25 +08:00
Perfare
c4270e186d fixed bug 2020-03-28 13:46:30 +08:00
Perfare
182a42ace2 optimize ResourceReader 2020-03-28 13:33:37 +08:00
Perfare
06fbe69a97 performance improvement 2020-03-28 04:24:32 +08:00
Perfare
a0bf4f9acd update LICENSE 2020-03-28 01:22:26 +08:00
Perfare
12568ba044 fix ico 2020-03-27 21:52:16 +08:00
Perfare
de95b02285 update to .net framework 4.7.2 2020-03-27 21:42:40 +08:00
Perfare
286edfe72c improve texture channel filter 2020-03-27 16:52:21 +08:00
Perfare
d717b223b7 delete some useless features 2020-03-27 01:06:22 +08:00
Perfare
9e195832ef reduce memory usage 2020-03-26 03:44:07 +08:00
Perfare
c8d08b2793 improve file type check 2020-03-26 02:17:48 +08:00
Perfare
2bcd9662be improve export 2020-03-26 01:01:02 +08:00
Perfare
ea461ee3d2 improve Texture2D decode 2020-03-25 22:45:53 +08:00
Perfare
fda821b441 add more information to the asset list 2020-03-25 14:01:59 +08:00
Perfare
5c193c761a using strong typing for setting 2020-03-25 11:18:12 +08:00
Perfare
14f47c6d30 fixed bug 2020-03-24 14:09:54 +08:00
Perfare
e53eacef78 improved 2020-03-24 11:31:57 +08:00
Perfare
ada26db659 improved 2020-03-24 10:42:39 +08:00
Perfare
48ca96807f Merge pull request #485 from K0lb3/patch-1
kSPMTight fix
2020-03-24 10:29:01 +08:00
Perfare
2018028853 fixed bug 2020-03-24 09:17:26 +08:00
Perfare
6f138dcc05 Update README.md 2020-03-24 08:52:30 +08:00
Perfare
69bcd2be67 update project 2020-03-24 07:45:47 +08:00
Perfare
45ad53b19a using Nuget 2020-03-24 07:19:59 +08:00
Perfare
6230240ee3 Merge pull request #499 from qiankanglai/master
corner case as protection
2020-03-24 07:09:18 +08:00
Perfare
73ec9f4bee update FBX SDK 2020.0.1 VS2017 2020-03-24 07:04:42 +08:00
Perfare
f3a0bf505e refactor Texture2D convert 2020-03-24 06:41:58 +08:00
Kanglai Qian
290708876d corner case as protection 2020-03-14 21:17:34 +08:00
Perfare
5b96a29cca move file 2020-03-14 16:06:21 +08:00
Perfare
948e2c4d92 Merge pull request #495 from qiankanglai/texchannel
texture channel support
2020-03-14 00:02:33 +08:00
Perfare
76da1c33ae Merge pull request #493 from Druhin13/master
Optimized images
2020-03-14 00:01:13 +08:00
Perfare
72b84ee24d Merge pull request #494 from qiankanglai/tga
support exporting texture2d as tga
2020-03-14 00:00:40 +08:00
Kanglai Qian
7b33d41172 texture channel 2020-03-03 12:46:51 +08:00
Kanglai Qian
c7043c1a83 support export texture2d as tga 2020-03-03 11:23:36 +08:00
Druhin Tarafder
d0baf26c61 Merge pull request #1 from Druhin13/imgbot
Optimized images
2020-03-02 14:39:00 +05:30
ImgBotApp
60ac10b043 [ImgBot] Optimize images
/AssetStudioGUI/Resources/preview.png -- 6.89kb -> 3.87kb (43.78%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
2020-03-02 08:56:17 +00:00
Perfare
80dc24b487 Update README.md 2020-02-28 15:41:39 +08:00
Perfare
9d32a9dd6a 2019.3 support 2020-02-28 15:39:11 +08:00
Perfare
d96cc3c762 Merge pull request #489 from DaZombieKiller/2020
Support for SerializedFile version 22
2020-02-27 23:09:26 +08:00
Zombie
509df42730 Support for SerializedFile version 22 2020-02-27 20:29:02 +10:00
K0lb3
4efa5b0507 kSPMTight fix
SpritePackingMode.kSPMTight can occur outside of settingsRaw.packed == 1.

[sample file](https://cdn.discordapp.com/attachments/603359898507673632/678238497894563860/kuroyukiwedding_base_1_a)
from Dengeki Bunko: Crossing Void
2020-02-20 09:42:19 +01:00
Perfare
cffe96b409 Skip reading failed assets 2019-10-20 08:05:55 +08:00
Perfare
16dddc01e3 always show the debug menu 2019-08-12 05:50:04 +08:00
Perfare
b5d2c2cadb improved 2019-08-12 04:36:07 +08:00
Perfare
1d2c0ab6cb Fixed #428 2019-08-12 04:17:06 +08:00
Perfare
c6b7e04c47 improved 2019-08-06 17:57:14 +08:00
Perfare
5704813b28 Improved UI 2019-08-06 17:43:51 +08:00
Perfare
465c989e75 fixed bug 2019-08-06 15:49:41 +08:00
Perfare
d335aaef9e improved 2019-08-06 09:48:21 +08:00
Perfare
495b48c783 improved Sprite export 2019-08-01 15:23:36 +08:00
Perfare
05b55722fb change text 2019-07-30 03:34:15 +08:00
Perfare
de54257eef improved bone export 2019-07-29 13:41:42 +08:00
Perfare
e62b6c3d77 improved 2019-07-29 00:31:43 +08:00
Perfare
dc05e5b5eb Fixed bug 2019-07-29 00:25:26 +08:00
Perfare
f377381e26 Support for exporting raw data 2019-07-28 19:48:06 +08:00
Perfare
20f9fe493f add more options for export model 2019-07-28 18:55:08 +08:00
Perfare
0b462754a5 Implemented BlendShape export 2019-07-28 16:41:23 +08:00
Perfare
b1ea8dd346 clean up code 2019-07-28 03:47:12 +08:00
Perfare
4a46f897bd add default values to materials 2019-07-28 00:26:56 +08:00
Perfare
6a5ec80de7 fixed bug 2019-07-27 23:20:47 +08:00
Perfare
4f2046d412 improved 2019-07-27 22:54:18 +08:00
Perfare
1cf59e8d67 fixed bug 2019-07-27 18:01:57 +08:00
Perfare
e9e8390bbc Supported merge GameObject to export 2019-07-17 12:51:00 +08:00
Perfare
738b084440 Fixed bug 2019-07-16 17:53:50 +08:00
Perfare
32cce894ac Fixed #373 2019-07-16 17:49:10 +08:00
Perfare
a6264b39d1 improved morph export 2019-07-16 13:21:32 +08:00
Perfare
eb4981808b Fixed coding errors 2019-07-16 05:32:54 +08:00
120 changed files with 25209 additions and 4165 deletions

172
.gitignore vendored
View File

@@ -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

View File

@@ -1,15 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2024
# Visual Studio Version 16
VisualStudioVersion = 16.0.29920.165
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBX", "AssetStudioFBX\AssetStudioFBX.vcxproj", "{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBX", "AssetStudioFBX\AssetStudioFBX.vcxproj", "{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Texture2DDecoder", "Texture2DDecoder\Texture2DDecoder.vcxproj", "{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{AF56B63C-1764-41B7-9E60-8D485422AC3B}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{80AEC261-21EE-4E4F-A93B-7A744DC84888}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -19,43 +21,51 @@ Global
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
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Debug|x64.ActiveCfg = Debug|Any CPU
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Debug|x64.Build.0 = Debug|Any CPU
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Debug|x86.ActiveCfg = Debug|Any CPU
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Debug|x86.Build.0 = Debug|Any CPU
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Release|x64.ActiveCfg = Release|Any CPU
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Release|x64.Build.0 = Release|Any CPU
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Release|x86.ActiveCfg = Release|Any CPU
{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}.Release|x86.Build.0 = Release|Any CPU
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Debug|x64.ActiveCfg = Debug|x64
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Debug|x64.Build.0 = Debug|x64
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Debug|x86.ActiveCfg = Debug|Win32
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Debug|x86.Build.0 = Debug|Win32
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Release|x64.ActiveCfg = Release|x64
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Release|x64.Build.0 = Release|x64
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Release|x86.ActiveCfg = Release|Win32
{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}.Release|x86.Build.0 = Release|Win32
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Debug|x64.ActiveCfg = Debug|x64
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Debug|x64.Build.0 = Debug|x64
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Debug|x86.ActiveCfg = Debug|Win32
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Debug|x86.Build.0 = Debug|Win32
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Release|x64.ActiveCfg = Release|x64
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Release|x64.Build.0 = Release|x64
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Release|x86.ActiveCfg = Release|Win32
{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}.Release|x86.Build.0 = Release|Win32
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Debug|x64.ActiveCfg = Debug|x64
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Debug|x64.Build.0 = Debug|x64
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Debug|x86.ActiveCfg = Debug|x86
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Debug|x86.Build.0 = Debug|x86
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Release|x64.ActiveCfg = Release|x64
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Release|x64.Build.0 = Release|x64
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Release|x86.ActiveCfg = Release|x86
{80AEC261-21EE-4E4F-A93B-7A744DC84888}.Release|x86.Build.0 = Release|x86
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Debug|x64.ActiveCfg = Debug|x64
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Debug|x64.Build.0 = Debug|x64
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Debug|x86.ActiveCfg = Debug|x86
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Debug|x86.Build.0 = Debug|x86
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Release|x64.ActiveCfg = Release|x64
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Release|x64.Build.0 = Release|x64
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Release|x86.ActiveCfg = Release|x86
{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F5C476A6-2B3B-416F-8BD5-6FE454FF3972}
SolutionGuid = {F8734F96-97B6-40CA-B791-6D5467F2F713}
EndGlobalSection
EndGlobal

View File

@@ -4,12 +4,12 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{AF56B63C-1764-41B7-9E60-8D485422AC3B}</ProjectGuid>
<ProjectGuid>{7662F8C2-7BFD-442E-A948-A43B4F7EB06E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AssetStudio</RootNamespace>
<AssemblyName>AssetStudio</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
@@ -23,7 +23,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
@@ -38,6 +38,7 @@
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
@@ -56,22 +57,7 @@
<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" />
@@ -114,8 +100,10 @@
<Compile Include="Classes\NamedObject.cs" />
<Compile Include="Classes\Object.cs" />
<Compile Include="Classes\PlayerSettings.cs" />
<Compile Include="Classes\PPtr.cs" />
<Compile Include="Classes\RectTransform.cs" />
<Compile Include="Classes\Renderer.cs" />
<Compile Include="Classes\RuntimeAnimatorController.cs" />
<Compile Include="Classes\Shader.cs" />
<Compile Include="Classes\SkinnedMeshRenderer.cs" />
<Compile Include="Classes\Sprite.cs" />
@@ -128,26 +116,39 @@
<Compile Include="ClassIDType.cs" />
<Compile Include="CommonString.cs" />
<Compile Include="EndianBinaryReader.cs" />
<Compile Include="Extensions\BinaryReaderExtensions.cs" />
<Compile Include="Extensions\BinaryWriterExtensions.cs" />
<Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="FileIdentifier.cs" />
<Compile Include="IImported.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="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="ObjectInfo.cs" />
<Compile Include="ObjectReader.cs" />
<Compile Include="Classes\PPtr.cs" />
<Compile Include="Progress.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ResourceReader.cs" />
<Compile Include="SerializedFile.cs" />
<Compile Include="SerializedFileHeader.cs" />
<Compile Include="SerializedType.cs" />
<Compile Include="SevenZipHelper.cs" />
<Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="StreamFile.cs" />
<Compile Include="TypeTreeHelper.cs" />
<Compile Include="TypeTreeNode.cs" />
<Compile Include="UType.cs" />
<Compile Include="WebFile.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using static AssetStudio.ImportHelper;
@@ -8,12 +9,12 @@ namespace AssetStudio
public class AssetsManager
{
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 +37,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,7 +53,7 @@ namespace AssetStudio
assetsFileListHash.Clear();
ReadAssets();
ProcessGameObject();
ProcessAssets();
}
private void LoadFile(string fullName)
@@ -74,21 +75,21 @@ namespace AssetStudio
private void LoadAssetsFile(string fullName, EndianBinaryReader reader)
{
var fileName = Path.GetFileName(fullName);
if (!assetsFileListHash.Contains(fileName.ToUpper()))
if (!assetsFileListHash.Contains(fileName))
{
Logger.Info($"Loading {fileName}");
try
{
var assetsFile = new SerializedFile(this, fullName, reader);
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))
{
if (!File.Exists(sharedFilePath))
{
@@ -102,7 +103,7 @@ namespace AssetStudio
if (File.Exists(sharedFilePath))
{
importFiles.Add(sharedFilePath);
importFilesHash.Add(sharedFileName.ToUpper());
importFilesHash.Add(sharedFileName);
}
}
}
@@ -110,7 +111,7 @@ namespace AssetStudio
catch
{
reader.Dispose();
//Logger.Error($"Unable to load assets file {fileName}");
//Logger.Warning($"Unable to load assets file {fileName}");
}
}
else
@@ -121,8 +122,8 @@ namespace AssetStudio
private void LoadAssetsFromMemory(string fullName, EndianBinaryReader reader, string originalPath, string unityVersion = null)
{
var upperFileName = Path.GetFileName(fullName).ToUpper();
if (!assetsFileListHash.Contains(upperFileName))
var fileName = Path.GetFileName(fullName);
if (!assetsFileListHash.Contains(fileName))
{
try
{
@@ -133,15 +134,12 @@ namespace AssetStudio
assetsFile.SetVersion(unityVersion);
}
assetsFileList.Add(assetsFile);
assetsFileListHash.Add(assetsFile.upperFileName);
assetsFileListHash.Add(assetsFile.fileName);
}
catch
{
//Logger.Error($"Unable to load assets file {fileName} from {Path.GetFileName(originalPath)}");
}
finally
{
resourceFileReaders.Add(upperFileName, reader);
resourceFileReaders.Add(fileName, reader);
}
}
}
@@ -155,8 +153,16 @@ namespace AssetStudio
var bundleFile = new BundleFile(reader, fullName);
foreach (var file in bundleFile.fileList)
{
var dummyPath = Path.GetDirectoryName(fullName) + "\\" + file.fileName;
LoadAssetsFromMemory(dummyPath, new EndianBinaryReader(file.stream), parentPath ?? fullName, bundleFile.versionEngine);
var subReader = new EndianBinaryReader(file.stream);
if (SerializedFile.IsSerializedFile(subReader))
{
var dummyPath = Path.GetDirectoryName(fullName) + Path.DirectorySeparatorChar + file.fileName;
LoadAssetsFromMemory(dummyPath, subReader, parentPath ?? fullName, bundleFile.m_Header.unityRevision);
}
else
{
resourceFileReaders.Add(file.fileName, subReader);
}
}
}
catch
@@ -195,6 +201,9 @@ namespace AssetStudio
case FileType.WebFile:
LoadWebFile(dummyPath, fileReader);
break;
case FileType.ResourceFile:
resourceFileReaders.Add(file.fileName, fileReader);
break;
}
}
}
@@ -235,96 +244,110 @@ 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;
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 +355,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 +393,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);
}
}
}
}
}
}
}

View File

@@ -1,246 +1,306 @@
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(EndianBinaryReader reader, string path)
{
m_Header = new Header();
m_Header.signature = reader.ReadStringToNull();
switch (m_Header.signature)
{
case "UnityArchive":
break; //TODO
case "UnityWeb":
case "UnityRaw":
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA":
ReadHeaderAndBlocksInfo(reader);
using (var blocksStream = CreateBlocksStream(path))
{
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;
ReadBlocksAndDirectory(reader, blocksStream);
ReadFiles(blocksStream, path);
}
break;
case "UnityFS":
ReadHeader(reader);
ReadBlocksInfoAndDirectory(reader);
using (var blocksStream = CreateBlocksStream(path))
{
var format = bundleReader.ReadInt32();
versionPlayer = bundleReader.ReadStringToNull();
versionEngine = bundleReader.ReadStringToNull();
if (format == 6)
{
ReadFormat6(bundleReader);
}
break;
ReadBlocks(reader, blocksStream);
ReadFiles(blocksStream, path);
}
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";
m_Header.version = reader.ReadUInt32();
m_Header.unityVersion = reader.ReadStringToNull();
m_Header.unityRevision = reader.ReadStringToNull();
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();
var headerSize = 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 = headerSize;
}
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(Path.GetFileName(path), 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.fileName = Path.GetFileName(node.path);
if (node.size >= int.MaxValue)
{
/*var memoryMappedFile = MemoryMappedFile.CreateNew(file.fileName, entryinfo_size);
file.stream = memoryMappedFile.CreateViewStream();*/
var extractPath = path + "_unpacked" + Path.DirectorySeparatorChar;
Directory.CreateDirectory(extractPath);
file.stream = File.Create(extractPath + file.fileName);
}
else
{
dataStream = new MemoryStream();
file.stream = new MemoryStream((int)node.size);
}
foreach (var blockInfo in blockInfos)
blocksStream.Position = node.offset;
blocksStream.CopyTo(file.stream, node.size);
file.stream.Position = 0;
}
}
private void ReadHeader(EndianBinaryReader reader)
{
m_Header.version = reader.ReadUInt32();
m_Header.unityVersion = reader.ReadStringToNull();
m_Header.unityRevision = reader.ReadStringToNull();
m_Header.size = reader.ReadInt64();
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32();
m_Header.flags = reader.ReadUInt32();
}
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader)
{
byte[] blocksInfoBytes;
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
{
if (m_Header.version >= 7)
{
switch (blockInfo.flag & 0x3F)
{
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?
}
reader.AlignStream(16);
}
dataStream.Position = 0;
using (dataStream)
{
var entryinfo_count = blocksInfoReader.ReadInt32();
for (int i = 0; i < entryinfo_count; i++)
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
}
var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes);
MemoryStream blocksInfoUncompresseddStream;
switch (m_Header.flags & 0x3F) //kArchiveCompressionTypeMask
{
default: //None
{
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);
blocksInfoUncompresseddStream = blocksInfoCompressedStream;
break;
}
case 1: //LZMA
{
blocksInfoUncompresseddStream = SevenZipHelper.StreamDecompress(blocksInfoCompressedStream);
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()
};
}
var nodesCount = blocksInfoReader.ReadInt32();
m_DirectoryInfo = new Node[nodesCount];
for (int i = 0; i < nodesCount; i++)
{
m_DirectoryInfo[i] = new Node
{
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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -29,7 +29,7 @@ namespace AssetStudio
public string m_Source;
public long m_Offset;
public long m_Size;
public Lazy<byte[]> m_AudioData;
public ResourceReader m_AudioData;
public AudioClip(ObjectReader reader) : base(reader)
{
@@ -87,7 +87,7 @@ namespace AssetStudio
{
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size);
}
m_AudioData = new Lazy<byte[]>(resourceReader.GetData);
m_AudioData = resourceReader;
}
}

View File

@@ -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());
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(version, m_Channel.format);
}
}
}
@@ -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(version, m_Channel.format));
}
}
}
@@ -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
{
@@ -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)
{
@@ -680,7 +694,7 @@ namespace AssetStudio
DecompressCompressedMesh();
}
BuildFaces();
GetTriangles();
}
private void ReadVertexData()
@@ -701,7 +715,7 @@ namespace AssetStudio
m_Channel.dimension = 4;
}
var componentByteSize = (int)MeshHelper.GetChannelFormatSize(m_Channel.format);
var componentByteSize = (int)MeshHelper.GetFormatSize(version, m_Channel.format);
var componentBytes = new byte[m_VertexCount * m_Channel.dimension * componentByteSize];
for (int v = 0; v < m_VertexCount; v++)
{
@@ -726,8 +740,8 @@ namespace AssetStudio
int[] componentsIntArray = null;
float[] componentsFloatArray = null;
if (m_Channel.format == 10 || m_Channel.format == 11)
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes);
if (MeshHelper.IsIntFormat(version, m_Channel.format))
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, componentByteSize);
else
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, componentByteSize);
@@ -759,10 +773,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 +862,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 +1047,7 @@ namespace AssetStudio
}
}
private void BuildFaces()
private void GetTriangles()
{
foreach (var m_SubMesh in m_SubMeshes)
{
@@ -1017,43 +1056,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,30 +1127,211 @@ 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)
private enum VertexChannelFormat
{
switch (format)
kChannelFormatFloat,
kChannelFormatFloat16,
kChannelFormatColor,
kChannelFormatByte,
kChannelFormatUInt32
}
private enum VertexFormat
{
kVertexFormatFloat,
kVertexFormatFloat16,
kVertexFormatColor,
kVertexFormatUNorm8,
kVertexFormatSNorm8,
kVertexFormatUNorm16,
kVertexFormatSNorm16,
kVertexFormatUInt8,
kVertexFormatSInt8,
kVertexFormatUInt16,
kVertexFormatSInt16,
kVertexFormatUInt32,
kVertexFormatSInt32
}
private enum VertexFormatV2019
{
kVertexFormatFloat,
kVertexFormatFloat16,
kVertexFormatUNorm8,
kVertexFormatSNorm8,
kVertexFormatUNorm16,
kVertexFormatSNorm16,
kVertexFormatUInt8,
kVertexFormatSInt8,
kVertexFormatUInt16,
kVertexFormatSInt16,
kVertexFormatUInt32,
kVertexFormatSInt32
}
public static uint GetFormatSize(int[] version, int format)
{
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 4u;
case VertexChannelFormat.kChannelFormatFloat16:
return 2u;
case VertexChannelFormat.kChannelFormatColor: //in 4.x is size 4
return 1u;
case VertexChannelFormat.kChannelFormatByte:
return 1u;
case VertexChannelFormat.kChannelFormatUInt32: //in 5.x
return 4u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else if (version[0] < 2019)
{
switch ((VertexFormat)format)
{
case VertexFormat.kVertexFormatFloat:
return 4u;
case VertexFormat.kVertexFormatFloat16:
return 2u;
case VertexFormat.kVertexFormatColor:
return 1u;
case VertexFormat.kVertexFormatUNorm8:
return 1u;
case VertexFormat.kVertexFormatSNorm8:
return 1u;
case VertexFormat.kVertexFormatUNorm16:
return 2u;
case VertexFormat.kVertexFormatSNorm16:
return 2u;
case VertexFormat.kVertexFormatUInt8:
return 1u;
case VertexFormat.kVertexFormatSInt8:
return 1u;
case VertexFormat.kVertexFormatUInt16:
return 2u;
case VertexFormat.kVertexFormatSInt16:
return 2u;
case VertexFormat.kVertexFormatUInt32:
return 4u;
case VertexFormat.kVertexFormatSInt32:
return 4u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else
{
switch ((VertexFormatV2019)format)
{
case VertexFormatV2019.kVertexFormatFloat:
return 4u;
case VertexFormatV2019.kVertexFormatFloat16:
return 2u;
case VertexFormatV2019.kVertexFormatUNorm8:
return 1u;
case VertexFormatV2019.kVertexFormatSNorm8:
return 1u;
case VertexFormatV2019.kVertexFormatUNorm16:
return 2u;
case VertexFormatV2019.kVertexFormatSNorm16:
return 2u;
case VertexFormatV2019.kVertexFormatUInt8:
return 1u;
case VertexFormatV2019.kVertexFormatSInt8:
return 1u;
case VertexFormatV2019.kVertexFormatUInt16:
return 2u;
case VertexFormatV2019.kVertexFormatSInt16:
return 2u;
case VertexFormatV2019.kVertexFormatUInt32:
return 4u;
case VertexFormatV2019.kVertexFormatSInt32:
return 4u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
}
public static bool IsIntFormat(int[] version, int format)
{
if (version[0] < 2017)
{
return format == 4;
}
else if (version[0] < 2019)
{
return format >= 7;
}
else
{
return format >= 6;
}
}
@@ -1116,12 +1358,23 @@ namespace AssetStudio
return result;
}
public static int[] BytesToIntArray(byte[] inputBytes)
public static int[] BytesToIntArray(byte[] inputBytes, int size)
{
var result = new int[inputBytes.Length / 4];
for (int i = 0; i < inputBytes.Length / 4; i++)
var result = new int[inputBytes.Length / size];
for (int i = 0; i < inputBytes.Length / size; i++)
{
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
switch (size)
{
case 1:
result[i] = inputBytes[i];
break;
case 2:
result[i] = BitConverter.ToInt16(inputBytes, i * 2);
break;
case 4:
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
break;
}
}
return result;
}

View File

@@ -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;
}
}

View File

@@ -39,13 +39,17 @@ 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();
}
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();
}
reader.AlignStream();
}
else

View File

@@ -591,6 +591,7 @@ 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;
@@ -616,6 +617,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
{
@@ -759,9 +764,18 @@ namespace AssetStudio
{
m_ParsedForm = new SerializedShader(reader);
platforms = reader.ReadUInt32Array().Select(x => (ShaderCompilerPlatform)x).ToArray();
offsets = reader.ReadUInt32Array();
compressedLengths = reader.ReadUInt32Array();
decompressedLengths = reader.ReadUInt32Array();
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.ReadBytes(reader.ReadInt32());
}
else

View File

@@ -32,6 +32,12 @@ namespace AssetStudio
kSPMRectangle
};
public enum SpriteMeshType
{
kSpriteMeshTypeFullRect,
kSpriteMeshTypeTight
};
public class SpriteSettings
{
public uint settingsRaw;
@@ -39,6 +45,7 @@ namespace AssetStudio
public uint packed;
public SpritePackingMode packingMode;
public SpritePackingRotation packingRotation;
public SpriteMeshType meshType;
public SpriteSettings(BinaryReader reader)
{
@@ -47,8 +54,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
}
}

View File

@@ -1,9 +1,4 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace AssetStudio
{
@@ -56,7 +51,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)
@@ -107,7 +102,7 @@ namespace AssetStudio
{
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, image_data_size);
}
image_data = new Lazy<byte[]>(resourceReader.GetData);
image_data = resourceReader;
}
}
@@ -170,5 +165,11 @@ 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,
}
}

View File

@@ -8,7 +8,7 @@ namespace AssetStudio
{
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;
@@ -47,7 +47,7 @@ namespace AssetStudio
{
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size);
}
m_VideoData = new Lazy<byte[]>(resourceReader.GetData);
m_VideoData = resourceReader;
}
}
}

View File

@@ -112,7 +112,8 @@ namespace AssetStudio
{1083, "BoundsInt"},
{1093, "m_CorrespondingSourceObject"},
{1121, "m_PrefabInstance"},
{1138, "m_PrefabAsset"}
{1138, "m_PrefabAsset"},
{1152, "FileSize"}
};
}
}

View File

@@ -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);

View File

@@ -134,6 +134,10 @@ namespace AssetStudio
public string Path { 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
@@ -145,17 +149,13 @@ namespace AssetStudio
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 +205,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 +227,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 +242,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

View File

@@ -8,7 +8,8 @@ namespace AssetStudio
{
AssetsFile,
BundleFile,
WebFile
WebFile,
ResourceFile
}
public static class ImportHelper
@@ -76,7 +77,7 @@ namespace AssetStudio
{
case "UnityWeb":
case "UnityRaw":
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA":
case "UnityArchive":
case "UnityFS":
return FileType.BundleFile;
case "UnityWebData1.0":
@@ -96,7 +97,14 @@ namespace AssetStudio
{
return FileType.WebFile;
}
return FileType.AssetsFile;
if (SerializedFile.IsSerializedFile(reader))
{
return FileType.AssetsFile;
}
else
{
return FileType.ResourceFile;
}
}
}
}

View File

@@ -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);

View File

@@ -7,7 +7,7 @@ namespace AssetStudio
{
public class ObjectInfo
{
public uint byteStart;
public long byteStart;
public uint byteSize;
public int typeID;
public int classID;

View File

@@ -10,7 +10,7 @@ namespace AssetStudio
{
public SerializedFile assetsFile;
public long m_PathID;
public uint byteStart;
public long byteStart;
public uint byteSize;
public ClassIDType type;
public SerializedType serializedType;

View File

@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AssetStudio")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyCopyright("Copyright © Perfare 2018-2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("af56b63c-1764-41b7-9e60-8d485422ac3b")]
[assembly: Guid("7662f8c2-7bfd-442e-a948-a43b4f7eb06e")]
// 程序集的版本信息由下列四个值组成:
//
@@ -29,8 +29,8 @@ using System.Runtime.InteropServices;
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("0.14.38.5")]
[assembly: AssemblyFileVersion("0.14.38.5")]

View File

@@ -34,17 +34,18 @@ namespace AssetStudio
{
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;
needSearch = false;
reader.BaseStream.Position = offset;
return reader.ReadBytes(size);
}
var currentDirectory = Path.GetDirectoryName(assetsFile.fullName);
var resourceFilePath = currentDirectory + "\\" + resourceFileName;
var assetsFileDirectory = Path.GetDirectoryName(assetsFile.fullName);
var resourceFilePath = assetsFileDirectory + Path.DirectorySeparatorChar + 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,11 +53,11 @@ namespace AssetStudio
}
if (File.Exists(resourceFilePath))
{
using (var resourceReader = new BinaryReader(File.OpenRead(resourceFilePath)))
{
resourceReader.BaseStream.Position = offset;
return resourceReader.ReadBytes(size);
}
reader = new BinaryReader(File.OpenRead(resourceFilePath));
needSearch = false;
assetsFile.assetsManager.resourceFileReaders.Add(resourceFileName, reader);
reader.BaseStream.Position = offset;
return reader.ReadBytes(size);
}
throw new FileNotFoundException($"Can't find the resource file {resourceFileName}");

View File

@@ -13,10 +13,10 @@ namespace AssetStudio
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;
@@ -24,6 +24,7 @@ namespace AssetStudio
public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform;
private bool m_EnableTypeTree = true;
public List<SerializedType> m_Types;
public List<SerializedType> m_RefTypes;
public List<ObjectInfo> m_Objects;
private List<LocalSerializedObjectIdentifier> m_ScriptTypes;
public List<FileIdentifier> m_Externals;
@@ -34,7 +35,6 @@ namespace AssetStudio
this.reader = reader;
this.fullName = fullName;
fileName = Path.GetFileName(fullName);
upperFileName = fileName.ToUpper();
//ReadHeader
header = new SerializedFileHeader();
@@ -55,6 +55,14 @@ namespace AssetStudio
m_FileEndianess = (EndianType)reader.ReadByte();
}
if (header.m_Version >= 22)
{
header.m_MetadataSize = reader.ReadUInt32();
header.m_FileSize = reader.ReadInt64();
header.m_DataOffset = reader.ReadInt64();
reader.ReadInt64(); // unknown
}
//ReadMetadata
if (m_FileEndianess == EndianType.LittleEndian)
{
@@ -86,18 +94,25 @@ namespace AssetStudio
m_Types.Add(ReadSerializedType());
}
var bigIDEnabled = 0;
if (header.m_Version >= 7 && header.m_Version < 14)
{
var bigIDEnabled = reader.ReadInt32();
bigIDEnabled = reader.ReadInt32();
}
//ReadObjects
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 < 14)
{
objectInfo.m_PathID = reader.ReadInt32();
}
@@ -106,7 +121,12 @@ namespace AssetStudio
reader.AlignStream();
objectInfo.m_PathID = reader.ReadInt64();
}
objectInfo.byteStart = reader.ReadUInt32();
if (header.m_Version >= 22)
objectInfo.byteStart = reader.ReadInt64();
else
objectInfo.byteStart = reader.ReadUInt32();
objectInfo.byteStart += header.m_DataOffset;
objectInfo.byteSize = reader.ReadUInt32();
objectInfo.typeID = reader.ReadInt32();
@@ -114,7 +134,6 @@ namespace AssetStudio
{
objectInfo.classID = reader.ReadUInt16();
objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID);
var isDestroyed = reader.ReadUInt16();
}
else
{
@@ -122,6 +141,16 @@ namespace AssetStudio
objectInfo.serializedType = type;
objectInfo.classID = type.classID;
}
if (header.m_Version < 11)
{
var isDestroyed = reader.ReadUInt16();
}
if (header.m_Version >= 11 && header.m_Version < 17)
{
var m_ScriptTypeIndex = reader.ReadInt16();
if (objectInfo.serializedType != null)
objectInfo.serializedType.m_ScriptTypeIndex = m_ScriptTypeIndex;
}
if (header.m_Version == 15 || header.m_Version == 16)
{
var stripped = reader.ReadByte();
@@ -169,10 +198,22 @@ namespace AssetStudio
m_Externals.Add(m_External);
}
if (header.m_Version >= 20)
{
int refTypesCount = reader.ReadInt32();
m_RefTypes = new List<SerializedType>(refTypesCount);
for (int i = 0; i < refTypesCount; i++)
{
m_RefTypes.Add(ReadSerializedType());
}
}
if (header.m_Version >= 5)
{
//var userInformation = reader.ReadStringToNull();
var userInformation = reader.ReadStringToNull();
}
//reader.AlignStream(16);
}
public void SetVersion(string stringVersion)
@@ -214,13 +255,18 @@ namespace AssetStudio
var typeTree = new List<TypeTreeNode>();
if (header.m_Version >= 12 || header.m_Version == 10)
{
ReadTypeTree5(typeTree);
TypeTreeBlobRead(typeTree);
}
else
{
ReadTypeTree(typeTree);
}
if (header.m_Version >= 21)
{
type.m_TypeDependencies = reader.ReadInt32Array();
}
type.m_Nodes = typeTree;
}
@@ -257,42 +303,37 @@ namespace AssetStudio
}
}
private void ReadTypeTree5(List<TypeTreeNode> typeTree)
private void TypeTreeBlobRead(List<TypeTreeNode> typeTree)
{
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();
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 >= 19)
{
typeTreeNode.m_RefTypeHash = reader.ReadUInt64();
}
}
reader.Position += numberOfNodes * nodeSize;
using (var stringBufferReader = new BinaryReader(new MemoryStream(reader.ReadBytes(stringBufferSize))))
var m_StringBuffer = reader.ReadBytes(stringBufferSize);
using (var stringBufferReader = new BinaryReader(new MemoryStream(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;
}
var typeTreeNode = typeTree[i];
typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset);
typeTreeNode.m_Name = ReadString(stringBufferReader, typeTreeNode.m_NameStrOffset);
}
reader.Position += stringBufferSize;
}
string ReadString(BinaryReader stringBufferReader, uint value)
@@ -311,5 +352,48 @@ namespace AssetStudio
return offset.ToString();
}
}
public void AddObject(Object obj)
{
Objects.Add(obj);
ObjectsDic.Add(obj.m_PathID, obj);
}
public static bool IsSerializedFile(EndianBinaryReader reader)
{
var fileSize = reader.BaseStream.Length;
if (fileSize < 20)
{
return false;
}
var m_MetadataSize = reader.ReadUInt32();
long m_FileSize = reader.ReadUInt32();
var m_Version = reader.ReadUInt32();
long m_DataOffset = reader.ReadUInt32();
var m_Endianess = reader.ReadByte();
var m_Reserved = reader.ReadBytes(3);
if (m_Version >= 22)
{
if (fileSize < 48)
{
return false;
}
m_MetadataSize = reader.ReadUInt32();
m_FileSize = reader.ReadInt64();
m_DataOffset = reader.ReadInt64();
}
if (m_FileSize != fileSize)
{
reader.Position = 0;
return false;
}
if (m_DataOffset > fileSize)
{
reader.Position = 0;
return false;
}
reader.Position = 0;
return true;
}
}
}

View File

@@ -8,9 +8,9 @@ namespace AssetStudio
public class SerializedFileHeader
{
public uint m_MetadataSize;
public uint m_FileSize;
public long m_FileSize;
public uint m_Version;
public uint m_DataOffset;
public long m_DataOffset;
public byte m_Endianess;
public byte[] m_Reserved;
}

View File

@@ -13,5 +13,6 @@ namespace AssetStudio
public List<TypeTreeNode> m_Nodes;
public byte[] m_ScriptID; //Hash128
public byte[] m_OldTypeHash; //Hash128
public int[] m_TypeDependencies;
}
}

10
AssetStudio/StreamFile.cs Normal file
View File

@@ -0,0 +1,10 @@
using System.IO;
namespace AssetStudio
{
public class StreamFile
{
public string fileName;
public Stream stream;
}
}

View File

@@ -31,6 +31,7 @@ namespace AssetStudio
value = reader.ReadSByte();
break;
case "UInt8":
case "char":
value = reader.ReadByte();
break;
case "short":
@@ -56,6 +57,7 @@ namespace AssetStudio
break;
case "UInt64":
case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64();
break;
case "float":
@@ -73,26 +75,6 @@ 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)
@@ -102,12 +84,11 @@ namespace AssetStudio
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 = GetMembers(members, 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 = GetMembers(map, 4);
var next = 4 + first.Count;
var second = GetMembers(map, next);
for (int j = 0; j < size; j++)
{
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
@@ -131,20 +112,37 @@ namespace AssetStudio
}
default:
{
if (i != members.Count && members[i + 1].m_Type == "Array")
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
{
goto 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, 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 = GetMembers(members, i);
i += @class.Count - 1;
for (int j = 1; j < @class.Count; j++)
{
ReadStringValue(sb, @class, reader, ref j);
}
break;
}
break;
}
}
if (append)
@@ -168,7 +166,6 @@ namespace AssetStudio
private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i)
{
var member = members[i];
var level = member.m_Level;
var varTypeStr = member.m_Type;
object value;
var align = (member.m_MetaFlag & 0x4000) != 0;
@@ -178,6 +175,7 @@ namespace AssetStudio
value = reader.ReadSByte();
break;
case "UInt8":
case "char":
value = reader.ReadByte();
break;
case "short":
@@ -203,6 +201,7 @@ namespace AssetStudio
break;
case "UInt64":
case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64();
break;
case "float":
@@ -222,14 +221,13 @@ namespace AssetStudio
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
var map = GetMembers(members, i);
i += map.Count - 1;
var first = GetMembers(map, 4);
var next = 4 + first.Count;
var second = GetMembers(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 +246,17 @@ namespace AssetStudio
}
default:
{
if (i != members.Count && members[i + 1].m_Type == "Array") //Array
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
var vector = GetMembers(members, 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 +264,10 @@ namespace AssetStudio
}
else //Class
{
var @class = GetMembers(members, level, i);
@class.RemoveAt(0);
i += @class.Count;
var @class = GetMembers(members, i);
i += @class.Count - 1;
var obj = new UType();
for (int j = 0; j < @class.Count; j++)
for (int j = 1; j < @class.Count; j++)
{
var classmember = @class[j];
var name = classmember.m_Name;
@@ -287,10 +283,11 @@ namespace AssetStudio
return value;
}
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int level, int index)
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int index)
{
var member2 = new List<TypeTreeNode>();
member2.Add(members[0]);
member2.Add(members[index]);
var level = members[index].m_Level;
for (int i = index + 1; i < members.Count; i++)
{
var member = members[i];
@@ -303,140 +300,5 @@ namespace AssetStudio
}
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);
}
}
}

View File

@@ -11,11 +11,12 @@ namespace AssetStudio
public string m_Name;
public int m_ByteSize;
public int m_Index;
public int m_IsArray;
public int m_IsArray; //m_TypeFlags
public int m_Version;
public int m_MetaFlag;
public int m_Level;
public uint m_TypeStrOffset;
public uint m_NameStrOffset;
public ulong m_RefTypeHash;
}
}

View File

@@ -9,73 +9,37 @@ namespace AssetStudio
public class UType : IDictionary<string, object>
{
private List<string> keys;
private List<object> values;
private IDictionary<string, 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;
}
values = new Dictionary<string, object>();
}
public object this[string key]
{
get
{
var index = GetValueIndex(key);
if (index != -1)
{
return values[index];
}
else
if (!values.ContainsKey(key))
{
return null;
}
return values[key];
}
set
{
var index = GetValueIndex(key);
if (index == -1)
if (!values.ContainsKey(key))
{
keys.Add(key);
values.Add(value);
}
else
{
values[index] = value;
}
values[key] = value;
}
}
public ICollection<string> Keys => keys;
public ICollection<object> Values => values;
public ICollection<object> Values => values.Values;
public int Count => keys.Count;
@@ -84,13 +48,13 @@ namespace AssetStudio
public void Add(string key, object value)
{
keys.Add(key);
values.Add(value);
values.Add(key, value);
}
public void Add(KeyValuePair<string, object> item)
{
keys.Add(item.Key);
values.Add(item.Value);
values.Add(item);
}
public void Clear()
@@ -101,55 +65,44 @@ namespace AssetStudio
public bool Contains(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
return values.Contains(item);
}
public bool ContainsKey(string key)
{
return GetValueIndex(key) != -1;
return values.ContainsKey(key);
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
throw new NotImplementedException();
values.CopyTo(array, arrayIndex);
}
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]);
}
return values.GetEnumerator();
}
public bool Remove(string key)
{
throw new NotImplementedException();
keys.Remove(key);
return values.Remove(key);
}
public bool Remove(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
keys.Remove(item.Key);
return values.Remove(item);
}
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;
}
return values.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
return values.GetEnumerator();
}
}
}

View File

@@ -12,7 +12,7 @@ namespace AssetStudio
{
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
{
@@ -78,14 +78,15 @@ 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.fileName = Path.GetFileName(data.path);
reader.BaseStream.Position = data.dataOffset;
file.stream = new MemoryStream(reader.ReadBytes(data.dataLength));
fileList.Add(file);
fileList[i] = file;
}
}
}

View File

@@ -9,7 +9,7 @@ using namespace System::Security::Permissions;
[assembly:AssemblyConfigurationAttribute(L"")];
[assembly:AssemblyCompanyAttribute(L"")];
[assembly:AssemblyProductAttribute(L"AssetStudioFBX")];
[assembly:AssemblyCopyrightAttribute(L"Copyright © Perfare 2018")];
[assembly:AssemblyCopyrightAttribute(L"Copyright © Perfare 2018-2020")];
[assembly:AssemblyTrademarkAttribute(L"")];
[assembly:AssemblyCultureAttribute(L"")];

View File

@@ -2,9 +2,14 @@
namespace AssetStudio
{
char* Fbx::StringToCharArray(String^ s)
char* Fbx::StringToUTF8(String^ s)
{
return (char*)(void*)Marshal::StringToHGlobalAnsi(s);
auto bytes = Text::Encoding::UTF8->GetBytes(s);
auto chars = new char[bytes->Length + 1];
pin_ptr<unsigned char> ptr = &bytes[0];
memcpy(chars, ptr, bytes->Length);
chars[bytes->Length] = '\0';
return chars;
}
void Fbx::Init(FbxManager** pSdkManager, FbxScene** pScene)

View File

@@ -10,19 +10,18 @@
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); \
name = StringToUTF8(str); \
block \
} \
finally \
{ \
Marshal::FreeHGlobal((IntPtr)name); \
delete name; \
} \
}
@@ -43,13 +42,14 @@ namespace AssetStudio {
public:
static Vector3 QuaternionToEuler(Quaternion q);
static Quaternion EulerToQuaternion(Vector3 v);
static char* StringToCharArray(String^ s);
static char* StringToUTF8(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);
static void Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision,
bool allNodes, bool skins, bool animation, bool blendShape, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii);
private:
bool exportSkins;
@@ -67,7 +67,7 @@ namespace AssetStudio {
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(String^ name, IImported^ imported, bool allNodes, bool skins, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii);
~Exporter();
void Exporter::LinkTexture(ImportedMaterialTexture^ texture, FbxFileTexture* pTexture, FbxProperty& prop);
@@ -76,11 +76,11 @@ namespace AssetStudio {
void SearchHierarchy(ImportedFrame^ frame, HashSet<String^>^ exportFrames);
void SetJointsFromImportedMeshes(bool allBones);
void ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame);
void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList);
void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ iMesh);
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);
void ExportAnimations(bool eulerFilter, float filterValue);
void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision);
void ExportMorphs();
};
};
}

View File

@@ -1,57 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<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="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</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>15.0</VCProjectVersion>
<ProjectGuid>{4F8EF5EF-732B-49CF-9EB3-B23E19AE6267}</ProjectGuid>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{B82DD1BA-4EEC-4F29-A686-03D7F0DF39B8}</ProjectGuid>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<Keyword>ManagedCProj</Keyword>
<RootNamespace>AssetStudioFBX</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.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>
<PlatformToolset>v142</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>
<PlatformToolset>v142</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
@@ -60,92 +60,79 @@
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<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 Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<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>
<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>
<PropertyGroup />
<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>
<PreprocessorDefinitions>FBXSDK_SHARED;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\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>
<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>
<PreprocessorDefinitions>FBXSDK_SHARED;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>libfbxsdk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>FBXSDK_SHARED;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>libfbxsdk.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)'=='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>
<AdditionalIncludeDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\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>
<AdditionalLibraryDirectories>C:\Program Files\Autodesk\FBX\FBX SDK\2020.0.1\lib\vs2017\x64\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="AssetStudioFBX.h" />
</ItemGroup>
<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>
<Project>{7662f8c2-7bfd-442e-a948-a43b4f7eb06e}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@@ -3,12 +3,21 @@
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
<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;hm;inl;inc;ipp;xsd</Extensions>
<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>
<ClInclude Include="AssetStudioFBX.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AssemblyInfo.cpp">
@@ -21,9 +30,4 @@
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AssetStudioFBX.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -2,7 +2,8 @@
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)
void Fbx::Exporter::Export(String^ path, IImported^ imported, bool eulerFilter, float filterPrecision,
bool allNodes, bool skins, bool animation, bool blendShape, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii)
{
FileInfo^ file = gcnew FileInfo(path);
DirectoryInfo^ dir = file->Directory;
@@ -12,18 +13,23 @@ namespace AssetStudio
}
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);
auto name = Path::GetFileName(path);
Exporter^ exporter = gcnew Exporter(name, imported, allNodes, skins, castToBone, boneSize, scaleFactor, versionIndex, isAscii);
if (blendShape)
{
exporter->ExportMorphs();
}
if (animation)
{
exporter->ExportAnimations(eulerFilter, filterPrecision);
}
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)
Fbx::Exporter::Exporter(String^ name, IImported^ imported, bool allNodes, bool skins, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii)
{
this->imported = imported;
exportSkins = skins;
@@ -51,7 +57,16 @@ namespace AssetStudio
FbxGlobalSettings& globalSettings = pScene->GetGlobalSettings();
globalSettings.SetSystemUnit(FbxSystemUnit(scaleFactor));
cDest = StringToCharArray(path);
if (imported->AnimationList->Count > 0)
{
auto ani = imported->AnimationList[0];
if (ani->SampleRate == 60.0f)
{
globalSettings.SetTimeMode(FbxTime::eFrames60);
}
}
cDest = StringToUTF8(name);
pExporter = FbxExporter::Create(pScene, "");
int pFileFormat = 0;
@@ -78,7 +93,7 @@ namespace AssetStudio
}
framePaths = nullptr;
if (!allFrames)
if (!allNodes)
{
framePaths = SearchHierarchy();
if (!framePaths)
@@ -88,7 +103,7 @@ namespace AssetStudio
}
pBindPose = FbxPose::Create(pScene, "BindPose");
pBindPose->SetIsBindPose(true);
pScene->AddPose(pBindPose);
frameToNode = gcnew Dictionary<ImportedFrame^, size_t>();
meshFrames = imported->MeshList != nullptr ? gcnew List<ImportedFrame^>() : nullptr;
@@ -96,7 +111,7 @@ namespace AssetStudio
if (imported->MeshList != nullptr)
{
SetJointsFromImportedMeshes(allBones);
SetJointsFromImportedMeshes(castToBone);
pMaterials = new FbxArray<FbxSurfacePhong*>();
pTextures = new FbxArray<FbxFileTexture*>();
@@ -155,23 +170,35 @@ namespace AssetStudio
}
if (cDest != NULL)
{
Marshal::FreeHGlobal((IntPtr)cDest);
delete cDest;
}
}
void Fbx::Exporter::SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool allBones)
void Fbx::Exporter::SetJointsNode(ImportedFrame^ frame, HashSet<String^>^ bonePaths, bool castToBone)
{
size_t pointer;
if (frameToNode->TryGetValue(frame, pointer))
{
auto pNode = (FbxNode*)pointer;
if (allBones || bonePaths->Contains(frame->Path))
if (castToBone)
{
FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
pJoint->Size.Set(FbxDouble(boneSize));
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->SetNodeAttribute(pJoint);
}
else if (bonePaths->Contains(frame->Path))
{
FbxSkeleton* pJoint = FbxSkeleton::Create(pScene, "");
pJoint->Size.Set(FbxDouble(boneSize));
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->SetNodeAttribute(pJoint);
pJoint = FbxSkeleton::Create(pScene, "");
pJoint->Size.Set(FbxDouble(boneSize));
pJoint->SetSkeletonType(FbxSkeleton::eLimbNode);
pNode->GetParent()->SetNodeAttribute(pJoint);
}
else
{
FbxNull* pNull = FbxNull::Create(pScene, "");
@@ -185,7 +212,7 @@ namespace AssetStudio
}
for (int i = 0; i < frame->Count; i++)
{
SetJointsNode(frame[i], bonePaths, allBones);
SetJointsNode(frame[i], bonePaths, castToBone);
}
}
@@ -236,7 +263,7 @@ namespace AssetStudio
}
}
void Fbx::Exporter::SetJointsFromImportedMeshes(bool allBones)
void Fbx::Exporter::SetJointsFromImportedMeshes(bool castToBone)
{
if (!exportSkins)
{
@@ -257,7 +284,7 @@ namespace AssetStudio
}
}
SetJointsNode(imported->RootFrame, bonePaths, allBones);
SetJointsNode(imported->RootFrame, bonePaths, castToBone);
}
void Fbx::Exporter::ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame)
@@ -293,9 +320,9 @@ namespace AssetStudio
}
}
void Fbx::Exporter::ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList)
void Fbx::Exporter::ExportMesh(FbxNode* pFrameNode, ImportedMesh^ iMesh)
{
List<ImportedBone^>^ boneList = meshList->BoneList;
List<ImportedBone^>^ boneList = iMesh->BoneList;
bool hasBones;
if (exportSkins && boneList != nullptr)
{
@@ -306,63 +333,88 @@ namespace AssetStudio
hasBones = false;
}
FbxArray<FbxNode*>* pBoneNodeList = nullptr;
FbxArray<FbxCluster*>* pClusterArray = nullptr;
try
{
if (hasBones)
{
pBoneNodeList = new FbxArray<FbxNode*>();
pBoneNodeList->Reserve(boneList->Count);
pClusterArray = new FbxArray<FbxCluster*>(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);
if (bone->Path != nullptr)
{
auto frame = imported->RootFrame->FindFrameByPath(bone->Path);
auto boneNode = (FbxNode*)frameToNode[frame];
FbxString lClusterName = boneNode->GetNameOnly() + FbxString("Cluster");
FbxCluster* pCluster = FbxCluster::Create(pScene, lClusterName.Buffer());
pCluster->SetLink(boneNode);
pCluster->SetLinkMode(FbxCluster::eTotalOne);
pClusterArray->Add(pCluster);
}
else
{
pClusterArray->Add(NULL);
}
}
}
FbxMesh* pMesh = FbxMesh::Create(pScene, "");
FbxMesh* pMesh = FbxMesh::Create(pScene, pFrameNode->GetName());
pFrameNode->SetNodeAttribute(pMesh);
int vertexCount = 0;
for (int i = 0; i < meshList->SubmeshList->Count; i++)
for (int i = 0; i < iMesh->SubmeshList->Count; i++)
{
vertexCount += meshList->SubmeshList[i]->VertexList->Count;
vertexCount += iMesh->SubmeshList[i]->VertexList->Count;
}
pMesh->InitControlPoints(vertexCount);
FbxVector4* pControlPoints = pMesh->GetControlPoints();
FbxGeometryElementNormal* lGeometryElementNormal = pMesh->CreateElementNormal();
lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
FbxGeometryElementNormal* lGeometryElementNormal = NULL;
if (iMesh->hasNormal)
{
lGeometryElementNormal = pMesh->CreateElementNormal();
lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
}
FbxGeometryElementUV* lGeometryElementUV = pMesh->CreateElementUV("UV0");
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
if (iMesh->hasUV[0])
{
auto lGeometryElementUV = pMesh->CreateElementUV("UV0", FbxLayerElement::eTextureDiffuse);
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
}
FbxGeometryElementTangent* lGeometryElementTangent = pMesh->CreateElementTangent();
lGeometryElementTangent->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementTangent->SetReferenceMode(FbxGeometryElement::eDirect);
if (iMesh->hasUV[1])
{
auto lGeometryElementUV = pMesh->CreateElementUV("UV1", FbxLayerElement::eTextureNormalMap);
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
}
FbxGeometryElementVertexColor* lGeometryElementVertexColor = nullptr;
bool vertexColours = vertexCount > 0 && dynamic_cast<ImportedVertexWithColour^>(meshList->SubmeshList[0]->VertexList[0]) != nullptr;
if (vertexColours)
/*for (int uv = 0; uv < 8; uv++)
{
if (iMesh->hasUV[uv])
{
auto lGeometryElementUV = pMesh->CreateElementUV(FbxString("UV") + FbxString(uv));
lGeometryElementUV->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementUV->SetReferenceMode(FbxGeometryElement::eDirect);
}
}*/
FbxGeometryElementTangent* lGeometryElementTangent = NULL;
if (iMesh->hasTangent)
{
lGeometryElementTangent = pMesh->CreateElementTangent();
lGeometryElementTangent->SetMappingMode(FbxGeometryElement::eByControlPoint);
lGeometryElementTangent->SetReferenceMode(FbxGeometryElement::eDirect);
}
FbxGeometryElementVertexColor* lGeometryElementVertexColor = NULL;
if (iMesh->hasColor)
{
lGeometryElementVertexColor = pMesh->CreateElementVertexColor();
lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint);
@@ -374,9 +426,9 @@ namespace AssetStudio
lGeometryElementMaterial->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
int firstVertex = 0;
for (int i = 0; i < meshList->SubmeshList->Count; i++)
for (int i = 0; i < iMesh->SubmeshList->Count; i++)
{
ImportedSubmesh^ meshObj = meshList->SubmeshList[i];
ImportedSubmesh^ meshObj = iMesh->SubmeshList[i];
List<ImportedVertex^>^ vertexList = meshObj->VertexList;
List<ImportedFace^>^ faceList = meshObj->FaceList;
@@ -387,7 +439,7 @@ namespace AssetStudio
char* pMatName = NULL;
try
{
pMatName = StringToCharArray(mat->Name);
pMatName = StringToUTF8(mat->Name);
int foundMat = -1;
for (int j = 0; j < pMaterials->GetCount(); j++)
{
@@ -414,15 +466,15 @@ namespace AssetStudio
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->DiffuseFactor.Set(FbxDouble(diffuse.A));
pMat->Ambient.Set(FbxDouble3(ambient.R, ambient.G, ambient.B));
pMat->AmbientFactor.Set(FbxDouble(ambient.A));
//pMat->AmbientFactor.Set(FbxDouble(ambient.A));
pMat->Emissive.Set(FbxDouble3(emissive.R, emissive.G, emissive.B));
pMat->EmissiveFactor.Set(FbxDouble(emissive.A));
//pMat->EmissiveFactor.Set(FbxDouble(emissive.A));
pMat->Specular.Set(FbxDouble3(specular.R, specular.G, specular.B));
pMat->SpecularFactor.Set(FbxDouble(specular.A));
//pMat->SpecularFactor.Set(FbxDouble(specular.A));
pMat->Reflection.Set(FbxDouble3(reflection.R, reflection.G, reflection.B));
pMat->ReflectionFactor.Set(FbxDouble(reflection.A));
//pMat->ReflectionFactor.Set(FbxDouble(reflection.A));
pMat->Shininess.Set(FbxDouble(mat->Shininess));
pMat->TransparencyFactor.Set(FbxDouble(mat->Transparency));
pMat->ShadingModel.Set(lShadingName);
@@ -432,7 +484,7 @@ namespace AssetStudio
bool hasTexture = false;
for each (ImportedMaterialTexture^ texture in mat->Textures)
for each (ImportedMaterialTexture ^ texture in mat->Textures)
{
auto pTexture = ExportTexture(ImportedHelpers::FindTexture(texture->Name, imported->TextureList));
if (pTexture != NULL)
@@ -467,45 +519,59 @@ namespace AssetStudio
}
finally
{
Marshal::FreeHGlobal((IntPtr)pMatName);
delete pMatName;
}
}
for (int j = 0; j < vertexList->Count; j++)
{
ImportedVertex^ vertex = vertexList[j];
ImportedVertex^ iVertex = vertexList[j];
Vector3 coords = vertex->Position;
pControlPoints[j + firstVertex] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
Vector3 vertex = iVertex->Vertex;
pControlPoints[j + firstVertex] = FbxVector4(vertex.X, vertex.Y, vertex.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)
if (iMesh->hasNormal)
{
lGeometryElementUV->GetDirectArray().Add(FbxVector2(uv[0], uv[1]));
Vector3 normal = iVertex->Normal;
lGeometryElementNormal->GetDirectArray().Add(FbxVector4(normal.X, normal.Y, normal.Z, 0));
}
Vector4 tangent = vertex->Tangent;
lGeometryElementTangent->GetDirectArray().Add(FbxVector4(tangent.X, tangent.Y, tangent.Z, tangent.W));
if (vertexColours)
//for (int uv = 0; uv < 8; uv++)
for (int uv = 0; uv < 2; uv++)
{
ImportedVertexWithColour^ vert = (ImportedVertexWithColour^)vertexList[j];
lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(vert->Colour.R, vert->Colour.G, vert->Colour.B, vert->Colour.A));
if (iMesh->hasUV[uv])
{
auto m_UV = iVertex->UV[uv];
auto lGeometryElementUV = pMesh->GetElementUV(uv);
lGeometryElementUV->GetDirectArray().Add(FbxVector2(m_UV[0], m_UV[1]));
}
}
if (hasBones && vertex->BoneIndices != nullptr)
if (iMesh->hasTangent)
{
auto boneIndices = vertex->BoneIndices;
auto weights4 = vertex->Weights;
Vector4 tangent = iVertex->Tangent;
lGeometryElementTangent->GetDirectArray().Add(FbxVector4(tangent.X, tangent.Y, tangent.Z, tangent.W));
}
if (iMesh->hasColor)
{
auto color = iVertex->Color;
lGeometryElementVertexColor->GetDirectArray().Add(FbxColor(color.R, color.G, color.B, color.A));
}
if (hasBones && iVertex->BoneIndices != nullptr)
{
auto boneIndices = iVertex->BoneIndices;
auto weights4 = iVertex->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]);
if (pCluster)
{
pCluster->AddControlPointIndex(j + firstVertex, weights4[k]);
}
}
}
}
@@ -531,7 +597,7 @@ namespace AssetStudio
for (int j = 0; j < boneList->Count; j++)
{
FbxCluster* pCluster = pClusterArray->GetAt(j);
if (pCluster->GetControlPointIndicesCount() > 0)
if (pCluster)
{
auto boneMatrix = boneList[j]->Matrix;
FbxAMatrix lBoneMatrix;
@@ -558,10 +624,6 @@ namespace AssetStudio
}
finally
{
if (pBoneNodeList != NULL)
{
delete pBoneNodeList;
}
if (pClusterArray != NULL)
{
delete pClusterArray;
@@ -579,7 +641,7 @@ namespace AssetStudio
char* pTexName = NULL;
try
{
pTexName = StringToCharArray(matTexName);
pTexName = StringToUTF8(matTexName);
int foundTex = -1;
for (int i = 0; i < pTextures->GetCount(); i++)
{
@@ -608,17 +670,7 @@ namespace AssetStudio
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();
}
FileInfo^ file = gcnew FileInfo(matTex->Name);
BinaryWriter^ writer = gcnew BinaryWriter(file->Create());
writer->Write(matTex->Data);
writer->Close();
@@ -626,7 +678,7 @@ namespace AssetStudio
}
finally
{
Marshal::FreeHGlobal((IntPtr)pTexName);
delete pTexName;
}
}
@@ -640,7 +692,7 @@ namespace AssetStudio
prop.ConnectSrcObject(pTexture);
}
void Fbx::Exporter::ExportAnimations(bool eulerFilter, float filterPrecision, bool flatInbetween)
void Fbx::Exporter::ExportAnimations(bool eulerFilter, float filterPrecision)
{
auto importedAnimationList = imported->AnimationList;
if (importedAnimationList == nullptr)
@@ -667,11 +719,11 @@ namespace AssetStudio
{
kTakeName = FbxString("Take") + FbxString(i);
}
ExportKeyframedAnimation(importedAnimation, kTakeName, lFilter, filterPrecision, flatInbetween);
ExportKeyframedAnimation(importedAnimation, kTakeName, lFilter, filterPrecision);
}
}
void Fbx::Exporter::ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision, bool flatInbetween)
void Fbx::Exporter::ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision)
{
List<ImportedAnimationKeyframedTrack^>^ pAnimationList = parser->TrackList;
@@ -760,210 +812,104 @@ namespace AssetStudio
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())
//BlendShape
if (keyframeList->BlendShape != nullptr)
{
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;
FbxString channelName;
WITH_MARSHALLED_STRING
(
pShapeName,
morph->ClipName + (meshList->SubmeshList->Count > 1 ? "_" + meshObjIdx : String::Empty),
lBlendShape = FbxBlendShape::Create(pScene, pShapeName);
pClipName,
keyframeList->BlendShape->ChannelName,
channelName = FbxString(pClipName);
);
FbxProperty rootGroupProp = FbxProperty::Create(lBlendShape, FbxStringDT, "RootGroup");
pBaseMesh->AddDeformer(lBlendShape);
List<ImportedMorphKeyframe^>^ keyframes = morph->KeyframeList;
for (int i = 0; i < morph->Channels->Count; i++)
auto lGeometry = (FbxGeometry*)pNode->GetNodeAttribute();
int lBlendShapeDeformerCount = lGeometry->GetDeformerCount(FbxDeformer::eBlendShape);
if (lBlendShapeDeformerCount > 0)
{
FbxBlendShapeChannel* lBlendShapeChannel;
if (!flatInbetween)
FbxBlendShape* lBlendShape = (FbxBlendShape*)lGeometry->GetDeformer(0, FbxDeformer::eBlendShape);
int lBlendShapeChannelCount = lBlendShape->GetBlendShapeChannelCount();
for (int lChannelIndex = 0; lChannelIndex < lBlendShapeChannelCount; ++lChannelIndex)
{
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)
FbxBlendShapeChannel* lChannel = lBlendShape->GetBlendShapeChannel(lChannelIndex);
FbxString lChannelName = lChannel->GetNameOnly();
if (lChannelName == channelName)
{
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);
FbxAnimCurve* lAnimCurve = lGeometry->GetShapeChannel(0, lChannelIndex, lAnimLayer, true);
lAnimCurve->KeyModifyBegin();
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)
for each (auto keyframe in keyframeList->BlendShape->Keyframes)
{
Vector3 coords = keyframe->VertexList[j]->Position;
pControlPoints[controlPointIndex] = FbxVector4(coords.X, coords.Y, coords.Z, 0);
lTime.SetSecondDouble(keyframe->time);
int lKeyIndex = lAnimCurve->KeyAdd(lTime);
lAnimCurve->KeySetValue(lKeyIndex, keyframe->value);
lAnimCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);
}
}
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));
}
}
lAnimCurve->KeyModifyEnd();
}
}
}
meshVertexIndex += meshList->SubmeshList[meshObjIdx]->VertexList->Count;
}
}
}*/
}
}
void Fbx::Exporter::ExportMorphs()
{
if (imported->MeshList == nullptr)
{
return;
}
for each (ImportedMorph ^ morph in imported->MorphList)
{
auto frame = imported->RootFrame->FindFrameByPath(morph->Path);
if (frame != nullptr)
{
FbxNode* pNode = (FbxNode*)frameToNode[frame];
FbxMesh* pMesh = pNode->GetMesh();
FbxBlendShape* lBlendShape = FbxBlendShape::Create(pScene, pMesh->GetNameOnly() + FbxString("BlendShape"));
pMesh->AddDeformer(lBlendShape);
for (int i = 0; i < morph->Channels->Count; i++)
{
auto channel = morph->Channels[i];
FbxBlendShapeChannel* lBlendShapeChannel;
WITH_MARSHALLED_STRING
(
pChannelName,
channel->Name,
lBlendShapeChannel = FbxBlendShapeChannel::Create(pScene, pChannelName);
);
lBlendShape->AddBlendShapeChannel(lBlendShapeChannel);
for each (ImportedMorphKeyframe ^ keyframe in channel->KeyframeList)
{
FbxShape* lShape = FbxShape::Create(pScene, FbxString(keyframe->Weight));
lBlendShapeChannel->AddTargetShape(lShape, keyframe->Weight);
auto vectorCount = pMesh->GetControlPointsCount();
FbxVector4* orilVector4 = pMesh->GetControlPoints();
lShape->InitControlPoints(vectorCount);
FbxVector4* lVector4 = lShape->GetControlPoints();
for (int j = 0; j < vectorCount; j++)
{
auto vertex = orilVector4[j];
lVector4[j] = FbxVector4(vertex);
}
for (int j = 0; j < keyframe->VertexList->Count; j++)
{
auto index = keyframe->VertexList[j]->Index;
auto vertex = keyframe->VertexList[j]->Vertex->Vertex;
lVector4[index] = FbxVector4(vertex.X, vertex.Y, vertex.Z, 0);
}
}
}
}
}
}
}

View File

@@ -1,37 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<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')" />
<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>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{52B196FB-4C8A-499B-B877-1A0EB4F33EC0}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AssetStudioGUI</RootNamespace>
<AssemblyName>AssetStudioGUI</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<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>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
@@ -39,20 +20,21 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<DebugType>none</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
@@ -60,24 +42,31 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<DebugType>none</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\as.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="OpenTK">
<HintPath>Libraries\OpenTK.dll</HintPath>
<Reference Include="OpenTK, Version=3.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>..\packages\OpenTK.3.1.0\lib\net20\OpenTK.dll</HintPath>
</Reference>
<Reference Include="OpenTK.GLControl">
<HintPath>Libraries\OpenTK.GLControl.dll</HintPath>
<Reference Include="OpenTK.GLControl, Version=3.1.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>..\packages\OpenTK.GLControl.3.1.0\lib\net20\OpenTK.GLControl.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -85,37 +74,43 @@
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<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">
<Compile Include="AssetStudioGUIForm.designer.cs">
<DependentUpon>AssetStudioGUIForm.cs</DependentUpon>
</Compile>
<Compile Include="Components\TypeTreeItem.cs" />
<Compile Include="Components\AssetItem.cs" />
<Compile Include="Components\GameObjectTreeNode.cs" />
<Compile Include="Components\GOHierarchy.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Components\OpenFolderDialog.cs" />
<Compile Include="Components\TreeViewExtensions.cs" />
<Compile Include="Components\TypeTreeItem.cs" />
<Compile Include="Exporter.cs" />
<Compile Include="ExportOptions.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ExportOptions.designer.cs">
<DependentUpon>ExportOptions.cs</DependentUpon>
</Compile>
<Compile Include="GUILogger.cs" />
<Compile Include="GUIProgress.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Studio.cs" />
<Compile Include="TGASharpLib.cs" />
<EmbeddedResource Include="AssetStudioGUIForm.resx">
<DependentUpon>AssetStudioGUIForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="ExportOptions.resx">
<DependentUpon>ExportOptions.cs</DependentUpon>
</EmbeddedResource>
@@ -129,11 +124,8 @@
<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="OpenTK.dll.config" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -145,21 +137,7 @@
</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>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\preview.png" />
@@ -167,26 +145,35 @@
<ItemGroup>
<None Include="Resources\as.ico" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x86'">
<ContentWithTargetPath Include="Libraries\x86\fmod.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>fmod.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x86\libfbxsdk.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>libfbxsdk.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
<ContentWithTargetPath Include="Libraries\x64\fmod.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>fmod.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Libraries\x64\libfbxsdk.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>libfbxsdk.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetStudioUtility\AssetStudioUtility.csproj">
<Project>{9131c403-7fe8-444d-9af5-5fe5df76ff24}</Project>
<Project>{80aec261-21ee-4e4f-a93b-7a744dc84888}</Project>
<Name>AssetStudioUtility</Name>
</ProjectReference>
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj">
<Project>{af56b63c-1764-41b7-9e60-8d485422ac3b}</Project>
<Project>{7662f8c2-7bfd-442e-a948-a43b4f7eb06e}</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>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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
});
}
}
}

View File

@@ -40,7 +40,7 @@ namespace AssetStudioGUI
hItem = node.Handle,
mask = TVIF_STATE,
stateMask = TVIS_STATEIMAGEMASK,
state = 0
state = node.StateImageIndex //freeze bugfix (no)
};
SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
}

View File

@@ -31,27 +31,35 @@
this.OKbutton = new System.Windows.Forms.Button();
this.Cancel = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.pathIDAsDumpName = new System.Windows.Forms.CheckBox();
this.pathIDAsImageName = new System.Windows.Forms.CheckBox();
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.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.groupBox1.SuspendLayout();
this.panel1.SuspendLayout();
@@ -63,20 +71,20 @@
//
// OKbutton
//
this.OKbutton.Location = new System.Drawing.Point(321, 267);
this.OKbutton.Location = new System.Drawing.Point(308, 347);
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(389, 347);
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,44 +93,132 @@
// groupBox1
//
this.groupBox1.AutoSize = true;
this.groupBox1.Controls.Add(this.pathIDAsDumpName);
this.groupBox1.Controls.Add(this.pathIDAsImageName);
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(246, 327);
this.groupBox1.TabIndex = 9;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Convert";
this.groupBox1.Text = "Export";
//
// pathIDAsDumpName
//
this.pathIDAsDumpName.AutoSize = true;
this.pathIDAsDumpName.Checked = true;
this.pathIDAsDumpName.CheckState = System.Windows.Forms.CheckState.Checked;
this.pathIDAsDumpName.Location = new System.Drawing.Point(6, 217);
this.pathIDAsDumpName.Name = "pathIDAsDumpName";
this.pathIDAsDumpName.Size = new System.Drawing.Size(201, 17);
this.pathIDAsDumpName.TabIndex = 12;
this.pathIDAsDumpName.Text = "Dump assets with PathID as filename";
this.pathIDAsDumpName.UseVisualStyleBackColor = true;
//
// pathIDAsImageName
//
this.pathIDAsImageName.AutoSize = true;
this.pathIDAsImageName.Checked = true;
this.pathIDAsImageName.CheckState = System.Windows.Forms.CheckState.Checked;
this.pathIDAsImageName.Location = new System.Drawing.Point(6, 196);
this.pathIDAsImageName.Name = "pathIDAsImageName";
this.pathIDAsImageName.Size = new System.Drawing.Size(234, 17);
this.pathIDAsImageName.TabIndex = 11;
this.pathIDAsImageName.Text = "Export image assets with PathID as filename";
this.pathIDAsImageName.UseVisualStyleBackColor = true;
//
// 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(47, 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(52, 17);
this.tojpg.TabIndex = 4;
this.tojpg.Text = "JPEG";
this.tojpg.UseVisualStyleBackColor = true;
@@ -131,9 +227,9 @@
//
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(48, 17);
this.topng.TabIndex = 3;
this.topng.TabStop = true;
this.topng.Text = "PNG";
@@ -142,9 +238,9 @@
// 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(48, 17);
this.tobmp.TabIndex = 2;
this.tobmp.Text = "BMP";
this.tobmp.UseVisualStyleBackColor = true;
@@ -154,9 +250,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 +260,53 @@
// groupBox2
//
this.groupBox2.AutoSize = true;
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(258, 13);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(214, 276);
this.groupBox2.Size = new System.Drawing.Size(206, 327);
this.groupBox2.TabIndex = 11;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Fbx";
//
// 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 +315,9 @@
0,
0,
131072});
this.scaleFactor.Location = new System.Drawing.Point(83, 155);
this.scaleFactor.Location = new System.Drawing.Point(83, 219);
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 +329,9 @@
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(6, 157);
this.label5.Location = new System.Drawing.Point(6, 221);
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 +342,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, 252);
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, 256);
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 +367,25 @@
"7.3",
"7.4",
"7.5"});
this.fbxVersion.Location = new System.Drawing.Point(75, 236);
this.fbxVersion.Location = new System.Drawing.Point(77, 284);
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, 287);
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, 190);
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 +396,30 @@
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(6, 130);
this.label2.Location = new System.Drawing.Point(6, 192);
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 +431,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 +441,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,10 +478,10 @@
// 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(477, 380);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.Cancel);
@@ -405,17 +516,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 +534,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 pathIDAsImageName;
private System.Windows.Forms.CheckBox pathIDAsDumpName;
}
}

View File

@@ -1,11 +1,4 @@
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 System.Windows.Forms;
namespace AssetStudioGUI
@@ -15,9 +8,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;
foreach (Control c in panel1.Controls)
{
if (c.Text == str)
@@ -26,46 +21,50 @@ 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;
boneSize.Value = Properties.Settings.Default.boneSize;
scaleFactor.Value = Properties.Settings.Default.scaleFactor;
fbxVersion.SelectedIndex = Properties.Settings.Default.fbxVersion;
fbxFormat.SelectedIndex = Properties.Settings.Default.fbxFormat;
pathIDAsImageName.Checked = Properties.Settings.Default.pathIDAsImageName;
pathIDAsDumpName.Checked = Properties.Settings.Default.pathIDAsDumpName;
}
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 = 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.boneSize = boneSize.Value;
Properties.Settings.Default.scaleFactor = scaleFactor.Value;
Properties.Settings.Default.fbxVersion = fbxVersion.SelectedIndex;
Properties.Settings.Default.fbxFormat = fbxFormat.SelectedIndex;
Properties.Settings.Default.pathIDAsImageName = pathIDAsImageName.Checked;
Properties.Settings.Default.pathIDAsDumpName = pathIDAsDumpName.Checked;
Properties.Settings.Default.Save();
DialogResult = DialogResult.OK;
Close();

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Text;
using AssetStudio;
using TGASharpLib;
namespace AssetStudioGUI
{
@@ -11,15 +12,16 @@ namespace AssetStudioGUI
{
public static bool ExportTexture2D(AssetItem item, string exportPathName)
{
var converter = new Texture2DConverter((Texture2D)item.Asset);
var convertTexture = (bool)Properties.Settings.Default["convertTexture"];
if (convertTexture)
string exportFullName;
var m_Texture2D = (Texture2D)item.Asset;
if (Properties.Settings.Default.convertTexture)
{
var bitmap = converter.ConvertToBitmap(true);
var bitmap = m_Texture2D.ConvertToBitmap(true);
if (bitmap == null)
return false;
ImageFormat format = null;
var ext = (string)Properties.Settings.Default["convertType"];
var ext = Properties.Settings.Default.convertType;
bool tga = false;
switch (ext)
{
case "BMP":
@@ -31,20 +33,35 @@ namespace AssetStudioGUI
case "JPEG":
format = ImageFormat.Jpeg;
break;
case "TGA":
tga = true;
break;
}
var exportFullName = exportPathName + item.Text + "." + ext.ToLower();
if (Properties.Settings.Default.pathIDAsImageName)
exportFullName = exportPathName + item.m_PathID.ToString() + "." + ext.ToLower();
else
exportFullName = exportPathName + item.Text + "." + ext.ToLower();
if (ExportFileExists(exportFullName))
return false;
bitmap.Save(exportFullName, format);
if (tga)
{
var file = new TGA(bitmap);
file.Save(exportFullName);
}
else
bitmap.Save(exportFullName, format);
bitmap.Dispose();
return true;
}
else
{
var exportFullName = exportPathName + item.Text + converter.GetExtensionName();
if (Properties.Settings.Default.pathIDAsImageName)
exportFullName = exportPathName + item.m_PathID.ToString() + ".tex";
else
exportFullName = exportPathName + item.Text + ".tex";
if (ExportFileExists(exportFullName))
return false;
File.WriteAllBytes(exportFullName, converter.ConvertToContainer());
File.WriteAllBytes(exportFullName, m_Texture2D.image_data.GetData());
return true;
}
}
@@ -52,12 +69,11 @@ 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))
@@ -82,7 +98,7 @@ namespace AssetStudioGUI
var exportFullName = exportPath + item.Text + ".shader";
if (ExportFileExists(exportFullName))
return false;
var m_Shader = (Shader) item.Asset;
var m_Shader = (Shader)item.Asset;
if (m_Shader.compressedBlob != null) //5.5 and up
{
var strs = ShaderConverter.ConvertMultiple(m_Shader);
@@ -103,7 +119,15 @@ namespace AssetStudioGUI
public static bool ExportTextAsset(AssetItem item, string exportPath)
{
var m_TextAsset = (TextAsset)(item.Asset);
var exportFullName = exportPath + item.Text + (item.Extension ?? ".txt");
var extension = ".txt";
if (Properties.Settings.Default.restoreExtensionName)
{
if (!string.IsNullOrEmpty(item.Container))
{
extension = Path.GetExtension(item.Container);
}
}
var exportFullName = exportPath + item.Text + extension;
if (ExportFileExists(exportFullName))
return false;
File.WriteAllBytes(exportFullName, m_TextAsset.m_Script);
@@ -167,24 +191,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)
{
@@ -224,7 +249,7 @@ namespace AssetStudioGUI
public static bool ExportVideoClip(AssetItem item, string exportPath)
{
var m_VideoClip = (VideoClip)item.Asset;
var m_VideoData = m_VideoClip.m_VideoData.Value;
var m_VideoData = m_VideoClip.m_VideoData.GetData();
if (m_VideoData != null && m_VideoData.Length != 0)
{
var exportFullName = exportPath + item.Text + Path.GetExtension(m_VideoClip.m_OriginalPath);
@@ -249,7 +274,9 @@ namespace AssetStudioGUI
public static bool ExportSprite(AssetItem item, string exportPath)
{
ImageFormat format = null;
var type = (string)Properties.Settings.Default["convertType"];
string exportFullName;
var type = Properties.Settings.Default.convertType;
bool tga = false;
switch (type)
{
case "BMP":
@@ -261,14 +288,26 @@ namespace AssetStudioGUI
case "JPEG":
format = ImageFormat.Jpeg;
break;
case "TGA":
tga = true;
break;
}
var exportFullName = exportPath + item.Text + "." + type.ToLower();
if (Properties.Settings.Default.pathIDAsImageName)
exportFullName = exportPath + item.m_PathID.ToString() + "." + type.ToLower();
else
exportFullName = exportPath + item.Text + "." + type.ToLower();
if (ExportFileExists(exportFullName))
return false;
var bitmap = SpriteHelper.GetImageFromSprite((Sprite)item.Asset);
var bitmap = ((Sprite)item.Asset).GetImage();
if (bitmap != null)
{
bitmap.Save(exportFullName, format);
if (tga)
{
var file = new TGA(bitmap);
file.Save(exportFullName);
}
else
bitmap.Save(exportFullName, format);
bitmap.Dispose();
return true;
}
@@ -299,30 +338,94 @@ namespace AssetStudioGUI
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);
ExportFbx(convert, exportPath);
return true;
}
public static bool ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
public static void ExportGameObject(GameObject gameObject, string exportPath, List<AssetItem> animationList = null)
{
var convert = animationList != null ? new ModelConverter(gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(gameObject);
exportPath = exportPath + Studio.FixFileName(gameObject.m_Name) + ".fbx";
return ExportFbx(convert, exportPath);
ExportFbx(convert, exportPath);
}
private static bool ExportFbx(IImported convert, string exportPath)
public static void ExportGameObjectMerge(List<GameObject> gameObject, string exportPath, List<AssetItem> animationList = null)
{
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);
return true;
var rootName = Path.GetFileNameWithoutExtension(exportPath);
var convert = animationList != null ? new ModelConverter(rootName, gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(rootName, gameObject);
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 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, scaleFactor, fbxVersion, fbxFormat == 1);
}
public static bool ExportDumpFile(AssetItem item, string exportPath)
{
string exportFullName;
if (Properties.Settings.Default.pathIDAsDumpName)
{
exportFullName = exportPath + item.m_PathID.ToString() + ".txt";
}
else
{
exportFullName = exportPath + item.Text + ".txt";
}
if (ExportFileExists(exportFullName))
return false;
var str = item.Asset.Dump();
if (str != null)
{
File.WriteAllText(exportFullName, 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);
}
}
}
}

View File

@@ -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.

Binary file not shown.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,22 +0,0 @@
crunch/crnlib uses the ZLIB license:
http://opensource.org/licenses/Zlib
Copyright (c) 2010-2016 Richard Geldreich, Jr. and Binomial LLC
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

View File

@@ -1,13 +0,0 @@
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,25 @@
<configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
<dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
<dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
<dllmap os="linux" dll="libX11" target="libX11.so.6"/>
<dllmap os="linux" dll="libXi" target="libXi.so.6"/>
<dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
<dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
<dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
<!-- XQuartz compatibility (X11 on Mac) -->
<dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
<dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
<dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
<dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
<dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
<dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
</configuration>

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AssetStudioGUI
@@ -8,7 +9,7 @@ namespace AssetStudioGUI
static class Program
{
/// <summary>
/// The main entry point for the application.
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()

View File

@@ -2,35 +2,35 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("AssetStudioGUI")]
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("AssetStudioGUI Mod by VaDiM")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AssetStudioGUI")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyCopyright("Copyright © Perfare 2018-2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
// ComVisible 设置为 false 会使此程序集中的类型
// COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("05c04c20-dd89-4895-9f06-33d5cfbfe925")]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("52b196fb-4c8a-499b-b877-1a0eb4f33ec0")]
// Version information for an assembly consists of the following four values:
// 程序集的版本信息由下列四个值组成:
//
// Major Version
// Minor Version
// Build Number
// Revision
// 主版本
// 次版本
// 生成号
// 修订号
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("0.14.38.5")]
[assembly: AssemblyFileVersion("0.14.38.5")]

View File

@@ -19,7 +19,7 @@ namespace AssetStudioGUI.Properties {
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@@ -48,6 +48,7 @@ namespace AssetStudioGUI.Properties {
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性
/// 重写当前线程的 CurrentUICulture 属性。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {

View File

@@ -1,10 +1,10 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
// Этот код создан программой.
// Исполняемая версия:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
// повторной генерации кода.
// </auto-generated>
//------------------------------------------------------------------------------
@@ -12,7 +12,7 @@ namespace AssetStudioGUI.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.6.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -119,18 +119,6 @@ namespace AssetStudioGUI.Properties {
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool displayOriginalName {
get {
return ((bool)(this["displayOriginalName"]));
}
set {
this["displayOriginalName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
@@ -158,36 +146,36 @@ namespace AssetStudioGUI.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool allFrames {
public bool exportAllNodes {
get {
return ((bool)(this["allFrames"]));
return ((bool)(this["exportAllNodes"]));
}
set {
this["allFrames"] = value;
this["exportAllNodes"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool allBones {
public bool exportSkins {
get {
return ((bool)(this["allBones"]));
return ((bool)(this["exportSkins"]));
}
set {
this["allBones"] = value;
this["exportSkins"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool skins {
public bool exportAnimations {
get {
return ((bool)(this["skins"]));
return ((bool)(this["exportAnimations"]));
}
set {
this["skins"] = value;
this["exportAnimations"] = value;
}
}
@@ -203,18 +191,6 @@ namespace AssetStudioGUI.Properties {
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool flatInbetween {
get {
return ((bool)(this["flatInbetween"]));
}
set {
this["flatInbetween"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("3")]
@@ -250,5 +226,65 @@ namespace AssetStudioGUI.Properties {
this["scaleFactor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool exportBlendShape {
get {
return ((bool)(this["exportBlendShape"]));
}
set {
this["exportBlendShape"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool castToBone {
get {
return ((bool)(this["castToBone"]));
}
set {
this["castToBone"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool restoreExtensionName {
get {
return ((bool)(this["restoreExtensionName"]));
}
set {
this["restoreExtensionName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool pathIDAsImageName {
get {
return ((bool)(this["pathIDAsImageName"]));
}
set {
this["pathIDAsImageName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool pathIDAsDumpName {
get {
return ((bool)(this["pathIDAsDumpName"]));
}
set {
this["pathIDAsDumpName"] = value;
}
}
}
}

View File

@@ -26,30 +26,24 @@
<Setting Name="convertType" Type="System.String" Scope="User">
<Value Profile="(Default)">PNG</Value>
</Setting>
<Setting Name="displayOriginalName" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="eulerFilter" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="filterPrecision" Type="System.Decimal" Scope="User">
<Value Profile="(Default)">0.25</Value>
</Setting>
<Setting Name="allFrames" Type="System.Boolean" Scope="User">
<Setting Name="exportAllNodes" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="allBones" Type="System.Boolean" Scope="User">
<Setting Name="exportSkins" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="skins" Type="System.Boolean" Scope="User">
<Setting Name="exportAnimations" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="boneSize" Type="System.Decimal" Scope="User">
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="flatInbetween" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="fbxVersion" Type="System.Int32" Scope="User">
<Value Profile="(Default)">3</Value>
</Setting>
@@ -59,5 +53,20 @@
<Setting Name="scaleFactor" Type="System.Decimal" Scope="User">
<Value Profile="(Default)">1</Value>
</Setting>
<Setting Name="exportBlendShape" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="castToBone" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="restoreExtensionName" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="pathIDAsImageName" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="pathIDAsDumpName" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -1,4 +1,5 @@
using System;
using AssetStudio;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
@@ -6,18 +7,25 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using AssetStudio;
using static AssetStudioGUI.Exporter;
using Object = AssetStudio.Object;
namespace AssetStudioGUI
{
internal enum ExportType
{
Convert,
Raw,
Dump
}
internal static class Studio
{
public static AssetsManager assetsManager = new AssetsManager();
public static ScriptDumper scriptDumper = new ScriptDumper();
public static List<AssetItem> exportableAssets = new List<AssetItem>();
public static List<AssetItem> visibleAssets = new List<AssetItem>();
internal static Action<string> StatusStripUpdate = x => { };
public static void ExtractFile(string[] fileNames)
{
@@ -38,16 +46,16 @@ namespace AssetStudioGUI
Progress.Report(i + 1, fileNames.Length);
}
Logger.Info($"Finished extracting {extractedCount} files.");
StatusStripUpdate($"Finished extracting {extractedCount} files.");
});
}
private static int ExtractBundleFile(string bundleFileName, EndianBinaryReader reader)
{
Logger.Info($"Decompressing {Path.GetFileName(bundleFileName)} ...");
StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFileName)} ...");
var bundleFile = new BundleFile(reader, bundleFileName);
reader.Dispose();
if (bundleFile.fileList.Count > 0)
if (bundleFile.fileList.Length > 0)
{
var extractPath = bundleFileName + "_unpacked\\";
return ExtractStreamFile(extractPath, bundleFile.fileList);
@@ -57,10 +65,10 @@ namespace AssetStudioGUI
private static int ExtractWebDataFile(string webFileName, EndianBinaryReader reader)
{
Logger.Info($"Decompressing {Path.GetFileName(webFileName)} ...");
StatusStripUpdate($"Decompressing {Path.GetFileName(webFileName)} ...");
var webFile = new WebFile(reader);
reader.Dispose();
if (webFile.fileList.Count > 0)
if (webFile.fileList.Length > 0)
{
var extractPath = webFileName + "_unpacked\\";
return ExtractStreamFile(extractPath, webFile.fileList);
@@ -68,7 +76,7 @@ namespace AssetStudioGUI
return 0;
}
private static int ExtractStreamFile(string extractPath, List<StreamFile> fileList)
private static int ExtractStreamFile(string extractPath,StreamFile[] fileList)
{
int extractedCount = 0;
foreach (var file in fileList)
@@ -88,24 +96,25 @@ namespace AssetStudioGUI
return extractedCount;
}
public static void BuildAssetList(Dictionary<Object, AssetItem> tempDic, bool displayAll, bool displayOriginalName, out string productName)
public static (string, List<TreeNode>) BuildAssetData()
{
Logger.Info("Building asset list...");
StatusStripUpdate("Building asset list...");
productName = string.Empty;
var assetsNameHash = new HashSet<string>();
var progressCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
int j = 0;
string productName = null;
var assetsNameHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var objectCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count);
var objectAssetItemDic = new Dictionary<Object, AssetItem>(objectCount);
int i = 0;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
var tempExportableAssets = new List<AssetItem>();
AssetBundle ab = null;
foreach (var asset in assetsFile.Objects.Values)
Dictionary<long, string> containers = null;
foreach (var asset in assetsFile.Objects)
{
var assetItem = new AssetItem(asset);
tempDic.Add(asset, assetItem);
assetItem.UniqueID = " #" + j;
objectAssetItemDic.Add(asset, assetItem);
assetItem.UniqueID = " #" + i;
var exportable = false;
switch (asset)
{
@@ -165,20 +174,12 @@ namespace AssetStudioGUI
productName = m_PlayerSettings.productName;
break;
case AssetBundle m_AssetBundle:
ab = m_AssetBundle;
assetItem.Text = ab.m_Name;
break;
case SpriteAtlas m_SpriteAtlas:
foreach (var m_PackedSprite in m_SpriteAtlas.m_PackedSprites)
containers = new Dictionary<long, string>();
foreach (var m_Container in m_AssetBundle.m_Container)
{
if (m_PackedSprite.TryGet(out var m_Sprite))
{
if (m_Sprite.m_SpriteAtlas.IsNull())
{
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
}
}
containers[m_Container.Value.asset.m_PathID] = m_Container.Key;
}
assetItem.Text = m_AssetBundle.m_Name;
break;
case NamedObject m_NamedObject:
assetItem.Text = m_NamedObject.m_Name;
@@ -188,68 +189,52 @@ namespace AssetStudioGUI
{
assetItem.Text = assetItem.TypeString + assetItem.UniqueID;
}
assetItem.SubItems.AddRange(new[] { assetItem.TypeString, assetItem.FullSize.ToString() });
//处理同名文件
if (!assetsNameHash.Add((assetItem.TypeString + assetItem.Text).ToUpper()))
if (!assetsNameHash.Add(assetItem.TypeString + assetItem.Text))
{
assetItem.Text += assetItem.UniqueID;
}
//处理非法文件名
assetItem.Text = FixFileName(assetItem.Text);
if (displayAll)
{
exportable = true;
}
if (exportable)
if (Properties.Settings.Default.displayAll || exportable)
{
tempExportableAssets.Add(assetItem);
}
Progress.Report(++j, progressCount);
Progress.Report(++i, objectCount);
}
if (displayOriginalName && ab != null)
foreach (var item in tempExportableAssets)
{
foreach (var item in tempExportableAssets)
if (containers != null)
{
var originalPath = ab.m_Container.FirstOrDefault(y => y.Value.asset.m_PathID == item.Asset.m_PathID).Key;
if (!string.IsNullOrEmpty(originalPath))
if (containers.TryGetValue(item.Asset.m_PathID, out var container))
{
var extension = Path.GetExtension(originalPath);
if (!string.IsNullOrEmpty(extension) && item.Type == ClassIDType.TextAsset)
if (!string.IsNullOrEmpty(container))
{
item.Extension = extension;
}
item.Text = Path.GetDirectoryName(originalPath) + "\\" + Path.GetFileNameWithoutExtension(originalPath);
if (!assetsNameHash.Add((item.TypeString + item.Text).ToUpper()))
{
item.Text += item.UniqueID;
item.Container = container;
}
}
}
item.SetSubItems();
}
exportableAssets.AddRange(tempExportableAssets);
tempExportableAssets.Clear();
containers?.Clear();
}
visibleAssets = exportableAssets;
assetsNameHash.Clear();
}
public static List<TreeNode> BuildTreeStructure(Dictionary<Object, AssetItem> tempDic)
{
Logger.Info("Building tree structure...");
StatusStripUpdate("Building tree structure...");
var treeNodeCollection = new List<TreeNode>();
var treeNodeDictionary = new Dictionary<GameObject, GameObjectTreeNode>();
var progressCount = assetsManager.assetsFileList.Count;
int i = 0;
var assetsFileCount = assetsManager.assetsFileList.Count;
int j = 0;
Progress.Reset();
foreach (var assetsFile in assetsManager.assetsFileList)
{
var fileNode = new GameObjectTreeNode(assetsFile.fileName); //RootNode
foreach (var obj in assetsFile.Objects.Values)
foreach (var obj in assetsFile.Objects)
{
if (obj is GameObject m_GameObject)
{
@@ -259,24 +244,26 @@ namespace AssetStudioGUI
treeNodeDictionary.Add(m_GameObject, currentNode);
}
if (m_GameObject.m_MeshFilter != null)
foreach (var pptr in m_GameObject.m_Components)
{
if (m_GameObject.m_MeshFilter.m_Mesh.TryGet(out var m_Mesh))
if (pptr.TryGet(out var m_Component))
{
var item = tempDic[m_Mesh];
item.TreeNode = currentNode;
objectAssetItemDic[m_Component].TreeNode = currentNode;
if (m_Component is MeshFilter m_MeshFilter)
{
if (m_MeshFilter.m_Mesh.TryGet(out var m_Mesh))
{
objectAssetItemDic[m_Mesh].TreeNode = currentNode;
}
}
else if (m_Component is SkinnedMeshRenderer m_SkinnedMeshRenderer)
{
if (m_SkinnedMeshRenderer.m_Mesh.TryGet(out var m_Mesh))
{
objectAssetItemDic[m_Mesh].TreeNode = currentNode;
}
}
}
tempDic[m_GameObject.m_MeshFilter].TreeNode = currentNode;
}
if (m_GameObject.m_SkinnedMeshRenderer != null)
{
if (m_GameObject.m_SkinnedMeshRenderer.m_Mesh.TryGet(out var m_Mesh))
{
var item = tempDic[m_Mesh];
item.TreeNode = currentNode;
}
tempDic[m_GameObject.m_SkinnedMeshRenderer].TreeNode = currentNode;
}
var parentNode = fileNode;
@@ -305,12 +292,13 @@ namespace AssetStudioGUI
treeNodeCollection.Add(fileNode);
}
Progress.Report(++i, progressCount);
Progress.Report(++j, assetsFileCount);
}
treeNodeDictionary.Clear();
return treeNodeCollection;
objectAssetItemDic.Clear();
return (productName, treeNodeCollection);
}
public static Dictionary<string, SortedDictionary<int, TypeTreeItem>> BuildClassStructure()
@@ -355,7 +343,7 @@ namespace AssetStudioGUI
return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_'));
}
public static void ExportAssets(string savePath, List<AssetItem> toExportAssets, int assetGroupSelectedIndex, bool openAfterExport)
public static void ExportAssets(string savePath, List<AssetItem> toExportAssets, ExportType exportType)
{
ThreadPool.QueueUserWorkItem(state =>
{
@@ -367,95 +355,53 @@ namespace AssetStudioGUI
Progress.Reset();
foreach (var asset in toExportAssets)
{
var exportpath = savePath + "\\";
if (assetGroupSelectedIndex == 1)
string exportPath;
switch (Properties.Settings.Default.assetGroupOption)
{
exportpath += Path.GetFileNameWithoutExtension(asset.SourceFile.fullName) + "_export\\";
case 0: //type name
exportPath = Path.Combine(savePath, asset.TypeString);
break;
case 1: //container path
if (!string.IsNullOrEmpty(asset.Container))
{
exportPath = Path.Combine(savePath, Path.GetDirectoryName(asset.Container));
}
else
{
exportPath = savePath;
}
break;
case 2: //source file
exportPath = Path.Combine(savePath, asset.SourceFile.fullName + "_export");
break;
default:
exportPath = savePath;
break;
}
else if (assetGroupSelectedIndex == 0)
{
exportpath = savePath + "\\" + asset.TypeString + "\\";
}
Logger.Info($"Exporting {asset.TypeString}: {asset.Text}");
exportPath += Path.DirectorySeparatorChar;
StatusStripUpdate($"Exporting {asset.TypeString}: {asset.Text}");
try
{
switch (asset.Type)
switch (exportType)
{
case ClassIDType.Texture2D:
if (ExportTexture2D(asset, exportpath))
case ExportType.Raw:
if (ExportRawFile(asset, exportPath))
{
exportedCount++;
}
break;
case ClassIDType.AudioClip:
if (ExportAudioClip(asset, exportpath))
case ExportType.Dump:
if (ExportDumpFile(asset, exportPath))
{
exportedCount++;
}
break;
case ClassIDType.Shader:
if (ExportShader(asset, exportpath))
case ExportType.Convert:
if (ExportConvertFile(asset, exportPath))
{
exportedCount++;
}
break;
case ClassIDType.TextAsset:
if (ExportTextAsset(asset, exportpath))
{
exportedCount++;
}
break;
case ClassIDType.MonoBehaviour:
if (ExportMonoBehaviour(asset, exportpath))
{
exportedCount++;
}
break;
case ClassIDType.Font:
if (ExportFont(asset, exportpath))
{
exportedCount++;
}
break;
case ClassIDType.Mesh:
if (ExportMesh(asset, exportpath))
{
exportedCount++;
}
break;
case ClassIDType.VideoClip:
if (ExportVideoClip(asset, exportpath))
{
exportedCount++;
}
break;
case ClassIDType.MovieTexture:
if (ExportMovieTexture(asset, exportpath))
{
exportedCount++;
}
break;
case ClassIDType.Sprite:
if (ExportSprite(asset, exportpath))
{
exportedCount++;
}
break;
case ClassIDType.Animator:
if (ExportAnimator(asset, exportpath))
{
exportedCount++;
}
break;
case ClassIDType.AnimationClip:
break;
default:
if (ExportRawFile(asset, exportpath))
{
exportedCount++;
}
break;
}
}
catch (Exception ex)
@@ -473,16 +419,16 @@ namespace AssetStudioGUI
statusText += $" {toExportCount - exportedCount} assets skipped (not extractable or files already exist)";
}
Logger.Info(statusText);
StatusStripUpdate(statusText);
if (openAfterExport && exportedCount > 0)
if (Properties.Settings.Default.openAfterExport && exportedCount > 0)
{
Process.Start(savePath);
}
});
}
public static void ExportSplitObjects(string savePath, TreeNodeCollection nodes, bool openAfterExport)
public static void ExportSplitObjects(string savePath, TreeNodeCollection nodes)
{
ThreadPool.QueueUserWorkItem(state =>
{
@@ -521,7 +467,7 @@ namespace AssetStudioGUI
}
Directory.CreateDirectory(targetPath);
//导出FBX
Logger.Info($"Exporting {filename}.fbx");
StatusStripUpdate($"Exporting {filename}.fbx");
try
{
ExportGameObject(j.gameObject, targetPath);
@@ -532,14 +478,14 @@ namespace AssetStudioGUI
}
Progress.Report(++k, count);
Logger.Info($"Finished exporting {filename}.fbx");
StatusStripUpdate($"Finished exporting {filename}.fbx");
}
}
if (openAfterExport)
if (Properties.Settings.Default.openAfterExport)
{
Process.Start(savePath);
}
Logger.Info("Finished");
StatusStripUpdate("Finished");
});
}
@@ -552,31 +498,31 @@ namespace AssetStudioGUI
}
}
public static void ExportAnimatorWithAnimationClip(AssetItem animator, List<AssetItem> animationList, string exportPath, bool openAfterExport)
public static void ExportAnimatorWithAnimationClip(AssetItem animator, List<AssetItem> animationList, string exportPath)
{
ThreadPool.QueueUserWorkItem(state =>
{
Progress.Reset();
Logger.Info($"Exporting {animator.Text}");
StatusStripUpdate($"Exporting {animator.Text}");
try
{
ExportAnimator(animator, exportPath, animationList);
if (openAfterExport)
if (Properties.Settings.Default.openAfterExport)
{
Process.Start(exportPath);
}
Progress.Report(1, 1);
Logger.Info($"Finished exporting {animator.Text}");
StatusStripUpdate($"Finished exporting {animator.Text}");
}
catch (Exception ex)
{
MessageBox.Show($"Export Animator:{animator.Text} error\r\n{ex.Message}\r\n{ex.StackTrace}");
Logger.Info("Error in export");
StatusStripUpdate("Error in export");
}
});
}
public static void ExportObjectsWithAnimationClip(string exportPath, TreeNodeCollection nodes, bool openAfterExport, List<AssetItem> animationList = null)
public static void ExportObjectsWithAnimationClip(string exportPath, TreeNodeCollection nodes, List<AssetItem> animationList = null)
{
ThreadPool.QueueUserWorkItem(state =>
{
@@ -589,33 +535,58 @@ namespace AssetStudioGUI
Progress.Reset();
foreach (var gameObject in gameObjects)
{
Logger.Info($"Exporting {gameObject.m_Name}");
StatusStripUpdate($"Exporting {gameObject.m_Name}");
try
{
ExportGameObject(gameObject, exportPath, animationList);
Logger.Info($"Finished exporting {gameObject.m_Name}");
StatusStripUpdate($"Finished exporting {gameObject.m_Name}");
}
catch (Exception ex)
{
MessageBox.Show($"Export GameObject:{gameObject.m_Name} error\r\n{ex.Message}\r\n{ex.StackTrace}");
Logger.Info("Error in export");
StatusStripUpdate("Error in export");
}
Progress.Report(++i, count);
}
if (openAfterExport)
if (Properties.Settings.Default.openAfterExport)
{
Process.Start(exportPath);
}
}
else
{
Logger.Info("No Object can be exported.");
StatusStripUpdate("No Object can be exported.");
}
});
}
private static void GetSelectedParentNode(TreeNodeCollection nodes, List<GameObject> gameObjects)
public static void ExportObjectsMergeWithAnimationClip(string exportPath, List<GameObject> gameObjects, List<AssetItem> animationList = null)
{
ThreadPool.QueueUserWorkItem(state =>
{
var name = Path.GetFileName(exportPath);
Progress.Reset();
StatusStripUpdate($"Exporting {name}");
try
{
ExportGameObjectMerge(gameObjects, exportPath, animationList);
Progress.Report(1, 1);
StatusStripUpdate($"Finished exporting {name}");
}
catch (Exception ex)
{
MessageBox.Show($"Export Model:{name} error\r\n{ex.Message}\r\n{ex.StackTrace}");
StatusStripUpdate("Error in export");
}
if (Properties.Settings.Default.openAfterExport)
{
Process.Start(Path.GetDirectoryName(exportPath));
}
});
}
public static void GetSelectedParentNode(TreeNodeCollection nodes, List<GameObject> gameObjects)
{
foreach (GameObjectTreeNode i in nodes)
{

File diff suppressed because it is too large Load Diff

View File

@@ -1,69 +1,81 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="AssetStudioGUI.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<AssetStudioGUI.Properties.Settings>
<setting name="displayAll" serializeAs="String">
<value>False</value>
</setting>
<setting name="enablePreview" serializeAs="String">
<value>True</value>
</setting>
<setting name="displayInfo" serializeAs="String">
<value>True</value>
</setting>
<setting name="openAfterExport" serializeAs="String">
<value>True</value>
</setting>
<setting name="assetGroupOption" serializeAs="String">
<value>0</value>
</setting>
<setting name="convertTexture" serializeAs="String">
<value>True</value>
</setting>
<setting name="convertAudio" serializeAs="String">
<value>True</value>
</setting>
<setting name="convertType" serializeAs="String">
<value>PNG</value>
</setting>
<setting name="displayOriginalName" serializeAs="String">
<value>False</value>
</setting>
<setting name="eulerFilter" serializeAs="String">
<value>True</value>
</setting>
<setting name="filterPrecision" serializeAs="String">
<value>0.25</value>
</setting>
<setting name="allFrames" serializeAs="String">
<value>True</value>
</setting>
<setting name="allBones" serializeAs="String">
<value>True</value>
</setting>
<setting name="skins" serializeAs="String">
<value>True</value>
</setting>
<setting name="boneSize" serializeAs="String">
<value>10</value>
</setting>
<setting name="flatInbetween" serializeAs="String">
<value>False</value>
</setting>
<setting name="fbxVersion" serializeAs="String">
<value>3</value>
</setting>
<setting name="fbxFormat" serializeAs="String">
<value>0</value>
</setting>
<setting name="scaleFactor" serializeAs="String">
<value>1</value>
</setting>
</AssetStudioGUI.Properties.Settings>
</userSettings>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="AssetStudioGUI.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<userSettings>
<AssetStudioGUI.Properties.Settings>
<setting name="displayAll" serializeAs="String">
<value>False</value>
</setting>
<setting name="enablePreview" serializeAs="String">
<value>True</value>
</setting>
<setting name="displayInfo" serializeAs="String">
<value>True</value>
</setting>
<setting name="openAfterExport" serializeAs="String">
<value>True</value>
</setting>
<setting name="assetGroupOption" serializeAs="String">
<value>0</value>
</setting>
<setting name="convertTexture" serializeAs="String">
<value>True</value>
</setting>
<setting name="convertAudio" serializeAs="String">
<value>True</value>
</setting>
<setting name="convertType" serializeAs="String">
<value>PNG</value>
</setting>
<setting name="eulerFilter" serializeAs="String">
<value>True</value>
</setting>
<setting name="filterPrecision" serializeAs="String">
<value>0.25</value>
</setting>
<setting name="exportAllNodes" serializeAs="String">
<value>True</value>
</setting>
<setting name="exportSkins" serializeAs="String">
<value>True</value>
</setting>
<setting name="exportAnimations" serializeAs="String">
<value>True</value>
</setting>
<setting name="boneSize" serializeAs="String">
<value>10</value>
</setting>
<setting name="fbxVersion" serializeAs="String">
<value>3</value>
</setting>
<setting name="fbxFormat" serializeAs="String">
<value>0</value>
</setting>
<setting name="scaleFactor" serializeAs="String">
<value>1</value>
</setting>
<setting name="exportBlendShape" serializeAs="String">
<value>True</value>
</setting>
<setting name="castToBone" serializeAs="String">
<value>False</value>
</setting>
<setting name="restoreExtensionName" serializeAs="String">
<value>True</value>
</setting>
<setting name="pathIDAsImageName" serializeAs="String">
<value>False</value>
</setting>
<setting name="pathIDAsDumpName" serializeAs="String">
<value>False</value>
</setting>
</AssetStudioGUI.Properties.Settings>
</userSettings>
</configuration>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="OpenTK" version="3.1.0" targetFramework="net472" />
<package id="OpenTK.GLControl" version="3.1.0" targetFramework="net472" />
</packages>

View File

@@ -4,13 +4,14 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{9131C403-7FE8-444D-9AF5-5FE5DF76FF24}</ProjectGuid>
<ProjectGuid>{80AEC261-21EE-4E4F-A93B-7A744DC84888}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AssetStudio</RootNamespace>
<RootNamespace>AssetStudioUtility</RootNamespace>
<AssemblyName>AssetStudioUtility</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
@@ -18,6 +19,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -25,8 +27,9 @@
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<DebugType>none</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -36,6 +39,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -45,6 +49,7 @@
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -59,6 +64,7 @@
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
@@ -73,16 +79,21 @@
<Compile Include="ShaderConverter.cs" />
<Compile Include="SpriteHelper.cs" />
<Compile Include="Texture2DConverter.cs" />
<Compile Include="Texture2DExtensions.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetStudioFBX\AssetStudioFBX.vcxproj">
<Project>{4f8ef5ef-732b-49cf-9eb3-b23e19ae6267}</Project>
<Project>{b82dd1ba-4eec-4f29-a686-03d7f0df39b8}</Project>
<Name>AssetStudioFBX</Name>
</ProjectReference>
<ProjectReference Include="..\AssetStudio\AssetStudio.csproj">
<Project>{af56b63c-1764-41b7-9e60-8d485422ac3b}</Project>
<Project>{7662f8c2-7bfd-442e-a948-a43b4f7eb06e}</Project>
<Name>AssetStudio</Name>
</ProjectReference>
<ProjectReference Include="..\Texture2DDecoder\Texture2DDecoder.vcxproj">
<Project>{bec7b5e6-0a7b-4824-97a7-eea04d9eba29}</Project>
<Name>Texture2DDecoder</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -15,7 +15,7 @@ namespace AssetStudio
public byte[] ConvertToWav()
{
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 null;
var exinfo = new FMOD.CREATESOUNDEXINFO();
@@ -116,24 +116,24 @@ namespace AssetStudio
case AudioCompressionFormat.MP3:
return ".fsb";
case AudioCompressionFormat.VAG:
return ".vag";
return ".fsb";
case AudioCompressionFormat.HEVAG:
return ".vag";
return ".fsb";
case AudioCompressionFormat.XMA:
return ".wav";
return ".fsb";
case AudioCompressionFormat.AAC:
return ".m4a";
case AudioCompressionFormat.GCADPCM:
return ".fsb";
case AudioCompressionFormat.ATRAC9:
return ".at9";
return ".fsb";
}
}
return ".AudioClip";
}
public bool IsFMODSupport
public bool IsSupport
{
get
{
@@ -147,7 +147,6 @@ namespace AssetStudio
case AudioType.S3M:
case AudioType.XM:
case AudioType.XMA:
case AudioType.VAG:
case AudioType.AUDIOQUEUE:
return true;
default:
@@ -162,11 +161,7 @@ namespace AssetStudio
case AudioCompressionFormat.Vorbis:
case AudioCompressionFormat.ADPCM:
case AudioCompressionFormat.MP3:
case AudioCompressionFormat.VAG:
case AudioCompressionFormat.HEVAG:
case AudioCompressionFormat.XMA:
case AudioCompressionFormat.GCADPCM:
case AudioCompressionFormat.ATRAC9:
return true;
default:
return false;

View File

@@ -21,47 +21,74 @@ namespace AssetStudio
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
private Dictionary<Texture2D, string> textureNameDictionary = new Dictionary<Texture2D, string>();
private Dictionary<Transform, ImportedFrame> transformDictionary = new Dictionary<Transform, ImportedFrame>();
Dictionary<uint, string> morphChannelNames = new Dictionary<uint, string>();
public ModelConverter(GameObject m_GameObject)
public ModelConverter(GameObject m_GameObject, AnimationClip[] animationList = null)
{
if (m_GameObject.m_Animator != null)
{
InitWithAnimator(m_GameObject.m_Animator);
CollectAnimationClip(m_GameObject.m_Animator);
if (animationList == null)
{
CollectAnimationClip(m_GameObject.m_Animator);
}
}
else
{
InitWithGameObject(m_GameObject);
}
if (animationList != null)
{
foreach (var animationClip in animationList)
{
animationClipHashSet.Add(animationClip);
}
}
ConvertAnimations();
}
public ModelConverter(GameObject m_GameObject, AnimationClip[] animationList)
public ModelConverter(string rootName, List<GameObject> m_GameObjects, AnimationClip[] animationList = null)
{
if (m_GameObject.m_Animator != null)
RootFrame = CreateFrame(rootName, Vector3.Zero, new Quaternion(0, 0, 0, 0), Vector3.One);
foreach (var m_GameObject in m_GameObjects)
{
InitWithAnimator(m_GameObject.m_Animator);
if (m_GameObject.m_Animator != null && animationList == null)
{
CollectAnimationClip(m_GameObject.m_Animator);
}
var m_Transform = m_GameObject.m_Transform;
ConvertTransforms(m_Transform, RootFrame);
CreateBonePathHash(m_Transform);
}
foreach (var m_GameObject in m_GameObjects)
{
var m_Transform = m_GameObject.m_Transform;
ConvertMeshRenderer(m_Transform);
}
if (animationList != null)
{
foreach (var animationClip in animationList)
{
animationClipHashSet.Add(animationClip);
}
}
ConvertAnimations();
}
public ModelConverter(Animator m_Animator, AnimationClip[] animationList = null)
{
InitWithAnimator(m_Animator);
if (animationList == null)
{
CollectAnimationClip(m_Animator);
}
else
InitWithGameObject(m_GameObject);
foreach (var animationClip in animationList)
{
animationClipHashSet.Add(animationClip);
}
ConvertAnimations();
}
public ModelConverter(Animator m_Animator)
{
InitWithAnimator(m_Animator);
CollectAnimationClip(m_Animator);
ConvertAnimations();
}
public ModelConverter(Animator m_Animator, AnimationClip[] animationList)
{
InitWithAnimator(m_Animator);
foreach (var animationClip in animationList)
{
animationClipHashSet.Add(animationClip);
foreach (var animationClip in animationList)
{
animationClipHashSet.Add(animationClip);
}
}
ConvertAnimations();
}
@@ -256,6 +283,16 @@ namespace AssetStudio
}
combine = true;
}
iMesh.hasNormal = mesh.m_Normals?.Length > 0;
iMesh.hasUV = new bool[8];
for (int uv = 0; uv < 8; uv++)
{
iMesh.hasUV[uv] = mesh.GetUV(uv)?.Length > 0;
}
iMesh.hasTangent = mesh.m_Tangents != null && mesh.m_Tangents.Length == mesh.m_VertexCount * 4;
iMesh.hasColor = mesh.m_Colors?.Length > 0;
int firstFace = 0;
for (int i = 0; i < mesh.m_SubMeshes.Length; i++)
{
@@ -278,19 +315,18 @@ namespace AssetStudio
ImportedMaterial iMat = ConvertMaterial(mat);
iSubmesh.Material = iMat.Name;
iSubmesh.VertexList = new List<ImportedVertex>((int)submesh.vertexCount);
var vertexColours = mesh.m_Colors != null && (mesh.m_Colors.Length == mesh.m_VertexCount * 3 || mesh.m_Colors.Length == mesh.m_VertexCount * 4);
for (var j = mesh.m_SubMeshes[i].firstVertex; j < mesh.m_SubMeshes[i].firstVertex + mesh.m_SubMeshes[i].vertexCount; j++)
{
var iVertex = vertexColours ? new ImportedVertexWithColour() : new ImportedVertex();
var iVertex = new ImportedVertex();
//Vertices
int c = 3;
if (mesh.m_Vertices.Length == mesh.m_VertexCount * 4)
{
c = 4;
}
iVertex.Position = new Vector3(-mesh.m_Vertices[j * c], mesh.m_Vertices[j * c + 1], mesh.m_Vertices[j * c + 2]);
iVertex.Vertex = new Vector3(-mesh.m_Vertices[j * c], mesh.m_Vertices[j * c + 1], mesh.m_Vertices[j * c + 2]);
//Normals
if (mesh.m_Normals?.Length > 0)
if (iMesh.hasNormal)
{
if (mesh.m_Normals.Length == mesh.m_VertexCount * 3)
{
@@ -302,32 +338,41 @@ namespace AssetStudio
}
iVertex.Normal = new Vector3(-mesh.m_Normals[j * c], mesh.m_Normals[j * c + 1], mesh.m_Normals[j * c + 2]);
}
//UV
iVertex.UV = new float[8][];
for (int uv = 0; uv < 8; uv++)
{
if (iMesh.hasUV[uv])
{
var m_UV = mesh.GetUV(uv);
if (m_UV.Length == mesh.m_VertexCount * 2)
{
c = 2;
}
else if (m_UV.Length == mesh.m_VertexCount * 3)
{
c = 3;
}
iVertex.UV[uv] = new[] { m_UV[j * c], m_UV[j * c + 1] };
}
}
//Tangent
if (iMesh.hasTangent)
{
iVertex.Tangent = new Vector4(-mesh.m_Tangents[j * 4], mesh.m_Tangents[j * 4 + 1], mesh.m_Tangents[j * 4 + 2], mesh.m_Tangents[j * 4 + 3]);
}
//Colors
if (vertexColours)
if (iMesh.hasColor)
{
if (mesh.m_Colors.Length == mesh.m_VertexCount * 3)
{
((ImportedVertexWithColour)iVertex).Colour = new Color(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f);
iVertex.Color = new Color(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f);
}
else
{
((ImportedVertexWithColour)iVertex).Colour = new Color(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]);
iVertex.Color = new Color(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]);
}
}
//UV
if (mesh.m_UV0 != null && mesh.m_UV0.Length == mesh.m_VertexCount * 2)
{
iVertex.UV = new[] { mesh.m_UV0[j * 2], mesh.m_UV0[j * 2 + 1] };
}
else if (mesh.m_UV1 != null && mesh.m_UV1.Length == mesh.m_VertexCount * 2)
{
iVertex.UV = new[] { mesh.m_UV1[j * 2], mesh.m_UV1[j * 2 + 1] };
}
//Tangent
if (mesh.m_Tangents != null && mesh.m_Tangents.Length == mesh.m_VertexCount * 4)
{
iVertex.Tangent = new Vector4(-mesh.m_Tangents[j * 4], mesh.m_Tangents[j * 4 + 1], mesh.m_Tangents[j * 4 + 2], -mesh.m_Tangents[j * 4 + 3]);
}
//BoneInfluence
if (mesh.m_Skin?.Length > 0)
{
@@ -361,97 +406,133 @@ namespace AssetStudio
if (meshR is SkinnedMeshRenderer sMesh)
{
//Bone
/*
* 0 - None
* 1 - m_Bones
* 2 - m_BoneNameHashes
*/
var boneType = 0;
if (sMesh.m_Bones.Length > 0)
{
var boneMax = Math.Min(sMesh.m_Bones.Length, mesh.m_BindPose.Length);
iMesh.BoneList = new List<ImportedBone>(boneMax);
for (int i = 0; i < boneMax; i++)
if (sMesh.m_Bones.Length == mesh.m_BindPose.Length)
{
var verifiedBoneCount = sMesh.m_Bones.Count(x => x.TryGet(out _));
if (verifiedBoneCount > 0)
{
boneType = 1;
}
if (verifiedBoneCount != sMesh.m_Bones.Length)
{
//尝试使用m_BoneNameHashes 4.3 and up
if (mesh.m_BindPose.Length > 0 && (mesh.m_BindPose.Length == mesh.m_BoneNameHashes?.Length))
{
//有效bone数量是否大于SkinnedMeshRenderer
var verifiedBoneCount2 = mesh.m_BoneNameHashes.Count(x => FixBonePath(GetPathFromHash(x)) != null);
if (verifiedBoneCount2 > verifiedBoneCount)
{
boneType = 2;
}
}
}
}
else
{
//Logger.Error("");
}
}
else
{
//尝试使用m_BoneNameHashes 4.3 and up
if (mesh.m_BindPose.Length > 0 && (mesh.m_BindPose.Length == mesh.m_BoneNameHashes?.Length))
{
boneType = 2;
}
}
if (boneType == 1)
{
var boneCount = sMesh.m_Bones.Length;
iMesh.BoneList = new List<ImportedBone>(boneCount);
for (int i = 0; i < boneCount; i++)
{
var bone = new ImportedBone();
if (sMesh.m_Bones[i].TryGet(out var m_Transform))
{
bone.Path = GetTransformPath(m_Transform);
}
if (!string.IsNullOrEmpty(bone.Path))
{
var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1));
bone.Matrix = convert * mesh.m_BindPose[i] * convert;
iMesh.BoneList.Add(bone);
}
var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1));
bone.Matrix = convert * mesh.m_BindPose[i] * convert;
iMesh.BoneList.Add(bone);
}
}
if (iMesh.BoneList == null || iMesh.BoneList.Count == 0)
else if (boneType == 2)
{
if (mesh.m_BindPose.Length > 0 && mesh.m_BoneNameHashes?.Length > 0)
var boneCount = mesh.m_BindPose.Length;
iMesh.BoneList = new List<ImportedBone>(boneCount);
for (int i = 0; i < boneCount; i++)
{
var boneMax = Math.Min(mesh.m_BindPose.Length, mesh.m_BoneNameHashes.Length);
iMesh.BoneList = new List<ImportedBone>(boneMax);
for (int i = 0; i < boneMax; i++)
{
var bone = new ImportedBone();
var boneHash = mesh.m_BoneNameHashes[i];
var path = GetPathFromHash(boneHash);
bone.Path = FixBonePath(path);
if (!string.IsNullOrEmpty(bone.Path))
{
var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1));
bone.Matrix = convert * mesh.m_BindPose[i] * convert;
iMesh.BoneList.Add(bone);
}
}
var bone = new ImportedBone();
var boneHash = mesh.m_BoneNameHashes[i];
var path = GetPathFromHash(boneHash);
bone.Path = FixBonePath(path);
var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1));
bone.Matrix = convert * mesh.m_BindPose[i] * convert;
iMesh.BoneList.Add(bone);
}
}
//Morphs
if (mesh.m_Shapes?.shapes != null)
if (mesh.m_Shapes?.channels?.Length > 0)
{
if (mesh.m_Shapes.shapes.Length > 0)
var morph = new ImportedMorph();
MorphList.Add(morph);
morph.Path = iMesh.Path;
morph.Channels = new List<ImportedMorphChannel>(mesh.m_Shapes.channels.Length);
for (int i = 0; i < mesh.m_Shapes.channels.Length; i++)
{
ImportedMorph morph = null;
string lastGroup = "";
for (int i = 0; i < mesh.m_Shapes.channels.Length; i++)
var channel = new ImportedMorphChannel();
morph.Channels.Add(channel);
var shapeChannel = mesh.m_Shapes.channels[i];
var blendShapeName = "blendShape." + shapeChannel.name;
var crc = new SevenZip.CRC();
var bytes = Encoding.UTF8.GetBytes(blendShapeName);
crc.Update(bytes, 0, (uint)bytes.Length);
morphChannelNames[crc.GetDigest()] = blendShapeName;
channel.Name = shapeChannel.name;
channel.KeyframeList = new List<ImportedMorphKeyframe>(shapeChannel.frameCount);
var frameEnd = shapeChannel.frameIndex + shapeChannel.frameCount;
for (int frameIdx = shapeChannel.frameIndex; frameIdx < frameEnd; frameIdx++)
{
string group = BlendShapeNameGroup(mesh, i);
if (group != lastGroup)
var keyframe = new ImportedMorphKeyframe();
channel.KeyframeList.Add(keyframe);
keyframe.Weight = mesh.m_Shapes.fullWeights[frameIdx];
var shape = mesh.m_Shapes.shapes[frameIdx];
keyframe.hasNormals = shape.hasNormals;
keyframe.hasTangents = shape.hasTangents;
keyframe.VertexList = new List<ImportedMorphVertex>((int)shape.vertexCount);
var vertexEnd = shape.firstVertex + shape.vertexCount;
for (uint j = shape.firstVertex; j < vertexEnd; j++)
{
morph = new ImportedMorph();
MorphList.Add(morph);
morph.Path = iMesh.Path;
morph.ClipName = group;
morph.Channels = new List<Tuple<float, int, int>>(mesh.m_Shapes.channels.Length);
morph.KeyframeList = new List<ImportedMorphKeyframe>(mesh.m_Shapes.shapes.Length);
lastGroup = group;
}
morph.Channels.Add(new Tuple<float, int, int>(i < sMesh.m_BlendShapeWeights.Length ? sMesh.m_BlendShapeWeights[i] : 0f, morph.KeyframeList.Count, mesh.m_Shapes.channels[i].frameCount));
for (int frameIdx = 0; frameIdx < mesh.m_Shapes.channels[i].frameCount; frameIdx++)
{
ImportedMorphKeyframe keyframe = new ImportedMorphKeyframe();
keyframe.Name = BlendShapeNameExtension(mesh, i) + "_" + frameIdx;
int shapeIdx = mesh.m_Shapes.channels[i].frameIndex + frameIdx;
keyframe.VertexList = new List<ImportedVertex>((int)mesh.m_Shapes.shapes[shapeIdx].vertexCount);
keyframe.MorphedVertexIndices = new List<ushort>((int)mesh.m_Shapes.shapes[shapeIdx].vertexCount);
keyframe.Weight = shapeIdx < mesh.m_Shapes.fullWeights.Length ? mesh.m_Shapes.fullWeights[shapeIdx] : 100f;
int lastVertIndex = (int)(mesh.m_Shapes.shapes[shapeIdx].firstVertex + mesh.m_Shapes.shapes[shapeIdx].vertexCount);
for (int j = (int)mesh.m_Shapes.shapes[shapeIdx].firstVertex; j < lastVertIndex; j++)
var destVertex = new ImportedMorphVertex();
keyframe.VertexList.Add(destVertex);
var morphVertex = mesh.m_Shapes.vertices[j];
destVertex.Index = morphVertex.index;
var sourceVertex = GetSourceVertex(iMesh.SubmeshList, (int)morphVertex.index);
destVertex.Vertex = new ImportedVertex();
var morphPos = morphVertex.vertex;
destVertex.Vertex.Vertex = sourceVertex.Vertex + new Vector3(-morphPos.X, morphPos.Y, morphPos.Z);
if (shape.hasNormals)
{
var morphVert = mesh.m_Shapes.vertices[j];
ImportedVertex vert = GetSourceVertex(iMesh.SubmeshList, (int)morphVert.index);
ImportedVertex destVert = new ImportedVertex();
Vector3 morphPos = morphVert.vertex;
morphPos.X *= -1;
destVert.Position = vert.Position + morphPos;
Vector3 morphNormal = morphVert.normal;
morphNormal.X *= -1;
destVert.Normal = morphNormal;
Vector4 morphTangent = new Vector4(morphVert.tangent, 0);
morphTangent.X *= -1;
destVert.Tangent = morphTangent;
keyframe.VertexList.Add(destVert);
keyframe.MorphedVertexIndices.Add((ushort)morphVert.index);
var morphNormal = morphVertex.normal;
destVertex.Vertex.Normal = new Vector3(-morphNormal.X, morphNormal.Y, morphNormal.Z);
}
if (shape.hasTangents)
{
var morphTangent = morphVertex.tangent;
destVertex.Vertex.Tangent = new Vector4(-morphTangent.X, morphTangent.Y, morphTangent.Z, 0);
}
morph.KeyframeList.Add(keyframe);
}
}
}
@@ -541,6 +622,14 @@ namespace AssetStudio
}
iMat = new ImportedMaterial();
iMat.Name = mat.m_Name;
//default values
iMat.Diffuse = new Color(0.8f, 0.8f, 0.8f, 1);
iMat.Ambient = new Color(0.2f, 0.2f, 0.2f, 1);
iMat.Emissive = new Color(0, 0, 0, 1);
iMat.Specular = new Color(0.2f, 0.2f, 0.2f, 1);
iMat.Reflection = new Color(0, 0, 0, 1);
iMat.Shininess = 20f;
iMat.Transparency = 0f;
foreach (var col in mat.m_SavedProperties.m_Colors)
{
switch (col.Key)
@@ -555,7 +644,6 @@ namespace AssetStudio
iMat.Emissive = col.Value;
break;
case "_SpecularColor":
case "_SpecColor":
iMat.Specular = col.Value;
break;
case "_ReflectColor":
@@ -638,7 +726,7 @@ namespace AssetStudio
return iMat;
}
private void ConvertTexture2D(Texture2D tex2D, string name)
private void ConvertTexture2D(Texture2D m_Texture2D, string name)
{
var iTex = ImportedHelpers.FindTexture(name, TextureList);
if (iTex != null)
@@ -646,7 +734,7 @@ namespace AssetStudio
return;
}
var bitmap = new Texture2DConverter(tex2D).ConvertToBitmap(true);
var bitmap = m_Texture2D.ConvertToBitmap(true);
if (bitmap != null)
{
using (var stream = new MemoryStream())
@@ -678,6 +766,7 @@ namespace AssetStudio
}
}
iAnim.Name = name;
iAnim.SampleRate = animationClip.m_SampleRate;
iAnim.TrackList = new List<ImportedAnimationKeyframedTrack>();
AnimationList.Add(iAnim);
if (animationClip.m_Legacy)
@@ -740,6 +829,31 @@ namespace AssetStudio
}
}
}
foreach (var m_FloatCurve in animationClip.m_FloatCurves)
{
if (m_FloatCurve.classID == ClassIDType.SkinnedMeshRenderer) //BlendShape
{
var channelName = m_FloatCurve.attribute;
int dotPos = channelName.IndexOf('.');
if (dotPos >= 0)
{
channelName = channelName.Substring(dotPos + 1);
}
var path = FixBonePath(m_FloatCurve.path);
if (string.IsNullOrEmpty(path))
{
path = GetPathByChannelName(channelName);
}
var track = iAnim.FindTrack(path);
track.BlendShape = new ImportedBlendShape();
track.BlendShape.ChannelName = channelName;
foreach (var m_Curve in m_FloatCurve.curve.m_Curve)
{
track.BlendShape.Keyframes.Add(new ImportedKeyframe<float>(m_Curve.time, m_Curve.value));
}
}
}
}
else
{
@@ -789,55 +903,79 @@ namespace AssetStudio
private void ReadCurveData(ImportedKeyframedAnimation iAnim, AnimationClipBindingConstant m_ClipBindingConstant, int index, float time, float[] data, int offset, ref int curveIndex)
{
var binding = m_ClipBindingConstant.FindBinding(index);
if (binding.path == 0)
if (binding.typeID == ClassIDType.SkinnedMeshRenderer) //BlendShape
{
var channelName = GetChannelNameFromHash(binding.attribute);
if (string.IsNullOrEmpty(channelName))
{
curveIndex++;
return;
}
int dotPos = channelName.IndexOf('.');
if (dotPos >= 0)
{
channelName = channelName.Substring(dotPos + 1);
}
var bPath = FixBonePath(GetPathFromHash(binding.path));
if (string.IsNullOrEmpty(bPath))
{
bPath = GetPathByChannelName(channelName);
}
var bTrack = iAnim.FindTrack(bPath);
bTrack.BlendShape = new ImportedBlendShape();
bTrack.BlendShape.ChannelName = channelName;
bTrack.BlendShape.Keyframes.Add(new ImportedKeyframe<float>(time, data[curveIndex++ + offset]));
}
else if (binding.typeID == ClassIDType.Transform)
{
var path = FixBonePath(GetPathFromHash(binding.path));
var track = iAnim.FindTrack(path);
switch (binding.attribute)
{
case 1:
track.Translations.Add(new ImportedKeyframe<Vector3>(time, new Vector3
(
-data[curveIndex++ + offset],
data[curveIndex++ + offset],
data[curveIndex++ + offset]
)));
break;
case 2:
var value = Fbx.QuaternionToEuler(new Quaternion
(
data[curveIndex++ + offset],
-data[curveIndex++ + offset],
-data[curveIndex++ + offset],
data[curveIndex++ + offset]
));
track.Rotations.Add(new ImportedKeyframe<Vector3>(time, value));
break;
case 3:
track.Scalings.Add(new ImportedKeyframe<Vector3>(time, new Vector3
(
data[curveIndex++ + offset],
data[curveIndex++ + offset],
data[curveIndex++ + offset]
)));
break;
case 4:
track.Rotations.Add(new ImportedKeyframe<Vector3>(time, new Vector3
(
data[curveIndex++ + offset],
-data[curveIndex++ + offset],
-data[curveIndex++ + offset]
)));
break;
default:
curveIndex++;
break;
}
}
else
{
curveIndex++;
return;
}
var path = FixBonePath(GetPathFromHash(binding.path));
var track = iAnim.FindTrack(path);
switch (binding.attribute)
{
case 1:
track.Translations.Add(new ImportedKeyframe<Vector3>(time, new Vector3
(
-data[curveIndex++ + offset],
data[curveIndex++ + offset],
data[curveIndex++ + offset]
)));
break;
case 2:
var value = Fbx.QuaternionToEuler(new Quaternion
(
data[curveIndex++ + offset],
-data[curveIndex++ + offset],
-data[curveIndex++ + offset],
data[curveIndex++ + offset]
));
track.Rotations.Add(new ImportedKeyframe<Vector3>(time, value));
break;
case 3:
track.Scalings.Add(new ImportedKeyframe<Vector3>(time, new Vector3
(
data[curveIndex++ + offset],
data[curveIndex++ + offset],
data[curveIndex++ + offset]
)));
break;
case 4:
track.Rotations.Add(new ImportedKeyframe<Vector3>(time, new Vector3
(
data[curveIndex++ + offset],
-data[curveIndex++ + offset],
-data[curveIndex++ + offset]
)));
break;
default:
//track.Curve.Add(new ImportedKeyframe<float>(time, data[curveIndex++]));
curveIndex++;
break;
}
}
@@ -855,28 +993,6 @@ namespace AssetStudio
return boneName;
}
private static string BlendShapeNameGroup(Mesh mesh, int index)
{
string name = mesh.m_Shapes.channels[index].name;
int dotPos = name.IndexOf('.');
if (dotPos >= 0)
{
return name.Substring(0, dotPos);
}
return "Ungrouped";
}
private static string BlendShapeNameExtension(Mesh mesh, int index)
{
string name = mesh.m_Shapes.channels[index].name;
int dotPos = name.IndexOf('.');
if (dotPos >= 0)
{
return name.Substring(dotPos + 1);
}
return name;
}
private static ImportedVertex GetSourceVertex(List<ImportedSubmesh> submeshList, int morphVertIndex)
{
foreach (var submesh in submeshList)
@@ -963,5 +1079,32 @@ namespace AssetStudio
}
}
}
private string GetPathByChannelName(string channelName)
{
foreach (var morph in MorphList)
{
foreach (var channel in morph.Channels)
{
if (channel.Name == channelName)
{
return morph.Path;
}
}
}
return null;
}
private string GetChannelNameFromHash(uint attribute)
{
if (morphChannelNames.TryGetValue(attribute, out var name))
{
return name;
}
else
{
return null;
}
}
}
}

View File

@@ -2,9 +2,10 @@
{
public static class ModelExporter
{
public static void ExportFbx(string path, IImported imported, bool eulerFilter, float filterPrecision, bool allFrames, bool allBones, bool skins, float boneSize, float scaleFactor, bool flatInbetween, int versionIndex, bool isAscii)
public static void ExportFbx(string path, IImported imported, bool eulerFilter, float filterPrecision,
bool allNodes, bool skins, bool animation, bool blendShape, bool castToBone, float boneSize, float scaleFactor, int versionIndex, bool isAscii)
{
Fbx.Exporter.Export(path, imported, eulerFilter, filterPrecision, allFrames, allBones, skins, boneSize, scaleFactor, flatInbetween, versionIndex, isAscii);
Fbx.Exporter.Export(path, imported, eulerFilter, filterPrecision, allNodes, skins, animation, blendShape, castToBone, boneSize, scaleFactor, versionIndex, isAscii);
}
}
}

View File

@@ -5,12 +5,12 @@ using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("AssetStudioTools")]
[assembly: AssemblyTitle("AssetStudioUtility")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AssetStudioTools")]
[assembly: AssemblyCopyright("Copyright © Perfare 2018")]
[assembly: AssemblyProduct("AssetStudioUtility")]
[assembly: AssemblyCopyright("Copyright © Perfare 2018-2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("9131c403-7fe8-444d-9af5-5fe5df76ff24")]
[assembly: Guid("80aec261-21ee-4e4f-a93b-7a744dc84888")]
// 程序集的版本信息由下列四个值组成:
//
@@ -29,8 +29,8 @@ using System.Runtime.InteropServices;
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("0.14.38.5")]
[assembly: AssemblyFileVersion("0.14.38.5")]

View File

@@ -20,7 +20,7 @@ namespace AssetStudio
}
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
{
var program = new ShaderProgram(blobReader);
var program = new ShaderProgram(blobReader, shader.version);
return program.Export(Encoding.UTF8.GetString(shader.m_Script));
}
}
@@ -49,7 +49,7 @@ namespace AssetStudio
}
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
{
var program = new ShaderProgram(blobReader);
var program = new ShaderProgram(blobReader, shader.version);
var m_Script = ConvertSerializedShader(shader.m_ParsedForm, shader.platforms[i]);
strs[i] = header + program.Export(m_Script);
}
@@ -556,13 +556,22 @@ namespace AssetStudio
{
private ShaderSubProgram[] m_SubPrograms;
public ShaderProgram(BinaryReader reader)
public ShaderProgram(BinaryReader reader, int[] version)
{
var subProgramsCapacity = reader.ReadInt32();
m_SubPrograms = new ShaderSubProgram[subProgramsCapacity];
int entrySize;
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
{
entrySize = 12;
}
else
{
entrySize = 8;
}
for (int i = 0; i < subProgramsCapacity; i++)
{
reader.BaseStream.Position = 4 + i * 8;
reader.BaseStream.Position = 4 + i * entrySize;
var offset = reader.ReadInt32();
reader.BaseStream.Position = offset;
m_SubPrograms[i] = new ShaderSubProgram(reader);

View File

@@ -9,7 +9,7 @@ namespace AssetStudio
{
public static class SpriteHelper
{
public static Bitmap GetImageFromSprite(Sprite m_Sprite)
public static Bitmap GetImage(this Sprite m_Sprite)
{
if (m_Sprite.m_SpriteAtlas != null && m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlas))
{
@@ -30,18 +30,18 @@ namespace AssetStudio
private static Bitmap CutImage(Texture2D m_Texture2D, Sprite m_Sprite, RectangleF textureRect, Vector2 textureRectOffset, SpriteSettings settingsRaw)
{
var texture2D = new Texture2DConverter(m_Texture2D);
var originalImage = texture2D.ConvertToBitmap(false);
var originalImage = m_Texture2D.ConvertToBitmap(false);
if (originalImage != null)
{
using (originalImage)
{
//var spriteImage = originalImage.Clone(textureRect, PixelFormat.Format32bppArgb);
var spriteImage = new Bitmap((int)textureRect.Width, (int)textureRect.Height, PixelFormat.Format32bppArgb);
var destRect = new Rectangle(0, 0, (int)textureRect.Width, (int)textureRect.Height);
var textureRectI = Rectangle.Round(textureRect);
var spriteImage = new Bitmap(textureRectI.Width, textureRectI.Height, PixelFormat.Format32bppArgb);
var destRect = new Rectangle(0, 0, textureRectI.Width, textureRectI.Height);
using (var graphic = Graphics.FromImage(spriteImage))
{
graphic.DrawImage(originalImage, destRect, textureRect, GraphicsUnit.Pixel);
graphic.DrawImage(originalImage, destRect, textureRectI, GraphicsUnit.Pixel);
}
if (settingsRaw.packed == 1)
{
@@ -61,49 +61,52 @@ namespace AssetStudio
spriteImage.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
}
}
//Tight
if (settingsRaw.packingMode == SpritePackingMode.kSPMTight)
//Tight
if (settingsRaw.packingMode == SpritePackingMode.kSPMTight)
{
try
{
try
var triangles = GetTriangles(m_Sprite.m_RD);
var points = triangles.Select(x => x.Select(y => new PointF(y.X, y.Y)).ToArray());
using (var path = new GraphicsPath())
{
var triangles = GetTriangles(m_Sprite.m_RD);
var points = triangles.Select(x => x.Select(y => new PointF(y.X, y.Y)).ToArray());
using (var path = new GraphicsPath())
foreach (var p in points)
{
foreach (var p in points)
path.AddPolygon(p);
}
using (var matr = new Matrix())
{
var version = m_Sprite.version;
if (version[0] < 5
|| (version[0] == 5 && version[1] < 4)
|| (version[0] == 5 && version[1] == 4 && version[2] <= 1)) //5.4.1p3 down
{
path.AddPolygon(p);
matr.Translate(m_Sprite.m_Rect.Width * 0.5f - textureRectOffset.X, m_Sprite.m_Rect.Height * 0.5f - textureRectOffset.Y);
}
using (var matr = new Matrix())
else
{
if (m_Sprite.m_Pivot == Vector2.Zero) //5.4.2 down
matr.Translate(m_Sprite.m_Rect.Width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.Height * m_Sprite.m_Pivot.Y - textureRectOffset.Y);
}
matr.Scale(m_Sprite.m_PixelsToUnits, m_Sprite.m_PixelsToUnits);
path.Transform(matr);
var bitmap = new Bitmap(textureRectI.Width, textureRectI.Height);
using (var graphic = Graphics.FromImage(bitmap))
{
using (var brush = new TextureBrush(spriteImage))
{
matr.Translate(m_Sprite.m_Rect.Width * 0.5f - textureRectOffset.X, m_Sprite.m_Rect.Height * 0.5f - textureRectOffset.Y);
}
else
{
matr.Translate(m_Sprite.m_Rect.Width * m_Sprite.m_Pivot.X - textureRectOffset.X, m_Sprite.m_Rect.Height * m_Sprite.m_Pivot.Y - textureRectOffset.Y);
}
matr.Scale(m_Sprite.m_PixelsToUnits, m_Sprite.m_PixelsToUnits);
path.Transform(matr);
var bitmap = new Bitmap((int)textureRect.Width, (int)textureRect.Height);
using (var graphic = Graphics.FromImage(bitmap))
{
using (var brush = new TextureBrush(spriteImage))
{
graphic.FillPath(brush, path);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
return bitmap;
}
graphic.FillPath(brush, path);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
return bitmap;
}
}
}
}
catch
{
// ignored
}
}
catch
{
// ignored
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
using System.Drawing;
namespace AssetStudio
{
public static class Texture2DExtensions
{
public static Bitmap ConvertToBitmap(this Texture2D m_Texture2D, bool flip)
{
var converter = new Texture2DConverter(m_Texture2D);
return converter.ConvertToBitmap(flip);
}
}
}

View File

@@ -1,7 +1,7 @@
MIT License
Copyright (c) 2016 Radu
Copyright (c) 2016-2018 Perfare
Copyright (c) 2016 Radu
Copyright (c) 2016-2020 Perfare
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -7,12 +7,12 @@ AssetStudio is a tool for exploring, extracting and exporting assets and assetbu
## Features
* Support version:
* 2.5 - 2019.1
* 2.5 - 2019.3
* Support asset types:
* **Texture2D** : support convert to bmp, png or jpeg. export to containers: DDS, PVR and KTX
* **Sprite** : bmp, png or jpeg
* **Texture2D** : convert to png, tga, jpeg, bmp
* **Sprite** : crop Texture2D to png, tga, jpeg, bmp
* **AudioClip** : mp3, ogg, wav, m4a, fsb. support convert FSB file to WAV(PCM)
* **Font**
* **Font** : ttf, otf
* **Mesh** : obj
* **TextAsset**
* **Shader**
@@ -24,9 +24,8 @@ AssetStudio is a tool for exploring, extracting and exporting assets and assetbu
## Usage
### Requirements
- [.NET Framework 4.0](https://www.microsoft.com/en-us/download/details.aspx?id=17718)
- [Microsoft Visual C++ 2013 Redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=40784)
- [Microsoft Visual C++ 2015 Redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=53840)
- [.NET Framework 4.7.2](https://dotnet.microsoft.com/download/dotnet-framework/net472)
- [Microsoft Visual C++ 2017 Redistributable](https://support.microsoft.com/help/2977003/the-latest-supported-visual-c-downloads)
### How to use
@@ -42,6 +41,13 @@ AssetStudio is a tool for exploring, extracting and exporting assets and assetbu
## Build
* The project uses some C# 7 syntax, need Visual Studio 2017 or newer
* **AssetStudioFBX** uses FBX SDK 2019.0 VS2015, before building, you need to install the FBX SDK and modify the project file, change include directory and library directory to point to the FBX SDK directory
* If you want to change the FBX SDK version, you need to replace `libfbxsdk.dll` which in `AssetStudioGUI/Libraries/x86/` and `AssetStudioGUI/Libraries/x64` directory to the new version
* Visual Studio 2019 or newer
* **AssetStudioFBX** uses FBX SDK 2020.0.1 VS2017, before building, you need to install the FBX SDK and modify the project file, change include directory and library directory to point to the FBX SDK directory
* If you want to change the FBX SDK version, you need to replace `libfbxsdk.dll` which in `AssetStudioGUI/Libraries/x86/` and `AssetStudioGUI/Libraries/x64/` directory to the new version
## Open source libraries used
### Texture2DDecoder
* [Ishotihadus/mikunyan](https://github.com/Ishotihadus/mikunyan)
* [BinomialLLC/crunch](https://github.com/BinomialLLC/crunch)
* [Unity-Technologies/crunch](https://github.com/Unity-Technologies/crunch/tree/unity)

View File

@@ -0,0 +1,20 @@
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"Texture2DDecoder")];
[assembly:AssemblyDescriptionAttribute(L"")];
[assembly:AssemblyConfigurationAttribute(L"")];
[assembly:AssemblyCompanyAttribute(L"")];
[assembly:AssemblyProductAttribute(L"Texture2DDecoder")];
[assembly:AssemblyCopyrightAttribute(L"Copyright © Perfare 2020")];
[assembly:AssemblyTrademarkAttribute(L"")];
[assembly:AssemblyCultureAttribute(L"")];
[assembly:AssemblyVersionAttribute("1.0.*")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];

View File

@@ -0,0 +1,148 @@
#include <string.h>
#include "Texture2DDecoder.h"
#include "bcn.h"
#include "pvrtc.h"
#include "etc.h"
#include "atc.h"
#include "astc.h"
#include "crunch.h"
#include "unitycrunch.h"
namespace Texture2DDecoder {
bool TextureDecoder::DecodeDXT1(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_bc1(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeDXT5(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_bc3(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodePVRTC(array<Byte>^ data, long w, long h, array<Byte>^ image, bool is2bpp) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_pvrtc(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin), is2bpp ? 1 : 0);
}
bool TextureDecoder::DecodeETC1(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_etc1(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeETC2(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_etc2(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeETC2A1(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_etc2a1(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeETC2A8(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_etc2a8(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeEACR(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_eacr(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeEACRSigned(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_eacr_signed(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeEACRG(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_eacrg(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeEACRGSigned(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_eacrg_signed(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeBC4(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_bc4(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeBC5(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_bc5(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeBC6(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_bc6(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeBC7(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_bc7(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeATCRGB4(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_atc_rgb4(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeATCRGBA8(array<Byte>^ data, long w, long h, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_atc_rgba8(dataPin, w, h, reinterpret_cast<uint32_t*>(imagePin));
}
bool TextureDecoder::DecodeASTC(array<Byte>^ data, long w, long h, int bw, int bh, array<Byte>^ image) {
pin_ptr<unsigned char> dataPin = &data[0];
pin_ptr<unsigned char> imagePin = &image[0];
return decode_astc(dataPin, w, h, bw, bh, reinterpret_cast<uint32_t*>(imagePin));
}
array<Byte>^ TextureDecoder::UnpackCrunch(array<Byte>^ data) {
pin_ptr<unsigned char> dataPin = &data[0];
void* ret;
uint32_t retSize;
if (!crunch_unpack_level(dataPin, data->Length, 0, &ret, &retSize)) {
return nullptr;
}
auto buff = gcnew array<Byte>(retSize);
pin_ptr<unsigned char> buffPin = &buff[0];
memcpy(buffPin, ret, retSize);
delete ret;
return buff;
}
array<Byte>^ TextureDecoder::UnpackUnityCrunch(array<Byte>^ data) {
pin_ptr<unsigned char> dataPin = &data[0];
void* ret;
uint32_t retSize;
if (!unity_crunch_unpack_level(dataPin, data->Length, 0, &ret, &retSize)) {
return nullptr;
}
auto buff = gcnew array<Byte>(retSize);
pin_ptr<unsigned char> buffPin = &buff[0];
memcpy(buffPin, ret, retSize);
delete ret;
return buff;
}
}

View File

@@ -0,0 +1,30 @@
#pragma once
using namespace System;
namespace Texture2DDecoder {
public ref class TextureDecoder
{
public:
static bool DecodeDXT1(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeDXT5(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodePVRTC(array<Byte>^ data, long w, long h, array<Byte>^ image, bool is2bpp);
static bool DecodeETC1(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeETC2(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeETC2A1(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeETC2A8(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeEACR(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeEACRSigned(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeEACRG(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeEACRGSigned(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeBC4(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeBC5(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeBC6(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeBC7(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeATCRGB4(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeATCRGBA8(array<Byte>^ data, long w, long h, array<Byte>^ image);
static bool DecodeASTC(array<Byte>^ data, long w, long h, int bw, int bh, array<Byte>^ image);
static array<Byte>^ UnpackCrunch(array<Byte>^ data);
static array<Byte>^ UnpackUnityCrunch(array<Byte>^ data);
};
}

View File

@@ -0,0 +1,147 @@
<?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>
<ProjectGuid>{BEC7B5E6-0A7B-4824-97A7-EEA04D9EBA29}</ProjectGuid>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<Keyword>ManagedCProj</Keyword>
<RootNamespace>Texture2DDecoder</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>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CLRSupport>true</CLRSupport>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</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|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 />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies />
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies />
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies />
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies />
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="astc.h" />
<ClInclude Include="atc.h" />
<ClInclude Include="bcn.h" />
<ClInclude Include="color.h" />
<ClInclude Include="crunch.h" />
<ClInclude Include="crunch\crnlib.h" />
<ClInclude Include="crunch\crn_decomp.h" />
<ClInclude Include="endianness.h" />
<ClInclude Include="etc.h" />
<ClInclude Include="fp16.h" />
<ClInclude Include="fp16\bitcasts.h" />
<ClInclude Include="fp16\fp16.h" />
<ClInclude Include="pvrtc.h" />
<ClInclude Include="Texture2DDecoder.h" />
<ClInclude Include="unitycrunch.h" />
<ClInclude Include="unitycrunch\crnlib.h" />
<ClInclude Include="unitycrunch\crn_decomp.h" />
<ClInclude Include="unitycrunch\crn_defs.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AssemblyInfo.cpp" />
<ClCompile Include="astc.cpp" />
<ClCompile Include="atc.cpp" />
<ClCompile Include="bcn.cpp" />
<ClCompile Include="crunch.cpp" />
<ClCompile Include="etc.cpp" />
<ClCompile Include="pvrtc.cpp" />
<ClCompile Include="Texture2DDecoder.cpp" />
<ClCompile Include="unitycrunch.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,102 @@
<?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>
<ClInclude Include="astc.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="atc.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="bcn.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="color.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="crunch.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="endianness.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="etc.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="fp16.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="pvrtc.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="Texture2DDecoder.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="unitycrunch.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="crunch\crn_decomp.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="crunch\crnlib.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="fp16\bitcasts.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="fp16\fp16.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="unitycrunch\crn_decomp.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="unitycrunch\crn_defs.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="unitycrunch\crnlib.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AssemblyInfo.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="astc.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="atc.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="bcn.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="crunch.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="etc.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="pvrtc.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="Texture2DDecoder.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="unitycrunch.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>

1148
Texture2DDecoder/astc.cpp Normal file

File diff suppressed because it is too large Load Diff

8
Texture2DDecoder/astc.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef ASTC_H
#define ASTC_H
#include <stdint.h>
int decode_astc(const uint8_t *, const long, const long, const int, const int, uint32_t *);
#endif /* end of include guard: ASTC_H */

91
Texture2DDecoder/atc.cpp Normal file
View File

@@ -0,0 +1,91 @@
#include "bcn.h"
#include "atc.h"
#include "color.h"
#include <algorithm>
static uint8_t expand_quantized(uint8_t v, int bits) {
v = v << (8 - bits);
return v | (v >> bits);
}
void decode_atc_block(const uint8_t* _src, uint32_t* _dst)
{
uint8_t colors[4 * 4];
uint32_t c0 = _src[0] | (_src[1] << 8);
uint32_t c1 = _src[2] | (_src[3] << 8);
if (0 == (c0 & 0x8000))
{
colors[0] = expand_quantized((c0 >> 0) & 0x1f, 5);
colors[1] = expand_quantized((c0 >> 5) & 0x1f, 5);
colors[2] = expand_quantized((c0 >> 10) & 0x1f, 5);
colors[12] = expand_quantized((c1 >> 0) & 0x1f, 5);
colors[13] = expand_quantized((c1 >> 5) & 0x3f, 6);
colors[14] = expand_quantized((c1 >> 11) & 0x1f, 5);
colors[4] = (5 * colors[0] + 3 * colors[12]) / 8;
colors[5] = (5 * colors[1] + 3 * colors[13]) / 8;
colors[6] = (5 * colors[2] + 3 * colors[14]) / 8;
colors[8] = (3 * colors[0] + 5 * colors[12]) / 8;
colors[9] = (3 * colors[1] + 5 * colors[13]) / 8;
colors[10] = (3 * colors[2] + 5 * colors[14]) / 8;
}
else
{
colors[0] = 0;
colors[1] = 0;
colors[2] = 0;
colors[8] = expand_quantized((c0 >> 0) & 0x1f, 5);
colors[9] = expand_quantized((c0 >> 5) & 0x1f, 5);
colors[10] = expand_quantized((c0 >> 10) & 0x1f, 5);
colors[12] = expand_quantized((c1 >> 0) & 0x1f, 5);
colors[13] = expand_quantized((c1 >> 5) & 0x3f, 6);
colors[14] = expand_quantized((c1 >> 11) & 0x1f, 5);
colors[4] = std::max(0, colors[8] - colors[12] / 4);
colors[5] = std::max(0, colors[9] - colors[13] / 4);
colors[6] = std::max(0, colors[10] - colors[14] / 4);
}
for (uint32_t i = 0, next = 8 * 4; i < 16; i += 1, next += 2)
{
int32_t idx = ((_src[next >> 3] >> (next & 7)) & 3) * 4;
_dst[i] = color(colors[idx + 2], colors[idx + 1], colors[idx + 0], 255);
}
}
int decode_atc_rgb4(const uint8_t* data, uint32_t m_width, uint32_t m_height, uint32_t* image) {
uint32_t m_block_width = 4;
uint32_t m_block_height = 4;
uint32_t m_blocks_x = (m_width + m_block_width - 1) / m_block_width;
uint32_t m_blocks_y = (m_height + m_block_height - 1) / m_block_height;
uint32_t buffer[16];
for (uint32_t by = 0; by < m_blocks_y; by++) {
for (uint32_t bx = 0; bx < m_blocks_x; bx++, data += 8) {
decode_atc_block(data, buffer);
copy_block_buffer(bx, by, m_width, m_height, m_block_width, m_block_height, buffer, image);
}
}
return 1;
}
int decode_atc_rgba8(const uint8_t* data, uint32_t m_width, uint32_t m_height, uint32_t* image) {
uint32_t m_block_width = 4;
uint32_t m_block_height = 4;
uint32_t m_blocks_x = (m_width + m_block_width - 1) / m_block_width;
uint32_t m_blocks_y = (m_height + m_block_height - 1) / m_block_height;
uint32_t buffer[16];
for (uint32_t by = 0; by < m_blocks_y; by++) {
for (uint32_t bx = 0; bx < m_blocks_x; bx++, data += 16) {
decode_atc_block(data + 8, buffer);
decode_bc3_alpha(data, buffer, 3);
copy_block_buffer(bx, by, m_width, m_height, m_block_width, m_block_height, buffer, image);
}
}
return 1;
}

5
Texture2DDecoder/atc.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
int decode_atc_rgb4(const uint8_t* data, uint32_t m_width, uint32_t m_height, uint32_t* image);
int decode_atc_rgba8(const uint8_t* data, uint32_t m_width, uint32_t m_height, uint32_t* image);

Some files were not shown because too many files have changed in this diff Show More