11//#define DISABLE_TWINDDLING_ROUTINE
22#define ASSUME_IMAGE_TILING
33
4+ using AssetRipper . TextureDecoder . Rgb ;
5+ using AssetRipper . TextureDecoder . Rgb . Formats ;
6+ using System . Diagnostics ;
7+
48namespace AssetRipper . TextureDecoder . Pvrtc
59{
610 public static partial class PvrtcDecoder
711 {
812 /// <summary>
9- /// Decompresses PVRTC to RGBA 8888
13+ /// Decompresses PVRTC to BGRA 8888
1014 /// </summary>
1115 /// <param name="input">The PVRTC texture data to decompress</param>
1216 /// <param name="xDim">X dimension (width) of the texture</param>
1317 /// <param name="yDim">Y dimension (height) of the texture</param>
1418 /// <param name="output">The decompressed texture data</param>
1519 /// <param name="do2bitMode">Signifies whether the data is PVRTC2 or PVRTC4</param>
1620 /// <returns>The number of bytes read from <paramref name="input"/></returns>
17- [ MethodImpl ( MethodImplOptions . AggressiveInlining | MethodImplOptions . AggressiveOptimization ) ]
1821 public static int DecompressPVRTC ( ReadOnlySpan < byte > input , int xDim , int yDim , bool do2bitMode , out byte [ ] output )
1922 {
20- output = new byte [ xDim * yDim * sizeof ( uint ) ] ;
21- return DecompressPVRTC ( input , xDim , yDim , do2bitMode , output ) ;
23+ return DecompressPVRTC < ColorBGRA32 , byte > ( input , xDim , yDim , do2bitMode , out output ) ;
2224 }
2325
2426 /// <summary>
25- /// Decompresses PVRTC to RGBA 8888
27+ /// Decompresses PVRTC to BGRA 8888
2628 /// </summary>
2729 /// <param name="input">The PVRTC texture data to decompress</param>
2830 /// <param name="xDim">X dimension (width) of the texture</param>
2931 /// <param name="yDim">Y dimension (height) of the texture</param>
3032 /// <param name="output">The decompressed texture data</param>
3133 /// <param name="do2bitMode">Signifies whether the data is PVRTC2 or PVRTC4</param>
3234 /// <returns>The number of bytes read from <paramref name="input"/></returns>
33- [ MethodImpl ( MethodImplOptions . AggressiveInlining | MethodImplOptions . AggressiveOptimization ) ]
3435 public static int DecompressPVRTC ( ReadOnlySpan < byte > input , int xDim , int yDim , bool do2bitMode , Span < byte > output )
36+ {
37+ return DecompressPVRTC < ColorBGRA32 , byte > ( input , xDim , yDim , do2bitMode , output ) ;
38+ }
39+
40+ /// <summary>
41+ /// Decompresses PVRTC
42+ /// </summary>
43+ /// <typeparam name="TOutputColor">The <see cref="IColor{T}"/> type used for each pixel.</typeparam>
44+ /// <typeparam name="TOutputChannelValue">The channel type used in <typeparamref name="TOutputColor"/>.</typeparam>
45+ /// <param name="input">The PVRTC texture data to decompress</param>
46+ /// <param name="xDim">X dimension (width) of the texture</param>
47+ /// <param name="yDim">Y dimension (height) of the texture</param>
48+ /// <param name="output">The decompressed texture data</param>
49+ /// <param name="do2bitMode">Signifies whether the data is PVRTC2 or PVRTC4</param>
50+ /// <returns>The number of bytes read from <paramref name="input"/></returns>
51+ public static int DecompressPVRTC < TOutputColor , TOutputChannelValue > ( ReadOnlySpan < byte > input , int xDim , int yDim , bool do2bitMode , out byte [ ] output )
52+ where TOutputChannelValue : unmanaged
53+ where TOutputColor : unmanaged, IColor < TOutputChannelValue >
54+ {
55+ output = new byte [ xDim * yDim * Unsafe . SizeOf < TOutputColor > ( ) ] ;
56+ return DecompressPVRTC < TOutputColor , TOutputChannelValue > ( input , xDim , yDim , do2bitMode , output ) ;
57+ }
58+
59+ /// <summary>
60+ /// Decompresses PVRTC
61+ /// </summary>
62+ /// <typeparam name="TOutputColor">The <see cref="IColor{T}"/> type used for each pixel.</typeparam>
63+ /// <typeparam name="TOutputChannelValue">The channel type used in <typeparamref name="TOutputColor"/>.</typeparam>
64+ /// <param name="input">The PVRTC texture data to decompress</param>
65+ /// <param name="xDim">X dimension (width) of the texture</param>
66+ /// <param name="yDim">Y dimension (height) of the texture</param>
67+ /// <param name="output">The decompressed texture data</param>
68+ /// <param name="do2bitMode">Signifies whether the data is PVRTC2 or PVRTC4</param>
69+ /// <returns>The number of bytes read from <paramref name="input"/></returns>
70+ public static int DecompressPVRTC < TOutputColor , TOutputChannelValue > ( ReadOnlySpan < byte > input , int xDim , int yDim , bool do2bitMode , Span < byte > output )
71+ where TOutputChannelValue : unmanaged
72+ where TOutputColor : unmanaged, IColor < TOutputChannelValue >
73+ {
74+ ThrowHelper . ThrowIfNotLittleEndian ( ) ;
75+ return DecompressPVRTC < TOutputColor , TOutputChannelValue > ( input , xDim , yDim , do2bitMode , MemoryMarshal . Cast < byte , TOutputColor > ( output ) ) ;
76+ }
77+
78+ /// <summary>
79+ /// Decompresses PVRTC
80+ /// </summary>
81+ /// <typeparam name="TOutputColor">The <see cref="IColor{T}"/> type used for each pixel.</typeparam>
82+ /// <typeparam name="TOutputChannelValue">The channel type used in <typeparamref name="TOutputColor"/>.</typeparam>
83+ /// <param name="input">The PVRTC texture data to decompress</param>
84+ /// <param name="xDim">X dimension (width) of the texture</param>
85+ /// <param name="yDim">Y dimension (height) of the texture</param>
86+ /// <param name="output">The decompressed texture data</param>
87+ /// <param name="do2bitMode">Signifies whether the data is PVRTC2 or PVRTC4</param>
88+ /// <returns>The number of bytes read from <paramref name="input"/></returns>
89+ public static int DecompressPVRTC < TOutputColor , TOutputChannelValue > ( ReadOnlySpan < byte > input , int xDim , int yDim , bool do2bitMode , Span < TOutputColor > output )
90+ where TOutputChannelValue : unmanaged
91+ where TOutputColor : unmanaged, IColor < TOutputChannelValue >
3592 {
3693 ThrowHelper . ThrowIfNotLittleEndian ( ) ;
3794 int xBlockSize = do2bitMode ? BlockX2bpp : BlockX4bpp ;
@@ -109,12 +166,12 @@ public static int DecompressPVRTC(ReadOnlySpan<byte> input, int xDim, int yDim,
109166 InterpolateColours ( m_colors [ 0 ] , m_colors [ 1 ] , m_colors [ 2 ] , m_colors [ 3 ] , 1 , do2bitMode , x , y , bSig ) ;
110167 GetModulationValue ( x , y , do2bitMode , modulationVals , modulationModes , out int mod , out bool doPT ) ;
111168
112- // compute the modulated color. Swap red and blue channel
113- int position = ( x + y * xDim ) << 2 ;
114- output [ position + 0 ] = ( byte ) ( ( aSig [ 2 ] * 8 + mod * ( bSig [ 2 ] - aSig [ 2 ] ) ) >> 3 ) ;
115- output [ position + 1 ] = ( byte ) ( ( aSig [ 1 ] * 8 + mod * ( bSig [ 1 ] - aSig [ 1 ] ) ) >> 3 ) ;
116- output [ position + 2 ] = ( byte ) ( ( aSig [ 0 ] * 8 + mod * ( bSig [ 0 ] - aSig [ 0 ] ) ) >> 3 ) ;
117- output [ position + 3 ] = doPT ? ( byte ) 0 : ( byte ) ( ( aSig [ 3 ] * 8 + mod * ( bSig [ 3 ] - aSig [ 3 ] ) ) >> 3 ) ;
169+ // compute the modulated color.
170+ byte red = ( byte ) ( ( aSig [ 0 ] * 8 + mod * ( bSig [ 0 ] - aSig [ 0 ] ) ) >> 3 ) ;
171+ byte green = ( byte ) ( ( aSig [ 1 ] * 8 + mod * ( bSig [ 1 ] - aSig [ 1 ] ) ) >> 3 ) ;
172+ byte blue = ( byte ) ( ( aSig [ 2 ] * 8 + mod * ( bSig [ 2 ] - aSig [ 2 ] ) ) >> 3 ) ;
173+ byte alpha = doPT ? ( byte ) 0 : ( byte ) ( ( aSig [ 3 ] * 8 + mod * ( bSig [ 3 ] - aSig [ 3 ] ) ) >> 3 ) ;
174+ output [ x + y * xDim ] . SetConvertedChannels < TOutputColor , TOutputChannelValue , byte > ( red , green , blue , alpha ) ;
118175 }
119176 }
120177
@@ -133,24 +190,10 @@ public static int DecompressPVRTC(ReadOnlySpan<byte> input, int xDim, int yDim,
133190 /// <returns>The twiddled offset of the pixel</returns>
134191 private static uint TwiddleUV ( uint ySize , uint xSize , uint yPos , uint xPos )
135192 {
136- #if DEBUG
137- if ( yPos >= ySize )
138- {
139- throw new Exception ( ) ;
140- }
141- if ( xPos >= xSize )
142- {
143- throw new Exception ( ) ;
144- }
145- if ( ! BitOperations . IsPow2 ( ySize ) )
146- {
147- throw new Exception ( ) ;
148- }
149- if ( ! BitOperations . IsPow2 ( xSize ) )
150- {
151- throw new Exception ( ) ;
152- }
153- #endif
193+ Debug . Assert ( yPos < ySize ) ;
194+ Debug . Assert ( xPos < xSize ) ;
195+ Debug . Assert ( BitOperations . IsPow2 ( ySize ) ) ;
196+ Debug . Assert ( BitOperations . IsPow2 ( xSize ) ) ;
154197
155198 uint minDimension ;
156199 uint maxValue ;
@@ -291,16 +334,11 @@ private static void InterpolateColours(ReadOnlySpan<int> colorP, ReadOnlySpan<in
291334 }
292335 }
293336
294- #if DEBUG
295337 // sanity check
296- for ( int i = 0 ; i < 4 ; i ++ )
297- {
298- if ( result [ i ] >= 256 )
299- {
300- throw new Exception ( "Sanity failed" ) ;
301- }
302- }
303- #endif
338+ Debug . Assert ( result [ 0 ] < 256 ) ;
339+ Debug . Assert ( result [ 1 ] < 256 ) ;
340+ Debug . Assert ( result [ 2 ] < 256 ) ;
341+ Debug . Assert ( result [ 3 ] < 256 ) ;
304342
305343 // convert from 5554 to 8888, do RGB 5.3 => 8
306344 for ( int i = 0 ; i < 3 ; i ++ )
@@ -309,16 +347,11 @@ private static void InterpolateColours(ReadOnlySpan<int> colorP, ReadOnlySpan<in
309347 }
310348 result [ 3 ] += result [ 3 ] >> 4 ;
311349
312- #if DEBUG
313350 // 2nd sanity check
314- for ( int i = 0 ; i < 4 ; i ++ )
315- {
316- if ( result [ i ] >= 256 )
317- {
318- throw new Exception ( "2nd sanity failed" ) ;
319- }
320- }
321- #endif
351+ Debug . Assert ( result [ 0 ] < 256 ) ;
352+ Debug . Assert ( result [ 1 ] < 256 ) ;
353+ Debug . Assert ( result [ 2 ] < 256 ) ;
354+ Debug . Assert ( result [ 3 ] < 256 ) ;
322355 }
323356
324357 /// <summary>
0 commit comments