Compare commits

...
5 Commits
Author SHA1 Message Date
ds5678 801edea4cf Bump version prefix to 2.6.1
Updated Directory.Build.props to increment the VersionPrefix from 2.6.0 to 2.6.1. This prepares the project for the next release.
2026-02-26 18:14:11 -08:00
ds5678 3cb859c6ac Update NuGet package versions across project files
Updated several NuGet dependencies to their latest versions:
- AssetRipper.Text.SourceGeneration to 1.2.3
- Microsoft.SourceLink.GitHub to 10.0.103
- Microsoft.NET.Test.Sdk to 18.3.0
- NUnit to 4.5.0
- coverlet.collector to 8.0.0
These updates provide bug fixes, new features, and improved compatibility.
2026-02-26 17:55:38 -08:00
ds5678 0738ba4b50 Multi-target .NET 8 and 10
I currently don't use any API above .NET 8, so multi-targeting 8 and 10 is fine for now. However, if I later need a higher .NET version, I won't hesitate to drop support.
2026-02-26 17:49:35 -08:00
ds5678 09067cecbb Replace Unsafe.As with Unsafe.BitCast where appropriate 2026-02-26 17:39:51 -08:00
ds5678 ec6754a5d2 Replace tuple with record struct in color generation 2026-02-26 17:28:31 -08:00
11 changed files with 268 additions and 263 deletions

No files matched your search

