11using AssetRipper . Conversions . UnityCrunch . Structures ;
22using System ;
3+ using System . Diagnostics ;
34using System . Diagnostics . CodeAnalysis ;
45
56namespace AssetRipper . Conversions . UnityCrunch ;
@@ -16,12 +17,7 @@ public static partial class UnityCrunch
1617 /// </summary>
1718 public const int MaxLevels = 16 ;
1819
19- public static bool TryDecompress ( ReadOnlySpan < byte > input , [ NotNullWhen ( true ) ] out byte [ ] ? output )
20- {
21- return TryDecompress ( input , 0 , out output ) ;
22- }
23-
24- public static unsafe bool TryDecompress ( ReadOnlySpan < byte > input , int levelIndex , [ NotNullWhen ( true ) ] out byte [ ] ? output )
20+ public static unsafe bool TryDecompress ( ReadOnlySpan < byte > input , [ NotNullWhen ( true ) ] out byte [ ] ? output )
2521 {
2622 if ( input . Length == 0 )
2723 {
@@ -46,35 +42,54 @@ public static unsafe bool TryDecompress(ReadOnlySpan<byte> input, int levelIndex
4642 }
4743
4844 // m_struct_size
49- int width = int . Max ( 1 , textureInfo . field_1 >> levelIndex ) ;
50- int height = int . Max ( 1 , textureInfo . field_2 >> levelIndex ) ;
51- // m_levels
45+ int fullWidth = textureInfo . field_1 ;
46+ int fullHeight = textureInfo . field_2 ;
47+ int levelCount = textureInfo . field_3 ;
5248 int faceCount = textureInfo . field_4 ;
53- int bytesPerBlock = textureInfo . field_5 ;
49+ int bytesPerDxtBlock = textureInfo . field_5 ;
5450 // m_userdata0
5551 // m_userdata1
5652 // m_format
5753
58- int blocksX = ( width + 3 ) >> 2 ;
59- int blocksY = ( height + 3 ) >> 2 ;
60- int rowPitch = blocksX * crnd_get_bytes_per_dxt_block ( textureInfo . field_8 ) ;
61- int faceSize = rowPitch * blocksY ;
62- int totalFaceSize = faceCount * faceSize ;
54+ Debug . Assert ( bytesPerDxtBlock == crnd_get_bytes_per_dxt_block ( textureInfo . field_8 ) ) ;
55+
56+ if ( levelCount < 1 || levelCount > MaxLevels || faceCount < 1 || faceCount > MaxFaces )
57+ {
58+ crnd_unpack_end ( context ) ;
59+ return False ( out output ) ;
60+ }
61+
62+ int completeImageSize = CalculateCompleteImageSize ( fullWidth , fullHeight , bytesPerDxtBlock , levelCount ) ;
63+
64+ byte [ ] result = new byte [ completeImageSize * faceCount ] ;
6365
64- byte [ ] result = new byte [ totalFaceSize ] ;
66+ byte * * pResultArray = stackalloc byte * [ MaxFaces ] ;
6567
6668 fixed ( byte * pResult = result )
6769 {
68- byte * * pResultArray = stackalloc byte * [ MaxFaces ] { null , null , null , null , null , null } ;
69- for ( int i = 0 ; i < faceCount ; i ++ )
70+ int offset = 0 ;
71+ for ( int levelIndex = 0 ; levelIndex < levelCount ; levelIndex ++ )
7072 {
71- pResultArray [ i ] = pResult + i * faceSize ;
72- }
73+ int width = int . Max ( 1 , fullWidth >> levelIndex ) ;
74+ int height = int . Max ( 1 , fullHeight >> levelIndex ) ;
75+ int blocksX = ( width + 3 ) >> 2 ;
76+ int blocksY = ( height + 3 ) >> 2 ;
77+ int rowPitch = blocksX * bytesPerDxtBlock ;
78+ int faceSize = rowPitch * blocksY ;
7379
74- if ( ! crnd_unpack_level ( context , pResultArray , faceSize , rowPitch , levelIndex ) )
75- {
76- crnd_unpack_end ( context ) ;
77- return False ( out output ) ;
80+ new Span < nint > ( pResultArray , MaxFaces ) . Clear ( ) ;
81+ for ( int i = 0 ; i < faceCount ; i ++ )
82+ {
83+ pResultArray [ i ] = pResult + offset + i * completeImageSize ;
84+ }
85+
86+ if ( ! crnd_unpack_level ( context , pResultArray , faceSize , rowPitch , levelIndex ) )
87+ {
88+ crnd_unpack_end ( context ) ;
89+ return False ( out output ) ;
90+ }
91+
92+ offset += faceSize ;
7893 }
7994 }
8095 crnd_unpack_end ( context ) ;
@@ -83,10 +98,24 @@ public static unsafe bool TryDecompress(ReadOnlySpan<byte> input, int levelIndex
8398
8499 return true ;
85100
86- static unsafe bool False ( [ NotNullWhen ( true ) ] out byte [ ] ? output )
101+ static bool False ( [ NotNullWhen ( true ) ] out byte [ ] ? output )
87102 {
88103 output = null ;
89104 return false ;
90105 }
106+
107+ static int CalculateCompleteImageSize ( int width , int height , int bytesPerDxtBlock , int levelCount )
108+ {
109+ int totalSize = 0 ;
110+ for ( int levelIndex = 0 ; levelIndex < levelCount ; levelIndex ++ )
111+ {
112+ int levelWidth = int . Max ( 1 , width >> levelIndex ) ;
113+ int levelHeight = int . Max ( 1 , height >> levelIndex ) ;
114+ int blocksX = ( levelWidth + 3 ) >> 2 ;
115+ int blocksY = ( levelHeight + 3 ) >> 2 ;
116+ totalSize += blocksX * blocksY * bytesPerDxtBlock ;
117+ }
118+ return totalSize ;
119+ }
91120 }
92121}
0 commit comments