4 Commits
Author SHA1 Message Date
ds5678 ee81b0cff8 Bump version to 1.0.3
Updated the `<VersionPrefix>` property in `Directory.Build.props`
from `1.0.2` to `1.0.3` to reflect a new release or update.
2025-09-21 21:29:29 -07:00
ds5678 293571cd58 Improve handling of mip levels 2025-09-21 21:29:10 -07:00
ds5678 c6a5667654 Bump version to 1.0.2
Updated the `<VersionPrefix>` property in the `Directory.Build.props` file from `1.0.1` to `1.0.2`. This version increment likely signifies a new release or update, potentially including new features, bug fixes, or other improvements.
2025-09-21 20:40:02 -07:00
ds5678 e8309e17ce Improve handling of multiple faces 2025-09-21 20:39:36 -07:00
3 changed files with 74 additions and 17 deletions

No files matched your search

+1
View File
@@ -4,3 +4,4 @@ bin/
obj/
source.ll
launchSettings.json
*.user
@@ -1,17 +1,23 @@
using AssetRipper.Conversions.UnityCrunch.Structures;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace AssetRipper.Conversions.UnityCrunch;
public static partial class UnityCrunch
{
public static bool TryDecompress(ReadOnlySpan<byte> input, [NotNullWhen(true)] out byte[]? output)
{
return TryDecompress(input, 0, out output);
}
/// <summary>
/// <see href="https://github.com/Unity-Technologies/crunch/blob/8708900eca8ec609d279270e72936258f81ddfb7/inc/crnlib.h#L92"/>
/// </summary>
public const int MaxFaces = 6;
public static unsafe bool TryDecompress(ReadOnlySpan<byte> input, int levelIndex, [NotNullWhen(true)] out byte[]? output)
/// <summary>
/// <see href="https://github.com/Unity-Technologies/crunch/blob/8708900eca8ec609d279270e72936258f81ddfb7/inc/crnlib.h#L93"/>
/// </summary>
public const int MaxLevels = 16;
public static unsafe bool TryDecompress(ReadOnlySpan<byte> input, [NotNullWhen(true)] out byte[]? output)
{
if (input.Length == 0)
{
@@ -35,19 +41,55 @@ public static partial class UnityCrunch
return False(out output);
}
int width = int.Max(1, textureInfo.field_1 >> levelIndex);
int height = int.Max(1, textureInfo.field_2 >> levelIndex);
int blocksX = int.Max(1, (width + 3) >> 2);
int blocksY = int.Max(1, (height + 3) >> 2);
int rowPitch = blocksX * crnd_get_bytes_per_dxt_block(textureInfo.field_8);
int totalFaceSize = rowPitch * blocksY;
byte[] result = new byte[totalFaceSize];
// m_struct_size
int fullWidth = textureInfo.field_1;
int fullHeight = textureInfo.field_2;
int levelCount = textureInfo.field_3;
int faceCount = textureInfo.field_4;
int bytesPerDxtBlock = textureInfo.field_5;
// m_userdata0
// m_userdata1
// m_format
Debug.Assert(bytesPerDxtBlock == crnd_get_bytes_per_dxt_block(textureInfo.field_8));
if (levelCount < 1 || levelCount > MaxLevels || faceCount < 1 || faceCount > MaxFaces)
{
crnd_unpack_end(context);
return False(out output);
}
int completeImageSize = CalculateCompleteImageSize(fullWidth, fullHeight, bytesPerDxtBlock, levelCount);
byte[] result = new byte[completeImageSize * faceCount];
byte** pResultArray = stackalloc byte*[MaxFaces];
fixed (byte* pResult = result)
{
if (!crnd_unpack_level(context, &pResult, totalFaceSize, rowPitch, levelIndex))
int offset = 0;
for (int levelIndex = 0; levelIndex < levelCount; levelIndex++)
{
crnd_unpack_end(context);
return False(out output);
int width = int.Max(1, fullWidth >> levelIndex);
int height = int.Max(1, fullHeight >> levelIndex);
int blocksX = (width + 3) >> 2;
int blocksY = (height + 3) >> 2;
int rowPitch = blocksX * bytesPerDxtBlock;
int faceSize = rowPitch * blocksY;
new Span<nint>(pResultArray, MaxFaces).Clear();
for (int i = 0; i < faceCount; i++)
{
pResultArray[i] = pResult + offset + i * completeImageSize;
}
if (!crnd_unpack_level(context, pResultArray, faceSize, rowPitch, levelIndex))
{
crnd_unpack_end(context);
return False(out output);
}
offset += faceSize;
}
}
crnd_unpack_end(context);
@@ -56,10 +98,24 @@ public static partial class UnityCrunch
return true;
static unsafe bool False([NotNullWhen(true)] out byte[]? output)
static bool False([NotNullWhen(true)] out byte[]? output)
{
output = null;
return false;
}
static int CalculateCompleteImageSize(int width, int height, int bytesPerDxtBlock, int levelCount)
{
int totalSize = 0;
for (int levelIndex = 0; levelIndex < levelCount; levelIndex++)
{
int levelWidth = int.Max(1, width >> levelIndex);
int levelHeight = int.Max(1, height >> levelIndex);
int blocksX = (levelWidth + 3) >> 2;
int blocksY = (levelHeight + 3) >> 2;
totalSize += blocksX * blocksY * bytesPerDxtBlock;
}
return totalSize;
}
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<VersionPrefix>1.0.1</VersionPrefix>
<VersionPrefix>1.0.3</VersionPrefix>
<Copyright>Copyright (c) 2025 ds5678</Copyright>
<Authors>ds5678</Authors>
<Company>AssetRipper</Company>