Add support for latest Tuanjie versions (up to v1.9)

still partial
This commit is contained in:
VaDiM
2026-05-27 02:50:58 +03:00
parent 22e4b0e8a1
commit 7adfdef62f
12 changed files with 392 additions and 181 deletions
+1
View File
@@ -61,5 +61,6 @@
ArmLinux,
ArmLinuxServer,
VisionOS,
PlayableAds,
}
}
+6 -40
View File
@@ -1,4 +1,5 @@
using System;
using AssetStudio.Classes.Tuanjie.AnimationClip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -682,45 +683,6 @@ namespace AssetStudio
}
}
public class ACLClip //Tuanjie
{
public uint m_FrameCount;
public uint m_BoneCount;
public float m_SampleRate;
public uint m_CurveCount;
public byte[] m_Tracks;
public uint[] m_ACLDecoderMap;
public bool m_UseACLFastSampleMode;
public ACLClip() { }
public ACLClip(ObjectReader reader)
{
var version = reader.version;
m_FrameCount = reader.ReadUInt32();
m_BoneCount = reader.ReadUInt32();
m_SampleRate = reader.ReadSingle();
if (version >= (2022, 3, 55)) //2022.3.55t1(1.5.0) and up
{
m_CurveCount = reader.ReadUInt32();
}
m_Tracks = reader.ReadUInt8Array();
if (version >= (2022, 3, 61)) //2022.3.61t1(1.6.0) and up
{
reader.AlignStream();
}
m_ACLDecoderMap = reader.ReadUInt32Array();
if (version > (2022, 3, 55) || (version == (2022, 3, 55) && version.Build >= 4)) //2022.3.55t4(1.5.3) and up
{
m_UseACLFastSampleMode = reader.ReadBoolean();
if (version >= (2022, 3, 61)) //2022.3.61t1(1.6.0) and up
{
reader.AlignStream();
}
}
}
}
public class OffsetPtr
{
public Clip data;
@@ -899,6 +861,10 @@ namespace AssetStudio
}
m_Mirror = reader.ReadBoolean();
if (version.IsTuanjie && version >= (2022, 3, 62, 8)) //2022.3.62t8(1.9.0) and up
{
var m_LockToRoot = reader.ReadBoolean();
}
if (version >= (4, 3)) //4.3 and up
{
m_LoopTime = reader.ReadBoolean();
+21
View File
@@ -128,6 +128,11 @@ namespace AssetStudio
}
m_ConditionConstantArray = conditionConstantList.ToArray();
if (version.IsTuanjie && version >= (2022, 3, 62, 2)) //2022.3.62t2(1.8.0) and up
{
var m_PriorityOrder = reader.ReadInt32();
}
m_DestinationState = reader.ReadUInt32();
if (version >= 5) //5.0 and up
{
@@ -157,6 +162,11 @@ namespace AssetStudio
m_CanTransitionToSelf = reader.ReadBoolean();
}
if (version.IsTuanjie && version >= (2022, 3, 62, 8)) //2022.3.62t8(1.9.0) and up
{
var m_UseInertialization = reader.ReadBoolean();
}
reader.AlignStream();
}
}
@@ -400,6 +410,12 @@ namespace AssetStudio
{
m_CycleOffset = reader.ReadSingle();
}
if (version.IsTuanjie && version >= (2022, 3, 62, 2)) //2022.3.62t2(1.8.0) and up
{
var m_OverrideDuration = reader.ReadSingle();
}
m_IKOnFeet = reader.ReadBoolean();
if (version >= 5) //5.0 and up
{
@@ -412,6 +428,11 @@ namespace AssetStudio
m_Mirror = reader.ReadBoolean();
}
if (version.IsTuanjie && version >= (2022, 3, 62, 2)) //2022.3.62t2(1.8.0) and up
{
var m_UseOverrideDuration = reader.ReadBoolean();
}
reader.AlignStream();
}
}
+46 -139
View File
@@ -1,7 +1,7 @@
using System;
using AssetStudio.Classes.Tuanjie.Mesh;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using static AssetStudio.CustomOptions.GameSpecificOptions.CustomMeshOptions;
@@ -517,105 +517,7 @@ namespace AssetStudio
}
}
}
public class VGPackedHierarchyNode
{
public Vector4[] LODBounds = new Vector4[8];
public Vector3[] AABBCenter = new Vector3[8];
public uint[] MinLODError_MaxParentLODError = new uint[8];
public Vector3[] AABBExtent = new Vector3[8];
public uint[] ChildStartIndex = new uint[8];
public uint[] PageIndex_PageCount_PageBlockCount = new uint[8];
public VGPackedHierarchyNode(ObjectReader reader)
{
for (var i = 0; i < 8; i++)
{
LODBounds[i] = reader.ReadVector4();
AABBCenter[i] = reader.ReadVector3();
MinLODError_MaxParentLODError[i] = reader.ReadUInt32();
AABBExtent[i] = reader.ReadVector3();
ChildStartIndex[i] = reader.ReadUInt32();
PageIndex_PageCount_PageBlockCount[i] = reader.ReadUInt32();
}
}
}
public class VGPageStreamingInfo
{
public uint offset;
public uint wholeSize;
public uint dataSize;
public uint dependencyOffset;
public uint dependencyCount;
public uint flags;
public VGPageStreamingInfo(BinaryReader reader)
{
offset = reader.ReadUInt32();
wholeSize = reader.ReadUInt32();
dataSize = reader.ReadUInt32();
dependencyOffset = reader.ReadUInt32();
dependencyCount = reader.ReadUInt32();
flags = reader.ReadUInt32();
}
}
public class SharedClusterData //Tuanjie
{
public SharedClusterData(ObjectReader reader, byte rev)
{
var m_LightmapUseUV1 = reader.ReadInt32();
var m_fileScale = reader.ReadSingle();
if (rev == 1)
{
var NumInputTriangles = reader.ReadUInt32();
var NumInputVertices = reader.ReadUInt32();
var NumInputMeshes = reader.ReadUInt16();
var NumInputTexCoords = reader.ReadUInt16();
var ResourceFlags = reader.ReadUInt32();
}
var rootClusterPageSize = reader.ReadInt32();
reader.Position += rootClusterPageSize; //skip byte[] rootClusterPage
if (rev == 1)
{
var imposterAtlasSize = reader.ReadInt32();
reader.Position += imposterAtlasSize * 2; //skip ushort[] imposterAtlas
}
var hierarchyNodesSize = reader.ReadInt32();
for (var i = 0; i < hierarchyNodesSize; i++)
{
var hierarchyNode = new VGPackedHierarchyNode(reader);
}
if (rev == 1)
{
var hierarchyRootOffsetsSize = reader.ReadInt32();
reader.Position += hierarchyRootOffsetsSize * 4; //skip uint[] hierarchyRootOffsets
}
var pageStreamingInfosSize = reader.ReadInt32();
for (var i = 0; i < pageStreamingInfosSize; i++)
{
var pageStreamingInfo = new VGPageStreamingInfo(reader);
}
var pageIndicesOfDependenciesSize = reader.ReadInt32();
reader.Position += pageIndicesOfDependenciesSize * 4; //skip uint[] pageIndicesOfDependencies
if (rev == 2)
{
var inputTrianglesCount = reader.ReadUInt32();
var inputVerticesCount = reader.ReadUInt32();
var inputMeshesCount = reader.ReadUInt16();
var inputTexCoordsCount = reader.ReadUInt16();
var resourceFlags = reader.ReadUInt32();
var imposterAtlasSize = reader.ReadInt32();
reader.Position += imposterAtlasSize * 2; //skip ushort[] imposterAtlas
var hierarchyRootOffsetsSize = reader.ReadInt32();
reader.Position += hierarchyRootOffsetsSize * 4; //skip uint[] hierarchyRootOffsets
}
var streamableClusterPageSize = reader.ReadInt32();
reader.Position += streamableClusterPageSize; //skip byte[] streamableClusterPageSize
}
}
public sealed class Mesh : NamedObject
{
private bool isLoaded;
@@ -677,12 +579,12 @@ namespace AssetStudio
if (version <= (2, 5)) //2.0 - 2.5 down
{
int m_IndexBufferSize = reader.ReadInt32();
int m_IndexBufferCount = reader.ReadInt32();
if (m_Use16BitIndices)
{
var indexBufferList = new List<uint>();
for (var i = 0; i < m_IndexBufferSize / 2; i++)
for (var i = 0; i < m_IndexBufferCount / 2; i++)
{
indexBufferList.Add(reader.ReadUInt16());
}
@@ -694,14 +596,14 @@ namespace AssetStudio
}
else
{
m_IndexBuffer = reader.ReadUInt32Array(m_IndexBufferSize / 4);
m_IndexBuffer = reader.ReadUInt32Array(m_IndexBufferCount / 4);
}
}
int m_SubMeshesSize = reader.ReadInt32();
reader.ThrowIfTooLarge(m_SubMeshesSize * 12f);
int m_SubMeshesCount = reader.ReadInt32();
reader.ThrowIfTooLarge(m_SubMeshesCount * 12f);
m_SubMeshes = new List<SubMesh>();
for (var i = 0; i < m_SubMeshesSize; i++)
for (var i = 0; i < m_SubMeshesCount; i++)
{
m_SubMeshes.Add(new SubMesh(reader));
}
@@ -723,14 +625,11 @@ namespace AssetStudio
{
if (version >= 2019) //2019 and up
{
var m_BonesAABBSize = reader.ReadInt32();
for (var i = 0; i < m_BonesAABBSize; i++)
{
var m_BonesAABB = new MinMaxAABB(reader);
}
var m_BonesAABBCount = reader.ReadInt32();
reader.Position += m_BonesAABBCount * 24; //skip MinMaxAABB[] m_BonesAABB
var m_VariableBoneCountWeightsSize = reader.ReadInt32();
reader.Position += m_VariableBoneCountWeightsSize * 4; //skip uint[] m_VariableBoneCountWeights
var m_VariableBoneCountWeightsCount = reader.ReadInt32();
reader.Position += m_VariableBoneCountWeightsCount * 4; //skip uint[] m_VariableBoneCountWeights
}
var m_MeshCompression = reader.ReadByte();
@@ -744,33 +643,41 @@ namespace AssetStudio
var m_KeepVertices = reader.ReadBoolean();
var m_KeepIndices = reader.ReadBoolean();
}
var tuanjieParsingMode = reader.assetsFile.assetsManager.Options.GameSpecific.Meshes.TuanjieMeshParsingMode;
var useSharedClusterData = tuanjieParsingMode == MeshParsingMode.Tuanjie;
if (tuanjieParsingMode == MeshParsingMode.Auto)
{
//SharedClusterData becomes optional from v1.6.1, but idk in what cases
useSharedClusterData = version < (2022, 3, 61, 2) || !serializedType.Match(6165448184371784201);
}
if (version.IsTuanjie && useSharedClusterData)
{
if (version < (2022, 3, 48, 3)) //2022.3.48t3(1.4.0) down
{
_ = new SharedClusterData(reader, rev: 1);
}
else if (version < (2022, 3, 61, 2)) //2022.3.48t3(1.4.0) - 2022.3.61t1(1.6.0)
{
_ = new SharedClusterData(reader, rev: 2);
}
else //2022.3.61t2(1.6.1) and up
{
reader.AlignStream();
_ = new SharedClusterData(reader, rev: 3);
}
}
reader.AlignStream();
if (version.IsTuanjie)
{
var tuanjieParsingMode = assetsFile.assetsManager.Options.GameSpecific.Meshes.TuanjieMeshParsingMode;
var parseAsTuanjie = tuanjieParsingMode == MeshParsingMode.Tuanjie;
if (tuanjieParsingMode == MeshParsingMode.Auto)
{
//Tuanjie features becomes optional from v1.6.1, but idk in what cases (platform dependent?)
parseAsTuanjie = version < (2022, 3, 61, 2) || !serializedType.Match(6165448184371784201, 16777665667907586384);
}
if (parseAsTuanjie)
{
if (version >= (2022, 3, 62)) //2022.3.62t1(1.7.0) and up
{
var m_GIFacetMesh = new GIFacetMesh(reader);
var m_GISDFMesh = new GISDFMesh(reader);
}
if (version < (2022, 3, 48, 3)) //2022.3.48t3(1.4.0) down
{
_ = new SharedClusterData(reader, rev: 1);
}
else if (version < (2022, 3, 61, 2)) //2022.3.48t3(1.4.0) - 2022.3.61t1(1.6.0)
{
_ = new SharedClusterData(reader, rev: 2);
}
else //2022.3.61t2(1.6.1) and up
{
_ = new SharedClusterData(reader, rev: 3);
}
}
}
//Unity fixed it in 2017.3.1p1 and later versions
if (version >= (2017, 4) //2017.4
|| version == (2017, 3, 1) && version.IsPatch //fixed after 2017.3.1px
+4 -1
View File
@@ -69,7 +69,10 @@ namespace AssetStudio
if (version.IsTuanjie) //2022.3.2t3(1.0.0) and up
{
var m_virtualGeometry = reader.ReadByte();
var m_virtualGeometryShadow = reader.ReadByte();
if (version < (2022, 3, 62, 2)) //2022.3.62t2(1.8.0) down
{
var m_virtualGeometryShadow = reader.ReadByte();
}
if (version >= (2022, 3, 48, 3)) //2022.3.48t3(1.4.0) and up
{
reader.AlignStream();
+5 -1
View File
@@ -63,7 +63,9 @@ namespace AssetStudio
m_Width = parsedTex2d.m_Width;
m_Height = parsedTex2d.m_Height;
m_CompleteImageSize = parsedTex2d.m_CompleteImageSize;
m_TextureFormat = parsedTex2d.m_TextureFormat;
m_TextureFormat = version.IsTuanjie && version >= (2022, 3, 62, 8)
? parsedTex2d.m_TextureFormat.ToTuanjie() //2022.3.62t8(1.9.0) and up
: parsedTex2d.m_TextureFormat;
m_MipMap = parsedTex2d.m_MipMap;
m_MipCount = parsedTex2d.m_MipCount;
m_ImageCount = parsedTex2d.m_ImageCount;
@@ -104,6 +106,8 @@ namespace AssetStudio
var m_TextureManagerMultiFormatSettingSize = reader.ReadInt32();
reader.Position += m_TextureManagerMultiFormatSettingSize; //skip byte[] m_TextureManagerMultiFormatSetting
reader.AlignStream();
m_TextureFormat = version >= (2022, 3, 62, 8) ? m_TextureFormat.ToTuanjie() : m_TextureFormat; //2022.3.62t8(1.9.0) and up
}
if (version < (5, 2)) //5.2 down
{
+31
View File
@@ -311,5 +311,36 @@
/// Four channel (RGBA) texture format, 16-bits signed integer per channel.
/// </summary>
RGBA64_SIGNED,
//Tuanjie engine
//(adding 1000 for compatibility with Unity formats)
/// <summary>
/// Offset for Tuanjie texture formats.
/// </summary>
TUANJIE_OFFSET = 1000,
/// <summary>
/// PNG (32 bits) compressed RGBA texture format.
/// </summary>
PNG_32_RGBA = TUANJIE_OFFSET + 75,
/// <summary>
/// PNG (24 bits) compressed RGB texture format.
/// </summary>
PNG_24_RGB = TUANJIE_OFFSET + 76,
/// <summary>
/// PNG (8 bits) compressed RGBA texture format.
/// </summary>
PNG_8_RGBA = TUANJIE_OFFSET + 77,
}
public static class TextureFormatExtensions
{
public static TextureFormat ToTuanjie(this TextureFormat format)
{
return format > TextureFormat.RGBA64 && format < TextureFormat.TUANJIE_OFFSET
? TextureFormat.TUANJIE_OFFSET + (int)format
: format;
}
public static bool IsPng(this TextureFormat format) => format >= TextureFormat.PNG_32_RGBA && format <= TextureFormat.PNG_8_RGBA;
}
}
@@ -0,0 +1,45 @@
namespace AssetStudio.Classes.Tuanjie.AnimationClip
{
public sealed class ACLClip
{
public uint m_FrameCount;
public uint m_BoneCount;
public float m_SampleRate;
public uint m_CurveCount;
public byte[] m_Tracks;
public uint[] m_ACLDecoderMap;
public bool m_UseACLFastSampleMode;
public ACLClip() { }
public ACLClip(ObjectReader reader)
{
var version = reader.version;
m_FrameCount = reader.ReadUInt32();
m_BoneCount = reader.ReadUInt32();
m_SampleRate = reader.ReadSingle();
if (version >= (2022, 3, 55)) //2022.3.55t1(1.5.0) and up
{
m_CurveCount = reader.ReadUInt32();
}
if (version >= (2022, 3, 62, 8)) //2022.3.62t8(1.9.0) and up
{
var m_BeginTime = reader.ReadSingle();
}
m_Tracks = reader.ReadUInt8Array();
if (version >= (2022, 3, 61)) //2022.3.61t1(1.6.0) and up
{
reader.AlignStream();
}
m_ACLDecoderMap = reader.ReadUInt32Array();
if (version > (2022, 3, 55) || (version == (2022, 3, 55) && version.Build >= 4)) //2022.3.55t4(1.5.3) and up
{
m_UseACLFastSampleMode = reader.ReadBoolean();
if (version >= (2022, 3, 61)) //2022.3.61t1(1.6.0) and up
{
reader.AlignStream();
}
}
}
}
}
+200
View File
@@ -0,0 +1,200 @@
using System.Collections.Generic;
namespace AssetStudio.Classes.Tuanjie.Mesh
{
public sealed class GIFacetInfo
{
public float[] matrix; //Matrix3x4f
public byte orientation;
public GIFacetInfo(ObjectReader reader)
{
matrix = reader.ReadSingleArray(12);
orientation = reader.ReadByte();
reader.AlignStream();
}
}
public sealed class GIFacetMesh
{
public MinMaxAABB m_aabb;
public bool m_doubleSide;
public List<GIFacetInfo> m_GIFacetInfo;
public GIFacetMesh(ObjectReader reader)
{
m_aabb = new MinMaxAABB(reader);
m_doubleSide = reader.ReadBoolean();
reader.AlignStream();
var m_GIFacetInfoCount = reader.ReadInt32();
m_GIFacetInfo = new List<GIFacetInfo>();
for (var i = 0; i < m_GIFacetInfoCount; i++)
{
m_GIFacetInfo.Add(new GIFacetInfo(reader));
}
}
}
public sealed class GISDFMeshLOD
{
public uint brickMappingSizeX;
public uint brickMappingSizeY;
public uint brickMappingSizeZ;
public Vector3 volumeToMappingScale;
public Vector3 volumeToMappingBias;
public float SDFDecodeScale;
public float SDFDecodeBias;
public uint[] activeBrickIDs;
public byte[] activeBrickData;
public GISDFMeshLOD(ObjectReader reader)
{
brickMappingSizeX = reader.ReadUInt32();
brickMappingSizeY = reader.ReadUInt32();
brickMappingSizeZ = reader.ReadUInt32();
volumeToMappingScale = reader.ReadVector3();
volumeToMappingBias = reader.ReadVector3();
SDFDecodeScale = reader.ReadSingle();
SDFDecodeBias = reader.ReadSingle();
activeBrickIDs = reader.ReadUInt32Array();
activeBrickData = reader.ReadUInt8Array();
reader.AlignStream();
}
}
public sealed class GISDFMesh
{
public AABB localAABB;
public float sdfGenBias;
public bool is2Sided;
public List<GISDFMeshLOD> LODs;
public GISDFMesh(ObjectReader reader)
{
localAABB = new AABB(reader);
sdfGenBias = reader.ReadSingle();
is2Sided = reader.ReadBoolean();
reader.AlignStream();
var LODsCount = reader.ReadInt32();
LODs = new List<GISDFMeshLOD>();
for (var i = 0; i < LODsCount; i++)
{
LODs.Add(new GISDFMeshLOD(reader));
}
}
}
public sealed class VGPackedHierarchyNode
{
public Vector4[] LODBounds = new Vector4[8];
public Vector3[] AABBCenter = new Vector3[8];
public uint[] MinLODError_MaxParentLODError = new uint[8];
public Vector3[] AABBExtent = new Vector3[8];
public uint[] ChildStartIndex = new uint[8];
public uint[] PageIndex_PageCount_PageBlockCount = new uint[8];
public VGPackedHierarchyNode(ObjectReader reader)
{
for (var i = 0; i < 8; i++)
{
LODBounds[i] = reader.ReadVector4();
AABBCenter[i] = reader.ReadVector3();
MinLODError_MaxParentLODError[i] = reader.ReadUInt32();
AABBExtent[i] = reader.ReadVector3();
ChildStartIndex[i] = reader.ReadUInt32();
PageIndex_PageCount_PageBlockCount[i] = reader.ReadUInt32();
}
}
}
public sealed class VGPageStreamingInfo
{
public uint offset;
public uint wholeSize;
public uint dataSize;
public uint dependencyOffset;
public uint dependencyCount;
public uint flags;
public VGPageStreamingInfo(ObjectReader reader)
{
offset = reader.ReadUInt32();
wholeSize = reader.ReadUInt32();
dataSize = reader.ReadUInt32();
dependencyOffset = reader.ReadUInt32();
dependencyCount = reader.ReadUInt32();
flags = reader.ReadUInt32();
}
}
public sealed class SharedClusterData
{
public int m_LightmapUseUV1;
public float m_fileScale;
public byte[] rootClusterPage;
public List<VGPackedHierarchyNode> hierarchyNodes;
public List<VGPageStreamingInfo> pageStreamingInfos;
public uint[] pageIndicesOfDependencies;
public byte[] streamableClusterPageSize;
public SharedClusterData(ObjectReader reader, byte rev)
{
m_LightmapUseUV1 = reader.ReadInt32();
if (reader.version < (2022, 3, 62)) //2022.3.62t1(1.7.0) down
{
m_fileScale = reader.ReadSingle();
}
if (rev == 1)
{
var NumInputTriangles = reader.ReadUInt32();
var NumInputVertices = reader.ReadUInt32();
var NumInputMeshes = reader.ReadUInt16();
var NumInputTexCoords = reader.ReadUInt16();
var ResourceFlags = reader.ReadUInt32();
}
rootClusterPage = reader.ReadUInt8Array();
reader.AlignStream();
if (rev == 1)
{
var imposterAtlasCount = reader.ReadInt32();
reader.Position += imposterAtlasCount * 2; //skip ushort[] imposterAtlas
reader.AlignStream();
}
var hierarchyNodesCount = reader.ReadInt32();
hierarchyNodes = new List<VGPackedHierarchyNode>();
for (var i = 0; i < hierarchyNodesCount; i++)
{
hierarchyNodes.Add(new VGPackedHierarchyNode(reader));
}
if (rev == 1)
{
var hierarchyRootOffsetsCount = reader.ReadInt32();
reader.Position += hierarchyRootOffsetsCount * 4; //skip uint[] hierarchyRootOffsets
}
var pageStreamingInfosCount = reader.ReadInt32();
pageStreamingInfos = new List<VGPageStreamingInfo>();
for (var i = 0; i < pageStreamingInfosCount; i++)
{
pageStreamingInfos.Add(new VGPageStreamingInfo(reader));
}
pageIndicesOfDependencies = reader.ReadUInt32Array();
if (rev == 2)
{
var inputTrianglesCount = reader.ReadUInt32();
var inputVerticesCount = reader.ReadUInt32();
var inputMeshesCount = reader.ReadUInt16();
var inputTexCoordsCount = reader.ReadUInt16();
var resourceFlags = reader.ReadUInt32();
var imposterAtlasCount = reader.ReadInt32();
reader.Position += imposterAtlasCount * 2; //skip ushort[] imposterAtlas
reader.AlignStream();
var hierarchyRootOffsetsCount = reader.ReadInt32();
reader.Position += hierarchyRootOffsetsCount * 4; //skip uint[] hierarchyRootOffsets
}
streamableClusterPageSize = reader.ReadUInt8Array();
reader.AlignStream();
}
}
}
+7
View File
@@ -48,6 +48,13 @@ namespace AssetStudioCLI
debugLog += sb.ToString();
}
if (type == ImageFormat.Png && m_Texture2D.m_TextureFormat.IsPng())
{
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
if (!converter.TryConvertToBgra32Image(flip: true, out var image))
{
Logger.Error($"{debugLog}Export error. Failed to convert texture \"{m_Texture2D.m_Name}\" into image");
+7
View File
@@ -47,6 +47,13 @@ namespace AssetStudioGUI
debugLog += sb.ToString();
}
if (type == ImageFormat.Png && m_Texture2D.m_TextureFormat.IsPng())
{
File.WriteAllBytes(exportFullPath, m_Texture2D.image_data.GetData());
debugLog += $"{item.TypeString} \"{item.Text}\" exported to \"{exportFullPath}\"";
return true;
}
if (!converter.TryConvertToBgra32Image(flip: true, out var image))
{
Logger.Warning($"{debugLog}Failed to convert texture \"{m_Texture2D.m_Name}\" into image");
+19
View File
@@ -322,6 +322,11 @@ namespace AssetStudio
case TextureFormat.RGBA64: //test pass
flag = DecodeRGBA64(buff, destSpan);
break;
case TextureFormat.PNG_8_RGBA:
case TextureFormat.PNG_24_RGB: //test pass
case TextureFormat.PNG_32_RGBA: //test pass
flag = DecodePng(buff, destSpan);
break;
}
}
finally
@@ -811,6 +816,20 @@ namespace AssetStudio
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool DecodePng(ReadOnlySpan<byte> buff, Span<byte> destSpan)
{
try
{
Image.Load<Bgra32>(buff).CopyPixelDataTo(destSpan);
return true;
}
catch (Exception)
{
return false;
}
}
private bool TryUnpackCrunch(ReadOnlySpan<byte> buff, out ReadOnlySpan<byte> result)
{
if (m_Texture2D.version >= (2017, 3) //2017.3 and up