@@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AssetRipper.Text.SourceGeneration" Version="1.2.2" />
<PackageReference Include="AssetRipper.Text.SourceGeneration" Version="1.2.3" />
</ItemGroup>
<ItemGroup>
@@ -82,14 +82,14 @@ internal static class NumericConversionGenerator
writer.WriteLine("if (typeof(TFrom) == typeof(TTo))");
using (new CurlyBrackets(writer))
{
writer.WriteLine("return Unsafe.As<TFrom, TTo>(ref value);");
writer.WriteLine("return Unsafe.BitCast<TFrom, TTo>(value);");
}
foreach (CSharpPrimitives.Data from in CSharpPrimitives.List)
{
writer.WriteLine($"else if (typeof(TFrom) == typeof({from.LangName}))");
using (new CurlyBrackets(writer))
{
writer.WriteLine($"return {ConvertMethodName(from.Type)}<TTo>(Unsafe.As<TFrom, {from.LangName}>(ref value));");
writer.WriteLine($"return {ConvertMethodName(from.Type)}<TTo>(Unsafe.BitCast<TFrom, {from.LangName}>(value));");
}
}
writer.WriteLine("else");
@@ -133,32 +133,32 @@ internal static class NumericConversionGenerator
{
if (from == to)
{
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref value);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(value);");
}
else if (to.HasPointerSize(out CSharpPrimitives.Data? bit32To, out CSharpPrimitives.Data? bit64To))
{
using (new If(writer, "IntPtr.Size == sizeof(int)"))
{
writer.WriteLine($"{to.LangName} converted = ({to.LangName}){methodName}<{bit32To.LangName}>(value);");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
using (new Else(writer))
{
writer.WriteLine($"{to.LangName} converted = ({to.LangName}){methodName}<{bit64To.LangName}>(value);");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
}
else if (to.IsSignedInteger(out CSharpPrimitives.Data? unsignedTo))
{
writer.WriteLine($"{to.LangName} converted = {ChangeSign}({methodName}<{unsignedTo.LangName}>(value));");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
else if (from.IsFloatingPoint)
{
if (to.IsFloatingPoint)
{
writer.WriteLine($"{to.LangName} converted = ({to.LangName})value;");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
else
{
@@ -176,7 +176,7 @@ internal static class NumericConversionGenerator
string maxValue = to.MaxValue;
writer.WriteLine($"{from.LangName} x = value * ({from.LangName}){maxValue};");
writer.WriteLine($"{to.LangName} converted = ({from.LangName}){maxValue} < x ? {maxValue} : (x > ({from.LangName}){minValue} ? ({to.LangName})x : {minValue});");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
}
}
@@ -191,12 +191,12 @@ internal static class NumericConversionGenerator
writer.WriteComment($"There isn't enough precision to convert from {from.LangName} to {to.LangName}, so we convert to {conversionType.LangName} first.");
writer.WriteLine($"{conversionType.LangName} x = {methodName}<{conversionType.LangName}>(value);");
writer.WriteLine($"{to.LangName} converted = ({to.LangName})x;");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
else
{
writer.WriteLine($"{to.LangName} converted = ({to.LangName})value / ({to.LangName}){from.MaxValue};");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
}
else
@@ -216,7 +216,7 @@ internal static class NumericConversionGenerator
writer.Write($"(({conversionType})value << {i * from.Size * 8}) | ");
}
writer.WriteLine("value);");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
}
else
@@ -227,14 +227,14 @@ internal static class NumericConversionGenerator
writer.WriteComment("This is a special case where we already know an optimal algorithm.");
writer.WriteLine("uint x = (value * 255u + 32895u) >> 16;");
writer.WriteLine("byte converted = unchecked((byte)x);");
writer.WriteLine("return Unsafe.As<byte, TTo>(ref converted);");
writer.WriteLine("return Unsafe.BitCast<byte, TTo>(converted);");
}
else if (from.Size < sizeof(double) && to.Size < sizeof(double))
{
writer.WriteLine($"double interpolated = (double)value / (double){from.MaxValue};");
writer.WriteLine($"double exact = interpolated * (double){to.MaxValue};");
writer.WriteLine($"{to.LangName} converted = ({to.LangName})double.Round(exact, MidpointRounding.AwayFromZero);");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
else
{
@@ -245,7 +245,7 @@ internal static class NumericConversionGenerator
{
int offset = (from.Size / to.Size - 1) * to.Size * 8;
writer.WriteLine($"{to.LangName} converted = ({to.LangName})(({conversionType})value >> {offset});");
writer.WriteLine($"return Unsafe.As<{to.LangName}, TTo>(ref converted);");
writer.WriteLine($"return Unsafe.BitCast<{to.LangName}, TTo>(converted);");
}
}
}
@@ -276,7 +276,7 @@ internal static class NumericConversionGenerator
using (new CurlyBrackets(writer))
{
writer.WriteLine($"{from.LangName} value = {methodName}Safe<{from.LangName}>();");
writer.WriteLine($"return Unsafe.As<{from.LangName}, T>(ref value);");
writer.WriteLine($"return Unsafe.BitCast<{from.LangName}, T>(value);");
}
}
writer.WriteLine("else");
@@ -13,18 +13,23 @@ internal static partial class Program
private const string FormatsNamespace = "AssetRipper.TextureDecoder.Rgb.Formats";
private const string FormatsFolder = "../../../../AssetRipper.TextureDecoder/Rgb/Formats/";
/// <summary>
/// Name, Type, Red, Blue, Green, Alpha, Fully Utilized
/// </summary>
private static readonly List<(string, Type, bool, bool, bool, bool, bool)> CustomColors = new()
private readonly record struct CustomColorDetails(string Name, Type Type, bool HasRed, bool HasGreen, bool HasBlue, bool HasAlpha, bool FullyUtilized)
{
public static implicit operator CustomColorDetails((string, Type, bool, bool, bool, bool, bool) details)
{
return new CustomColorDetails(details.Item1, details.Item2, details.Item3, details.Item4, details.Item5, details.Item6, details.Item7);
}
}
private static readonly CustomColorDetails[] CustomColors =
[
( "ColorARGB16", typeof(byte), true, true, true, true, false ),
( "ColorRGB16", typeof(byte), true, true, true, false, false ),
( "ColorRGB9e5", typeof(double), true, true, true, false, false ),
( "ColorRGBA16", typeof(byte), true, true, true, true, false ),
};
];
private static readonly List<string> GenericColors =
private static readonly string[] GenericColors =
[
"ColorR",
"ColorRG",
@@ -38,7 +43,7 @@ internal static partial class Program
static void Main()
{
foreach (var customColor in CustomColors)
foreach (CustomColorDetails customColor in CustomColors)
{
WriteCustomColor(customColor);
}
@@ -54,7 +59,7 @@ internal static partial class Program
Console.WriteLine("Done!");
}
private static void WriteCustomColor((string, Type, bool, bool, bool, bool, bool) details)
private static void WriteCustomColor(CustomColorDetails details)
{
(string name, Type type, bool hasRed, bool hasGreen, bool hasBlue, bool hasAlpha, bool fullyUtilized) = details;
Console.WriteLine(name);
@@ -11,7 +11,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AssetRipper.Text.SourceGeneration" Version="1.2.2" />
<PackageReference Include="AssetRipper.Text.SourceGeneration" Version="1.2.3" />
</ItemGroup>
</Project>
@@ -5,14 +5,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="NUnit" Version="4.5.0" />
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.11.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PackageReference Include="coverlet.collector" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsTrimmable>true</IsTrimmable>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<PackageId>AssetRipper.TextureDecoder</PackageId>
<PackageTags>C# Texture</PackageTags>
<RepositoryUrl>https://github.com/AssetRipper/TextureDecoder</RepositoryUrl>
@@ -20,7 +20,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.102">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.103">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -76,16 +76,16 @@ internal static class BinaryWriterExtensions
switch (Unsafe.SizeOf<T>())
{
case sizeof(byte):
writer.Write(Unsafe.As<T, byte>(ref value));
writer.Write(Unsafe.BitCast<T, byte>(value));
break;
case sizeof(ushort):
writer.Write(Unsafe.As<T, ushort>(ref value));
writer.Write(Unsafe.BitCast<T, ushort>(value));
break;
case sizeof(uint):
writer.Write(Unsafe.As<T, uint>(ref value));
writer.Write(Unsafe.BitCast<T, uint>(value));
break;
case sizeof(ulong):
writer.Write(Unsafe.As<T, ulong>(ref value));
writer.Write(Unsafe.BitCast<T, ulong>(value));
break;
}
}
+1 -1
View File
@@ -82,7 +82,7 @@ public static class Color
{
if (typeof(TThis) == typeof(TTarget))
{
return Unsafe.As<TThis, TTarget>(ref color);
return Unsafe.BitCast<TThis, TTarget>(color);
}
else
{
@@ -42,7 +42,7 @@ public static partial class NumericConversion
TFrom SignBit = TFrom.One << (Unsafe.SizeOf<TFrom>() * 8 - 1);
TFrom converted = (SignBit ^ value);
return Unsafe.As<TFrom, TTo>(ref converted);
return Unsafe.BitCast<TFrom, TTo>(converted);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
@@ -56,6 +56,6 @@ public static partial class NumericConversion
}
TTo SignBit = TTo.One << (Unsafe.SizeOf<TTo>() * 8 - 1);
return SignBit ^ Unsafe.As<TFrom, TTo>(ref value);
return SignBit ^ Unsafe.BitCast<TFrom, TTo>(value);
}
}
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -6,7 +6,7 @@
<IsAotCompatible>true</IsAotCompatible>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<VersionPrefix>2.6.0</VersionPrefix>
<VersionPrefix>2.6.1</VersionPrefix>
<Copyright>Copyright © ds5678</Copyright>
<Authors>ds5678</Authors>
<Company>AssetRipper</Company>