Compare commits

...
134 Commits
Author SHA1 Message Date
Jeremy Pritts 958b831205 Bump version and add source link 2023-07-01 14:22:50 -04:00
Jeremy Pritts 2085dbcce4 Add methods to DirectBitmap 2023-07-01 14:16:50 -04:00
Jeremy Pritts d6ad4d5a6f More ETC memory safety 2023-07-01 14:01:24 -04:00
Jeremy Pritts 1a5ca1405e Validate ASTC block dimensions 2023-07-01 13:56:53 -04:00
Jeremy Pritts d5da591f92 Use PolySharp instead of Nullable and IsExternalInit 2023-07-01 12:27:04 -04:00
Jeremy Pritts dd129401c7 Use ArrayPool when decompressing Bc4 and Bc5 2023-06-30 00:51:57 -04:00
Jeremy Pritts 6855b6b287 Decompress Bc6h as Half instead of float:
* Half is the "natural" decompression result
* Avoids converting pixels twice
2023-06-30 00:34:28 -04:00
Jeremy Pritts 0274cb1a05 Use BinaryPrimitives instead of MemoryMarshal 2023-06-29 23:55:58 -04:00
Jeremy Pritts e3e7779739 Small optimizations:
* Make mode a readonly variable
* Cache ActualBitsCount
* Unquantize in a separate pass
2023-06-29 23:36:34 -04:00
Jeremy Pritts 40326e20bc Move CompressedSize methods and BlockSize constants 2023-06-29 22:57:18 -04:00
Jeremy Pritts fa94774143 Separate BcDecoder into 7 classes 2023-06-29 22:45:23 -04:00
Jeremy Pritts 58b113e1e0 Remove some unnecessary variable assignments 2023-06-29 22:28:59 -04:00
Jeremy Pritts 862995196f Use stackalloc in Bc6h 2023-06-29 22:21:45 -04:00
Jeremy Pritts 691796b919 Small refactor:
* Use properties instead of fields
* Add lengths to BC array initializers
2023-06-29 22:08:20 -04:00
dependabot[bot] a6f54dd9b1 Bump Microsoft.NET.Test.Sdk from 17.6.2 to 17.6.3
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.6.2 to 17.6.3.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.6.2...v17.6.3)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-06-28 07:47:26 -04:00
Jeremy Pritts fe93d46a6c Resolve #19 2023-06-22 11:41:18 -04:00
Jeremy Pritts 7c6ac4ba0e Support double precision channels 2023-06-22 10:45:36 -04:00
Jeremy Pritts 977800b5bb Update csproj file 2023-06-21 09:59:10 -04:00
dependabot[bot] f9c8dd980f Bump Microsoft.NET.Test.Sdk from 17.6.1 to 17.6.2
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.6.1 to 17.6.2.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.6.1...v17.6.2)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-06-06 22:06:06 -04:00
dependabot[bot] aea23c3be6 Bump Microsoft.NET.Test.Sdk from 17.5.0 to 17.6.1
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.5.0 to 17.6.1.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.5.0...v17.6.1)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-06-01 22:31:56 -04:00
dependabot[bot] 6b65475bc1 Bump coverlet.collector from 3.2.0 to 6.0.0
Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 3.2.0 to 6.0.0.
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/compare/v3.2.0...v6.0.0)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-05-31 06:06:49 -04:00
dependabot[bot] 4835e38ec6 Bump NUnit3TestAdapter from 4.4.2 to 4.5.0
Bumps [NUnit3TestAdapter](https://github.com/nunit/nunit3-vs-adapter) from 4.4.2 to 4.5.0.
- [Release notes](https://github.com/nunit/nunit3-vs-adapter/releases)
- [Commits](https://github.com/nunit/nunit3-vs-adapter/compare/V4.4.2...V4.5.0)

---
updated-dependencies:
- dependency-name: NUnit3TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-05-31 06:04:34 -04:00
dependabot[bot] 874bef99eb Bump actions/setup-dotnet from 3.1.0 to 3.2.0
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v3.1.0...v3.2.0)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-05-29 22:10:00 -04:00
dependabot[bot] 6908984ff2 Bump actions/setup-dotnet from 3.0.3 to 3.1.0
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3.0.3 to 3.1.0.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v3.0.3...v3.1.0)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-05-25 23:14:49 -04:00
Jeremy Pritts f012b3a4d9 Add program for integer conversion
* Related to #19
2023-03-15 15:54:11 -04:00
dependabot[bot] 541176ad79 Bump NUnit.Analyzers from 3.6.0 to 3.6.1
Bumps [NUnit.Analyzers](https://github.com/nunit/nunit.analyzers) from 3.6.0 to 3.6.1.
- [Release notes](https://github.com/nunit/nunit.analyzers/releases)
- [Changelog](https://github.com/nunit/nunit.analyzers/blob/master/CHANGES.txt)
- [Commits](https://github.com/nunit/nunit.analyzers/compare/3.6.0...3.6.1)

---
updated-dependencies:
- dependency-name: NUnit.Analyzers
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-03-15 12:56:53 -04:00
dependabot[bot] a44a788060 Bump NUnit3TestAdapter from 4.3.1 to 4.4.2
Bumps [NUnit3TestAdapter](https://github.com/nunit/nunit3-vs-adapter) from 4.3.1 to 4.4.2.
- [Release notes](https://github.com/nunit/nunit3-vs-adapter/releases)
- [Commits](https://github.com/nunit/nunit3-vs-adapter/compare/V4.3.1...V4.4.2)

---
updated-dependencies:
- dependency-name: NUnit3TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-03-01 22:19:35 -05:00
dependabot[bot] 5c937aca17 Bump Microsoft.NET.Test.Sdk from 17.4.1 to 17.5.0
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.4.1 to 17.5.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.4.1...v17.5.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-02-22 13:59:17 -05:00
dependabot[bot] 04b086c372 Bump NUnit.Analyzers from 3.5.0 to 3.6.0
Bumps [NUnit.Analyzers](https://github.com/nunit/nunit.analyzers) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/nunit/nunit.analyzers/releases)
- [Changelog](https://github.com/nunit/nunit.analyzers/blob/master/CHANGES.txt)
- [Commits](https://github.com/nunit/nunit.analyzers/compare/3.5.0...3.6.0)

---
updated-dependencies:
- dependency-name: NUnit.Analyzers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-02-22 13:59:07 -05:00
dependabot[bot] 99b5d670f3 Bump BenchmarkDotNet from 0.13.4 to 0.13.5
Bumps [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) from 0.13.4 to 0.13.5.
- [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases)
- [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.4...v0.13.5)

---
updated-dependencies:
- dependency-name: BenchmarkDotNet
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-02-20 22:58:37 -05:00
dependabot[bot] 53beeff97e Bump BenchmarkDotNet from 0.13.3 to 0.13.4
Bumps [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) from 0.13.3 to 0.13.4.
- [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases)
- [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.3...v0.13.4)

---
updated-dependencies:
- dependency-name: BenchmarkDotNet
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-15 22:16:24 -05:00
dependabot[bot] c566ecc668 Bump BenchmarkDotNet from 0.13.2 to 0.13.3
Bumps [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) from 0.13.2 to 0.13.3.
- [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases)
- [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.2...v0.13.3)

---
updated-dependencies:
- dependency-name: BenchmarkDotNet
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-27 13:41:44 -05:00
dependabot[bot] 3d3746e2d7 Bump Microsoft.NET.Test.Sdk from 17.4.0 to 17.4.1
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.4.0 to 17.4.1.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.4.0...v17.4.1)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-12-27 13:41:36 -05:00
ds5678 cd37722a53 Delete .gitattributes 2022-11-23 23:14:11 -05:00
Jeremy Pritts 7cea861443 Refactor source generation to include the RGB console method 2022-11-23 19:06:54 -05:00
Jeremy Pritts fb48fa3b94 Add back support for earlier .NET versions, which was previously removed in 92d1909562 2022-11-23 16:18:31 -05:00
dependabot[bot] a6bc637d47 Bump NUnit3TestAdapter from 4.3.0 to 4.3.1
Bumps [NUnit3TestAdapter](https://github.com/nunit/nunit3-vs-adapter) from 4.3.0 to 4.3.1.
- [Release notes](https://github.com/nunit/nunit3-vs-adapter/releases)
- [Commits](https://github.com/nunit/nunit3-vs-adapter/compare/V4.3.0...V4.3.1)

---
updated-dependencies:
- dependency-name: NUnit3TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-11-20 21:39:16 -05:00
Jeremy Pritts ba40e2c7d7 Use .NET 7 in the GitHub workflow 2022-11-17 20:09:56 -05:00
Jeremy Pritts e2fba56e81 More optimized code generation:
* Use Half.One instead of (Half)1
* No generic instantiation for GetChannels or SetChannels
* In SetChannels, only set properties that are actually used
2022-11-17 19:47:13 -05:00
Jeremy Pritts 92d1909562 Bump to .NET 7 2022-11-17 19:27:19 -05:00
dependabot[bot] bb346aabbc Bump Microsoft.NET.Test.Sdk from 17.3.2 to 17.4.0
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.3.2 to 17.4.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.3.2...v17.4.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-11-11 10:41:19 -05:00
Jeremy Pritts 18abd1731b Standardize naming for floating point rgb formats 2022-11-07 09:58:53 -05:00
Naomi b4ad9bcb39 Add R11G11B10FloatToBGRA32 (#17)
* Add R11G11B10FloatToBGRA32 and ColorRGB32Half

* Requested changes.

* spaces to tabs

* Assert.Multiple
2022-11-06 23:26:54 -05:00
Jeremy Pritts e4c873b3b0 Use unsigned bitwise logic in UInt4Pair 2022-11-05 12:30:59 -04:00
Jeremy Pritts 9c89b6fac5 Add a UInt4Pair struct to clean up code in ARGB16 and RGBA16 2022-11-05 12:26:53 -04:00
Jeremy Pritts ce581c0ea6 Lossless conversion tests 2022-11-05 12:00:14 -04:00
Jeremy Pritts b992959c24 Find ChannelType implicitly in GenerationData 2022-11-05 11:58:10 -04:00
Jeremy Pritts 07c653873b Add an RgbaAttribute to all RGB formats 2022-11-05 00:03:58 -04:00
Jeremy Pritts 03373afddb Clean up the color source generator 2022-11-04 23:41:15 -04:00
Jeremy Pritts 35ed50dc26 Signed RGB color support with new source generation for standard RGB formats 2022-11-04 21:06:28 -04:00
Jeremy Pritts a5cfc5cbf7 IColor.Convert extension method 2022-11-04 16:22:42 -04:00
Jeremy Pritts dc1ecc5d46 Add support for sbyte and short in IColor<T> 2022-11-04 16:02:42 -04:00
Jeremy Pritts 89b76dafd3 Throw invalid cast for invalid number conversion when compiling on Debug mode 2022-11-04 15:09:41 -04:00
dependabot[bot] 56ba562fd5 Bump coverlet.collector from 3.1.2 to 3.2.0
Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 3.1.2 to 3.2.0.
- [Release notes](https://github.com/coverlet-coverage/coverlet/releases)
- [Commits](https://github.com/coverlet-coverage/coverlet/commits/v3.2.0)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-10-30 22:23:03 -04:00
dependabot[bot] 1b2208b38a Bump NUnit3TestAdapter from 4.2.1 to 4.3.0
Bumps [NUnit3TestAdapter](https://github.com/nunit/nunit3-vs-adapter) from 4.2.1 to 4.3.0.
- [Release notes](https://github.com/nunit/nunit3-vs-adapter/releases)
- [Commits](https://github.com/nunit/nunit3-vs-adapter/compare/V4.2.1...V4.3.0)

---
updated-dependencies:
- dependency-name: NUnit3TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-10-30 22:22:37 -04:00
dependabot[bot] 28e3a22265 Bump actions/setup-dotnet from 3.0.2 to 3.0.3
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v3.0.2...v3.0.3)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-10-27 21:28:15 -04:00
Jeremy Pritts 5705e12af0 Atc input span 2022-10-24 00:23:46 -04:00
dependabot[bot] 3e7eae579e Bump NUnit.Analyzers from 3.3.0 to 3.5.0
Bumps [NUnit.Analyzers](https://github.com/nunit/nunit.analyzers) from 3.3.0 to 3.5.0.
- [Release notes](https://github.com/nunit/nunit.analyzers/releases)
- [Changelog](https://github.com/nunit/nunit.analyzers/blob/master/CHANGES.txt)
- [Commits](https://github.com/nunit/nunit.analyzers/compare/3.3.0...3.5.0)

---
updated-dependencies:
- dependency-name: NUnit.Analyzers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-10-24 00:05:05 -04:00
Jeremy Pritts 7fb7530a37 Formatting 2022-10-24 00:03:49 -04:00
Jeremy Pritts b1dfd0b6d8 Inline variable declarations in BcHelpers 2022-10-23 23:51:03 -04:00
Jeremy Pritts 9259884731 Remove hacky C++ half to float conversion 2022-10-23 23:25:44 -04:00
Jeremy Pritts 4e1251649b Bc6h output span 2022-10-23 23:21:36 -04:00
Jeremy Pritts 26fcfb695e Bc6h input span 2022-10-23 22:58:26 -04:00
Jeremy Pritts 1c156c4cd3 Output span for Bc7 2022-10-23 22:45:18 -04:00
Jeremy Pritts c019bc5a04 Input span for Bc7 2022-10-23 22:38:03 -04:00
Jeremy Pritts 099daf3044 Make BcHelpers.SwapValues use ref instead of pointers 2022-10-23 22:30:23 -04:00
Jeremy Pritts 5de28c63c3 Use bool instead of int for isSigned in BC6H 2022-10-18 01:13:11 -04:00
dependabot[bot] f4d37ff16c Bump actions/setup-dotnet from 3.0.1 to 3.0.2
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v3.0.1...v3.0.2)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-10-13 22:11:17 -04:00
Jeremy Pritts 61c3a861f7 Bump version 2022-10-13 00:43:56 -04:00
Jeremy Pritts 437db55ae8 update gitignore 2022-10-13 00:42:25 -04:00
dependabot[bot] 6ed0c07a83 Bump actions/setup-dotnet from 3.0.0 to 3.0.1
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-10-04 22:42:28 -04:00
dependabot[bot] 54e3e20d0c Bump actions/setup-dotnet from 2 to 3.0.0
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 2 to 3.0.0.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v2...v3.0.0)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-29 23:07:12 -04:00
dependabot[bot] 1281377f2e Bump Microsoft.NET.Test.Sdk from 17.3.1 to 17.3.2
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.3.1 to 17.3.2.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.3.1...v17.3.2)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-09-27 00:50:01 -04:00
dependabot[bot] 7693de3ef9 Bump Microsoft.NET.Test.Sdk from 17.3.0 to 17.3.1
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.3.0 to 17.3.1.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.3.0...v17.3.1)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-08-30 23:22:44 -04:00
dependabot[bot] 4040a0a7a7 Bump BenchmarkDotNet from 0.13.1 to 0.13.2
Bumps [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) from 0.13.1 to 0.13.2.
- [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases)
- [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.1...v0.13.2)

---
updated-dependencies:
- dependency-name: BenchmarkDotNet
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-08-29 10:59:25 -04:00
dependabot[bot] 07d932c1a1 Bump Microsoft.NET.Test.Sdk from 17.2.0 to 17.3.0
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.2.0 to 17.3.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.2.0...v17.3.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-08-11 21:57:32 -04:00
Jeremy Pritts be63ebdb23 Ported Bc code 2022-07-16 15:49:16 -04:00
Jeremy Pritts 8458eb5866 RGB Half and Single 2022-07-14 10:00:05 -04:00
Jeremy Pritts 19204e4dd2 Make DirectBitmap a generic class 2022-07-14 09:52:13 -04:00
Jeremy Pritts 8aa1840eb4 Make DirectBitmap a struct 2022-07-14 09:37:21 -04:00
Jeremy Pritts 45267fc7fd replace System.Drawing.Common with StbImageWriteSharp 2022-07-14 09:30:54 -04:00
Jeremy Pritts 3ad6884592 mark as trimmable 2022-07-14 09:27:41 -04:00
Jeremy Pritts 7c65daebaa rgb9e5 benchmark 2022-07-12 10:20:35 -04:00
Jeremy Pritts 068140150b aggressive optimization 2022-07-12 09:56:02 -04:00
Jeremy Pritts 5f2e7dc5c3 add a benchmarks project 2022-07-12 09:35:08 -04:00
Jeremy Pritts 84eeba1e36 Remove specialized console application projects 2022-07-12 09:11:41 -04:00
Jeremy Pritts 88c33f5dfa move test files 2022-07-12 09:09:03 -04:00
Jeremy Pritts 9555cbf25c add a unified console application 2022-07-12 08:56:45 -04:00
Jeremy Pritts cab5e7cfb8 rename test generator 2022-07-11 23:05:35 -04:00
Jeremy Pritts 2611088bd9 move texture decoder project 2022-07-11 23:02:04 -04:00
Jeremy Pritts 2256161eab generic support to yuy2 2022-07-11 22:05:40 -04:00
Jeremy Pritts d9cbcc48d8 color extensions 2022-07-11 21:43:44 -04:00
Jeremy Pritts 113b793a6e aggressive conversion optimization 2022-07-11 20:51:26 -04:00
Jeremy Pritts fac3ca64df Make RGB9e5 a double precision color type 2022-07-11 20:37:06 -04:00
Jeremy Pritts 1485a246f1 add support for double and identity conversions 2022-07-11 20:30:52 -04:00
Jeremy Pritts 81ecc464e5 new rgb conversion code 2022-07-10 09:43:35 -04:00
Jeremy Pritts d158e90448 fix RGBAFloat 2022-07-10 09:29:53 -04:00
Jeremy Pritts 7f3808b075 Support for converting RG32, RGB48, and RGBA64 2022-07-07 00:38:12 -04:00
Jeremy Pritts 23c8e2c64a astc decoder return bytes read 2022-07-06 20:48:22 -04:00
Jeremy Pritts ea1c9c34ce rgb tests 2022-07-06 20:30:34 -04:00
Jeremy Pritts d55e1e69a8 return number of bytes read for pvrtc decoder methods 2022-07-06 20:00:28 -04:00
Jeremy Pritts f6ea7a9269 add a decompression method to pvrtc decoder with an out byte[] parameter 2022-07-06 11:15:49 -04:00
Jeremy Pritts 07b0e7d407 replace all pointer use in pvrtc decoder with span 2022-07-06 11:12:47 -04:00
Jeremy Pritts 56a70a2895 add a Pvrtc test 2022-07-06 10:15:28 -04:00
Jeremy Pritts f967a521b0 Dxt tests 2022-07-06 08:59:00 -04:00
Jeremy Pritts 4f775c4eff use more span in etc decoder 2022-07-06 08:53:08 -04:00
dependabot[bot] 9a5da95897 Bump Microsoft.NET.Test.Sdk from 17.1.0 to 17.2.0
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.1.0 to 17.2.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v17.1.0...v17.2.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-07-05 22:06:42 -04:00
Jeremy Pritts 4e037d8ddc use span more in atc decoder 2022-07-05 21:52:16 -04:00
Jeremy Pritts 5d2f86b18f return bytes read for atc decoding methods 2022-07-05 21:25:26 -04:00
Jeremy Pritts d701ff24fc ETC changes:
* Use span in the decoder more
* Return bytes read for all public decoding methods
* Make the tests read all the mip maps
2022-07-05 20:58:06 -04:00
Jeremy Pritts 7be1d516f1 re-enable etc tests 2022-07-05 20:26:44 -04:00
Jeremy Pritts 578a0633d1 use partial classes for astc and pvrtc 2022-07-05 19:00:38 -04:00
Jeremy Pritts 94e4994027 make rgb converter return bytes read 2022-07-05 18:52:32 -04:00
Jeremy Pritts 74d081ca21 add 3 new overloads to DxtDecoder for consistency with other decoders 2022-07-05 18:37:15 -04:00
Jeremy Pritts 8e1792bfaf disable atc and etc tests 2022-07-05 18:32:46 -04:00
Jeremy Pritts 734f158f7f add a real test project 2022-07-05 16:48:28 -04:00
Jeremy Pritts 7aa9794941 etc and yuy2 console app printing fix 2022-07-05 16:47:32 -04:00
Jeremy Pritts 9675ef0943 return the number of bytes read for dxt and yuy2 2022-07-05 11:59:09 -04:00
Jeremy Pritts d4f7b94dea string interpolation 2022-07-05 11:22:42 -04:00
Jeremy Pritts 20d450ac1f use out parameters instead of return for outputted byte arrays 2022-07-05 10:30:38 -04:00
Jeremy Pritts 2711b749db Resolve #4 2022-06-27 09:26:44 -04:00
Jeremy Pritts 6465aa35c3 formatting 2022-06-22 22:38:10 -04:00
Jeremy Pritts 80d8c58d3a remove empty documentation 2022-06-22 22:31:04 -04:00
Jeremy Pritts f8bee850bd use span for rgb 2022-06-22 22:24:08 -04:00
dependabot[bot] eeb8866c41 Bump actions/setup-dotnet from 1 to 2
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 1 to 2.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v1...v2)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-03-02 21:06:36 -05:00
dependabot[bot] 129576d48e Bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2022-03-02 21:06:25 -05:00
ds5678 f28d991abe Create dependabot.yml 2022-03-02 21:00:00 -05:00
Jeremy Pritts b1056490ec change utinyripper license file extension 2022-02-15 18:24:26 -05:00
Jeremy Pritts cab5cabc4e update package info, add net 5 target, and bump version 2022-02-11 20:44:02 -05:00
Jeremy Pritts b0038a5184 bump version 2022-02-05 23:50:03 -05:00
Jeremy Pritts 6665fab8d9 fix overflow in RGBAHalfToBGRA32 2022-02-05 23:48:53 -05:00
Jeremy Pritts 6998127fe8 bump version 2022-02-05 04:17:33 -05:00
Jeremy Pritts 8f68931c40 xml stub documentation 2022-02-05 04:04:38 -05:00
Jeremy Pritts eb9536456e clamp bytes during rgb conversion 2022-02-05 03:51:25 -05:00
220 changed files with 16835 additions and 2375 deletions

No files matched your search

-63
View File
@@ -1,63 +0,0 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
+18
View File
@@ -0,0 +1,18 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "nuget" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
# Workflow files stored in the
# default location of `.github/workflows`
directory: "/"
schedule:
interval: "daily"
+3 -3
View File
@@ -12,11 +12,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: 6.0.x
dotnet-version: 7.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
+4 -1
View File
@@ -3,4 +3,7 @@ obj
*.csproj.user
.vs
.idea
.vscode
.vscode
launchSettings.json
test.png
textureformats/
@@ -0,0 +1,25 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using BenchmarkDotNet.Attributes;
namespace AssetRipper.TextureDecoder.Benchmarks;
public class Argb32Decoding
{
private const int Width = 256;//ignoring smaller mips
private const int Height = 256;//ignoring smaller mips
private readonly byte[] inputData;
private readonly byte[] outputData;
public Argb32Decoding()
{
inputData = File.ReadAllBytes(PathConstants.PathToTestFiles + "Rgb/" + "test.argb32");
outputData = new byte[Width * Height * sizeof(uint)];
}
[Benchmark]
public int OriginalMethod() => RgbConverter.ARGB32ToBGRA32(inputData, Width, Height, outputData);
[Benchmark]
public int GenericMethod() => RgbConverter.Convert<ColorARGB32, byte, ColorBGRA32, byte>(inputData, Width, Height, outputData);
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetRipper.TextureDecoder\AssetRipper.TextureDecoder.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,7 @@
namespace AssetRipper.TextureDecoder.Benchmarks;
internal static class PathConstants
{
internal const string PathToRepositoryRoot = "../../../../../../../../";
internal const string PathToTestFiles = PathToRepositoryRoot + "TestFiles/";
}
@@ -0,0 +1,11 @@
using BenchmarkDotNet.Running;
namespace AssetRipper.TextureDecoder.Benchmarks;
internal class Program
{
static void Main()
{
BenchmarkRunner.Run(typeof(Program).Assembly);
}
}
@@ -0,0 +1,25 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using BenchmarkDotNet.Attributes;
namespace AssetRipper.TextureDecoder.Benchmarks;
public class Rgb9e5Decoding
{
private const int Width = 256;//ignoring smaller mips
private const int Height = 256;//ignoring smaller mips
private readonly byte[] inputData;
private readonly byte[] outputData;
public Rgb9e5Decoding()
{
inputData = File.ReadAllBytes(PathConstants.PathToTestFiles + "Rgb/" + "test.rgb9e5float");
outputData = new byte[Width * Height * sizeof(uint)];
}
[Benchmark]
public int OriginalMethod() => RgbConverter.RGB9e5FloatToBGRA32(inputData, Width, Height, outputData);
[Benchmark]
public int GenericMethod() => RgbConverter.Convert<ColorRGB9e5, double, ColorBGRA32, byte>(inputData, Width, Height, outputData);
}
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
@@ -0,0 +1,255 @@
using System.CodeDom.Compiler;
namespace AssetRipper.TextureDecoder.ColorGenerator;
internal static class Program
{
private const string AttributeNamespace = "AssetRipper.TextureDecoder.Attributes";
private const string OutputNamespace = "AssetRipper.TextureDecoder.Rgb.Formats";
private const string OutputFolder = "../../../../AssetRipper.TextureDecoder/Rgb/Formats/";
private static readonly Dictionary<Type, string> MinimumValues = new()
{
{ typeof(byte), "byte.MinValue" },
{ typeof(sbyte), "sbyte.MinValue" },
{ typeof(short), "short.MinValue" },
{ typeof(ushort), "ushort.MinValue" },
{ typeof(Half), "default" },
{ typeof(float), "0f" },
{ typeof(double), "0d" },
};
private static readonly Dictionary<Type, string> MaximumValues = new()
{
{ typeof(byte), "byte.MaxValue" },
{ typeof(sbyte), "sbyte.MaxValue" },
{ typeof(short), "short.MaxValue" },
{ typeof(ushort), "ushort.MaxValue" },
{ typeof(Half), "HalfConstants.One" },
{ typeof(float), "1f" },
{ typeof(double), "1d" },
};
private static readonly Dictionary<Type, string> TypeNames = new()
{
{ typeof(byte), "byte" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(ushort), "ushort" },
{ typeof(Half), "Half" },
{ typeof(float), "float" },
{ typeof(double), "double" },
};
/// <summary>
/// Name, Type, Red, Blue, Green, Alpha
/// </summary>
private static readonly List<(string, Type, bool, bool, bool, bool)> Colors = new()
{
( "ColorA8", typeof(byte), false, false, false, true ),
( "ColorR8", typeof(byte), true, false, false, false ),
( "ColorRG16", typeof(byte), true, true, false, false ),
( "ColorRGB24", typeof(byte), true, true, true, false ),
( "ColorRGBA32", typeof(byte), true, true, true, true ),
( "ColorR8Signed", typeof(sbyte), true, false, false, false ),
( "ColorRG16Signed", typeof(sbyte), true, true, false, false ),
( "ColorRGB24Signed", typeof(sbyte), true, true, true, false ),
( "ColorRGBA32Signed", typeof(sbyte), true, true, true, true ),
( "ColorR16", typeof(ushort), true, false, false, false ),
( "ColorRG32", typeof(ushort), true, true, false, false ),
( "ColorRGB48", typeof(ushort), true, true, true, false ),
( "ColorRGBA64", typeof(ushort), true, true, true, true ),
( "ColorR16Signed", typeof(short), true, false, false, false ),
( "ColorRG32Signed", typeof(short), true, true, false, false ),
( "ColorRGB48Signed", typeof(short), true, true, true, false ),
( "ColorRGBA64Signed", typeof(short), true, true, true, true ),
( "ColorR16Half", typeof(Half), true, false, false, false ),
( "ColorRG32Half", typeof(Half), true, true, false, false ),
( "ColorRGB48Half", typeof(Half), true, true, true, false ),
( "ColorRGBA64Half", typeof(Half), true, true, true, true ),
( "ColorR32Single", typeof(float), true, false, false, false ),
( "ColorRG64Single", typeof(float), true, true, false, false ),
( "ColorRGB96Single", typeof(float), true, true, true, false ),
( "ColorRGBA128Single", typeof(float), true, true, true, true ),
( "ColorR64Double", typeof(double), true, false, false, false ),
( "ColorRG128Double", typeof(double), true, true, false, false ),
( "ColorRGB192Double", typeof(double), true, true, true, false ),
( "ColorRGBA256Double", typeof(double), true, true, true, true ),
};
/// <summary>
/// Name, Type, Red, Blue, Green, Alpha, Fully Utilized
/// </summary>
private static readonly List<(string, Type, bool, bool, bool, bool, bool)> OtherColors = new()
{
( "ColorARGB16", typeof(byte), true, true, true, true, false ),
( "ColorARGB32", typeof(byte), true, true, true, true, true ),
( "ColorBGRA32", typeof(byte), true, true, true, true, true ),
( "ColorRGB16", typeof(byte), true, true, true, false, false ),
( "ColorRGB9e5", typeof(double), true, true, true, false, false ),
( "ColorRGBA16", typeof(byte), true, true, true, true, false ),
( "ColorRGB32Half", typeof(Half), true, true, true, false, false ),
};
static void Main()
{
foreach (var color in Colors)
{
WriteColor(color);
}
foreach (var otherColor in OtherColors)
{
WriteOtherColor(otherColor);
}
Console.WriteLine("Done!");
}
private static void WriteColor((string, Type, bool, bool, bool, bool) details)
{
(string name, Type type, bool hasRed, bool hasGreen, bool hasBlue, bool hasAlpha) = details;
Console.WriteLine(name);
using FileStream stream = File.Create($"{OutputFolder}{name}.g.cs");
using StreamWriter streamWriter = new StreamWriter(stream);
streamWriter.NewLine = "\n";
using IndentedTextWriter writer = new IndentedTextWriter(streamWriter, "\t");
writer.NewLine = "\n";
WriteColor(writer, name, type, hasRed, hasGreen, hasBlue, hasAlpha);
}
private static void WriteOtherColor((string, Type, bool, bool, bool, bool, bool) details)
{
(string name, Type type, bool hasRed, bool hasGreen, bool hasBlue, bool hasAlpha, bool fullyUtilized) = details;
Console.WriteLine(name);
using FileStream stream = File.Create($"{OutputFolder}{name}.g.cs");
using StreamWriter streamWriter = new StreamWriter(stream);
streamWriter.NewLine = "\n";
using IndentedTextWriter writer = new IndentedTextWriter(streamWriter, "\t");
writer.NewLine = "\n";
WriteOtherColor(writer, name, type, hasRed, hasGreen, hasBlue, hasAlpha, fullyUtilized);
}
private static void WriteOtherColor(IndentedTextWriter writer, string name, Type type, bool hasRed, bool hasGreen, bool hasBlue, bool hasAlpha, bool fullyUtilized)
{
string typeName = TypeNames[type];
writer.WriteLine("//This code is source generated. Do not edit manually.");
writer.WriteLine();
writer.WriteLine($"using {AttributeNamespace};");
writer.WriteLine();
writer.WriteLine($"namespace {OutputNamespace}");
writer.WriteLine('{');
writer.Indent++;
writer.WriteLine($"[RgbaAttribute(RedChannel = {hasRed.ToLowerString()}, GreenChannel = {hasGreen.ToLowerString()}, BlueChannel = {hasBlue.ToLowerString()}, AlphaChannel = {hasAlpha.ToLowerString()}, FullyUtilizedChannels = {fullyUtilized.ToLowerString()})]");
writer.WriteLine($"public partial struct {name} : IColor<{typeName}>");
writer.WriteLine('{');
writer.WriteLine('}');
writer.Indent--;
writer.WriteLine('}');
}
private static void WriteColor(IndentedTextWriter writer, string name, Type type, bool hasRed, bool hasGreen, bool hasBlue, bool hasAlpha)
{
string typeName = TypeNames[type];
writer.WriteLine("//This code is source generated. Do not edit manually.");
writer.WriteLine();
writer.WriteLine($"using {AttributeNamespace};");
writer.WriteLine();
writer.WriteLine($"namespace {OutputNamespace}");
writer.WriteLine('{');
writer.Indent++;
writer.WriteLine($"[RgbaAttribute(RedChannel = {hasRed.ToLowerString()}, GreenChannel = {hasGreen.ToLowerString()}, BlueChannel = {hasBlue.ToLowerString()}, AlphaChannel = {hasAlpha.ToLowerString()}, FullyUtilizedChannels = true)]");
writer.WriteLine($"public partial struct {name} : IColor<{typeName}>");
writer.WriteLine('{');
writer.Indent++;
WriteProperty(writer, hasRed, typeName, 'R', MinimumValues[type]);
writer.WriteLine();
WriteProperty(writer, hasGreen, typeName, 'G', MinimumValues[type]);
writer.WriteLine();
WriteProperty(writer, hasBlue, typeName, 'B', MinimumValues[type]);
writer.WriteLine();
WriteProperty(writer, hasAlpha, typeName, 'A', MaximumValues[type]);
writer.WriteLine();
WriteGetChannels(writer, typeName);
writer.WriteLine();
WriteSetChannels(writer, type, hasRed, hasGreen, hasBlue, hasAlpha);
writer.Indent--;
writer.WriteLine('}');
writer.Indent--;
writer.WriteLine('}');
}
private static void WriteGetChannels(IndentedTextWriter writer, string typeName)
{
writer.WriteLine($"public void GetChannels(out {typeName} r, out {typeName} g, out {typeName} b, out {typeName} a)");
writer.WriteLine('{');
writer.Indent++;
writer.WriteLine("r = R;");
writer.WriteLine("g = G;");
writer.WriteLine("b = B;");
writer.WriteLine("a = A;");
writer.Indent--;
writer.WriteLine('}');
}
private static void WriteSetChannels(IndentedTextWriter writer, Type type, bool hasRed, bool hasGreen, bool hasBlue, bool hasAlpha)
{
string typeName = TypeNames[type];
writer.WriteLine($"public void SetChannels({typeName} r, {typeName} g, {typeName} b, {typeName} a)");
writer.WriteLine('{');
writer.Indent++;
if (hasRed)
{
writer.WriteLine("R = r;");
}
if (hasGreen)
{
writer.WriteLine("G = g;");
}
if (hasBlue)
{
writer.WriteLine("B = b;");
}
if (hasAlpha)
{
writer.WriteLine("A = a;");
}
writer.Indent--;
writer.WriteLine('}');
}
private static void WriteProperty(IndentedTextWriter writer, bool hasColor, string typeName, char channel, string defaultValue)
{
if (hasColor)
{
writer.WriteLine($"public {typeName} {channel} {{ get; set; }}");
}
else
{
writer.WriteLine($"public {typeName} {channel} ");
writer.WriteLine('{');
writer.Indent++;
writer.WriteLine($"get => {defaultValue};");
writer.WriteLine("set { }");
writer.Indent--;
writer.WriteLine('}');
}
}
private static string ToLowerString(this bool value)
{
return value ? "true" : "false";
}
}
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StbImageWriteSharp" Version="1.16.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetRipper.TextureDecoder\AssetRipper.TextureDecoder.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,152 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using StbImageWriteSharp;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace AssetRipper.TextureDecoder.ConsoleApp;
public struct DirectBitmap<TColor, TColorArg>
where TColorArg : unmanaged
where TColor : unmanaged, IColor<TColorArg>
{
public DirectBitmap(int width, int height)
{
Width = width;
Height = height;
Data = new byte[CalculateByteSize(width, height)];
}
public DirectBitmap(int width, int height, byte[] data)
{
if (data.Length < CalculateByteSize(width, height))
{
throw new ArgumentException("Data does not have enough space.", nameof(data));
}
Width = width;
Height = height;
Data = data;
}
public void FlipY()
{
Span<TColor> pixels = Pixels;
for (int row = 0, irow = Height - 1; row < irow; row++, irow--)
{
Span<TColor> rowTop = pixels.Slice(row * Width, Width);
Span<TColor> rowBottom = pixels.Slice(irow * Width, Width);
for (int i = 0; i < Width; i++)
{
(rowTop[i], rowBottom[i]) = (rowBottom[i], rowTop[i]);
}
}
}
public void SaveAsBmp(string path)
{
using Stream stream = File.OpenWrite(path);
ImageWriter writer = new();
if (typeof(TColor) == typeof(ColorRGBA32))
{
writer.WriteBmp(Data, Width, Height, ColorComponents.RedGreenBlueAlpha, stream);
}
else if (typeof(TColor) == typeof(ColorRGB24))
{
writer.WriteBmp(Data, Width, Height, ColorComponents.RedGreenBlue, stream);
}
else
{
RgbConverter.Convert<TColor, TColorArg, ColorRGBA32, byte>(Bits, Width, Height, out byte[] output);
writer.WriteBmp(output, Width, Height, ColorComponents.RedGreenBlueAlpha, stream);
}
}
public void SaveAsHdr(string path)
{
using Stream stream = File.OpenWrite(path);
ImageWriter writer = new();
if (typeof(TColor) == typeof(ColorRGBA32))
{
writer.WriteHdr(Data, Width, Height, ColorComponents.RedGreenBlueAlpha, stream);
}
else if (typeof(TColor) == typeof(ColorRGB24))
{
writer.WriteHdr(Data, Width, Height, ColorComponents.RedGreenBlue, stream);
}
else
{
RgbConverter.Convert<TColor, TColorArg, ColorRGBA32, byte>(Bits, Width, Height, out byte[] output);
writer.WriteHdr(output, Width, Height, ColorComponents.RedGreenBlueAlpha, stream);
}
}
public void SaveAsJpg(string path)
{
using Stream stream = File.OpenWrite(path);
ImageWriter writer = new();
if (typeof(TColor) == typeof(ColorRGBA32))
{
writer.WriteJpg(Data, Width, Height, ColorComponents.RedGreenBlueAlpha, stream, default);
}
else if (typeof(TColor) == typeof(ColorRGB24))
{
writer.WriteJpg(Data, Width, Height, ColorComponents.RedGreenBlue, stream, default);
}
else
{
RgbConverter.Convert<TColor, TColorArg, ColorRGBA32, byte>(Bits, Width, Height, out byte[] output);
writer.WriteJpg(output, Width, Height, ColorComponents.RedGreenBlueAlpha, stream, default);
}
}
public void SaveAsPng(string path)
{
using Stream stream = File.OpenWrite(path);
ImageWriter writer = new();
if (typeof(TColor) == typeof(ColorRGBA32))
{
writer.WritePng(Data, Width, Height, ColorComponents.RedGreenBlueAlpha, stream);
}
else if (typeof(TColor) == typeof(ColorRGB24))
{
writer.WritePng(Data, Width, Height, ColorComponents.RedGreenBlue, stream);
}
else
{
RgbConverter.Convert<TColor, TColorArg, ColorRGBA32, byte>(Bits, Width, Height, out byte[] output);
writer.WritePng(output, Width, Height, ColorComponents.RedGreenBlueAlpha, stream);
}
}
public void SaveAsTga(string path)
{
using Stream stream = File.OpenWrite(path);
ImageWriter writer = new();
if (typeof(TColor) == typeof(ColorRGBA32))
{
writer.WriteTga(Data, Width, Height, ColorComponents.RedGreenBlueAlpha, stream);
}
else if (typeof(TColor) == typeof(ColorRGB24))
{
writer.WriteTga(Data, Width, Height, ColorComponents.RedGreenBlue, stream);
}
else
{
RgbConverter.Convert<TColor, TColorArg, ColorRGBA32, byte>(Bits, Width, Height, out byte[] output);
writer.WriteTga(output, Width, Height, ColorComponents.RedGreenBlueAlpha, stream);
}
}
public int Height { get; }
public int Width { get; }
public int ByteSize => CalculateByteSize(Width, Height);
public Span<byte> Bits => new Span<byte>(Data, 0, ByteSize);
public Span<TColor> Pixels => MemoryMarshal.Cast<byte, TColor>(Bits);
private byte[] Data { get; }
private static int CalculateByteSize(int width, int height)
{
return width * height * Unsafe.SizeOf<TColor>();
}
}
@@ -0,0 +1,243 @@
using AssetRipper.TextureDecoder.Astc;
using AssetRipper.TextureDecoder.Atc;
using AssetRipper.TextureDecoder.Bc;
using AssetRipper.TextureDecoder.Dxt;
using AssetRipper.TextureDecoder.Etc;
using AssetRipper.TextureDecoder.Pvrtc;
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using AssetRipper.TextureDecoder.Yuy2;
namespace AssetRipper.TextureDecoder.ConsoleApp;
internal static partial class Program
{
static void Main(string[] args)
{
if (args.Length < 4)
{
Console.WriteLine("Format: {path} {inputType} {outputType} {width} {height} {args5} {args6}");
return;
}
string path = args[0];
string inputType = args[1].ToLowerInvariant();
string outputType = args[2].ToLowerInvariant();
int width = int.Parse(args[3]);
int height = int.Parse(args[4]);
string args5 = args.GetArgument(5);
string args6 = args.GetArgument(6);
byte[] data = File.ReadAllBytes(path);
DirectBitmap<ColorBGRA32, byte> bitmap = new DirectBitmap<ColorBGRA32, byte>(width, height);
switch (inputType)
{
case "astc":
DecodeAstc(data, width, height, args5, args6, bitmap.Bits);
break;
case "atc":
DecodeAtc(data, width, height, args5, bitmap.Bits);
break;
case "bc":
DecodeBc(data, width, height, args5, args6, bitmap.Bits);
break;
case "dxt":
DecodeDxt(data, width, height, args5, bitmap.Bits);
break;
case "etc":
DecodeEtc(data, width, height, args5, bitmap.Bits);
break;
case "pvrtc":
DecodePvrtc(data, width, height, args5, bitmap.Bits);
break;
case "rgb":
DecodeRgb(data, width, height, args5, bitmap.Bits);
break;
case "yuy2":
Yuy2Decoder.DecompressYUY2(data, width, height, bitmap.Bits);
break;
default:
throw new NotSupportedException(inputType);
}
string dirPath = Path.GetDirectoryName(path) ?? Environment.CurrentDirectory;
string name = Path.GetFileName(path);
switch (outputType)
{
case "png":
{
string newPath = Path.Combine(dirPath, name + ".png");
bitmap.FlipY();
bitmap.SaveAsPng(newPath);
}
break;
case "bgra":
{
string newPath = Path.Combine(dirPath, name + ".bgra");
WriteAllBytes(newPath, bitmap.Bits);
}
break;
default:
throw new NotSupportedException(outputType);
}
Console.WriteLine("Done!");
}
private static string GetArgument(this string[] args, int index)
{
return index < args.Length ? args[index] : string.Empty;
}
private static void DecodeAstc(ReadOnlySpan<byte> input, int width, int height, string blockXSizeString, string blockYSizeString, Span<byte> output)
{
Console.WriteLine("Arg at index 5 : blockXSize");
Console.WriteLine("Arg at index 6 : blockYSize");
int blockXSize = int.Parse(blockXSizeString);
int blockYSize = int.Parse(blockYSizeString);
AstcDecoder.DecodeASTC(input, width, height, blockXSize, blockYSize, output);
}
private static void DecodeAtc(ReadOnlySpan<byte> input, int width, int height, string modeString, Span<byte> output)
{
Console.WriteLine("Arg at index 5 : mode");
Console.WriteLine(" 0 - ATC RGB4");
Console.WriteLine(" 1 - ATC RGBA8");
int mode = int.Parse(modeString);
switch (mode)
{
case 0:
AtcDecoder.DecompressAtcRgb4(input, width, height, output);
break;
case 1:
AtcDecoder.DecompressAtcRgba8(input, width, height, output);
break;
default:
throw new NotSupportedException(mode.ToString());
}
}
private static void DecodeBc(ReadOnlySpan<byte> input, int width, int height, string modeString, string isSignedString, Span<byte> output)
{
Console.WriteLine("Arg at index 5 : mode");
Console.WriteLine(" 1 - BC1");
Console.WriteLine(" 2 - BC2");
Console.WriteLine(" 3 - BC3");
Console.WriteLine(" 4 - BC4");
Console.WriteLine(" 5 - BC5");
Console.WriteLine(" 6 - BC6H");
Console.WriteLine(" 7 - BC7");
Console.WriteLine("Arg at index 6 : isSigned (BC6H only)");
int mode = int.Parse(modeString);
switch (mode)
{
case 1:
Bc1.Decompress(input, width, height, output);
break;
case 2:
Bc2.Decompress(input, width, height, output);
break;
case 3:
Bc3.Decompress(input, width, height, output);
break;
case 4:
Bc4.Decompress(input, width, height, output);
break;
case 5:
Bc5.Decompress(input, width, height, output);
break;
case 6:
Bc6h.Decompress(input, width, height, bool.Parse(isSignedString), output);
break;
case 7:
Bc7.Decompress(input, width, height, output);
break;
default:
throw new NotSupportedException(mode.ToString());
}
}
private static void DecodeDxt(ReadOnlySpan<byte> input, int width, int height, string modeString, Span<byte> output)
{
Console.WriteLine("Arg at index 5 : mode");
Console.WriteLine(" 0 - DXT1");
Console.WriteLine(" 1 - DXT3");
Console.WriteLine(" 2 - DXT5");
int mode = int.Parse(modeString);
switch (mode)
{
case 0:
DxtDecoder.DecompressDXT1(input, width, height, output);
break;
case 1:
DxtDecoder.DecompressDXT3(input, width, height, output);
break;
case 2:
DxtDecoder.DecompressDXT5(input, width, height, output);
break;
default:
throw new NotSupportedException(mode.ToString());
}
}
private static void DecodeEtc(ReadOnlySpan<byte> input, int width, int height, string modeString, Span<byte> output)
{
Console.WriteLine("Arg at index 5 : mode");
Console.WriteLine(" 0 - ETC");
Console.WriteLine(" 1 - ETC2");
Console.WriteLine(" 2 - ETC2a1");
Console.WriteLine(" 3 - ETC2a8");
Console.WriteLine(" 4 - EAC R");
Console.WriteLine(" 5 - EAC signed R");
Console.WriteLine(" 6 - EAC RG");
Console.WriteLine(" 7 - EAC signed RG");
int mode = int.Parse(modeString);
switch (mode)
{
case 0:
EtcDecoder.DecompressETC(input, width, height, output);
break;
case 1:
EtcDecoder.DecompressETC2(input, width, height, output);
break;
case 2:
EtcDecoder.DecompressETC2A1(input, width, height, output);
break;
case 3:
EtcDecoder.DecompressETC2A8(input, width, height, output);
break;
case 4:
EtcDecoder.DecompressEACRUnsigned(input, width, height, output);
break;
case 5:
EtcDecoder.DecompressEACRSigned(input, width, height, output);
break;
case 6:
EtcDecoder.DecompressEACRGUnsigned(input, width, height, output);
break;
case 7:
EtcDecoder.DecompressEACRGSigned(input, width, height, output);
break;
default:
throw new NotSupportedException(mode.ToString());
}
}
private static void DecodePvrtc(ReadOnlySpan<byte> input, int width, int height, string do2bitModeString, Span<byte> output)
{
Console.WriteLine("Arg at index 5 : 2bitMode");
bool do2bit = bool.Parse(do2bitModeString);
PvrtcDecoder.DecompressPVRTC(input, width, height, do2bit, output);
}
public static void WriteAllBytes(string path, ReadOnlySpan<byte> bytes)
{
ArgumentException.ThrowIfNullOrEmpty(path, nameof(path));
using Microsoft.Win32.SafeHandles.SafeFileHandle sfh = File.OpenHandle(path, FileMode.Create, FileAccess.Write, FileShare.Read);
RandomAccess.Write(sfh, bytes, 0);
}
}
@@ -0,0 +1,163 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
namespace AssetRipper.TextureDecoder.ConsoleApp;
static partial class Program
{
private static void DecodeRgb(ReadOnlySpan<byte> input, int width, int height, string modeString, Span<byte> output)
{
Console.WriteLine("Arg at index 5 : mode");
Console.WriteLine(" 0 - A8");
Console.WriteLine(" 1 - ARGB16");
Console.WriteLine(" 2 - ARGB32");
Console.WriteLine(" 3 - BGRA32");
Console.WriteLine(" 4 - R16");
Console.WriteLine(" 5 - R16Half");
Console.WriteLine(" 6 - R16Signed");
Console.WriteLine(" 7 - R32Single");
Console.WriteLine(" 8 - R64Double");
Console.WriteLine(" 9 - R8");
Console.WriteLine(" 10 - R8Signed");
Console.WriteLine(" 11 - RG16");
Console.WriteLine(" 12 - RG32Half");
Console.WriteLine(" 13 - RG16Signed");
Console.WriteLine(" 14 - RG32");
Console.WriteLine(" 15 - RG32Signed");
Console.WriteLine(" 16 - RG64Single");
Console.WriteLine(" 17 - RG128Double");
Console.WriteLine(" 18 - RGB16");
Console.WriteLine(" 19 - RGB24");
Console.WriteLine(" 20 - RGB24Signed");
Console.WriteLine(" 21 - RGB32Half");
Console.WriteLine(" 22 - RGB48");
Console.WriteLine(" 23 - RGB48Half");
Console.WriteLine(" 24 - RGB48Signed");
Console.WriteLine(" 25 - RGB96Single");
Console.WriteLine(" 26 - RGB192Double");
Console.WriteLine(" 27 - RGB9e5");
Console.WriteLine(" 28 - RGBA128Single");
Console.WriteLine(" 29 - RGBA16");
Console.WriteLine(" 30 - RGBA256Double");
Console.WriteLine(" 31 - RGBA32");
Console.WriteLine(" 32 - RGBA32Signed");
Console.WriteLine(" 33 - RGBA64");
Console.WriteLine(" 34 - RGBA64Half");
Console.WriteLine(" 35 - RGBA64Signed");
int mode = int.Parse(modeString);
switch(mode)
{
case 0:
RgbConverter.Convert<ColorA8, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 1:
RgbConverter.Convert<ColorARGB16, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 2:
RgbConverter.Convert<ColorARGB32, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 3:
RgbConverter.Convert<ColorBGRA32, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 4:
RgbConverter.Convert<ColorR16, ushort, ColorBGRA32, byte>(input, width, height, output);
break;
case 5:
RgbConverter.Convert<ColorR16Half, Half, ColorBGRA32, byte>(input, width, height, output);
break;
case 6:
RgbConverter.Convert<ColorR16Signed, short, ColorBGRA32, byte>(input, width, height, output);
break;
case 7:
RgbConverter.Convert<ColorR32Single, float, ColorBGRA32, byte>(input, width, height, output);
break;
case 8:
RgbConverter.Convert<ColorR64Double, double, ColorBGRA32, byte>(input, width, height, output);
break;
case 9:
RgbConverter.Convert<ColorR8, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 10:
RgbConverter.Convert<ColorR8Signed, sbyte, ColorBGRA32, byte>(input, width, height, output);
break;
case 11:
RgbConverter.Convert<ColorRG16, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 12:
RgbConverter.Convert<ColorRG32Half, Half, ColorBGRA32, byte>(input, width, height, output);
break;
case 13:
RgbConverter.Convert<ColorRG16Signed, sbyte, ColorBGRA32, byte>(input, width, height, output);
break;
case 14:
RgbConverter.Convert<ColorRG32, ushort, ColorBGRA32, byte>(input, width, height, output);
break;
case 15:
RgbConverter.Convert<ColorRG32Signed, short, ColorBGRA32, byte>(input, width, height, output);
break;
case 16:
RgbConverter.Convert<ColorRG64Single, float, ColorBGRA32, byte>(input, width, height, output);
break;
case 17:
RgbConverter.Convert<ColorRG128Double, double, ColorBGRA32, byte>(input, width, height, output);
break;
case 18:
RgbConverter.Convert<ColorRGB16, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 19:
RgbConverter.Convert<ColorRGB24, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 20:
RgbConverter.Convert<ColorRGB24Signed, sbyte, ColorBGRA32, byte>(input, width, height, output);
break;
case 21:
RgbConverter.Convert<ColorRGB32Half, Half, ColorBGRA32, byte>(input, width, height, output);
break;
case 22:
RgbConverter.Convert<ColorRGB48, ushort, ColorBGRA32, byte>(input, width, height, output);
break;
case 23:
RgbConverter.Convert<ColorRGB48Half, Half, ColorBGRA32, byte>(input, width, height, output);
break;
case 24:
RgbConverter.Convert<ColorRGB48Signed, short, ColorBGRA32, byte>(input, width, height, output);
break;
case 25:
RgbConverter.Convert<ColorRGB96Single, float, ColorBGRA32, byte>(input, width, height, output);
break;
case 26:
RgbConverter.Convert<ColorRGB192Double, double, ColorBGRA32, byte>(input, width, height, output);
break;
case 27:
RgbConverter.Convert<ColorRGB9e5, double, ColorBGRA32, byte>(input, width, height, output);
break;
case 28:
RgbConverter.Convert<ColorRGBA128Single, float, ColorBGRA32, byte>(input, width, height, output);
break;
case 29:
RgbConverter.Convert<ColorRGBA16, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 30:
RgbConverter.Convert<ColorRGBA256Double, double, ColorBGRA32, byte>(input, width, height, output);
break;
case 31:
RgbConverter.Convert<ColorRGBA32, byte, ColorBGRA32, byte>(input, width, height, output);
break;
case 32:
RgbConverter.Convert<ColorRGBA32Signed, sbyte, ColorBGRA32, byte>(input, width, height, output);
break;
case 33:
RgbConverter.Convert<ColorRGBA64, ushort, ColorBGRA32, byte>(input, width, height, output);
break;
case 34:
RgbConverter.Convert<ColorRGBA64Half, Half, ColorBGRA32, byte>(input, width, height, output);
break;
case 35:
RgbConverter.Convert<ColorRGBA64Signed, short, ColorBGRA32, byte>(input, width, height, output);
break;
default:
throw new NotSupportedException(mode.ToString());
}
}
}
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AssetRipper.TextureDecoder\AssetRipper.TextureDecoder.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,20 @@
namespace AssetRipper.TextureDecoder.TestGenerator
{
internal struct ColorRandomValues
{
public string DefaultR;
public string DefaultG;
public string DefaultB;
public string DefaultA;
public string SetValue;
public ColorRandomValues(string defaultR, string defaultG, string defaultB, string defaultA, string setValue)
{
DefaultR = defaultR;
DefaultG = defaultG;
DefaultB = defaultB;
DefaultA = defaultA;
SetValue = setValue;
}
}
}
@@ -0,0 +1,125 @@
using AssetRipper.TextureDecoder.Attributes;
using AssetRipper.TextureDecoder.Rgb;
using System.Reflection;
namespace AssetRipper.TextureDecoder.TestGenerator
{
internal readonly struct GenerationData
{
public Type ColorType { get; }
public Type ChannelType { get; }
public int ColorSize { get; }
public bool RedChannel { get; }
public bool GreenChannel { get; }
public bool BlueChannel { get; }
public bool AlphaChannel { get; }
public bool FullyUtilizedChannels { get; }
public bool IsFloatingPoint
{
get
{
return ChannelType == typeof(Half) || ChannelType == typeof(float) || ChannelType == typeof(double);
}
}
public int BitSizePerChannel
{
get
{
if (ChannelType == typeof(byte) || ChannelType == typeof(sbyte))
{
return 8;
}
else if (ChannelType == typeof(ushort) || ChannelType == typeof(short) || ChannelType == typeof(Half))
{
return 16;
}
else if (ChannelType == typeof(float))
{
return 32;
}
else if (ChannelType == typeof(double))
{
return 64;
}
else
{
throw new NotSupportedException(ChannelType.Name);
}
}
}
public string ChannelTypeName
{
get
{
return ChannelType.Name switch
{
"Byte" => "byte",
"SByte" => "sbyte",
"UInt16" => "ushort",
"Int16" => "short",
"Single" => "float",
"Double" => "double",
_ => ChannelType.Name,
};
}
}
public GenerationData(Type colorType, int colorSize)
{
ColorType = colorType;
ChannelType = ColorType.GetInterfaces().Single(t => t.Name == $"{nameof(IColor<byte>)}`1").GenericTypeArguments[0];
ColorSize = colorSize;
RgbaAttribute attribute = colorType.GetCustomAttribute<RgbaAttribute>() ?? throw new NullReferenceException(colorType.Name);
RedChannel = attribute.RedChannel;
GreenChannel = attribute.GreenChannel;
BlueChannel = attribute.BlueChannel;
AlphaChannel = attribute.AlphaChannel;
FullyUtilizedChannels = attribute.FullyUtilizedChannels;
}
public bool Contains(GenerationData other)
{
if (!FullyUtilizedChannels)
{
return false;
}
if (!IsFloatingPoint && other.IsFloatingPoint)
{
return false;
}
if (IsFloatingPoint && !other.IsFloatingPoint)
{
return false;
}
if (other.RedChannel && !RedChannel)
{
return false;
}
if (other.GreenChannel && !GreenChannel)
{
return false;
}
if (other.BlueChannel && !BlueChannel)
{
return false;
}
if (other.AlphaChannel && !AlphaChannel)
{
return false;
}
return BitSizePerChannel >= other.BitSizePerChannel;
}
}
}
@@ -0,0 +1,10 @@
using System.CodeDom.Compiler;
internal static class IndentedTextWriterExtensions
{
internal static void WriteSourceGenerationDisclaimer(this IndentedTextWriter textWriter)
{
textWriter.WriteLine($"//This code is source generated. Do not edit manually.");
textWriter.WriteLine();
}
}
@@ -0,0 +1,118 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.CodeDom.Compiler;
namespace AssetRipper.TextureDecoder.TestGenerator
{
internal static class Program
{
internal static readonly List<GenerationData> dataList = new()
{
new GenerationData(typeof(ColorA8), 1),
new GenerationData(typeof(ColorARGB16), 2),
new GenerationData(typeof(ColorARGB32), 4),
new GenerationData(typeof(ColorBGRA32), 4),
new GenerationData(typeof(ColorR16), 2),
new GenerationData(typeof(ColorR16Half), 2),
new GenerationData(typeof(ColorR16Signed), 2),
new GenerationData(typeof(ColorR32Single), 4),
new GenerationData(typeof(ColorR64Double), 8),
new GenerationData(typeof(ColorR8), 1),
new GenerationData(typeof(ColorR8Signed), 1),
new GenerationData(typeof(ColorRG16), 2),
new GenerationData(typeof(ColorRG32Half), 4),
new GenerationData(typeof(ColorRG16Signed), 2),
new GenerationData(typeof(ColorRG32), 4),
new GenerationData(typeof(ColorRG32Signed), 4),
new GenerationData(typeof(ColorRG64Single), 8),
new GenerationData(typeof(ColorRG128Double), 16),
new GenerationData(typeof(ColorRGB16), 2),
new GenerationData(typeof(ColorRGB24), 3),
new GenerationData(typeof(ColorRGB24Signed), 3),
new GenerationData(typeof(ColorRGB32Half), 4),
new GenerationData(typeof(ColorRGB48), 6),
new GenerationData(typeof(ColorRGB48Half), 6),
new GenerationData(typeof(ColorRGB48Signed), 6),
new GenerationData(typeof(ColorRGB96Single), 12),
new GenerationData(typeof(ColorRGB192Double), 24),
new GenerationData(typeof(ColorRGB9e5), 4),
new GenerationData(typeof(ColorRGBA128Single), 16),
new GenerationData(typeof(ColorRGBA16), 2),
new GenerationData(typeof(ColorRGBA256Double), 32),
new GenerationData(typeof(ColorRGBA32), 4),
new GenerationData(typeof(ColorRGBA32Signed), 4),
new GenerationData(typeof(ColorRGBA64), 8),
new GenerationData(typeof(ColorRGBA64Half), 8),
new GenerationData(typeof(ColorRGBA64Signed), 8),
};
static void Main()
{
TestClassGenerator.GenerateTestClasses();
GenerateRgbConsoleMethod();
Console.WriteLine("Done!");
}
private static void GenerateRgbConsoleMethod()
{
StringWriter streamWriter = new();
IndentedTextWriter textWriter = new IndentedTextWriter(streamWriter, "\t");
streamWriter.NewLine = "\n";
textWriter.NewLine = "\n";
textWriter.WriteSourceGenerationDisclaimer();
textWriter.WriteLine($"using {typeof(RgbConverter).Namespace};");
textWriter.WriteLine($"using {typeof(ColorBGRA32).Namespace};");
textWriter.WriteLine();
textWriter.WriteLine("namespace AssetRipper.TextureDecoder.ConsoleApp;");
textWriter.WriteLine("static partial class Program");
textWriter.WriteLine("{");
textWriter.Indent++;
textWriter.WriteLine("private static void DecodeRgb(ReadOnlySpan<byte> input, int width, int height, string modeString, Span<byte> output)");
textWriter.WriteLine("{");
textWriter.Indent++;
textWriter.WriteLine("Console.WriteLine(\"Arg at index 5 : mode\");");
for (int i = 0; i < dataList.Count; i++)
{
textWriter.WriteLine($"Console.WriteLine(\" {i} - {dataList[i].ColorType.Name.Substring(5)}\");");
}
textWriter.WriteLine("int mode = int.Parse(modeString);");
textWriter.WriteLine("switch(mode)");
textWriter.WriteLine("{");
textWriter.Indent++;
for (int i = 0; i < dataList.Count; i++)
{
textWriter.WriteLine($"case {i}:");
textWriter.Indent++;
GenerationData data = dataList[i];
textWriter.WriteLine($"RgbConverter.Convert<{data.ColorType.Name}, {data.ChannelTypeName}, ColorBGRA32, byte>(input, width, height, output);");
textWriter.WriteLine("break;");
textWriter.Indent--;
}
{
textWriter.WriteLine("default:");
textWriter.Indent++;
textWriter.WriteLine("throw new NotSupportedException(mode.ToString());");
textWriter.Indent--;
}
textWriter.Indent--;
textWriter.WriteLine("}");
textWriter.Indent--;
textWriter.WriteLine("}");
textWriter.Indent--;
textWriter.WriteLine("}");
textWriter.Flush();
streamWriter.Flush();
File.WriteAllText("../../../../AssetRipper.TextureDecoder.ConsoleApp/Program.g.cs", streamWriter.ToString());
Console.WriteLine("Program");
}
}
}
@@ -0,0 +1,260 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.TestGenerator;
using System.CodeDom.Compiler;
internal static class TestClassGenerator
{
private const string OutputNamespace = "AssetRipper.TextureDecoder.Tests.Formats";
private const string OutputFolder = "../../../../AssetRipper.TextureDecoder.Tests/Formats/";
private static readonly char[] channels = new char[] { 'R', 'G', 'B', 'A' };
private static readonly Dictionary<Type, ColorRandomValues> randomValueDictionary = new()
{
{ typeof(sbyte), new ColorRandomValues("-0b01010101", "0b01110010", "-0b00001111", "-0b01000111", "0b01001110") },
{ typeof(byte), new ColorRandomValues("0b11010101", "0b01110010", "0b10001111", "0b11000111", "0b01001110") },
{ typeof(short), new ColorRandomValues("-24000", "21354", "-80", "347", "31871") },
{ typeof(ushort), new ColorRandomValues("44000", "21354", "60080", "347", "33871") },
{ typeof(Half), new ColorRandomValues("(Half)0.447f", "(Half)0.224f", "(Half)0.95f", "(Half)0.897f", "(Half)0.333f") },
{ typeof(float), new ColorRandomValues("0.447f", "0.224f", "0.95f", "0.897f", "0.333f") },
{ typeof(double), new ColorRandomValues("0.447", "0.224", "0.95", "0.897", "0.333") },
};
internal static void GenerateTestClasses()
{
Directory.CreateDirectory(OutputFolder);
foreach (GenerationData data in Program.dataList)
{
using StringWriter streamWriter = new();
using IndentedTextWriter textWriter = new IndentedTextWriter(streamWriter, "\t");
streamWriter.NewLine = "\n";
textWriter.NewLine = "\n";
textWriter.WriteSourceGenerationDisclaimer();
textWriter.WriteNamespaceUsings(data);
textWriter.WriteFileScopedNamespace();
textWriter.WriteClassDefinitionOpen(data);
textWriter.Indent++;
textWriter.WriteCorrectSizeTest(data);
textWriter.WriteLine();
textWriter.WritePropertySymmetryTests(data);
textWriter.WriteIndependenceTests(data);
textWriter.WriteGetMethodMatchesProperties();
textWriter.WriteLine();
textWriter.WriteMethodSymmetryTest();
textWriter.WriteLine();
textWriter.WriteMakeRandomColor(data);
foreach (GenerationData otherData in Program.dataList)
{
if (otherData.Contains(data))
{
textWriter.WriteLine();
textWriter.WriteLosslessConversionTest(data, otherData);
}
}
textWriter.Indent--;
textWriter.WriteClassDefinitionClose();
textWriter.Flush();
streamWriter.Flush();
string outputFilePath = $"{OutputFolder}{data.ColorType.Name}Tests.g.cs";
File.WriteAllText(outputFilePath, streamWriter.ToString());
Console.WriteLine(data.ColorType.Name);
}
}
private static void WriteClassDefinitionClose(this IndentedTextWriter textWriter)
{
textWriter.WriteLine("}");
}
private static void WriteClassDefinitionOpen(this IndentedTextWriter textWriter, GenerationData data)
{
textWriter.WriteLine($"public partial class {data.ColorType.Name}Tests");
textWriter.WriteLine("{");
}
private static void WriteCorrectSizeTest(this IndentedTextWriter textWriter, GenerationData data)
{
textWriter.WriteLine("[Test]");
textWriter.WriteLine("public void CorrectSizeTest()");
textWriter.WriteLine("{");
textWriter.Indent += 1;
textWriter.WriteLine($"Assert.That(Unsafe.SizeOf<{data.ColorType.Name}>(), Is.EqualTo({data.ColorSize}));");
textWriter.Indent -= 1;
textWriter.WriteLine("}");
}
private static void WriteFileScopedNamespace(this IndentedTextWriter textWriter)
{
textWriter.WriteLine($"namespace {OutputNamespace};");
textWriter.WriteLine();//An empty line after the namespace declaration
}
private static void WriteGetMethodMatchesProperties(this IndentedTextWriter textWriter)
{
textWriter.WriteLine("[Test]");
textWriter.WriteLine($"public void GetMethodMatchesProperties()");
textWriter.WriteLine("{");
textWriter.Indent += 1;
textWriter.WriteLine("var color = MakeRandomColor();");
textWriter.WriteLine("color.GetChannels(out var r, out var g, out var b, out var a);");
textWriter.WriteLine("Assert.Multiple(() =>");
textWriter.WriteLine("{");
textWriter.Indent += 1;
foreach (char channel in channels)
{
textWriter.WriteLine($"Assert.That(color.{channel}, Is.EqualTo({char.ToLowerInvariant(channel)}));");
}
textWriter.Indent -= 1;
textWriter.WriteLine("});");
textWriter.Indent -= 1;
textWriter.WriteLine("}");
}
private static void WriteIndependenceTest(this IndentedTextWriter textWriter, GenerationData data, char channel)
{
textWriter.WriteLine("[Test]");
textWriter.WriteLine($"public void ChannelsAreIndependent_{channel}()");
textWriter.WriteLine("{");
textWriter.Indent += 1;
textWriter.WriteLine("var color = MakeRandomColor();");
foreach (char otherChannel in channels.Where(c => c != channel))
{
textWriter.WriteLine($"var {char.ToLowerInvariant(otherChannel)} = color.{otherChannel};");
}
textWriter.WriteLine($"color.{channel} = {randomValueDictionary[data.ChannelType].SetValue};");
textWriter.WriteLine("Assert.Multiple(() =>");
textWriter.WriteLine("{");
textWriter.Indent += 1;
foreach (char otherChannel in channels.Where(c => c != channel))
{
textWriter.WriteLine($"Assert.That(color.{otherChannel}, Is.EqualTo({char.ToLowerInvariant(otherChannel)}));");
}
textWriter.Indent -= 1;
textWriter.WriteLine("});");
textWriter.Indent -= 1;
textWriter.WriteLine("}");
}
private static void WriteIndependenceTests(this IndentedTextWriter textWriter, GenerationData data)
{
foreach (char channel in channels)
{
textWriter.WriteIndependenceTest(data, channel);
textWriter.WriteLine();
}
}
private static void WriteLosslessConversionTest(this IndentedTextWriter textWriter, GenerationData currentData, GenerationData containingData)
{
string currentName = currentData.ColorType.Name;
string containingName = containingData.ColorType.Name;
textWriter.WriteLine("[Test]");
textWriter.WriteLine($"public void ConversionTo{containingName}IsLossless()");
textWriter.WriteLine("{");
textWriter.Indent += 1;
textWriter.WriteLine($"{currentName} original = MakeRandomColor();");
textWriter.WriteLine($"{containingName} converted = original.{nameof(ColorExtensions.Convert)}<{currentName}, {currentData.ChannelTypeName}, {containingName}, {containingData.ChannelTypeName}>();");
textWriter.WriteLine($"{currentName} convertedBack = converted.{nameof(ColorExtensions.Convert)}<{containingName}, {containingData.ChannelTypeName}, {currentName}, {currentData.ChannelTypeName}>();");
textWriter.WriteLine("Assert.That(convertedBack, Is.EqualTo(original));");
textWriter.Indent -= 1;
textWriter.WriteLine("}");
}
private static void WriteMakeRandomColor(this IndentedTextWriter textWriter, GenerationData data)
{
textWriter.WriteLine($"public static {data.ColorType.Name} MakeRandomColor()");
textWriter.WriteLine("{");
textWriter.Indent += 1;
textWriter.WriteLine("return new()");
textWriter.WriteLine("{");
textWriter.Indent += 1;
ColorRandomValues randomValues = randomValueDictionary[data.ChannelType];
textWriter.WriteLine($"R = {randomValues.DefaultR},");
textWriter.WriteLine($"G = {randomValues.DefaultG},");
textWriter.WriteLine($"B = {randomValues.DefaultB},");
textWriter.WriteLine($"A = {randomValues.DefaultA},");
textWriter.Indent -= 1;
textWriter.WriteLine("};");
textWriter.Indent -= 1;
textWriter.WriteLine("}");
}
private static void WriteMethodSymmetryTest(this IndentedTextWriter textWriter)
{
textWriter.WriteLine("[Test]");
textWriter.WriteLine($"public void MethodsAreSymmetric()");
textWriter.WriteLine("{");
textWriter.Indent += 1;
textWriter.WriteLine("var color = MakeRandomColor();");
textWriter.WriteLine("color.GetChannels(out var r, out var g, out var b, out var a);");
textWriter.WriteLine("color.SetChannels(r, g, b, a);");
textWriter.WriteLine("Assert.Multiple(() =>");
textWriter.WriteLine("{");
textWriter.Indent += 1;
foreach (char channel in channels)
{
textWriter.WriteLine($"Assert.That(color.{channel}, Is.EqualTo({char.ToLowerInvariant(channel)}));");
}
textWriter.Indent -= 1;
textWriter.WriteLine("});");
textWriter.Indent -= 1;
textWriter.WriteLine("}");
}
private static void WriteNamespaceUsings(this IndentedTextWriter textWriter, GenerationData data)
{
textWriter.WriteLine($"using {typeof(ColorExtensions).Namespace};");
textWriter.WriteLine($"using {data.ColorType.Namespace};");
textWriter.WriteLine($"using {typeof(System.Runtime.CompilerServices.Unsafe).Namespace};");
textWriter.WriteLine();//An empty line after the usings
}
private static void WritePropertySymmetryTest(this IndentedTextWriter textWriter, GenerationData data, char channel)
{
textWriter.WriteLine("[Test]");
textWriter.WriteLine($"public void PropertyIsSymmetric_{channel}()");
textWriter.WriteLine("{");
textWriter.Indent += 1;
textWriter.WriteLine("var color = MakeRandomColor();");
char variableName = char.ToLowerInvariant(channel);
textWriter.WriteLine($"var {variableName} = color.{channel};");
textWriter.WriteLine($"color.{channel} = {variableName};");
textWriter.WriteLine($"Assert.That(color.{channel}, Is.EqualTo({variableName}));");
textWriter.Indent -= 1;
textWriter.WriteLine("}");
}
private static void WritePropertySymmetryTests(this IndentedTextWriter textWriter, GenerationData data)
{
foreach (char channel in channels)
{
textWriter.WritePropertySymmetryTest(data, channel);
textWriter.WriteLine();
}
}
}
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AssetRipper.TextureDecoder\AssetRipper.TextureDecoder.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,21 @@
namespace AssetRipper.TextureDecoder.Tests
{
public sealed class AtcTests
{
[Test]
public void DecompressAtcRgb4Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.AtcTestFilesFolder + "test.atc_rgb4");
int bytesRead = Atc.AtcDecoder.DecompressAtcRgb4(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressAtcRgba8Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.AtcTestFilesFolder + "test.atc_rgba8");
int bytesRead = Atc.AtcDecoder.DecompressAtcRgba8(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
}
}
+189
View File
@@ -0,0 +1,189 @@
using AssetRipper.TextureDecoder.Bc;
using AssetRipper.TextureDecoder.Dxt;
namespace AssetRipper.TextureDecoder.Tests
{
public sealed class BcTests
{
private const double MaxMeanDeviationBc6h = 0.5;
private const double MaxMeanDeviationBc7 = 0.1;//Bc7 is more accurate than Bc6h
private const double MaxStandardDeviationBc6h = 0.8;
private const double MaxStandardDeviationBc7 = 0.8;
private static byte[] originalBgra32LogoData = Array.Empty<byte>();
[SetUp]
public void InitializeOriginalData()
{
originalBgra32LogoData = File.ReadAllBytes(PathConstants.BcTestFilesFolder + "test.bgra32");
}
[Test]
public void DecompressDXT1Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.DxtTestFilesFolder + "test.dxt1");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4 }) //mipmaps 2 and 1 cause a buffer overrun for the output
{
int bytesRead = Bc1.Decompress(data.Slice(totalBytesRead), size, size, out byte[] bcDecodedData);
DxtDecoder.DecompressDXT1(data.Slice(totalBytesRead), size, size, out byte[] dxtDecodedData);
totalBytesRead += bytesRead;
AssertAlmostEqual(dxtDecodedData, bcDecodedData);
}
Assert.That(totalBytesRead + 16, Is.EqualTo(data.Length));
}
[Test]
public void DecompressDXT3Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.DxtTestFilesFolder + "test.dxt3");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4 }) //mipmaps 2 and 1 cause a buffer overrun for the output
{
int bytesRead = Bc2.Decompress(data.Slice(totalBytesRead), size, size, out byte[] bcDecodedData);
DxtDecoder.DecompressDXT3(data.Slice(totalBytesRead), size, size, out byte[] dxtDecodedData);
totalBytesRead += bytesRead;
AssertAlmostEqual(dxtDecodedData, bcDecodedData);
}
Assert.That(totalBytesRead + 32, Is.EqualTo(data.Length));
}
[Test]
public void DecompressDXT5Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.DxtTestFilesFolder + "test.dxt5");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4 }) //mipmaps 2 and 1 cause a buffer overrun for the output
{
int bytesRead = Bc3.Decompress(data.Slice(totalBytesRead), size, size, out byte[] bcDecodedData);
DxtDecoder.DecompressDXT5(data.Slice(totalBytesRead), size, size, out byte[] dxtDecodedData);
totalBytesRead += bytesRead;
AssertAlmostEqual(dxtDecodedData, bcDecodedData);
}
Assert.That(totalBytesRead + 32, Is.EqualTo(data.Length));
}
[Test]
public void DecompressBC4Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.BcTestFilesFolder + "test.bc4");
int bytesRead = Bc4.Decompress(data, 512, 512, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressBC5Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.BcTestFilesFolder + "test.bc5");
int bytesRead = Bc5.Decompress(data, 512, 512, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressBC6HFastTest()
{
AssertCorrectBC6HDecompression(PathConstants.BcTestFilesFolder + "test.bc6h_fast", 512, 512, false);
}
[Test]
public void DecompressBC6HNormalTest()
{
AssertCorrectBC6HDecompression(PathConstants.BcTestFilesFolder + "test.bc6h_normal", 512, 512, false);
}
[Test]
public void DecompressBC6HBestTest()
{
AssertCorrectBC6HDecompression(PathConstants.BcTestFilesFolder + "test.bc6h_best", 512, 512, false);
}
[Test]
public void DecompressBC7FastTest()
{
AssertCorrectBC7Decompression(PathConstants.BcTestFilesFolder + "test.bc7_fast", 512, 512);
}
[Test]
public void DecompressBC7NormalTest()
{
AssertCorrectBC7Decompression(PathConstants.BcTestFilesFolder + "test.bc7_normal", 512, 512);
}
[Test]
public void DecompressBC7BestTest()
{
AssertCorrectBC7Decompression(PathConstants.BcTestFilesFolder + "test.bc7_best", 512, 512);
}
private static void AssertCorrectBC6HDecompression(string path, int width, int height, bool isSigned)
{
ReadOnlySpan<byte> data = File.ReadAllBytes(path);
int bytesRead = Bc6h.Decompress(data, width, height, isSigned, out byte[] decodedData);
Assert.That(bytesRead, Is.EqualTo(data.Length));
AssertMinimalDeviation(decodedData, originalBgra32LogoData, MaxMeanDeviationBc6h, MaxStandardDeviationBc6h);
}
private static void AssertCorrectBC7Decompression(string path, int width, int height)
{
ReadOnlySpan<byte> data = File.ReadAllBytes(path);
int bytesRead = Bc7.Decompress(data, width, height, out byte[] decodedData);
Assert.That(bytesRead, Is.EqualTo(data.Length));
AssertMinimalDeviation(decodedData, originalBgra32LogoData, MaxMeanDeviationBc7, MaxStandardDeviationBc7);
}
private static void AssertAlmostEqual(byte[] array1, byte[] array2, int maxDifference = 2)
{
if (array1.Length != array2.Length)
{
Assert.Fail($"Differing array lengths\nArray 1 length {array1.Length}\nArray 2 length {array2.Length}");
return;
}
for (int i = 0; i < array1.Length; i++)
{
int difference = Math.Abs(array1[i] - array2[i]);
if (difference > maxDifference)
{
Assert.Fail($"Differing values at index {i}\nArray 1: {array1[i]}\nArray 2: {array2[i]}");
return;
}
}
}
private static void AssertMinimalDeviation(byte[] decoded, byte[] original, double maxMeanDeviation, double maxStandardDeviation)
{
if (decoded.Length != original.Length)
{
Assert.Fail($"Differing array lengths\nDecoded length {decoded.Length}\nOriginal length {original.Length}");
return;
}
long differenceSum = 0;
for (int i = 0; i < decoded.Length; i++)
{
differenceSum += decoded[i] - original[i];
}
double mean = differenceSum / (double)decoded.Length;
double sumOfSquaredDeviations = 0;
for (int i = 0; i < decoded.Length; i++)
{
double deviation = decoded[i] - original[i] - mean;
sumOfSquaredDeviations += deviation * deviation;
}
double standardDeviation = Math.Sqrt(sumOfSquaredDeviations / (decoded.Length - 1));
//Not sure if Bessel's correction is needed here, but it doesn't hurt, especially since length is around 1 million in the current use.
Assert.Multiple(() =>
{
Assert.That(mean, Is.LessThan(maxMeanDeviation), "Mean too far positive");
Assert.That(mean, Is.GreaterThan(-maxMeanDeviation), "Mean too far negative");
Assert.That(standardDeviation, Is.LessThan(maxStandardDeviation), "Standard deviation too large");
});
}
}
}
@@ -0,0 +1,44 @@
namespace AssetRipper.TextureDecoder.Tests
{
public sealed class DxtTests
{
[Test]
public void DecompressDXT1Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.DxtTestFilesFolder + "test.dxt1");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Dxt.DxtDecoder.DecompressDXT1(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressDXT3Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.DxtTestFilesFolder + "test.dxt3");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Dxt.DxtDecoder.DecompressDXT3(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressDXT5Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.DxtTestFilesFolder + "test.dxt5");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Dxt.DxtDecoder.DecompressDXT5(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
}
}
@@ -0,0 +1,109 @@
namespace AssetRipper.TextureDecoder.Tests
{
public sealed class EtcTests
{
[Test]
public void DecompressETCTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.EtcTestFilesFolder + "test.etc");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Etc.EtcDecoder.DecompressETC(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressETC2Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.EtcTestFilesFolder + "test.etc2");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Etc.EtcDecoder.DecompressETC2(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressETC2A1Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.EtcTestFilesFolder + "test.etc2a1");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Etc.EtcDecoder.DecompressETC2A1(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressETC2A8Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.EtcTestFilesFolder + "test.etc2a8");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Etc.EtcDecoder.DecompressETC2A8(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressEACRSignedTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.EtcTestFilesFolder + "test.eac_r");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Etc.EtcDecoder.DecompressEACRSigned(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressEACRUnsignedTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.EtcTestFilesFolder + "test.eac_r");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Etc.EtcDecoder.DecompressEACRUnsigned(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressEACRGSignedTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.EtcTestFilesFolder + "test.eac_rg");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Etc.EtcDecoder.DecompressEACRGSigned(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void DecompressEACRGUnsignedTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.EtcTestFilesFolder + "test.eac_rg");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Etc.EtcDecoder.DecompressEACRGUnsigned(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
}
}
@@ -0,0 +1,219 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorA8Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorA8>(), Is.EqualTo(1));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorA8 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorA8IsLossless()
{
ColorA8 original = MakeRandomColor();
ColorA8 converted = original.Convert<ColorA8, byte, ColorA8, byte>();
ColorA8 convertedBack = converted.Convert<ColorA8, byte, ColorA8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorA8 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorA8, byte, ColorARGB32, byte>();
ColorA8 convertedBack = converted.Convert<ColorARGB32, byte, ColorA8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorA8 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorA8, byte, ColorBGRA32, byte>();
ColorA8 convertedBack = converted.Convert<ColorBGRA32, byte, ColorA8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorA8 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorA8, byte, ColorRGBA32, byte>();
ColorA8 convertedBack = converted.Convert<ColorRGBA32, byte, ColorA8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorA8 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorA8, byte, ColorRGBA32Signed, sbyte>();
ColorA8 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorA8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorA8 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorA8, byte, ColorRGBA64, ushort>();
ColorA8 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorA8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorA8 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorA8, byte, ColorRGBA64Signed, short>();
ColorA8 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorA8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorARGB16Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorARGB16>(), Is.EqualTo(2));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorARGB16 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorARGB16 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorARGB16, byte, ColorARGB32, byte>();
ColorARGB16 convertedBack = converted.Convert<ColorARGB32, byte, ColorARGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorARGB16 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorARGB16, byte, ColorBGRA32, byte>();
ColorARGB16 convertedBack = converted.Convert<ColorBGRA32, byte, ColorARGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorARGB16 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorARGB16, byte, ColorRGBA32, byte>();
ColorARGB16 convertedBack = converted.Convert<ColorRGBA32, byte, ColorARGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorARGB16 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorARGB16, byte, ColorRGBA32Signed, sbyte>();
ColorARGB16 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorARGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorARGB16 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorARGB16, byte, ColorRGBA64, ushort>();
ColorARGB16 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorARGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorARGB16 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorARGB16, byte, ColorRGBA64Signed, short>();
ColorARGB16 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorARGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorARGB32Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorARGB32>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorARGB32 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorARGB32 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorARGB32, byte, ColorARGB32, byte>();
ColorARGB32 convertedBack = converted.Convert<ColorARGB32, byte, ColorARGB32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorARGB32 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorARGB32, byte, ColorBGRA32, byte>();
ColorARGB32 convertedBack = converted.Convert<ColorBGRA32, byte, ColorARGB32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorARGB32 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorARGB32, byte, ColorRGBA32, byte>();
ColorARGB32 convertedBack = converted.Convert<ColorRGBA32, byte, ColorARGB32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorARGB32 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorARGB32, byte, ColorRGBA32Signed, sbyte>();
ColorARGB32 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorARGB32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorARGB32 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorARGB32, byte, ColorRGBA64, ushort>();
ColorARGB32 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorARGB32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorARGB32 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorARGB32, byte, ColorRGBA64Signed, short>();
ColorARGB32 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorARGB32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorBGRA32Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorBGRA32>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorBGRA32 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorBGRA32 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorBGRA32, byte, ColorARGB32, byte>();
ColorBGRA32 convertedBack = converted.Convert<ColorARGB32, byte, ColorBGRA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorBGRA32 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorBGRA32, byte, ColorBGRA32, byte>();
ColorBGRA32 convertedBack = converted.Convert<ColorBGRA32, byte, ColorBGRA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorBGRA32 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorBGRA32, byte, ColorRGBA32, byte>();
ColorBGRA32 convertedBack = converted.Convert<ColorRGBA32, byte, ColorBGRA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorBGRA32 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorBGRA32, byte, ColorRGBA32Signed, sbyte>();
ColorBGRA32 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorBGRA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorBGRA32 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorBGRA32, byte, ColorRGBA64, ushort>();
ColorBGRA32 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorBGRA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorBGRA32 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorBGRA32, byte, ColorRGBA64Signed, short>();
ColorBGRA32 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorBGRA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,264 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorR16HalfTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorR16Half>(), Is.EqualTo(2));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorR16Half MakeRandomColor()
{
return new()
{
R = (Half)0.447f,
G = (Half)0.224f,
B = (Half)0.95f,
A = (Half)0.897f,
};
}
[Test]
public void ConversionToColorR16HalfIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorR16Half converted = original.Convert<ColorR16Half, Half, ColorR16Half, Half>();
ColorR16Half convertedBack = converted.Convert<ColorR16Half, Half, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR32SingleIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorR32Single converted = original.Convert<ColorR16Half, Half, ColorR32Single, float>();
ColorR16Half convertedBack = converted.Convert<ColorR32Single, float, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR64DoubleIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorR64Double converted = original.Convert<ColorR16Half, Half, ColorR64Double, double>();
ColorR16Half convertedBack = converted.Convert<ColorR64Double, double, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32HalfIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRG32Half converted = original.Convert<ColorR16Half, Half, ColorRG32Half, Half>();
ColorR16Half convertedBack = converted.Convert<ColorRG32Half, Half, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG64SingleIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRG64Single converted = original.Convert<ColorR16Half, Half, ColorRG64Single, float>();
ColorR16Half convertedBack = converted.Convert<ColorRG64Single, float, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG128DoubleIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRG128Double converted = original.Convert<ColorR16Half, Half, ColorRG128Double, double>();
ColorR16Half convertedBack = converted.Convert<ColorRG128Double, double, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48HalfIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRGB48Half converted = original.Convert<ColorR16Half, Half, ColorRGB48Half, Half>();
ColorR16Half convertedBack = converted.Convert<ColorRGB48Half, Half, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB96SingleIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRGB96Single converted = original.Convert<ColorR16Half, Half, ColorRGB96Single, float>();
ColorR16Half convertedBack = converted.Convert<ColorRGB96Single, float, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorR16Half, Half, ColorRGB192Double, double>();
ColorR16Half convertedBack = converted.Convert<ColorRGB192Double, double, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorR16Half, Half, ColorRGBA128Single, float>();
ColorR16Half convertedBack = converted.Convert<ColorRGBA128Single, float, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorR16Half, Half, ColorRGBA256Double, double>();
ColorR16Half convertedBack = converted.Convert<ColorRGBA256Double, double, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64HalfIsLossless()
{
ColorR16Half original = MakeRandomColor();
ColorRGBA64Half converted = original.Convert<ColorR16Half, Half, ColorRGBA64Half, Half>();
ColorR16Half convertedBack = converted.Convert<ColorRGBA64Half, Half, ColorR16Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,228 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorR16SignedTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorR16Signed>(), Is.EqualTo(2));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 31871;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorR16Signed MakeRandomColor()
{
return new()
{
R = -24000,
G = 21354,
B = -80,
A = 347,
};
}
[Test]
public void ConversionToColorR16IsLossless()
{
ColorR16Signed original = MakeRandomColor();
ColorR16 converted = original.Convert<ColorR16Signed, short, ColorR16, ushort>();
ColorR16Signed convertedBack = converted.Convert<ColorR16, ushort, ColorR16Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR16SignedIsLossless()
{
ColorR16Signed original = MakeRandomColor();
ColorR16Signed converted = original.Convert<ColorR16Signed, short, ColorR16Signed, short>();
ColorR16Signed convertedBack = converted.Convert<ColorR16Signed, short, ColorR16Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32IsLossless()
{
ColorR16Signed original = MakeRandomColor();
ColorRG32 converted = original.Convert<ColorR16Signed, short, ColorRG32, ushort>();
ColorR16Signed convertedBack = converted.Convert<ColorRG32, ushort, ColorR16Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32SignedIsLossless()
{
ColorR16Signed original = MakeRandomColor();
ColorRG32Signed converted = original.Convert<ColorR16Signed, short, ColorRG32Signed, short>();
ColorR16Signed convertedBack = converted.Convert<ColorRG32Signed, short, ColorR16Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorR16Signed original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorR16Signed, short, ColorRGB48, ushort>();
ColorR16Signed convertedBack = converted.Convert<ColorRGB48, ushort, ColorR16Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorR16Signed original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorR16Signed, short, ColorRGB48Signed, short>();
ColorR16Signed convertedBack = converted.Convert<ColorRGB48Signed, short, ColorR16Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorR16Signed original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorR16Signed, short, ColorRGBA64, ushort>();
ColorR16Signed convertedBack = converted.Convert<ColorRGBA64, ushort, ColorR16Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorR16Signed original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorR16Signed, short, ColorRGBA64Signed, short>();
ColorR16Signed convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorR16Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,228 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorR16Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorR16>(), Is.EqualTo(2));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 33871;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorR16 MakeRandomColor()
{
return new()
{
R = 44000,
G = 21354,
B = 60080,
A = 347,
};
}
[Test]
public void ConversionToColorR16IsLossless()
{
ColorR16 original = MakeRandomColor();
ColorR16 converted = original.Convert<ColorR16, ushort, ColorR16, ushort>();
ColorR16 convertedBack = converted.Convert<ColorR16, ushort, ColorR16, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR16SignedIsLossless()
{
ColorR16 original = MakeRandomColor();
ColorR16Signed converted = original.Convert<ColorR16, ushort, ColorR16Signed, short>();
ColorR16 convertedBack = converted.Convert<ColorR16Signed, short, ColorR16, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32IsLossless()
{
ColorR16 original = MakeRandomColor();
ColorRG32 converted = original.Convert<ColorR16, ushort, ColorRG32, ushort>();
ColorR16 convertedBack = converted.Convert<ColorRG32, ushort, ColorR16, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32SignedIsLossless()
{
ColorR16 original = MakeRandomColor();
ColorRG32Signed converted = original.Convert<ColorR16, ushort, ColorRG32Signed, short>();
ColorR16 convertedBack = converted.Convert<ColorRG32Signed, short, ColorR16, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorR16 original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorR16, ushort, ColorRGB48, ushort>();
ColorR16 convertedBack = converted.Convert<ColorRGB48, ushort, ColorR16, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorR16 original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorR16, ushort, ColorRGB48Signed, short>();
ColorR16 convertedBack = converted.Convert<ColorRGB48Signed, short, ColorR16, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorR16 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorR16, ushort, ColorRGBA64, ushort>();
ColorR16 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorR16, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorR16 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorR16, ushort, ColorRGBA64Signed, short>();
ColorR16 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorR16, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,228 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorR32SingleTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorR32Single>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorR32Single MakeRandomColor()
{
return new()
{
R = 0.447f,
G = 0.224f,
B = 0.95f,
A = 0.897f,
};
}
[Test]
public void ConversionToColorR32SingleIsLossless()
{
ColorR32Single original = MakeRandomColor();
ColorR32Single converted = original.Convert<ColorR32Single, float, ColorR32Single, float>();
ColorR32Single convertedBack = converted.Convert<ColorR32Single, float, ColorR32Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR64DoubleIsLossless()
{
ColorR32Single original = MakeRandomColor();
ColorR64Double converted = original.Convert<ColorR32Single, float, ColorR64Double, double>();
ColorR32Single convertedBack = converted.Convert<ColorR64Double, double, ColorR32Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG64SingleIsLossless()
{
ColorR32Single original = MakeRandomColor();
ColorRG64Single converted = original.Convert<ColorR32Single, float, ColorRG64Single, float>();
ColorR32Single convertedBack = converted.Convert<ColorRG64Single, float, ColorR32Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG128DoubleIsLossless()
{
ColorR32Single original = MakeRandomColor();
ColorRG128Double converted = original.Convert<ColorR32Single, float, ColorRG128Double, double>();
ColorR32Single convertedBack = converted.Convert<ColorRG128Double, double, ColorR32Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB96SingleIsLossless()
{
ColorR32Single original = MakeRandomColor();
ColorRGB96Single converted = original.Convert<ColorR32Single, float, ColorRGB96Single, float>();
ColorR32Single convertedBack = converted.Convert<ColorRGB96Single, float, ColorR32Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorR32Single original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorR32Single, float, ColorRGB192Double, double>();
ColorR32Single convertedBack = converted.Convert<ColorRGB192Double, double, ColorR32Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorR32Single original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorR32Single, float, ColorRGBA128Single, float>();
ColorR32Single convertedBack = converted.Convert<ColorRGBA128Single, float, ColorR32Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorR32Single original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorR32Single, float, ColorRGBA256Double, double>();
ColorR32Single convertedBack = converted.Convert<ColorRGBA256Double, double, ColorR32Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,192 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorR64DoubleTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorR64Double>(), Is.EqualTo(8));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorR64Double MakeRandomColor()
{
return new()
{
R = 0.447,
G = 0.224,
B = 0.95,
A = 0.897,
};
}
[Test]
public void ConversionToColorR64DoubleIsLossless()
{
ColorR64Double original = MakeRandomColor();
ColorR64Double converted = original.Convert<ColorR64Double, double, ColorR64Double, double>();
ColorR64Double convertedBack = converted.Convert<ColorR64Double, double, ColorR64Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG128DoubleIsLossless()
{
ColorR64Double original = MakeRandomColor();
ColorRG128Double converted = original.Convert<ColorR64Double, double, ColorRG128Double, double>();
ColorR64Double convertedBack = converted.Convert<ColorRG128Double, double, ColorR64Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorR64Double original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorR64Double, double, ColorRGB192Double, double>();
ColorR64Double convertedBack = converted.Convert<ColorRGB192Double, double, ColorR64Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorR64Double original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorR64Double, double, ColorRGBA256Double, double>();
ColorR64Double convertedBack = converted.Convert<ColorRGBA256Double, double, ColorR64Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,318 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorR8SignedTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorR8Signed>(), Is.EqualTo(1));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorR8Signed MakeRandomColor()
{
return new()
{
R = -0b01010101,
G = 0b01110010,
B = -0b00001111,
A = -0b01000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorR8Signed, sbyte, ColorARGB32, byte>();
ColorR8Signed convertedBack = converted.Convert<ColorARGB32, byte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorR8Signed, sbyte, ColorBGRA32, byte>();
ColorR8Signed convertedBack = converted.Convert<ColorBGRA32, byte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR16IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorR16 converted = original.Convert<ColorR8Signed, sbyte, ColorR16, ushort>();
ColorR8Signed convertedBack = converted.Convert<ColorR16, ushort, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR16SignedIsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorR16Signed converted = original.Convert<ColorR8Signed, sbyte, ColorR16Signed, short>();
ColorR8Signed convertedBack = converted.Convert<ColorR16Signed, short, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR8IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorR8 converted = original.Convert<ColorR8Signed, sbyte, ColorR8, byte>();
ColorR8Signed convertedBack = converted.Convert<ColorR8, byte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR8SignedIsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorR8Signed converted = original.Convert<ColorR8Signed, sbyte, ColorR8Signed, sbyte>();
ColorR8Signed convertedBack = converted.Convert<ColorR8Signed, sbyte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG16IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRG16 converted = original.Convert<ColorR8Signed, sbyte, ColorRG16, byte>();
ColorR8Signed convertedBack = converted.Convert<ColorRG16, byte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG16SignedIsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRG16Signed converted = original.Convert<ColorR8Signed, sbyte, ColorRG16Signed, sbyte>();
ColorR8Signed convertedBack = converted.Convert<ColorRG16Signed, sbyte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRG32 converted = original.Convert<ColorR8Signed, sbyte, ColorRG32, ushort>();
ColorR8Signed convertedBack = converted.Convert<ColorRG32, ushort, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32SignedIsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRG32Signed converted = original.Convert<ColorR8Signed, sbyte, ColorRG32Signed, short>();
ColorR8Signed convertedBack = converted.Convert<ColorRG32Signed, short, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRGB24 converted = original.Convert<ColorR8Signed, sbyte, ColorRGB24, byte>();
ColorR8Signed convertedBack = converted.Convert<ColorRGB24, byte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24SignedIsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRGB24Signed converted = original.Convert<ColorR8Signed, sbyte, ColorRGB24Signed, sbyte>();
ColorR8Signed convertedBack = converted.Convert<ColorRGB24Signed, sbyte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorR8Signed, sbyte, ColorRGB48, ushort>();
ColorR8Signed convertedBack = converted.Convert<ColorRGB48, ushort, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorR8Signed, sbyte, ColorRGB48Signed, short>();
ColorR8Signed convertedBack = converted.Convert<ColorRGB48Signed, short, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorR8Signed, sbyte, ColorRGBA32, byte>();
ColorR8Signed convertedBack = converted.Convert<ColorRGBA32, byte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorR8Signed, sbyte, ColorRGBA32Signed, sbyte>();
ColorR8Signed convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorR8Signed, sbyte, ColorRGBA64, ushort>();
ColorR8Signed convertedBack = converted.Convert<ColorRGBA64, ushort, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorR8Signed original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorR8Signed, sbyte, ColorRGBA64Signed, short>();
ColorR8Signed convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorR8Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,318 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorR8Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorR8>(), Is.EqualTo(1));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorR8 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorR8, byte, ColorARGB32, byte>();
ColorR8 convertedBack = converted.Convert<ColorARGB32, byte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorR8, byte, ColorBGRA32, byte>();
ColorR8 convertedBack = converted.Convert<ColorBGRA32, byte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR16IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorR16 converted = original.Convert<ColorR8, byte, ColorR16, ushort>();
ColorR8 convertedBack = converted.Convert<ColorR16, ushort, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR16SignedIsLossless()
{
ColorR8 original = MakeRandomColor();
ColorR16Signed converted = original.Convert<ColorR8, byte, ColorR16Signed, short>();
ColorR8 convertedBack = converted.Convert<ColorR16Signed, short, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR8IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorR8 converted = original.Convert<ColorR8, byte, ColorR8, byte>();
ColorR8 convertedBack = converted.Convert<ColorR8, byte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorR8SignedIsLossless()
{
ColorR8 original = MakeRandomColor();
ColorR8Signed converted = original.Convert<ColorR8, byte, ColorR8Signed, sbyte>();
ColorR8 convertedBack = converted.Convert<ColorR8Signed, sbyte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG16IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRG16 converted = original.Convert<ColorR8, byte, ColorRG16, byte>();
ColorR8 convertedBack = converted.Convert<ColorRG16, byte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG16SignedIsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRG16Signed converted = original.Convert<ColorR8, byte, ColorRG16Signed, sbyte>();
ColorR8 convertedBack = converted.Convert<ColorRG16Signed, sbyte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRG32 converted = original.Convert<ColorR8, byte, ColorRG32, ushort>();
ColorR8 convertedBack = converted.Convert<ColorRG32, ushort, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32SignedIsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRG32Signed converted = original.Convert<ColorR8, byte, ColorRG32Signed, short>();
ColorR8 convertedBack = converted.Convert<ColorRG32Signed, short, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRGB24 converted = original.Convert<ColorR8, byte, ColorRGB24, byte>();
ColorR8 convertedBack = converted.Convert<ColorRGB24, byte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24SignedIsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRGB24Signed converted = original.Convert<ColorR8, byte, ColorRGB24Signed, sbyte>();
ColorR8 convertedBack = converted.Convert<ColorRGB24Signed, sbyte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorR8, byte, ColorRGB48, ushort>();
ColorR8 convertedBack = converted.Convert<ColorRGB48, ushort, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorR8, byte, ColorRGB48Signed, short>();
ColorR8 convertedBack = converted.Convert<ColorRGB48Signed, short, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorR8, byte, ColorRGBA32, byte>();
ColorR8 convertedBack = converted.Convert<ColorRGBA32, byte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorR8, byte, ColorRGBA32Signed, sbyte>();
ColorR8 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorR8, byte, ColorRGBA64, ushort>();
ColorR8 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorR8 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorR8, byte, ColorRGBA64Signed, short>();
ColorR8 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorR8, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,183 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRG128DoubleTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRG128Double>(), Is.EqualTo(16));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRG128Double MakeRandomColor()
{
return new()
{
R = 0.447,
G = 0.224,
B = 0.95,
A = 0.897,
};
}
[Test]
public void ConversionToColorRG128DoubleIsLossless()
{
ColorRG128Double original = MakeRandomColor();
ColorRG128Double converted = original.Convert<ColorRG128Double, double, ColorRG128Double, double>();
ColorRG128Double convertedBack = converted.Convert<ColorRG128Double, double, ColorRG128Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorRG128Double original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorRG128Double, double, ColorRGB192Double, double>();
ColorRG128Double convertedBack = converted.Convert<ColorRGB192Double, double, ColorRG128Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRG128Double original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRG128Double, double, ColorRGBA256Double, double>();
ColorRG128Double convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRG128Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,282 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRG16SignedTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRG16Signed>(), Is.EqualTo(2));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRG16Signed MakeRandomColor()
{
return new()
{
R = -0b01010101,
G = 0b01110010,
B = -0b00001111,
A = -0b01000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorRG16Signed, sbyte, ColorARGB32, byte>();
ColorRG16Signed convertedBack = converted.Convert<ColorARGB32, byte, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorRG16Signed, sbyte, ColorBGRA32, byte>();
ColorRG16Signed convertedBack = converted.Convert<ColorBGRA32, byte, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG16IsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRG16 converted = original.Convert<ColorRG16Signed, sbyte, ColorRG16, byte>();
ColorRG16Signed convertedBack = converted.Convert<ColorRG16, byte, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG16SignedIsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRG16Signed converted = original.Convert<ColorRG16Signed, sbyte, ColorRG16Signed, sbyte>();
ColorRG16Signed convertedBack = converted.Convert<ColorRG16Signed, sbyte, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32IsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRG32 converted = original.Convert<ColorRG16Signed, sbyte, ColorRG32, ushort>();
ColorRG16Signed convertedBack = converted.Convert<ColorRG32, ushort, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32SignedIsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRG32Signed converted = original.Convert<ColorRG16Signed, sbyte, ColorRG32Signed, short>();
ColorRG16Signed convertedBack = converted.Convert<ColorRG32Signed, short, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24IsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRGB24 converted = original.Convert<ColorRG16Signed, sbyte, ColorRGB24, byte>();
ColorRG16Signed convertedBack = converted.Convert<ColorRGB24, byte, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24SignedIsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRGB24Signed converted = original.Convert<ColorRG16Signed, sbyte, ColorRGB24Signed, sbyte>();
ColorRG16Signed convertedBack = converted.Convert<ColorRGB24Signed, sbyte, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRG16Signed, sbyte, ColorRGB48, ushort>();
ColorRG16Signed convertedBack = converted.Convert<ColorRGB48, ushort, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRG16Signed, sbyte, ColorRGB48Signed, short>();
ColorRG16Signed convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorRG16Signed, sbyte, ColorRGBA32, byte>();
ColorRG16Signed convertedBack = converted.Convert<ColorRGBA32, byte, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorRG16Signed, sbyte, ColorRGBA32Signed, sbyte>();
ColorRG16Signed convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRG16Signed, sbyte, ColorRGBA64, ushort>();
ColorRG16Signed convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRG16Signed original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRG16Signed, sbyte, ColorRGBA64Signed, short>();
ColorRG16Signed convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRG16Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,282 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRG16Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRG16>(), Is.EqualTo(2));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRG16 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorRG16, byte, ColorARGB32, byte>();
ColorRG16 convertedBack = converted.Convert<ColorARGB32, byte, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorRG16, byte, ColorBGRA32, byte>();
ColorRG16 convertedBack = converted.Convert<ColorBGRA32, byte, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG16IsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRG16 converted = original.Convert<ColorRG16, byte, ColorRG16, byte>();
ColorRG16 convertedBack = converted.Convert<ColorRG16, byte, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG16SignedIsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRG16Signed converted = original.Convert<ColorRG16, byte, ColorRG16Signed, sbyte>();
ColorRG16 convertedBack = converted.Convert<ColorRG16Signed, sbyte, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32IsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRG32 converted = original.Convert<ColorRG16, byte, ColorRG32, ushort>();
ColorRG16 convertedBack = converted.Convert<ColorRG32, ushort, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32SignedIsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRG32Signed converted = original.Convert<ColorRG16, byte, ColorRG32Signed, short>();
ColorRG16 convertedBack = converted.Convert<ColorRG32Signed, short, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24IsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRGB24 converted = original.Convert<ColorRG16, byte, ColorRGB24, byte>();
ColorRG16 convertedBack = converted.Convert<ColorRGB24, byte, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24SignedIsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRGB24Signed converted = original.Convert<ColorRG16, byte, ColorRGB24Signed, sbyte>();
ColorRG16 convertedBack = converted.Convert<ColorRGB24Signed, sbyte, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRG16, byte, ColorRGB48, ushort>();
ColorRG16 convertedBack = converted.Convert<ColorRGB48, ushort, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRG16, byte, ColorRGB48Signed, short>();
ColorRG16 convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorRG16, byte, ColorRGBA32, byte>();
ColorRG16 convertedBack = converted.Convert<ColorRGBA32, byte, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorRG16, byte, ColorRGBA32Signed, sbyte>();
ColorRG16 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRG16, byte, ColorRGBA64, ushort>();
ColorRG16 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRG16 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRG16, byte, ColorRGBA64Signed, short>();
ColorRG16 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRG16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,237 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRG32HalfTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRG32Half>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRG32Half MakeRandomColor()
{
return new()
{
R = (Half)0.447f,
G = (Half)0.224f,
B = (Half)0.95f,
A = (Half)0.897f,
};
}
[Test]
public void ConversionToColorRG32HalfIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRG32Half converted = original.Convert<ColorRG32Half, Half, ColorRG32Half, Half>();
ColorRG32Half convertedBack = converted.Convert<ColorRG32Half, Half, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG64SingleIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRG64Single converted = original.Convert<ColorRG32Half, Half, ColorRG64Single, float>();
ColorRG32Half convertedBack = converted.Convert<ColorRG64Single, float, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG128DoubleIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRG128Double converted = original.Convert<ColorRG32Half, Half, ColorRG128Double, double>();
ColorRG32Half convertedBack = converted.Convert<ColorRG128Double, double, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48HalfIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRGB48Half converted = original.Convert<ColorRG32Half, Half, ColorRGB48Half, Half>();
ColorRG32Half convertedBack = converted.Convert<ColorRGB48Half, Half, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB96SingleIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRGB96Single converted = original.Convert<ColorRG32Half, Half, ColorRGB96Single, float>();
ColorRG32Half convertedBack = converted.Convert<ColorRGB96Single, float, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorRG32Half, Half, ColorRGB192Double, double>();
ColorRG32Half convertedBack = converted.Convert<ColorRGB192Double, double, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorRG32Half, Half, ColorRGBA128Single, float>();
ColorRG32Half convertedBack = converted.Convert<ColorRGBA128Single, float, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRG32Half, Half, ColorRGBA256Double, double>();
ColorRG32Half convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64HalfIsLossless()
{
ColorRG32Half original = MakeRandomColor();
ColorRGBA64Half converted = original.Convert<ColorRG32Half, Half, ColorRGBA64Half, Half>();
ColorRG32Half convertedBack = converted.Convert<ColorRGBA64Half, Half, ColorRG32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRG32SignedTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRG32Signed>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 31871;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRG32Signed MakeRandomColor()
{
return new()
{
R = -24000,
G = 21354,
B = -80,
A = 347,
};
}
[Test]
public void ConversionToColorRG32IsLossless()
{
ColorRG32Signed original = MakeRandomColor();
ColorRG32 converted = original.Convert<ColorRG32Signed, short, ColorRG32, ushort>();
ColorRG32Signed convertedBack = converted.Convert<ColorRG32, ushort, ColorRG32Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32SignedIsLossless()
{
ColorRG32Signed original = MakeRandomColor();
ColorRG32Signed converted = original.Convert<ColorRG32Signed, short, ColorRG32Signed, short>();
ColorRG32Signed convertedBack = converted.Convert<ColorRG32Signed, short, ColorRG32Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRG32Signed original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRG32Signed, short, ColorRGB48, ushort>();
ColorRG32Signed convertedBack = converted.Convert<ColorRGB48, ushort, ColorRG32Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRG32Signed original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRG32Signed, short, ColorRGB48Signed, short>();
ColorRG32Signed convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRG32Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRG32Signed original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRG32Signed, short, ColorRGBA64, ushort>();
ColorRG32Signed convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRG32Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRG32Signed original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRG32Signed, short, ColorRGBA64Signed, short>();
ColorRG32Signed convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRG32Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRG32Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRG32>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 33871;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRG32 MakeRandomColor()
{
return new()
{
R = 44000,
G = 21354,
B = 60080,
A = 347,
};
}
[Test]
public void ConversionToColorRG32IsLossless()
{
ColorRG32 original = MakeRandomColor();
ColorRG32 converted = original.Convert<ColorRG32, ushort, ColorRG32, ushort>();
ColorRG32 convertedBack = converted.Convert<ColorRG32, ushort, ColorRG32, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG32SignedIsLossless()
{
ColorRG32 original = MakeRandomColor();
ColorRG32Signed converted = original.Convert<ColorRG32, ushort, ColorRG32Signed, short>();
ColorRG32 convertedBack = converted.Convert<ColorRG32Signed, short, ColorRG32, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRG32 original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRG32, ushort, ColorRGB48, ushort>();
ColorRG32 convertedBack = converted.Convert<ColorRGB48, ushort, ColorRG32, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRG32 original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRG32, ushort, ColorRGB48Signed, short>();
ColorRG32 convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRG32, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRG32 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRG32, ushort, ColorRGBA64, ushort>();
ColorRG32 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRG32, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRG32 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRG32, ushort, ColorRGBA64Signed, short>();
ColorRG32 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRG32, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRG64SingleTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRG64Single>(), Is.EqualTo(8));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRG64Single MakeRandomColor()
{
return new()
{
R = 0.447f,
G = 0.224f,
B = 0.95f,
A = 0.897f,
};
}
[Test]
public void ConversionToColorRG64SingleIsLossless()
{
ColorRG64Single original = MakeRandomColor();
ColorRG64Single converted = original.Convert<ColorRG64Single, float, ColorRG64Single, float>();
ColorRG64Single convertedBack = converted.Convert<ColorRG64Single, float, ColorRG64Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRG128DoubleIsLossless()
{
ColorRG64Single original = MakeRandomColor();
ColorRG128Double converted = original.Convert<ColorRG64Single, float, ColorRG128Double, double>();
ColorRG64Single convertedBack = converted.Convert<ColorRG128Double, double, ColorRG64Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB96SingleIsLossless()
{
ColorRG64Single original = MakeRandomColor();
ColorRGB96Single converted = original.Convert<ColorRG64Single, float, ColorRGB96Single, float>();
ColorRG64Single convertedBack = converted.Convert<ColorRGB96Single, float, ColorRG64Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorRG64Single original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorRG64Single, float, ColorRGB192Double, double>();
ColorRG64Single convertedBack = converted.Convert<ColorRGB192Double, double, ColorRG64Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorRG64Single original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorRG64Single, float, ColorRGBA128Single, float>();
ColorRG64Single convertedBack = converted.Convert<ColorRGBA128Single, float, ColorRG64Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRG64Single original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRG64Single, float, ColorRGBA256Double, double>();
ColorRG64Single convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRG64Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,246 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB16Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB16>(), Is.EqualTo(2));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB16 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorRGB16, byte, ColorARGB32, byte>();
ColorRGB16 convertedBack = converted.Convert<ColorARGB32, byte, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorRGB16, byte, ColorBGRA32, byte>();
ColorRGB16 convertedBack = converted.Convert<ColorBGRA32, byte, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24IsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorRGB24 converted = original.Convert<ColorRGB16, byte, ColorRGB24, byte>();
ColorRGB16 convertedBack = converted.Convert<ColorRGB24, byte, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24SignedIsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorRGB24Signed converted = original.Convert<ColorRGB16, byte, ColorRGB24Signed, sbyte>();
ColorRGB16 convertedBack = converted.Convert<ColorRGB24Signed, sbyte, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRGB16, byte, ColorRGB48, ushort>();
ColorRGB16 convertedBack = converted.Convert<ColorRGB48, ushort, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRGB16, byte, ColorRGB48Signed, short>();
ColorRGB16 convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorRGB16, byte, ColorRGBA32, byte>();
ColorRGB16 convertedBack = converted.Convert<ColorRGBA32, byte, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorRGB16, byte, ColorRGBA32Signed, sbyte>();
ColorRGB16 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGB16, byte, ColorRGBA64, ushort>();
ColorRGB16 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGB16 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGB16, byte, ColorRGBA64Signed, short>();
ColorRGB16 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGB16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,174 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB192DoubleTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB192Double>(), Is.EqualTo(24));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB192Double MakeRandomColor()
{
return new()
{
R = 0.447,
G = 0.224,
B = 0.95,
A = 0.897,
};
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorRGB192Double original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorRGB192Double, double, ColorRGB192Double, double>();
ColorRGB192Double convertedBack = converted.Convert<ColorRGB192Double, double, ColorRGB192Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRGB192Double original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRGB192Double, double, ColorRGBA256Double, double>();
ColorRGB192Double convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRGB192Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,246 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB24SignedTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB24Signed>(), Is.EqualTo(3));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB24Signed MakeRandomColor()
{
return new()
{
R = -0b01010101,
G = 0b01110010,
B = -0b00001111,
A = -0b01000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorRGB24Signed, sbyte, ColorARGB32, byte>();
ColorRGB24Signed convertedBack = converted.Convert<ColorARGB32, byte, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorRGB24Signed, sbyte, ColorBGRA32, byte>();
ColorRGB24Signed convertedBack = converted.Convert<ColorBGRA32, byte, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24IsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorRGB24 converted = original.Convert<ColorRGB24Signed, sbyte, ColorRGB24, byte>();
ColorRGB24Signed convertedBack = converted.Convert<ColorRGB24, byte, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24SignedIsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorRGB24Signed converted = original.Convert<ColorRGB24Signed, sbyte, ColorRGB24Signed, sbyte>();
ColorRGB24Signed convertedBack = converted.Convert<ColorRGB24Signed, sbyte, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRGB24Signed, sbyte, ColorRGB48, ushort>();
ColorRGB24Signed convertedBack = converted.Convert<ColorRGB48, ushort, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRGB24Signed, sbyte, ColorRGB48Signed, short>();
ColorRGB24Signed convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorRGB24Signed, sbyte, ColorRGBA32, byte>();
ColorRGB24Signed convertedBack = converted.Convert<ColorRGBA32, byte, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorRGB24Signed, sbyte, ColorRGBA32Signed, sbyte>();
ColorRGB24Signed convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGB24Signed, sbyte, ColorRGBA64, ushort>();
ColorRGB24Signed convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGB24Signed original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGB24Signed, sbyte, ColorRGBA64Signed, short>();
ColorRGB24Signed convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGB24Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,246 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB24Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB24>(), Is.EqualTo(3));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB24 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorRGB24, byte, ColorARGB32, byte>();
ColorRGB24 convertedBack = converted.Convert<ColorARGB32, byte, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorRGB24, byte, ColorBGRA32, byte>();
ColorRGB24 convertedBack = converted.Convert<ColorBGRA32, byte, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24IsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorRGB24 converted = original.Convert<ColorRGB24, byte, ColorRGB24, byte>();
ColorRGB24 convertedBack = converted.Convert<ColorRGB24, byte, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB24SignedIsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorRGB24Signed converted = original.Convert<ColorRGB24, byte, ColorRGB24Signed, sbyte>();
ColorRGB24 convertedBack = converted.Convert<ColorRGB24Signed, sbyte, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRGB24, byte, ColorRGB48, ushort>();
ColorRGB24 convertedBack = converted.Convert<ColorRGB48, ushort, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRGB24, byte, ColorRGB48Signed, short>();
ColorRGB24 convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorRGB24, byte, ColorRGBA32, byte>();
ColorRGB24 convertedBack = converted.Convert<ColorRGBA32, byte, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorRGB24, byte, ColorRGBA32Signed, sbyte>();
ColorRGB24 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGB24, byte, ColorRGBA64, ushort>();
ColorRGB24 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGB24 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGB24, byte, ColorRGBA64Signed, short>();
ColorRGB24 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGB24, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB32HalfTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB32Half>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB32Half MakeRandomColor()
{
return new()
{
R = (Half)0.447f,
G = (Half)0.224f,
B = (Half)0.95f,
A = (Half)0.897f,
};
}
[Test]
public void ConversionToColorRGB48HalfIsLossless()
{
ColorRGB32Half original = MakeRandomColor();
ColorRGB48Half converted = original.Convert<ColorRGB32Half, Half, ColorRGB48Half, Half>();
ColorRGB32Half convertedBack = converted.Convert<ColorRGB48Half, Half, ColorRGB32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB96SingleIsLossless()
{
ColorRGB32Half original = MakeRandomColor();
ColorRGB96Single converted = original.Convert<ColorRGB32Half, Half, ColorRGB96Single, float>();
ColorRGB32Half convertedBack = converted.Convert<ColorRGB96Single, float, ColorRGB32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorRGB32Half original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorRGB32Half, Half, ColorRGB192Double, double>();
ColorRGB32Half convertedBack = converted.Convert<ColorRGB192Double, double, ColorRGB32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorRGB32Half original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorRGB32Half, Half, ColorRGBA128Single, float>();
ColorRGB32Half convertedBack = converted.Convert<ColorRGBA128Single, float, ColorRGB32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRGB32Half original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRGB32Half, Half, ColorRGBA256Double, double>();
ColorRGB32Half convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRGB32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64HalfIsLossless()
{
ColorRGB32Half original = MakeRandomColor();
ColorRGBA64Half converted = original.Convert<ColorRGB32Half, Half, ColorRGBA64Half, Half>();
ColorRGB32Half convertedBack = converted.Convert<ColorRGBA64Half, Half, ColorRGB32Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB48HalfTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB48Half>(), Is.EqualTo(6));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB48Half MakeRandomColor()
{
return new()
{
R = (Half)0.447f,
G = (Half)0.224f,
B = (Half)0.95f,
A = (Half)0.897f,
};
}
[Test]
public void ConversionToColorRGB48HalfIsLossless()
{
ColorRGB48Half original = MakeRandomColor();
ColorRGB48Half converted = original.Convert<ColorRGB48Half, Half, ColorRGB48Half, Half>();
ColorRGB48Half convertedBack = converted.Convert<ColorRGB48Half, Half, ColorRGB48Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB96SingleIsLossless()
{
ColorRGB48Half original = MakeRandomColor();
ColorRGB96Single converted = original.Convert<ColorRGB48Half, Half, ColorRGB96Single, float>();
ColorRGB48Half convertedBack = converted.Convert<ColorRGB96Single, float, ColorRGB48Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorRGB48Half original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorRGB48Half, Half, ColorRGB192Double, double>();
ColorRGB48Half convertedBack = converted.Convert<ColorRGB192Double, double, ColorRGB48Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorRGB48Half original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorRGB48Half, Half, ColorRGBA128Single, float>();
ColorRGB48Half convertedBack = converted.Convert<ColorRGBA128Single, float, ColorRGB48Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRGB48Half original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRGB48Half, Half, ColorRGBA256Double, double>();
ColorRGB48Half convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRGB48Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64HalfIsLossless()
{
ColorRGB48Half original = MakeRandomColor();
ColorRGBA64Half converted = original.Convert<ColorRGB48Half, Half, ColorRGBA64Half, Half>();
ColorRGB48Half convertedBack = converted.Convert<ColorRGBA64Half, Half, ColorRGB48Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,192 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB48SignedTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB48Signed>(), Is.EqualTo(6));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 31871;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB48Signed MakeRandomColor()
{
return new()
{
R = -24000,
G = 21354,
B = -80,
A = 347,
};
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRGB48Signed original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRGB48Signed, short, ColorRGB48, ushort>();
ColorRGB48Signed convertedBack = converted.Convert<ColorRGB48, ushort, ColorRGB48Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRGB48Signed original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRGB48Signed, short, ColorRGB48Signed, short>();
ColorRGB48Signed convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRGB48Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGB48Signed original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGB48Signed, short, ColorRGBA64, ushort>();
ColorRGB48Signed convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGB48Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGB48Signed original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGB48Signed, short, ColorRGBA64Signed, short>();
ColorRGB48Signed convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGB48Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,192 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB48Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB48>(), Is.EqualTo(6));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 33871;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB48 MakeRandomColor()
{
return new()
{
R = 44000,
G = 21354,
B = 60080,
A = 347,
};
}
[Test]
public void ConversionToColorRGB48IsLossless()
{
ColorRGB48 original = MakeRandomColor();
ColorRGB48 converted = original.Convert<ColorRGB48, ushort, ColorRGB48, ushort>();
ColorRGB48 convertedBack = converted.Convert<ColorRGB48, ushort, ColorRGB48, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB48SignedIsLossless()
{
ColorRGB48 original = MakeRandomColor();
ColorRGB48Signed converted = original.Convert<ColorRGB48, ushort, ColorRGB48Signed, short>();
ColorRGB48 convertedBack = converted.Convert<ColorRGB48Signed, short, ColorRGB48, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGB48 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGB48, ushort, ColorRGBA64, ushort>();
ColorRGB48 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGB48, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGB48 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGB48, ushort, ColorRGBA64Signed, short>();
ColorRGB48 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGB48, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,192 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB96SingleTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB96Single>(), Is.EqualTo(12));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB96Single MakeRandomColor()
{
return new()
{
R = 0.447f,
G = 0.224f,
B = 0.95f,
A = 0.897f,
};
}
[Test]
public void ConversionToColorRGB96SingleIsLossless()
{
ColorRGB96Single original = MakeRandomColor();
ColorRGB96Single converted = original.Convert<ColorRGB96Single, float, ColorRGB96Single, float>();
ColorRGB96Single convertedBack = converted.Convert<ColorRGB96Single, float, ColorRGB96Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorRGB96Single original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorRGB96Single, float, ColorRGB192Double, double>();
ColorRGB96Single convertedBack = converted.Convert<ColorRGB192Double, double, ColorRGB96Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorRGB96Single original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorRGB96Single, float, ColorRGBA128Single, float>();
ColorRGB96Single convertedBack = converted.Convert<ColorRGBA128Single, float, ColorRGB96Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRGB96Single original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRGB96Single, float, ColorRGBA256Double, double>();
ColorRGB96Single convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRGB96Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,174 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGB9e5Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGB9e5>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGB9e5 MakeRandomColor()
{
return new()
{
R = 0.447,
G = 0.224,
B = 0.95,
A = 0.897,
};
}
[Test]
public void ConversionToColorRGB192DoubleIsLossless()
{
ColorRGB9e5 original = MakeRandomColor();
ColorRGB192Double converted = original.Convert<ColorRGB9e5, double, ColorRGB192Double, double>();
ColorRGB9e5 convertedBack = converted.Convert<ColorRGB192Double, double, ColorRGB9e5, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRGB9e5 original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRGB9e5, double, ColorRGBA256Double, double>();
ColorRGB9e5 convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRGB9e5, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,174 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGBA128SingleTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGBA128Single>(), Is.EqualTo(16));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGBA128Single MakeRandomColor()
{
return new()
{
R = 0.447f,
G = 0.224f,
B = 0.95f,
A = 0.897f,
};
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorRGBA128Single original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorRGBA128Single, float, ColorRGBA128Single, float>();
ColorRGBA128Single convertedBack = converted.Convert<ColorRGBA128Single, float, ColorRGBA128Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRGBA128Single original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRGBA128Single, float, ColorRGBA256Double, double>();
ColorRGBA128Single convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRGBA128Single, float>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGBA16Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGBA16>(), Is.EqualTo(2));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGBA16 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorRGBA16 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorRGBA16, byte, ColorARGB32, byte>();
ColorRGBA16 convertedBack = converted.Convert<ColorARGB32, byte, ColorRGBA16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorRGBA16 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorRGBA16, byte, ColorBGRA32, byte>();
ColorRGBA16 convertedBack = converted.Convert<ColorBGRA32, byte, ColorRGBA16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorRGBA16 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorRGBA16, byte, ColorRGBA32, byte>();
ColorRGBA16 convertedBack = converted.Convert<ColorRGBA32, byte, ColorRGBA16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorRGBA16 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorRGBA16, byte, ColorRGBA32Signed, sbyte>();
ColorRGBA16 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorRGBA16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGBA16 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGBA16, byte, ColorRGBA64, ushort>();
ColorRGBA16 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGBA16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGBA16 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGBA16, byte, ColorRGBA64Signed, short>();
ColorRGBA16 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGBA16, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,165 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGBA256DoubleTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGBA256Double>(), Is.EqualTo(32));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0.333;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGBA256Double MakeRandomColor()
{
return new()
{
R = 0.447,
G = 0.224,
B = 0.95,
A = 0.897,
};
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRGBA256Double original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRGBA256Double, double, ColorRGBA256Double, double>();
ColorRGBA256Double convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRGBA256Double, double>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGBA32SignedTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGBA32Signed>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGBA32Signed MakeRandomColor()
{
return new()
{
R = -0b01010101,
G = 0b01110010,
B = -0b00001111,
A = -0b01000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorRGBA32Signed original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorRGBA32Signed, sbyte, ColorARGB32, byte>();
ColorRGBA32Signed convertedBack = converted.Convert<ColorARGB32, byte, ColorRGBA32Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorRGBA32Signed original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorRGBA32Signed, sbyte, ColorBGRA32, byte>();
ColorRGBA32Signed convertedBack = converted.Convert<ColorBGRA32, byte, ColorRGBA32Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorRGBA32Signed original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorRGBA32Signed, sbyte, ColorRGBA32, byte>();
ColorRGBA32Signed convertedBack = converted.Convert<ColorRGBA32, byte, ColorRGBA32Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorRGBA32Signed original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorRGBA32Signed, sbyte, ColorRGBA32Signed, sbyte>();
ColorRGBA32Signed convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorRGBA32Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGBA32Signed original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGBA32Signed, sbyte, ColorRGBA64, ushort>();
ColorRGBA32Signed convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGBA32Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGBA32Signed original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGBA32Signed, sbyte, ColorRGBA64Signed, short>();
ColorRGBA32Signed convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGBA32Signed, sbyte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,210 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGBA32Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGBA32>(), Is.EqualTo(4));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 0b01001110;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGBA32 MakeRandomColor()
{
return new()
{
R = 0b11010101,
G = 0b01110010,
B = 0b10001111,
A = 0b11000111,
};
}
[Test]
public void ConversionToColorARGB32IsLossless()
{
ColorRGBA32 original = MakeRandomColor();
ColorARGB32 converted = original.Convert<ColorRGBA32, byte, ColorARGB32, byte>();
ColorRGBA32 convertedBack = converted.Convert<ColorARGB32, byte, ColorRGBA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorBGRA32IsLossless()
{
ColorRGBA32 original = MakeRandomColor();
ColorBGRA32 converted = original.Convert<ColorRGBA32, byte, ColorBGRA32, byte>();
ColorRGBA32 convertedBack = converted.Convert<ColorBGRA32, byte, ColorRGBA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32IsLossless()
{
ColorRGBA32 original = MakeRandomColor();
ColorRGBA32 converted = original.Convert<ColorRGBA32, byte, ColorRGBA32, byte>();
ColorRGBA32 convertedBack = converted.Convert<ColorRGBA32, byte, ColorRGBA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA32SignedIsLossless()
{
ColorRGBA32 original = MakeRandomColor();
ColorRGBA32Signed converted = original.Convert<ColorRGBA32, byte, ColorRGBA32Signed, sbyte>();
ColorRGBA32 convertedBack = converted.Convert<ColorRGBA32Signed, sbyte, ColorRGBA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGBA32 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGBA32, byte, ColorRGBA64, ushort>();
ColorRGBA32 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGBA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGBA32 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGBA32, byte, ColorRGBA64Signed, short>();
ColorRGBA32 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGBA32, byte>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,183 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGBA64HalfTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGBA64Half>(), Is.EqualTo(8));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = (Half)0.333f;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGBA64Half MakeRandomColor()
{
return new()
{
R = (Half)0.447f,
G = (Half)0.224f,
B = (Half)0.95f,
A = (Half)0.897f,
};
}
[Test]
public void ConversionToColorRGBA128SingleIsLossless()
{
ColorRGBA64Half original = MakeRandomColor();
ColorRGBA128Single converted = original.Convert<ColorRGBA64Half, Half, ColorRGBA128Single, float>();
ColorRGBA64Half convertedBack = converted.Convert<ColorRGBA128Single, float, ColorRGBA64Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA256DoubleIsLossless()
{
ColorRGBA64Half original = MakeRandomColor();
ColorRGBA256Double converted = original.Convert<ColorRGBA64Half, Half, ColorRGBA256Double, double>();
ColorRGBA64Half convertedBack = converted.Convert<ColorRGBA256Double, double, ColorRGBA64Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64HalfIsLossless()
{
ColorRGBA64Half original = MakeRandomColor();
ColorRGBA64Half converted = original.Convert<ColorRGBA64Half, Half, ColorRGBA64Half, Half>();
ColorRGBA64Half convertedBack = converted.Convert<ColorRGBA64Half, Half, ColorRGBA64Half, Half>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,174 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGBA64SignedTests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGBA64Signed>(), Is.EqualTo(8));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 31871;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 31871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGBA64Signed MakeRandomColor()
{
return new()
{
R = -24000,
G = 21354,
B = -80,
A = 347,
};
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGBA64Signed original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGBA64Signed, short, ColorRGBA64, ushort>();
ColorRGBA64Signed convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGBA64Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGBA64Signed original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGBA64Signed, short, ColorRGBA64Signed, short>();
ColorRGBA64Signed convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGBA64Signed, short>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,174 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Runtime.CompilerServices;
namespace AssetRipper.TextureDecoder.Tests.Formats;
public partial class ColorRGBA64Tests
{
[Test]
public void CorrectSizeTest()
{
Assert.That(Unsafe.SizeOf<ColorRGBA64>(), Is.EqualTo(8));
}
[Test]
public void PropertyIsSymmetric_R()
{
var color = MakeRandomColor();
var r = color.R;
color.R = r;
Assert.That(color.R, Is.EqualTo(r));
}
[Test]
public void PropertyIsSymmetric_G()
{
var color = MakeRandomColor();
var g = color.G;
color.G = g;
Assert.That(color.G, Is.EqualTo(g));
}
[Test]
public void PropertyIsSymmetric_B()
{
var color = MakeRandomColor();
var b = color.B;
color.B = b;
Assert.That(color.B, Is.EqualTo(b));
}
[Test]
public void PropertyIsSymmetric_A()
{
var color = MakeRandomColor();
var a = color.A;
color.A = a;
Assert.That(color.A, Is.EqualTo(a));
}
[Test]
public void ChannelsAreIndependent_R()
{
var color = MakeRandomColor();
var g = color.G;
var b = color.B;
var a = color.A;
color.R = 33871;
Assert.Multiple(() =>
{
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_G()
{
var color = MakeRandomColor();
var r = color.R;
var b = color.B;
var a = color.A;
color.G = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_B()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var a = color.A;
color.B = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void ChannelsAreIndependent_A()
{
var color = MakeRandomColor();
var r = color.R;
var g = color.G;
var b = color.B;
color.A = 33871;
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
});
}
[Test]
public void GetMethodMatchesProperties()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
[Test]
public void MethodsAreSymmetric()
{
var color = MakeRandomColor();
color.GetChannels(out var r, out var g, out var b, out var a);
color.SetChannels(r, g, b, a);
Assert.Multiple(() =>
{
Assert.That(color.R, Is.EqualTo(r));
Assert.That(color.G, Is.EqualTo(g));
Assert.That(color.B, Is.EqualTo(b));
Assert.That(color.A, Is.EqualTo(a));
});
}
public static ColorRGBA64 MakeRandomColor()
{
return new()
{
R = 44000,
G = 21354,
B = 60080,
A = 347,
};
}
[Test]
public void ConversionToColorRGBA64IsLossless()
{
ColorRGBA64 original = MakeRandomColor();
ColorRGBA64 converted = original.Convert<ColorRGBA64, ushort, ColorRGBA64, ushort>();
ColorRGBA64 convertedBack = converted.Convert<ColorRGBA64, ushort, ColorRGBA64, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
[Test]
public void ConversionToColorRGBA64SignedIsLossless()
{
ColorRGBA64 original = MakeRandomColor();
ColorRGBA64Signed converted = original.Convert<ColorRGBA64, ushort, ColorRGBA64Signed, short>();
ColorRGBA64 convertedBack = converted.Convert<ColorRGBA64Signed, short, ColorRGBA64, ushort>();
Assert.That(convertedBack, Is.EqualTo(original));
}
}
@@ -0,0 +1,257 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
namespace AssetRipper.TextureDecoder.Tests
{
public sealed class NewRgbTests
{
[Test]
public void ConvertA8Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.alpha8");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.A8ToBGRA32(data.Slice(totalBytesRead), size, size, out byte[] originalDecodedData);
RgbConverter.Convert<ColorA8, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out byte[] newDecodedData);
totalBytesRead += bytesRead;
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertARGB16Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.argb4444");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.Convert<ColorARGB16, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGB24Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb24");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.RGB24ToBGRA32(data.Slice(totalBytesRead), size, size, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRGB24, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out byte[] newDecodedData);
totalBytesRead += bytesRead;
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGBA32Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgba32");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.RGBA32ToBGRA32(data.Slice(totalBytesRead), size, size, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRGBA32, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out byte[] newDecodedData);
totalBytesRead += bytesRead;
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertARGB32Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.argb32");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.ARGB32ToBGRA32(data.Slice(totalBytesRead), size, size, out byte[] originalDecodedData);
RgbConverter.Convert<ColorARGB32, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out byte[] newDecodedData);
totalBytesRead += bytesRead;
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGB16Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb565");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.RGB16ToBGRA32(data.Slice(totalBytesRead), size, size, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRGB16, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out byte[] newDecodedData);
totalBytesRead += bytesRead;
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertR16Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.r16");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.Convert<ColorR16, ushort, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGBA16Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgba4444");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.Convert<ColorRGBA16, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRG16Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rg16");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.RG16ToBGRA32(data.Slice(totalBytesRead), size, size, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRG16, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out byte[] newDecodedData);
totalBytesRead += bytesRead;
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertR8Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.r8");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = RgbConverter.R8ToBGRA32(data.Slice(totalBytesRead), size, size, out byte[] originalDecodedData);
RgbConverter.Convert<ColorR8, byte, ColorBGRA32, byte>(data.Slice(totalBytesRead), size, size, out byte[] newDecodedData);
totalBytesRead += bytesRead;
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRHalfTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rhalf");
RgbConverter.RHalfToBGRA32(data, 256, 256, out byte[] originalDecodedData);
RgbConverter.Convert<ColorR16Half, Half, ColorBGRA32, byte>(data, 256, 256, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRGHalfTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rghalf");
RgbConverter.RGHalfToBGRA32(data, 256, 256, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRG32Half, Half, ColorBGRA32, byte>(data, 256, 256, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRGB32HalfTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb24");
RgbConverter.Convert<ColorRGB24, byte, ColorRGB32Half, Half>(data, 256, 256, out var halfData);
int legacyBytesRead = RgbConverter.R11G11B10FloatToBGRA32(halfData, 256, 256, out var legacyRgbData);
int bytesRead = RgbConverter.Convert<ColorRGB32Half, Half, ColorBGRA32, byte>(halfData, 256, 256, out var rgbData);
Assert.Multiple(() =>
{
Assert.That(bytesRead, Is.EqualTo(halfData.Length));
Assert.That(legacyBytesRead, Is.EqualTo(halfData.Length));
Assert.That(rgbData, Is.EqualTo(legacyRgbData));
});
}
[Test]
public void ConvertRGBAHalfTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgbahalf");
RgbConverter.RGBAHalfToBGRA32(data, 256, 256, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRGBA64Half, Half, ColorBGRA32, byte>(data, 256, 256, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRFloatTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rfloat");
RgbConverter.RFloatToBGRA32(data, 256, 256, out byte[] originalDecodedData);
RgbConverter.Convert<ColorR32Single, float, ColorBGRA32, byte>(data, 256, 256, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRGFloatTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgfloat");
RgbConverter.RGFloatToBGRA32(data, 256, 256, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRG64Single, float, ColorBGRA32, byte>(data, 256, 256, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRGBAFloatTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgbafloat");
RgbConverter.RGBAFloatToBGRA32(data, 256, 256, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRGBA128Single, float, ColorBGRA32, byte>(data, 256, 256, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRGB9e5FloatTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb9e5float");
RgbConverter.RGB9e5FloatToBGRA32(data, 256, 256, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRGB9e5, double, ColorBGRA32, byte>(data, 256, 256, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRG32Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rg32");
RgbConverter.RG32ToBGRA32(data, 512, 512, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRG32, ushort, ColorBGRA32, byte>(data, 512, 512, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRGB48Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb48");
RgbConverter.RGB48ToBGRA32(data, 512, 512, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRGB48, ushort, ColorBGRA32, byte>(data, 512, 512, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
[Test]
public void ConvertRGBA64Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgba64");
RgbConverter.RGBA64ToBGRA32(data, 512, 512, out byte[] originalDecodedData);
RgbConverter.Convert<ColorRGBA64, ushort, ColorBGRA32, byte>(data, 512, 512, out byte[] newDecodedData);
Assert.That(originalDecodedData, Is.EqualTo(newDecodedData));
}
}
}
@@ -0,0 +1,18 @@
namespace AssetRipper.TextureDecoder.Tests
{
internal static class PathConstants
{
public const string ThisTestProjectFolder = "../../../";
public const string RepositoryRootFolder = ThisTestProjectFolder + "../";
public const string TestFilesFolder = RepositoryRootFolder + "TestFiles/";
public const string AstcTestFilesFolder = TestFilesFolder + "Astc/";
public const string AtcTestFilesFolder = TestFilesFolder + "Atc/";
public const string BcTestFilesFolder = TestFilesFolder + "Bc/";
public const string DxtTestFilesFolder = TestFilesFolder + "Dxt/";
public const string EtcTestFilesFolder = TestFilesFolder + "Etc/";
public const string PvrtcTestFilesFolder = TestFilesFolder + "Pvrtc/";
public const string RgbTestFilesFolder = TestFilesFolder + "Rgb/";
public const string Yuy2TestFilesFolder = TestFilesFolder + "Yuy2/";
}
}
@@ -0,0 +1,18 @@
namespace AssetRipper.TextureDecoder.Tests
{
public sealed class PvrtcTests
{
[Test]
public void DecompressPVRTCTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.PvrtcTestFilesFolder + "test.pvrtc4");
int totalBytesRead = 0;
foreach (int size in new int[] { 512, 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Pvrtc.PvrtcDecoder.DecompressPVRTC(data, size, size, false, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
}
}
@@ -0,0 +1,179 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
namespace AssetRipper.TextureDecoder.Tests
{
public sealed class RgbTests
{
[Test]
public void ConvertA8Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.alpha8");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Rgb.RgbConverter.A8ToBGRA32(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGB24Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb24");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Rgb.RgbConverter.RGB24ToBGRA32(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGBA32Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgba32");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Rgb.RgbConverter.RGBA32ToBGRA32(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertARGB32Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.argb32");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Rgb.RgbConverter.ARGB32ToBGRA32(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGB16Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb565");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Rgb.RgbConverter.RGB16ToBGRA32(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRG16Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rg16");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Rgb.RgbConverter.RG16ToBGRA32(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertR8Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.r8");
int totalBytesRead = 0;
foreach (int size in new int[] { 256, 128, 64, 32, 16, 8, 4, 2, 1 }) //mip maps
{
int bytesRead = Rgb.RgbConverter.R8ToBGRA32(data.Slice(totalBytesRead), size, size, out _);
totalBytesRead += bytesRead;
}
Assert.That(totalBytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRHalfTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rhalf");
int bytesRead = Rgb.RgbConverter.RHalfToBGRA32(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGHalfTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rghalf");
int bytesRead = Rgb.RgbConverter.RGHalfToBGRA32(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGBAHalfTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgbahalf");
int bytesRead = Rgb.RgbConverter.RGBAHalfToBGRA32(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRFloatTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rfloat");
int bytesRead = Rgb.RgbConverter.RFloatToBGRA32(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGFloatTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgfloat");
int bytesRead = Rgb.RgbConverter.RGFloatToBGRA32(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGBAFloatTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgbafloat");
int bytesRead = Rgb.RgbConverter.RGBAFloatToBGRA32(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGB9e5FloatTest()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb9e5float");
int bytesRead = Rgb.RgbConverter.RGB9e5FloatToBGRA32(data, 256, 256, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRG32Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rg32");
int bytesRead = Rgb.RgbConverter.RG32ToBGRA32(data, 512, 512, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGB48Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgb48");
int bytesRead = Rgb.RgbConverter.RGB48ToBGRA32(data, 512, 512, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
[Test]
public void ConvertRGBA64Test()
{
ReadOnlySpan<byte> data = File.ReadAllBytes(PathConstants.RgbTestFilesFolder + "test.rgba64");
int bytesRead = Rgb.RgbConverter.RGBA64ToBGRA32(data, 512, 512, out _);
Assert.That(bytesRead, Is.EqualTo(data.Length));
}
}
}
@@ -0,0 +1 @@
global using NUnit.Framework;
@@ -0,0 +1,21 @@
using AssetRipper.TextureDecoder.Rgb.Formats;
using AssetRipper.TextureDecoder.Yuy2;
namespace AssetRipper.TextureDecoder.Tests
{
public sealed class Yuy2Tests
{
private const int TestImageWidth = 256;
private const int TestImageHeight = 256;
[Test]
public void DecompressYUY2Test()
{
byte[] input = File.ReadAllBytes(PathConstants.Yuy2TestFilesFolder + "test.yuy2");
int bytesRead = Yuy2Decoder.DecompressYUY2(input, TestImageWidth, TestImageHeight, out byte[] originalOutput);
Assert.That(bytesRead, Is.EqualTo(input.Length));
Yuy2Decoder.DecompressYUY2<ColorBGRA32, byte>(input, TestImageWidth, TestImageHeight, out byte[] genericOutput);
Assert.That(originalOutput, Is.EqualTo(genericOutput));
}
}
}
@@ -1,37 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net5.0;net6.0;net7.0</TargetFrameworks>
<LangVersion>Latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<IsTrimmable>true</IsTrimmable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RootNamespace>AssetRipper.TextureDecoder</RootNamespace>
<Authors>ds5678</Authors>
<Company>AssetRipper</Company>
<Version>1.0.0.0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<PackageId>TextureDecoder</PackageId>
<Version>1.3.0.0</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<PackageId>AssetRipper.TextureDecoder</PackageId>
<PackageTags>C# Texture</PackageTags>
<RepositoryUrl>https://github.com/AssetRipper/TextureDecoder</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<PackageProjectUrl>https://github.com/AssetRipper/TextureDecoder</PackageProjectUrl>
<Copyright>Copyright (c) 2022 ds5678</Copyright>
<Copyright>Copyright (c) 2022 - 2023 ds5678</Copyright>
<Description>Managed library for decoding textures in multiple formats.</Description>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>bin\TextureDecoder.xml</DocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PolySharp" Version="1.13.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Half" Version="1.0.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup>
<DocumentationFile>bin\TextureDecoder.xml</DocumentationFile>
</PropertyGroup>
</Project>
@@ -0,0 +1,30 @@
namespace AssetRipper.TextureDecoder.Astc
{
public static partial class AstcDecoder
{
private unsafe struct BlockData
{
public int bw;
public int bh;
public int width;
public int height;
public int part_num;
public int dual_plane;
public int plane_selector;
public int weight_range;
/// <summary>
/// max: 120
/// </summary>
public int weight_num;
public fixed int cem[4];
public int cem_range;
/// <summary>
/// max: 32
/// </summary>
public int endpoint_value_num;
public fixed int endpoints[4 * 8];
public fixed int weights[144 * 2];
public fixed int partition[144];
}
}
}
@@ -0,0 +1,11 @@
namespace AssetRipper.TextureDecoder.Astc
{
public static partial class AstcDecoder
{
private struct IntSeqData
{
public int bits;
public int nonbits;
}
}
}
@@ -1,76 +1,62 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace TextureDecoder.Astc
namespace AssetRipper.TextureDecoder.Astc
{
public static class AstcDecoder
public static partial class AstcDecoder
{
private unsafe struct BlockData
private static void ValidateBlockDimension(int value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
public int bw;
public int bh;
public int width;
public int height;
public int part_num;
public int dual_plane;
public int plane_selector;
public int weight_range;
public int weight_num; // max: 120
public fixed int cem[4];
public int cem_range;
public int endpoint_value_num; // max: 32
public fixed int endpoints[4 * 8];
public fixed int weights[144 * 2];
public fixed int partition[144];
if (value < 4 || value > 12)
{
throw new ArgumentException($"Block dimension must be between 4 and 12, inclusive. Value: {value}", paramName);
}
}
private struct IntSeqData
public static int DecodeASTC(ReadOnlySpan<byte> input, int width, int height, int blockWidth, int blockHeight, out byte[] output)
{
public int bits;
public int nonbits;
output = new byte[width * height * 4];
return DecodeASTC(input, width, height, blockWidth, blockHeight, output);
}
public static byte[] DecodeASTC(byte[] input, int width, int height, int blockWidth, int blockHeight)
{
byte[] output = new byte[width * height * 4];
DecodeASTC(input, width, height, blockWidth, blockHeight, output);
return output;
}
public unsafe static void DecodeASTC(byte[] input, int width, int height, int blockWidth, int blockHeight, byte[] output)
public unsafe static int DecodeASTC(ReadOnlySpan<byte> input, int width, int height, int blockWidth, int blockHeight, Span<byte> output)
{
fixed (byte* inputPtr = input)
{
fixed (byte* outputPtr = output)
{
DecodeASTC(inputPtr, width, height, blockWidth, blockHeight, outputPtr);
return DecodeASTC(inputPtr, width, height, blockWidth, blockHeight, outputPtr);
}
}
}
public unsafe static void DecodeASTC(byte* input, int width, int height, int blockWidth, int blockHeight, byte* output)
private unsafe static int DecodeASTC(byte* input, int width, int height, int blockWidth, int blockHeight, byte* output)
{
ValidateBlockDimension(blockWidth);
ValidateBlockDimension(blockHeight);
int bcw = (width + blockWidth - 1) / blockWidth;
int bch = (height + blockHeight - 1) / blockHeight;
int clen_last = (width + blockWidth - 1) % blockWidth + 1;
uint* buf = stackalloc uint[blockWidth * blockHeight];
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 16)
for (int s = 0; s < bcw; s++, inputOffset += 16)
{
DecodeBlock(input, blockWidth, blockHeight, buf);
DecodeBlock(input + inputOffset, blockWidth, blockHeight, buf);
int clen = s < bcw - 1 ? blockWidth : clen_last;
uint* outputPtr = (uint*)(output + (t * blockHeight * 4 * width + s * 4 * blockWidth));
uint* bufPtr = buf;
for (int i = 0, y = t * blockHeight; i < blockHeight && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = bufPtr[j];
}
outputPtr += width;
bufPtr += blockWidth;
}
}
}
return inputOffset;
}
private unsafe static void DecodeBlock(byte* input, int blockWidth, int blockHeight, uint* output)
@@ -166,23 +152,17 @@ namespace TextureDecoder.Astc
pBlock->weight_num = pBlock->width * pBlock->height;
if (pBlock->dual_plane != 0)
pBlock->weight_num *= 2;
int weight_bits, config_bits, cem_base = 0;
switch (WeightPrecTableA[pBlock->weight_range])
{
case 3:
weight_bits = pBlock->weight_num * WeightPrecTableB[pBlock->weight_range] + (pBlock->weight_num * 8 + 4) / 5;
break;
case 5:
weight_bits = pBlock->weight_num * WeightPrecTableB[pBlock->weight_range] + (pBlock->weight_num * 7 + 2) / 3;
break;
default:
weight_bits = pBlock->weight_num * WeightPrecTableB[pBlock->weight_range];
break;
pBlock->weight_num *= 2;
}
int config_bits, cem_base = 0;
int weight_bits = WeightPrecTableA[pBlock->weight_range] switch
{
3 => pBlock->weight_num * WeightPrecTableB[pBlock->weight_range] + (pBlock->weight_num * 8 + 4) / 5,
5 => pBlock->weight_num * WeightPrecTableB[pBlock->weight_range] + (pBlock->weight_num * 7 + 2) / 3,
_ => pBlock->weight_num * WeightPrecTableB[pBlock->weight_range],
};
if (pBlock->part_num == 1)
{
pBlock->cem[0] = *((int*)(input + 1)) >> 5 & 0xf;
@@ -245,19 +225,12 @@ namespace TextureDecoder.Astc
for (int i = 0, endpoint_bits; i < CemTableA.Length; i++)
{
switch (CemTableA[i])
endpoint_bits = CemTableA[i] switch
{
case 3:
endpoint_bits = pBlock->endpoint_value_num * CemTableB[i] + (pBlock->endpoint_value_num * 8 + 4) / 5;
break;
case 5:
endpoint_bits = pBlock->endpoint_value_num * CemTableB[i] + (pBlock->endpoint_value_num * 7 + 2) / 3;
break;
default:
endpoint_bits = pBlock->endpoint_value_num * CemTableB[i];
break;
}
3 => pBlock->endpoint_value_num * CemTableB[i] + (pBlock->endpoint_value_num * 8 + 4) / 5,
5 => pBlock->endpoint_value_num * CemTableB[i] + (pBlock->endpoint_value_num * 7 + 2) / 3,
_ => pBlock->endpoint_value_num * CemTableB[i],
};
if (endpoint_bits <= remain_bits)
{
pBlock->cem_range = i;
@@ -336,35 +309,51 @@ namespace TextureDecoder.Astc
{
case 1:
for (int i = 0; i < pBlock->endpoint_value_num; i++)
{
ev[i] = epSeq[i].bits * 0xff;
}
break;
case 2:
for (int i = 0; i < pBlock->endpoint_value_num; i++)
{
ev[i] = epSeq[i].bits * 0x55;
}
break;
case 3:
for (int i = 0; i < pBlock->endpoint_value_num; i++)
{
ev[i] = epSeq[i].bits << 5 | epSeq[i].bits << 2 | epSeq[i].bits >> 1;
}
break;
case 4:
for (int i = 0; i < pBlock->endpoint_value_num; i++)
{
ev[i] = epSeq[i].bits << 4 | epSeq[i].bits;
}
break;
case 5:
for (int i = 0; i < pBlock->endpoint_value_num; i++)
{
ev[i] = epSeq[i].bits << 3 | epSeq[i].bits >> 2;
}
break;
case 6:
for (int i = 0; i < pBlock->endpoint_value_num; i++)
{
ev[i] = epSeq[i].bits << 2 | epSeq[i].bits >> 4;
}
break;
case 7:
for (int i = 0; i < pBlock->endpoint_value_num; i++)
{
ev[i] = epSeq[i].bits << 1 | epSeq[i].bits >> 6;
}
break;
case 8:
for (int i = 0; i < pBlock->endpoint_value_num; i++)
{
ev[i] = epSeq[i].bits;
}
break;
}
break;
@@ -399,27 +388,42 @@ namespace TextureDecoder.Astc
break;
case 8:
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5])
{
SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[2], v[4], 255, v[1], v[3], v[5], 255);
}
else
{
SetEndpointBlue(&pBlock->endpoints[cemOff], v[1], v[3], v[5], 255, v[0], v[2], v[4], 255);
}
break;
case 9:
BitTransferSigned(&v[1], &v[0]);
BitTransferSigned(&v[3], &v[2]);
BitTransferSigned(&v[5], &v[4]);
if (v[1] + v[3] + v[5] >= 0)
{
SetEndpointClamp(&pBlock->endpoints[cemOff], v[0], v[2], v[4], 255, v[0] + v[1], v[2] + v[3], v[4] + v[5], 255);
}
else
{
SetEndpointBlueClamp(&pBlock->endpoints[cemOff], v[0] + v[1], v[2] + v[3], v[4] + v[5], 255, v[0], v[2], v[4], 255);
}
break;
case 10:
SetEndpoint(&pBlock->endpoints[cemOff], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, v[4], v[0], v[1], v[2], v[5]);
break;
case 12:
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5])
{
SetEndpoint(&pBlock->endpoints[cemOff], v[0], v[2], v[4], v[6], v[1], v[3], v[5], v[7]);
}
else
{
SetEndpointBlue(&pBlock->endpoints[cemOff], v[1], v[3], v[5], v[7], v[0], v[2], v[4], v[6]);
}
break;
case 13:
BitTransferSigned(&v[1], &v[0]);
@@ -427,9 +431,14 @@ namespace TextureDecoder.Astc
BitTransferSigned(&v[5], &v[4]);
BitTransferSigned(&v[7], &v[6]);
if (v[1] + v[3] + v[5] >= 0)
{
SetEndpointClamp(&pBlock->endpoints[cemOff], v[0], v[2], v[4], v[6], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7]);
}
else
{
SetEndpointBlueClamp(&pBlock->endpoints[cemOff], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7], v[0], v[2], v[4], v[6]);
}
break;
}
}
@@ -447,23 +456,38 @@ namespace TextureDecoder.Astc
{
case 1:
for (int i = 0; i < block->weight_num; i++)
{
wv[i] = wSeq[i].bits != 0 ? 63 : 0;
}
break;
case 2:
for (int i = 0; i < block->weight_num; i++)
{
wv[i] = wSeq[i].bits << 4 | wSeq[i].bits << 2 | wSeq[i].bits;
}
break;
case 3:
for (int i = 0; i < block->weight_num; i++)
{
wv[i] = wSeq[i].bits << 3 | wSeq[i].bits;
}
break;
case 4:
for (int i = 0; i < block->weight_num; i++)
{
wv[i] = wSeq[i].bits << 2 | wSeq[i].bits >> 2;
}
break;
case 5:
for (int i = 0; i < block->weight_num; i++)
{
wv[i] = wSeq[i].bits << 1 | wSeq[i].bits >> 4;
}
break;
}
for (int i = 0; i < block->weight_num; i++)
@@ -518,7 +542,10 @@ namespace TextureDecoder.Astc
{
case 1:
for (int i = 0; i < block->weight_num; i++)
{
wv[i] = wSeq[i].nonbits * 28;
}
break;
case 2:
for (int i = 0; i < block->weight_num; i++)
@@ -711,7 +738,9 @@ namespace TextureDecoder.Astc
private unsafe static void DecodeIntseq(byte* input, int offset, int a, int b, int count, bool reverse, IntSeqData* _out)
{
if (count <= 0)
{
return;
}
int n = 0;
@@ -868,15 +897,25 @@ namespace TextureDecoder.Astc
{
ulong mask = len == 64 ? 0xffffffffffffffff : (1UL << len) - 1;
if (len < 1)
{
return 0;
}
else if (bit >= 64)
{
return *((ulong*)(input + 8)) >> (bit - 64) & mask;
}
else if (bit <= 0)
{
return *((ulong*)input) << -bit & mask;
}
else if (bit + len <= 64)
{
return *((ulong*)input) >> bit & mask;
}
else
{
return (*((ulong*)input) >> bit | *((ulong*)(input + 8)) << (64 - bit)) & mask;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -891,7 +930,9 @@ namespace TextureDecoder.Astc
*b = (*b >> 1) | (*a & 0x80);
*a = (*a >> 1) & 0x3f;
if ((*a & 0x20) != 0)
{
*a -= 0x40;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1,106 +1,109 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace TextureDecoder.Atc
namespace AssetRipper.TextureDecoder.Atc
{
public static class AtcDecoder
{
public static byte[] DecompressAtcRgb4(byte[] input, int width, int height)
public static int DecompressAtcRgb4(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressAtcRgb4(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressAtcRgb4(input, width, height, output);
}
public unsafe static void DecompressAtcRgb4(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressAtcRgb4(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
fixed (byte* outputPtr = output)
{
fixed (byte* outputPtr = output)
{
DecompressAtcRgb4(inputPtr, width, height, outputPtr);
}
return DecompressAtcRgb4(input, width, height, outputPtr);
}
}
public unsafe static void DecompressAtcRgb4(byte* input, int width, int height, byte* output)
private unsafe static int DecompressAtcRgb4(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 8)
for (int s = 0; s < bcw; s++, inputOffset += 8)
{
DecodeAtcRgb4Block(input, buf);
DecodeAtcRgb4Block(input.Slice(inputOffset, 8), new Span<uint>(buf, 16));
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = bufPtr[j];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
public static byte[] DecompressAtcRgba8(byte[] input, int width, int height)
public static int DecompressAtcRgba8(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressAtcRgba8(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressAtcRgba8(input, width, height, output);
}
public unsafe static void DecompressAtcRgba8(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressAtcRgba8(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
fixed (byte* outputPtr = output)
{
fixed (byte* outputPtr = output)
{
DecompressAtcRgba8(inputPtr, width, height, outputPtr);
}
return DecompressAtcRgba8(input, width, height, outputPtr);
}
}
public unsafe static void DecompressAtcRgba8(byte* input, int width, int height, byte* output)
private unsafe static int DecompressAtcRgba8(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 16)
for (int s = 0; s < bcw; s++, inputOffset += 16)
{
DecodeAtcRgba8Block(input, buf);
DecodeAtcRgba8Block(input.Slice(inputOffset, 16), new Span<uint>(buf, 16));
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = bufPtr[j];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
private unsafe static void DecodeAtcRgb4Block(byte* input, uint* output)
private unsafe static void DecodeAtcRgb4Block(ReadOnlySpan<byte> input, Span<uint> output)
{
int* colors = stackalloc int[16];
int c0 = *((ushort*)(input + 0));
int c1 = *((ushort*)(input + 2));
uint cindex = *((uint*)(input + 4));
Span<int> colors = stackalloc int[16];
int c0 = input.ReadAtOffset<ushort>(0);
int c1 = input.ReadAtOffset<ushort>(2);
uint cindex = input.ReadAtOffset<uint>(4);
DecodeColors(colors, c0, c1);
for (int i = 0; i < 4 * 4; i++)
{
uint cidx = cindex & 3;
int cidx = unchecked((int)(cindex & 3));
int cb = colors[cidx * 4 + 0];
int cg = colors[cidx * 4 + 1];
int cr = colors[cidx * 4 + 2];
@@ -109,18 +112,18 @@ namespace TextureDecoder.Atc
}
}
private unsafe static void DecodeAtcRgba8Block(byte* input, uint* output)
private unsafe static void DecodeAtcRgba8Block(ReadOnlySpan<byte> input, Span<uint> output)
{
int* alphas = stackalloc int[16];
ulong avalue = *((ulong*)input);
Span<int> alphas = stackalloc int[16];
ulong avalue = input.ReadAtOffset<ulong>(0);
int a0 = unchecked((int)(avalue >> 0) & 0xFF);
int a1 = unchecked((int)(avalue >> 8) & 0xFF);
ulong aindex = avalue >> 16;
int* colors = stackalloc int[16];
int c0 = *((ushort*)(input + 8));
int c1 = *((ushort*)(input + 10));
uint cindex = *((uint*)(input + 12));
Span<int> colors = stackalloc int[16];
int c0 = input.ReadAtOffset<ushort>(8);
int c1 = input.ReadAtOffset<ushort>(10);
uint cindex = input.ReadAtOffset<uint>(12);
DecodeColors(colors, c0, c1);
DecodeAlphas(alphas, a0, a1);
@@ -140,7 +143,13 @@ namespace TextureDecoder.Atc
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void DecodeColors(int* colors, int c0, int c1)
private static T ReadAtOffset<T>(this ReadOnlySpan<byte> input, int offset) where T : unmanaged
{
return MemoryMarshal.Read<T>(input.Slice(offset));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void DecodeColors(Span<int> colors, int c0, int c1)
{
if ((c0 & 0x8000) == 0)
{
@@ -181,7 +190,7 @@ namespace TextureDecoder.Atc
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void DecodeAlphas(int* alphas, int a0, int a1)
private unsafe static void DecodeAlphas(Span<int> alphas, int a0, int a1)
{
alphas[0] = a0;
alphas[1] = a1;
@@ -0,0 +1,30 @@
namespace AssetRipper.TextureDecoder.Attributes
{
[AttributeUsage(AttributeTargets.Struct)]
public sealed class RgbaAttribute : Attribute
{
/// <summary>
/// Does the format have a red channel?
/// </summary>
public bool RedChannel { get; init; }
/// <summary>
/// Does the format have a green channel?
/// </summary>
public bool GreenChannel { get; init; }
/// <summary>
/// Does the format have a blue channel?
/// </summary>
public bool BlueChannel { get; init; }
/// <summary>
/// Does the format have an alpha channel?
/// </summary>
public bool AlphaChannel { get; init; }
/// <summary>
/// Channels utilize the full range of possible values for their underlying type.
/// </summary>
/// <remarks>
/// In the case of floating point numbers, this means that the precision is the same in storage and memory.
/// </remarks>
public bool FullyUtilizedChannels { get; init; }
}
}
+33
View File
@@ -0,0 +1,33 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
namespace AssetRipper.TextureDecoder.Bc;
public static class Bc1
{
internal const int BlockSize = 8;
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * Unsafe.SizeOf<ColorBGRA32>()];
return Decompress(input, width, height, output);
}
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
int inputOffset = 0;
for (int i = 0; i < height; i += 4)
{
for (int j = 0; j < width; j += 4)
{
int outputOffset = ((i * width) + j) * Unsafe.SizeOf<ColorRGBA32>();
BcHelpers.DecompressBc1(input.Slice(inputOffset, BlockSize), output.Slice(outputOffset), width * 4);
inputOffset += BlockSize;
}
}
RgbConverter.Convert<ColorRGBA32, byte, ColorBGRA32, byte>(output, width, height, output);
return inputOffset;
}
internal static int GetCompressedSize(int w, int h) => ((w) >> 2) * ((h) >> 2) * BlockSize;
}
+33
View File
@@ -0,0 +1,33 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
namespace AssetRipper.TextureDecoder.Bc;
public static class Bc2
{
internal const int BlockSize = 16;
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * Unsafe.SizeOf<ColorBGRA32>()];
return Decompress(input, width, height, output);
}
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
int inputOffset = 0;
for (int i = 0; i < height; i += 4)
{
for (int j = 0; j < width; j += 4)
{
int outputOffset = ((i * width) + j) * Unsafe.SizeOf<ColorRGBA32>();
BcHelpers.DecompressBc2(input.Slice(inputOffset), output.Slice(outputOffset), width * 4);
inputOffset += BlockSize;
}
}
RgbConverter.Convert<ColorRGBA32, byte, ColorBGRA32, byte>(output, width, height, output);
return inputOffset;
}
internal static int GetCompressedSize(int w, int h) => ((w) >> 2) * ((h) >> 2) * BlockSize;
}
+33
View File
@@ -0,0 +1,33 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
namespace AssetRipper.TextureDecoder.Bc;
public static class Bc3
{
internal const int BlockSize = 16;
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * Unsafe.SizeOf<ColorBGRA32>()];
return Decompress(input, width, height, output);
}
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
int inputOffset = 0;
for (int i = 0; i < height; i += 4)
{
for (int j = 0; j < width; j += 4)
{
int outputOffset = ((i * width) + j) * Unsafe.SizeOf<ColorRGBA32>();
BcHelpers.DecompressBc3(input.Slice(inputOffset), output.Slice(outputOffset), width * 4);
inputOffset += BlockSize;
}
}
RgbConverter.Convert<ColorRGBA32, byte, ColorBGRA32, byte>(output, width, height, output);
return inputOffset;
}
internal static int GetCompressedSize(int w, int h) => ((w) >> 2) * ((h) >> 2) * BlockSize;
}
+38
View File
@@ -0,0 +1,38 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Buffers;
namespace AssetRipper.TextureDecoder.Bc;
public static class Bc4
{
internal const int BlockSize = 8;
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * Unsafe.SizeOf<ColorBGRA32>()];
return Decompress(input, width, height, output);
}
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
int bufferSize = width * height * Unsafe.SizeOf<ColorR8>();
byte[] bufferArray = ArrayPool<byte>.Shared.Rent(bufferSize);
Span<byte> buffer = new Span<byte>(bufferArray, 0, bufferSize);
int inputOffset = 0;
for (int i = 0; i < height; i += 4)
{
for (int j = 0; j < width; j += 4)
{
int bufferOffset = ((i * width) + j) * Unsafe.SizeOf<ColorR8>();
BcHelpers.DecompressBc4(input.Slice(inputOffset), buffer.Slice(bufferOffset), width);
inputOffset += BlockSize;
}
}
RgbConverter.Convert<ColorR8, byte, ColorBGRA32, byte>(buffer, width, height, output);
ArrayPool<byte>.Shared.Return(bufferArray);
return inputOffset;
}
internal static int GetCompressedSize(int w, int h) => ((w) >> 2) * ((h) >> 2) * BlockSize;
}
+38
View File
@@ -0,0 +1,38 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Buffers;
namespace AssetRipper.TextureDecoder.Bc;
public static class Bc5
{
internal const int BlockSize = 16;
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * Unsafe.SizeOf<ColorBGRA32>()];
return Decompress(input, width, height, output);
}
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
int bufferSize = width * height * Unsafe.SizeOf<ColorRG16>();
byte[] bufferArray = ArrayPool<byte>.Shared.Rent(bufferSize);
Span<byte> buffer = new Span<byte>(bufferArray, 0, bufferSize);
int inputOffset = 0;
for (int i = 0; i < height; i += 4)
{
for (int j = 0; j < width; j += 4)
{
int bufferOffset = ((i * width) + j) * Unsafe.SizeOf<ColorRG16>();
BcHelpers.DecompressBc5(input.Slice(inputOffset), buffer.Slice(bufferOffset), width * 2);
inputOffset += BlockSize;
}
}
RgbConverter.Convert<ColorRG16, byte, ColorBGRA32, byte>(buffer, width, height, output);
ArrayPool<byte>.Shared.Return(bufferArray);
return inputOffset;
}
internal static int GetCompressedSize(int w, int h) => ((w) >> 2) * ((h) >> 2) * BlockSize;
}
+42
View File
@@ -0,0 +1,42 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
using System.Buffers;
namespace AssetRipper.TextureDecoder.Bc;
public static class Bc6h
{
internal const int BlockSize = 16;
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, bool isSigned, out byte[] output)
{
output = new byte[width * height * Unsafe.SizeOf<ColorBGRA32>()];
return Decompress(input, width, height, isSigned, output);
}
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, bool isSigned, Span<byte> output)
{
int bufferSize = width * height * Unsafe.SizeOf<ColorRGB48Half>();
byte[] bufferArray = ArrayPool<byte>.Shared.Rent(bufferSize);
Span<byte> buffer = new Span<byte>(bufferArray, 0, bufferSize);
int inputOffset = 0;
for (int i = 0; i < height; i += 4)
{
for (int j = 0; j < width; j += 4)
{
int outputOffset = ((i * width) + j) * Unsafe.SizeOf<ColorRGB48Half>();
BcHelpers.DecompressBc6h(
input.Slice(inputOffset, BlockSize),
buffer.Slice(outputOffset),
width * 3,
isSigned);
inputOffset += BlockSize;
}
}
RgbConverter.Convert<ColorRGB48Half, Half, ColorBGRA32, byte>(buffer, width, height, output);
ArrayPool<byte>.Shared.Return(bufferArray);
return inputOffset;
}
internal static int GetCompressedSize(int w, int h) => ((w) >> 2) * ((h) >> 2) * BlockSize;
}
+249
View File
@@ -0,0 +1,249 @@
namespace AssetRipper.TextureDecoder.Bc;
internal static class Bc6hTables
{
internal static byte[][] ActualBitsCount { get; } = new byte[4][]
{
new byte[14] {10, 7, 11, 11, 11, 9, 8, 8, 8, 6, 10, 11, 12, 16},
new byte[14] {5, 6, 5, 4, 4, 5, 6, 5, 5, 6, 10, 9, 8, 4},
new byte[14] {5, 6, 4, 5, 4, 5, 5, 6, 5, 6, 10, 9, 8, 4},
new byte[14] {5, 6, 4, 4, 5, 5, 5, 5, 6, 6, 10, 9, 8, 4}
};
/// <summary>
/// There are 32 possible partition sets for a two-region tile.
/// Each 4x4 block represents a single shape.
/// Here also every fix-up index has MSB bit set.
/// </summary>
internal static byte[][][] PartitionSets { get; } = new byte[32][][]
{
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 0, 0, 0},
new byte[4] {1, 1, 1, 0},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {129, 0, 0, 0},
new byte[4] {1, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 0, 0, 0},
new byte[4] {129, 1, 0, 0},
new byte[4] {1, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {129, 0, 0, 0},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 0, 0, 0},
new byte[4] {129, 0, 0, 0},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {0, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {0, 1, 1, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {129, 1, 1, 0},
new byte[4] {1, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {129, 1, 1, 1},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {1, 0, 0, 0},
new byte[4] {1, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {1, 0, 0, 1},
new byte[4] {1, 0, 0, 1},
new byte[4] {1, 1, 0, 0}
}
};
internal static int[] AWeight3 { get; } = new int[8] { 0, 9, 18, 27, 37, 46, 55, 64 };
internal static int[] AWeight4 { get; } = new int[16] { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
}
+36
View File
@@ -0,0 +1,36 @@
using AssetRipper.TextureDecoder.Rgb;
using AssetRipper.TextureDecoder.Rgb.Formats;
namespace AssetRipper.TextureDecoder.Bc;
public static class Bc7
{
internal const int BlockSize = 16;
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * Unsafe.SizeOf<ColorBGRA32>()];
return Decompress(input, width, height, output);
}
public static int Decompress(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
int inputOffset = 0;
for (int i = 0; i < height; i += 4)
{
for (int j = 0; j < width; j += 4)
{
int outputOffset = ((i * width) + j) * Unsafe.SizeOf<ColorRGBA32>();
BcHelpers.DecompressBc7(
input.Slice(inputOffset, BlockSize),
output.Slice(outputOffset),
width * 4);
inputOffset += BlockSize;
}
}
RgbConverter.Convert<ColorRGBA32, byte, ColorBGRA32, byte>(output, width, height, output);
return inputOffset;
}
internal static int GetCompressedSize(int w, int h) => ((w) >> 2) * ((h) >> 2) * BlockSize;
}
+929
View File
@@ -0,0 +1,929 @@
namespace AssetRipper.TextureDecoder.Bc;
internal static class Bc7Tables
{
internal static byte[][] ActualBitsCount { get; } = new byte[2][]
{
new byte[8] { 4, 6, 5, 7, 5, 7, 7, 5 },
new byte[8] { 0, 0, 0, 0, 6, 8, 7, 5 }
};
/// <summary>
/// There are 64 possible partition sets for a two-region tile.
/// Each 4x4 block represents a single shape.
/// Here also every fix-up index has MSB bit set.
/// </summary>
internal static byte[][][][] PartitionSets { get; } = new byte[2][][][]
{
new byte[64][][]
{
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 0, 0, 0},
new byte[4] {1, 1, 1, 0},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {129, 0, 0, 0},
new byte[4] {1, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 0, 0, 0},
new byte[4] {129, 1, 0, 0},
new byte[4] {1, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {129, 0, 0, 0},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 0, 0, 0},
new byte[4] {129, 0, 0, 0},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {0, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {0, 1, 1, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {129, 1, 1, 0},
new byte[4] {1, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {129, 1, 1, 1},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 1},
new byte[4] {0, 0, 0, 1},
new byte[4] {1, 0, 0, 0},
new byte[4] {1, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {1, 0, 0, 1},
new byte[4] {1, 0, 0, 1},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 1},
new byte[4] {0, 1, 0, 1},
new byte[4] {0, 1, 0, 1},
new byte[4] {0, 1, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {0, 0, 0, 0},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 1},
new byte[4] {1, 0, 129, 0},
new byte[4] {0, 1, 0, 1},
new byte[4] {1, 0, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {129, 1, 0, 0},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {1, 1, 0, 0},
new byte[4] {0, 0, 1, 1},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 1},
new byte[4] {0, 1, 0, 1},
new byte[4] {129, 0, 1, 0},
new byte[4] {1, 0, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {1, 0, 0, 1},
new byte[4] {0, 1, 1, 0},
new byte[4] {1, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 1},
new byte[4] {1, 0, 1, 0},
new byte[4] {1, 0, 1, 0},
new byte[4] {0, 1, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {1, 1, 0, 0},
new byte[4] {1, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {129, 1, 0, 0},
new byte[4] {1, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {0, 0, 1, 0},
new byte[4] {0, 1, 0, 0},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {1, 0, 1, 1},
new byte[4] {1, 1, 0, 1},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 0},
new byte[4] {1, 0, 0, 1},
new byte[4] {1, 0, 0, 1},
new byte[4] {0, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {1, 1, 0, 0},
new byte[4] {1, 1, 0, 0},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {1, 0, 0, 1},
new byte[4] {1, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 1, 129, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 0},
new byte[4] {1, 1, 129, 0},
new byte[4] {0, 1, 0, 0},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 0},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 0, 1, 0},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 129, 0},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 0, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 1, 0, 0},
new byte[4] {129, 1, 1, 0},
new byte[4] {0, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {1, 1, 0, 0},
new byte[4] {1, 0, 0, 1},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 1, 1, 0},
new byte[4] {1, 1, 0, 0},
new byte[4] {1, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 129, 0},
new byte[4] {0, 0, 1, 1},
new byte[4] {1, 0, 0, 1},
new byte[4] {1, 1, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {1, 0, 0, 1},
new byte[4] {1, 1, 0, 0},
new byte[4] {0, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {1, 1, 0, 0},
new byte[4] {1, 1, 0, 0},
new byte[4] {1, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {1, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 1},
new byte[4] {1, 1, 1, 0},
new byte[4] {1, 0, 0, 0},
new byte[4] {0, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 1},
new byte[4] {1, 0, 0, 0},
new byte[4] {1, 1, 1, 0},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {1, 1, 1, 1},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 129, 0},
new byte[4] {0, 0, 1, 0},
new byte[4] {1, 1, 1, 0},
new byte[4] {1, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 0},
new byte[4] {0, 1, 0, 0},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 1, 1, 129}
}
},
new byte[64][][]
{
new byte[4][]
{
new byte[4] {128, 0, 1, 129},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 2, 2, 1},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 129},
new byte[4] {0, 0, 1, 1},
new byte[4] {130, 2, 1, 1},
new byte[4] {2, 2, 2, 1}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {2, 0, 0, 1},
new byte[4] {130, 2, 1, 1},
new byte[4] {2, 2, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 2, 2, 130},
new byte[4] {0, 0, 2, 2},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {129, 1, 2, 2},
new byte[4] {1, 1, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 129},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 2, 2},
new byte[4] {0, 0, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 2, 130},
new byte[4] {0, 0, 2, 2},
new byte[4] {1, 1, 1, 1},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 0, 1, 1},
new byte[4] {130, 2, 1, 1},
new byte[4] {2, 2, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {129, 1, 1, 1},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 1, 1},
new byte[4] {129, 1, 1, 1},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 129, 1},
new byte[4] {2, 2, 2, 2},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 2},
new byte[4] {0, 0, 129, 2},
new byte[4] {0, 0, 1, 2},
new byte[4] {0, 0, 1, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 2},
new byte[4] {0, 1, 129, 2},
new byte[4] {0, 1, 1, 2},
new byte[4] {0, 1, 1, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 2, 2},
new byte[4] {0, 129, 2, 2},
new byte[4] {0, 1, 2, 2},
new byte[4] {0, 1, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 129},
new byte[4] {0, 1, 1, 2},
new byte[4] {1, 1, 2, 2},
new byte[4] {1, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 129},
new byte[4] {2, 0, 0, 1},
new byte[4] {130, 2, 0, 0},
new byte[4] {2, 2, 2, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 129},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 1, 1, 2},
new byte[4] {1, 1, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 129},
new byte[4] {0, 0, 1, 1},
new byte[4] {130, 0, 0, 1},
new byte[4] {2, 2, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 2, 2},
new byte[4] {129, 1, 2, 2},
new byte[4] {1, 1, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 2, 130},
new byte[4] {0, 0, 2, 2},
new byte[4] {0, 0, 2, 2},
new byte[4] {1, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 129},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 2, 2, 2},
new byte[4] {0, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 129},
new byte[4] {0, 0, 0, 1},
new byte[4] {130, 2, 2, 1},
new byte[4] {2, 2, 2, 1}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 129, 1},
new byte[4] {0, 1, 2, 2},
new byte[4] {0, 1, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 0, 0},
new byte[4] {130, 2, 129, 0},
new byte[4] {2, 2, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 2, 130},
new byte[4] {0, 129, 2, 2},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 2},
new byte[4] {0, 0, 1, 2},
new byte[4] {129, 1, 2, 2},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {1, 2, 130, 1},
new byte[4] {129, 2, 2, 1},
new byte[4] {0, 1, 1, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 1, 129, 0},
new byte[4] {1, 2, 130, 1},
new byte[4] {1, 2, 2, 1}
},
new byte[4][]
{
new byte[4] {128, 0, 2, 2},
new byte[4] {1, 1, 0, 2},
new byte[4] {129, 1, 0, 2},
new byte[4] {0, 0, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {0, 129, 1, 0},
new byte[4] {2, 0, 0, 2},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {0, 1, 2, 2},
new byte[4] {0, 1, 130, 2},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {2, 0, 0, 0},
new byte[4] {130, 2, 1, 1},
new byte[4] {2, 2, 2, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 2},
new byte[4] {129, 1, 2, 2},
new byte[4] {1, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 2, 2, 130},
new byte[4] {0, 0, 2, 2},
new byte[4] {0, 0, 1, 2},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 129},
new byte[4] {0, 0, 1, 2},
new byte[4] {0, 0, 2, 2},
new byte[4] {0, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 2, 0},
new byte[4] {0, 129, 2, 0},
new byte[4] {0, 1, 130, 0},
new byte[4] {0, 1, 2, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {1, 1, 129, 1},
new byte[4] {2, 2, 130, 2},
new byte[4] {0, 0, 0, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 2, 0},
new byte[4] {1, 2, 0, 1},
new byte[4] {130, 0, 129, 2},
new byte[4] {0, 1, 2, 0}
},
new byte[4][]
{
new byte[4] {128, 1, 2, 0},
new byte[4] {2, 0, 1, 2},
new byte[4] {129, 130, 0, 1},
new byte[4] {0, 1, 2, 0}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {2, 2, 0, 0},
new byte[4] {1, 1, 130, 2},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 1, 1},
new byte[4] {1, 1, 130, 2},
new byte[4] {2, 2, 0, 0},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 129},
new byte[4] {0, 1, 0, 1},
new byte[4] {2, 2, 2, 2},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {130, 1, 2, 1},
new byte[4] {2, 1, 2, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 2, 2},
new byte[4] {1, 129, 2, 2},
new byte[4] {0, 0, 2, 2},
new byte[4] {1, 1, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 2, 130},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 2, 2},
new byte[4] {0, 0, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 2, 2, 0},
new byte[4] {1, 2, 130, 1},
new byte[4] {0, 2, 2, 0},
new byte[4] {1, 2, 2, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 1},
new byte[4] {2, 2, 130, 2},
new byte[4] {2, 2, 2, 2},
new byte[4] {0, 1, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {2, 1, 2, 1},
new byte[4] {130, 1, 2, 1},
new byte[4] {2, 1, 2, 129}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 129},
new byte[4] {0, 1, 0, 1},
new byte[4] {0, 1, 0, 1},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 2, 2, 130},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 2, 2, 2},
new byte[4] {0, 1, 1, 129}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 2},
new byte[4] {1, 129, 1, 2},
new byte[4] {0, 0, 0, 2},
new byte[4] {1, 1, 1, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {2, 129, 1, 2},
new byte[4] {2, 1, 1, 2},
new byte[4] {2, 1, 1, 130}
},
new byte[4][]
{
new byte[4] {128, 2, 2, 2},
new byte[4] {0, 129, 1, 1},
new byte[4] {0, 1, 1, 1},
new byte[4] {0, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 2},
new byte[4] {1, 1, 1, 2},
new byte[4] {129, 1, 1, 2},
new byte[4] {0, 0, 0, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {0, 129, 1, 0},
new byte[4] {0, 1, 1, 0},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {2, 1, 129, 2},
new byte[4] {2, 1, 1, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 0},
new byte[4] {0, 129, 1, 0},
new byte[4] {2, 2, 2, 2},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 2, 2},
new byte[4] {0, 0, 1, 1},
new byte[4] {0, 0, 129, 1},
new byte[4] {0, 0, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 2, 2},
new byte[4] {1, 1, 2, 2},
new byte[4] {129, 1, 2, 2},
new byte[4] {0, 0, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {0, 0, 0, 0},
new byte[4] {2, 129, 1, 130}
},
new byte[4][]
{
new byte[4] {128, 0, 0, 130},
new byte[4] {0, 0, 0, 1},
new byte[4] {0, 0, 0, 2},
new byte[4] {0, 0, 0, 129}
},
new byte[4][]
{
new byte[4] {128, 2, 2, 2},
new byte[4] {1, 2, 2, 2},
new byte[4] {0, 2, 2, 2},
new byte[4] {129, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 0, 129},
new byte[4] {2, 2, 2, 2},
new byte[4] {2, 2, 2, 2},
new byte[4] {2, 2, 2, 130}
},
new byte[4][]
{
new byte[4] {128, 1, 1, 129},
new byte[4] {2, 0, 1, 1},
new byte[4] {130, 2, 0, 1},
new byte[4] {2, 2, 2, 0}
}
}
};
internal static int[] AWeight2 { get; } = new int[4] { 0, 21, 43, 64 };
internal static int[] AWeight3 { get; } = new int[8] { 0, 9, 18, 27, 37, 46, 55, 64 };
internal static int[] AWeight4 { get; } = new int[16] { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
internal const byte bcdec_bc7_sModeHasPBits = 0b11001011;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,45 @@
namespace AssetRipper.TextureDecoder.Bc;
internal struct BitStream
{
public ulong low;
public ulong high;
public int ReadBits(int numBits)
{
uint mask = (uint)((1 << numBits) - 1);
// Read the low N bits
uint bits = (uint)(this.low & mask);
this.low >>= numBits;
// Put the low N bits of "high" into the high 64-N bits of "low".
this.low |= (this.high & mask) << ((sizeof(ulong) * 8) - numBits);
this.high >>= numBits;
return (int)bits;
}
public int ReadBit()
{
return this.ReadBits(1);
}
/// <summary>
/// Reversed bits pulling, used in BC6H decoding
/// </summary>
/// <param name="numBits"></param>
/// <returns></returns>
public int ReadBitsReversed(int numBits)
{
int bits = this.ReadBits(numBits);
// Reverse the bits.
int result = 0;
while (numBits-- != 0)
{
result <<= 1;
result |= bits & 1;
bits >>= 1;
}
return result;
}
}
+42
View File
@@ -0,0 +1,42 @@
/* bcdec.h - v0.94
provides functions to decompress blocks of BC compressed images
written by Sergii "iOrange" Kudlai in 2022
This library does not allocate memory and is trying to use as less stack as possible
The library was never optimized specifically for speed but for the overall size
it has zero external dependencies and is not using any runtime functions
Supported BC formats:
BC1 (also known as DXT1) + it's "binary alpha" variant BC1A (DXT1A)
BC2 (also known as DXT3)
BC3 (also known as DXT5)
BC4 (also known as ATI1N)
BC5 (also known as ATI2N)
BC6H (HDR format)
BC7
BC1/BC2/BC3/BC7 are expected to decompress into 4*4 RGBA blocks 8bit per component (32bit pixel)
BC4/BC5 are expected to decompress into 4*4 R/RG blocks 8bit per component (8bit and 16bit pixel)
BC6H is expected to decompress into 4*4 RGB blocks of either 32bit float or 16bit "half" per
component (96bit or 48bit pixel)
For more info, issues and suggestions please visit https://github.com/iOrange/bcdec
CREDITS:
Aras Pranckevicius (@aras-p) - BC1/BC3 decoders optimizations (up to 3x the speed)
- BC6H/BC7 bits pulling routines optimizations
- Split BC6H decompression function into 'half' and
'float' variants
LICENSE: See end of file for license information.
*/
/* Used information sources:
https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-block-compression
https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc6h-format
https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format
https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format-mode-reference
! WARNING ! Khronos's BPTC partitions tables contain mistakes, do not use them!
https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#BPTC
! Use tables from here instead !
https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt
Leaving it here as it's a nice read
https://fgiesen.wordpress.com/2021/10/04/gpu-bcn-decoding/
Fast half to float function from here
https://gist.github.com/rygorous/2144712
*/
@@ -0,0 +1,297 @@
using System.Buffers.Binary;
using System.Runtime.InteropServices;
namespace AssetRipper.TextureDecoder.Dxt
{
public static class DxtDecoder
{
/// <summary>
/// Decompress a DXT1 image
/// </summary>
/// <param name="input">Input buffer containing the compressed image.</param>
/// <param name="width">Pixel width of the image.</param>
/// <param name="height">Pixel height of the image.</param>
/// <param name="output">An output buffer of size 4 * width * height.</param>
/// <returns>Number of bytes read from <paramref name="input"/></returns>
public static int DecompressDXT1(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * sizeof(uint)];
return DecompressDXT1(input, width, height, output);
}
/// <summary>
/// Decompress a DXT1 image
/// </summary>
/// <param name="input">Input buffer containing the compressed image.</param>
/// <param name="width">Pixel width of the image.</param>
/// <param name="height">Pixel height of the image.</param>
/// <param name="output">An output buffer. Must be at least 4 * width * height.</param>
/// <returns>Number of bytes read from <paramref name="input"/></returns>
public static int DecompressDXT1(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
ThrowHelper.ThrowIfNotEnoughSpace(output, width, height);
int offset = 0;
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint[] buffer = new uint[16];
int[] colors = new int[4];
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, offset += 8)
{
int q0 = input[offset + 0] | input[offset + 1] << 8;
int q1 = input[offset + 2] | input[offset + 3] << 8;
Rgb565(q0, out int r0, out int g0, out int b0);
Rgb565(q1, out int r1, out int g1, out int b1);
colors[0] = Color(r0, g0, b0, 255);
colors[1] = Color(r1, g1, b1, 255);
if (q0 > q1)
{
colors[2] = Color((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 255);
colors[3] = Color((r0 + r1 * 2) / 3, (g0 + g1 * 2) / 3, (b0 + b1 * 2) / 3, 255);
}
else
{
colors[2] = Color((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 255);
}
uint d = ToUInt32(input, offset + 4);
for (int i = 0; i < 16; i++, d >>= 2)
{
buffer[i] = unchecked((uint)colors[d & 3]);
}
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
ReadOnlySpan<byte> bufferSpan = MemoryMarshal.Cast<uint, byte>(new ReadOnlySpan<uint>(buffer));
BlockCopy(bufferSpan, i * 4 * 4, output, (y * width + s * 4) * 4, clen);
}
}
}
return offset;
}
/// <summary>
/// Decompress a DXT3 image
/// </summary>
/// <param name="input">Input buffer containing the compressed image.</param>
/// <param name="width">Pixel width of the image.</param>
/// <param name="height">Pixel height of the image.</param>
/// <param name="output">An output buffer of size 4 * width * height.</param>
/// <returns>Number of bytes read from <paramref name="input"/></returns>
public static int DecompressDXT3(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * sizeof(uint)];
return DecompressDXT3(input, width, height, output);
}
/// <summary>
/// Decompress a DXT3 image
/// </summary>
/// <param name="input">Input buffer containing the compressed image.</param>
/// <param name="width">Pixel width of the image.</param>
/// <param name="height">Pixel height of the image.</param>
/// <param name="output">An output buffer. Must be at least 4 * width * height.</param>
/// <returns>Number of bytes read from <paramref name="input"/></returns>
public static int DecompressDXT3(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
ThrowHelper.ThrowIfNotEnoughSpace(output, width, height);
int offset = 0;
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint[] buffer = new uint[16];
int[] colors = new int[4];
int[] alphas = new int[16];
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, offset += 16)
{
for (int i = 0; i < 4; i++)
{
int alpha = input[offset + i * 2] | input[offset + i * 2 + 1] << 8;
alphas[i * 4 + 0] = (((alpha >> 0) & 0xF) * 0x11) << 24;
alphas[i * 4 + 1] = (((alpha >> 4) & 0xF) * 0x11) << 24;
alphas[i * 4 + 2] = (((alpha >> 8) & 0xF) * 0x11) << 24;
alphas[i * 4 + 3] = (((alpha >> 12) & 0xF) * 0x11) << 24;
}
int q0 = input[offset + 8] | input[offset + 9] << 8;
int q1 = input[offset + 10] | input[offset + 11] << 8;
Rgb565(q0, out int r0, out int g0, out int b0);
Rgb565(q1, out int r1, out int g1, out int b1);
colors[0] = Color(r0, g0, b0, 0);
colors[1] = Color(r1, g1, b1, 0);
if (q0 > q1)
{
colors[2] = Color((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 0);
colors[3] = Color((r0 + r1 * 2) / 3, (g0 + g1 * 2) / 3, (b0 + b1 * 2) / 3, 0);
}
else
{
colors[2] = Color((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 0);
}
uint d = ToUInt32(input, offset + 12);
for (int i = 0; i < 16; i++, d >>= 2)
{
buffer[i] = unchecked((uint)(colors[d & 3] | alphas[i]));
}
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
ReadOnlySpan<byte> bufferSpan = MemoryMarshal.Cast<uint, byte>(new ReadOnlySpan<uint>(buffer));
BlockCopy(bufferSpan, i * 4 * 4, output, (y * width + s * 4) * 4, clen);
}
}
}
return offset;
}
/// <summary>
/// Decompress a DXT5 image
/// </summary>
/// <param name="input">Input buffer containing the compressed image.</param>
/// <param name="width">Pixel width of the image.</param>
/// <param name="height">Pixel height of the image.</param>
/// <param name="output">An output buffer of size 4 * width * height.</param>
/// <returns>Number of bytes read from <paramref name="input"/></returns>
public static int DecompressDXT5(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * sizeof(uint)];
return DecompressDXT5(input, width, height, output);
}
/// <summary>
/// Decompress a DXT5 image
/// </summary>
/// <param name="input">Input buffer containing the compressed image.</param>
/// <param name="width">Pixel width of the image.</param>
/// <param name="height">Pixel height of the image.</param>
/// <param name="output">An output buffer. Must be at least 4 * width * height.</param>
/// <returns>Number of bytes read from <paramref name="input"/></returns>
public static int DecompressDXT5(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
ThrowHelper.ThrowIfNotEnoughSpace(output, width, height);
int offset = 0;
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint[] buffer = new uint[16];
int[] colors = new int[4];
int[] alphas = new int[8];
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, offset += 16)
{
alphas[0] = input[offset + 0];
alphas[1] = input[offset + 1];
if (alphas[0] > alphas[1])
{
alphas[2] = (alphas[0] * 6 + alphas[1]) / 7;
alphas[3] = (alphas[0] * 5 + alphas[1] * 2) / 7;
alphas[4] = (alphas[0] * 4 + alphas[1] * 3) / 7;
alphas[5] = (alphas[0] * 3 + alphas[1] * 4) / 7;
alphas[6] = (alphas[0] * 2 + alphas[1] * 5) / 7;
alphas[7] = (alphas[0] + alphas[1] * 6) / 7;
}
else
{
alphas[2] = (alphas[0] * 4 + alphas[1]) / 5;
alphas[3] = (alphas[0] * 3 + alphas[1] * 2) / 5;
alphas[4] = (alphas[0] * 2 + alphas[1] * 3) / 5;
alphas[5] = (alphas[0] + alphas[1] * 4) / 5;
alphas[7] = 255;
}
for (int i = 0; i < 8; i++)
{
alphas[i] <<= 24;
}
int q0 = input[offset + 8] | input[offset + 9] << 8;
int q1 = input[offset + 10] | input[offset + 11] << 8;
Rgb565(q0, out int r0, out int g0, out int b0);
Rgb565(q1, out int r1, out int g1, out int b1);
colors[0] = Color(r0, g0, b0, 0);
colors[1] = Color(r1, g1, b1, 0);
if (q0 > q1)
{
colors[2] = Color((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 0);
colors[3] = Color((r0 + r1 * 2) / 3, (g0 + g1 * 2) / 3, (b0 + b1 * 2) / 3, 0);
}
else
{
colors[2] = Color((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 0);
}
ulong da = ToUInt64(input, offset) >> 16;
uint dc = ToUInt32(input, offset + 12);
for (int i = 0; i < 16; i++, da >>= 3, dc >>= 2)
{
buffer[i] = unchecked((uint)(alphas[da & 7] | colors[dc & 3]));
}
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
ReadOnlySpan<byte> bufferSpan = MemoryMarshal.Cast<uint, byte>(new ReadOnlySpan<uint>(buffer));
BlockCopy(bufferSpan, i * 4 * 4, output, (y * width + s * 4) * 4, clen);
}
}
}
return offset;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Rgb565(int c, out int r, out int g, out int b)
{
r = (c & 0xf800) >> 8;
g = (c & 0x07e0) >> 3;
b = (c & 0x001f) << 3;
r |= r >> 5;
g |= g >> 6;
b |= b >> 5;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Color(int r, int g, int b, int a)
{
return r << 16 | g << 8 | b | a << 24;
}
/// <summary>
/// Based on <see cref="Buffer.BlockCopy(Array, int, Array, int, int)"/>
/// </summary>
/// <param name="source">The source buffer.</param>
/// <param name="sourceOffset">The zero-based byte offset into source.</param>
/// <param name="destination">The destination buffer.</param>
/// <param name="destinationOffset">The zero-based byte offset into destination.</param>
/// <param name="count">The number of bytes to copy.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void BlockCopy(ReadOnlySpan<byte> source, int sourceOffset, Span<byte> destination, int destinationOffset, int count)
{
source.Slice(sourceOffset, count).CopyTo(destination.Slice(destinationOffset));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint ToUInt32(ReadOnlySpan<byte> input, int offset)
{
return BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(offset));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ToUInt64(ReadOnlySpan<byte> input, int offset)
{
return BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(offset));
}
}
}
@@ -1,373 +1,423 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace TextureDecoder.Etc
namespace AssetRipper.TextureDecoder.Etc
{
public static class EtcDecoder
{
public static byte[] DecompressETC(byte[] input, int width, int height)
public static int DecompressETC(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressETC(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressETC(input, width, height, output);
}
public unsafe static void DecompressETC(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressETC(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
if (input.Length < requiredLength)
{
fixed (byte* outputPtr = output)
{
DecompressETC(inputPtr, width, height, outputPtr);
}
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
}
fixed (byte* outputPtr = output)
{
return DecompressETC(input, width, height, outputPtr);
}
}
public unsafe static void DecompressETC(byte* input, int width, int height, byte* output)
private unsafe static int DecompressETC(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
Span<uint> buf = stackalloc uint[16];
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 8)
for (int s = 0; s < bcw; s++, inputOffset += 8)
{
DecodeEtc1Block(input, buf);
DecodeEtc1Block(input.Slice(inputOffset, 8), buf);
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = buf[j + 4 * i];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
public static byte[] DecompressETC2(byte[] input, int width, int height)
public static int DecompressETC2(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressETC2(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressETC2(input, width, height, output);
}
public unsafe static void DecompressETC2(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressETC2(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
if (input.Length < requiredLength)
{
fixed (byte* outputPtr = output)
{
DecompressETC2(inputPtr, width, height, outputPtr);
}
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
}
fixed (byte* outputPtr = output)
{
return DecompressETC2(input, width, height, outputPtr);
}
}
public unsafe static void DecompressETC2(byte* input, int width, int height, byte* output)
private unsafe static int DecompressETC2(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
Span<uint> buf = stackalloc uint[16];
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 8)
for (int s = 0; s < bcw; s++, inputOffset += 8)
{
DecodeEtc2Block(input, buf);
DecodeEtc2Block(input.Slice(inputOffset, 8), buf);
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = buf[j + 4 * i];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
public static byte[] DecompressETC2A1(byte[] input, int width, int height)
public static int DecompressETC2A1(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressETC2A1(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressETC2A1(input, width, height, output);
}
public unsafe static void DecompressETC2A1(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressETC2A1(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
if (input.Length < requiredLength)
{
fixed (byte* outputPtr = output)
{
DecompressETC2A1(inputPtr, width, height, outputPtr);
}
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
}
fixed (byte* outputPtr = output)
{
return DecompressETC2A1(input, width, height, outputPtr);
}
}
public unsafe static void DecompressETC2A1(byte* input, int width, int height, byte* output)
private unsafe static int DecompressETC2A1(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int width4 = width * 4;
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
Span<uint> buf = stackalloc uint[16];
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 8)
for (int s = 0; s < bcw; s++, inputOffset += 8)
{
DecodeEtc2a1Block(input, buf);
DecodeEtc2a1Block(input.Slice(inputOffset, 8), buf);
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = buf[j + 4 * i];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
public static byte[] DecompressETC2A8(byte[] input, int width, int height)
public static int DecompressETC2A8(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressETC2A8(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressETC2A8(input, width, height, output);
}
public unsafe static void DecompressETC2A8(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressETC2A8(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 16;
if (input.Length < requiredLength)
{
fixed (byte* outputPtr = output)
{
DecompressETC2A8(inputPtr, width, height, outputPtr);
}
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
}
fixed (byte* outputPtr = output)
{
return DecompressETC2A8(input, width, height, outputPtr);
}
}
public unsafe static void DecompressETC2A8(byte* input, int width, int height, byte* output)
private unsafe static int DecompressETC2A8(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
Span<uint> buf = stackalloc uint[16];
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 16)
for (int s = 0; s < bcw; s++, inputOffset += 16)
{
DecodeEtc2Block(input + 8, buf);
DecodeEtc2a8Block(input, buf);
DecodeEtc2Block(input.Slice(inputOffset + 8, 8), buf);
DecodeEtc2a8Block(input.Slice(inputOffset + 0, 8), buf);
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = buf[j + 4 * i];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
public static byte[] DecompressEACRUnsigned(byte[] input, int width, int height)
public static int DecompressEACRUnsigned(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressEACRUnsigned(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressEACRUnsigned(input, width, height, output);
}
public unsafe static void DecompressEACRUnsigned(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressEACRUnsigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
if (input.Length < requiredLength)
{
fixed (byte* outputPtr = output)
{
DecompressEACRUnsigned(inputPtr, width, height, outputPtr);
}
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
}
fixed (byte* outputPtr = output)
{
return DecompressEACRUnsigned(input, width, height, outputPtr);
}
}
public unsafe static void DecompressEACRUnsigned(byte* input, int width, int height, byte* output)
private unsafe static int DecompressEACRUnsigned(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
Span<uint> buf = stackalloc uint[16];
for (int i = 0; i < 16; i++)
{
buf[i] = 0xFF000000;
}
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 8)
for (int s = 0; s < bcw; s++, inputOffset += 8)
{
DecodeEacUnsignedBlock(input, buf, 2);
DecodeEacUnsignedBlock(input.Slice(inputOffset, 8), buf, 2);
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = buf[j + 4 * i];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
public static byte[] DecompressEACRSigned(byte[] input, int width, int height)
public static int DecompressEACRSigned(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressEACRSigned(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressEACRSigned(input, width, height, output);
}
public unsafe static void DecompressEACRSigned(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressEACRSigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 8;
if (input.Length < requiredLength)
{
fixed (byte* outputPtr = output)
{
DecompressEACRSigned(inputPtr, width, height, outputPtr);
}
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
}
fixed (byte* outputPtr = output)
{
return DecompressEACRSigned(input, width, height, outputPtr);
}
}
public unsafe static void DecompressEACRSigned(byte* input, int width, int height, byte* output)
private unsafe static int DecompressEACRSigned(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
Span<uint> buf = stackalloc uint[16];
for (int i = 0; i < 16; i++)
{
buf[i] = 0xFF000000;
}
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 8)
for (int s = 0; s < bcw; s++, inputOffset += 8)
{
DecodeEacSignedBlock(input, buf, 2);
DecodeEacSignedBlock(input.Slice(inputOffset, 8), buf, 2);
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = buf[j + 4 * i];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
public static byte[] DecompressEACRGUnsigned(byte[] input, int width, int height)
public static int DecompressEACRGUnsigned(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
byte[] output = new byte[width * height * 4];
DecompressEACRGUnsigned(input, width, height, output);
return output;
output = new byte[width * height * 4];
return DecompressEACRGUnsigned(input, width, height, output);
}
public unsafe static void DecompressEACRGUnsigned(byte[] input, int width, int height, byte[] output)
public unsafe static int DecompressEACRGUnsigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
fixed (byte* inputPtr = input)
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
if (input.Length < bcw * bch * 16)
{
fixed (byte* outputPtr = output)
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {bcw * bch * 16}", nameof(input));
}
int clen_last = (width + 3) % 4 + 1;
Span<uint> buf = stackalloc uint[16];
for (int i = 0; i < 16; i++)
{
buf[i] = 0xFF000000;
}
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, inputOffset += 16)
{
DecompressEACRGUnsigned(inputPtr, width, height, outputPtr);
DecodeEacUnsignedBlock(input.Slice(inputOffset + 0, 8), buf, 2);
DecodeEacUnsignedBlock(input.Slice(inputOffset + 8, 8), buf, 1);
int clen = s < bcw - 1 ? 4 : clen_last;
int outputOffset = t * 16 * width + s * 16;
Span<uint> outputPtr = MemoryMarshal.Cast<byte, uint>(output.Slice(outputOffset));
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++)
{
outputPtr[j + i * width] = buf[j + 4 * i];
}
}
}
}
return inputOffset;
}
public static int DecompressEACRGSigned(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
{
output = new byte[width * height * 4];
return DecompressEACRGSigned(input, width, height, output);
}
public unsafe static int DecompressEACRGSigned(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
{
int requiredLength = ((width + 3) / 4) * ((height + 3) / 4) * 16;
if (input.Length < requiredLength)
{
throw new ArgumentException($"{nameof(input)} has length {input.Length} which is less than the required length {requiredLength}", nameof(input));
}
fixed (byte* outputPtr = output)
{
return DecompressEACRGSigned(input, width, height, outputPtr);
}
}
public unsafe static void DecompressEACRGUnsigned(byte* input, int width, int height, byte* output)
private unsafe static int DecompressEACRGSigned(ReadOnlySpan<byte> input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
Span<uint> buf = stackalloc uint[16];
for (int i = 0; i < 16; i++)
{
buf[i] = 0xFF000000;
}
int inputOffset = 0;
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 16)
for (int s = 0; s < bcw; s++, inputOffset += 16)
{
DecodeEacUnsignedBlock(input + 0, buf, 2);
DecodeEacUnsignedBlock(input + 8, buf, 1);
DecodeEacSignedBlock(input.Slice(inputOffset + 0, 8), buf, 2);
DecodeEacSignedBlock(input.Slice(inputOffset + 8, 8), buf, 1);
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
for (int j = 0; j < clen; j++)
{
outputPtr[j] = buf[j + 4 * i];
}
outputPtr += width;
bufPtr += 4;
}
}
}
return inputOffset;
}
public static byte[] DecompressEACRGSigned(byte[] input, int width, int height)
{
byte[] output = new byte[width * height * 4];
DecompressEACRGSigned(input, width, height, output);
return output;
}
public unsafe static void DecompressEACRGSigned(byte[] input, int width, int height, byte[] output)
{
fixed (byte* inputPtr = input)
{
fixed (byte* outputPtr = output)
{
DecompressEACRGSigned(inputPtr, width, height, outputPtr);
}
}
}
public unsafe static void DecompressEACRGSigned(byte* input, int width, int height, byte* output)
{
int bcw = (width + 3) / 4;
int bch = (height + 3) / 4;
int clen_last = (width + 3) % 4 + 1;
uint* buf = stackalloc uint[16];
for (int i = 0; i < 16; i++)
{
buf[i] = 0xFF000000;
}
for (int t = 0; t < bch; t++)
{
for (int s = 0; s < bcw; s++, input += 16)
{
DecodeEacSignedBlock(input + 0, buf, 2);
DecodeEacSignedBlock(input + 8, buf, 1);
int clen = s < bcw - 1 ? 4 : clen_last;
uint* outputPtr = (uint*)(output + (t * 16 * width + s * 16));
uint* bufPtr = buf;
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
{
for (int j = 0; j < clen; j++) outputPtr[j] = bufPtr[j];
outputPtr += width;
bufPtr += 4;
}
}
}
}
private unsafe static void DecodeEtc1Block(byte* input, uint* output)
/// <summary>
/// Parses an 8-byte Etc1 block from <paramref name="input"/>.
/// </summary>
private static void DecodeEtc1Block(ReadOnlySpan<byte> input, Span<uint> output)
{
byte i3 = input[3];
int* code = stackalloc int[2];
code[0] = (i3 >> 5) * 4;
code[1] = (i3 >> 2 & 7) * 4;
byte* c = stackalloc byte[6];
ReadOnlySpan<int> code = stackalloc int[2]
{
(i3 >> 5) * 4,
(i3 >> 2 & 7) * 4
};
Span<byte> c = stackalloc byte[6];
int ti = (i3 & 1) * 16;
if ((i3 & 2) != 0)
{
@@ -414,11 +464,11 @@ namespace TextureDecoder.Etc
}
}
private unsafe static void DecodeEtc2Block(byte* input, uint* output)
private static void DecodeEtc2Block(ReadOnlySpan<byte> input, Span<uint> output)
{
int j = input[6] << 8 | input[7];
int k = input[4] << 8 | input[5];
byte* c = stackalloc byte[3 * 3];
Span<byte> c = stackalloc byte[3 * 3];
if ((input[3] & 2) != 0)
{
@@ -438,7 +488,7 @@ namespace TextureDecoder.Etc
}
int ti = input[3] >> 1 & 6 | input[3] & 1;
byte d = Etc2DistanceTable[ti];
uint* color_set = stackalloc uint[]
ReadOnlySpan<uint> color_set = stackalloc uint[]
{
ApplicateColorRaw(c, 0),
ApplicateColor(c, 1, d),
@@ -479,7 +529,7 @@ namespace TextureDecoder.Etc
++di;
}
byte d = Etc2DistanceTable[di];
uint* color_set = stackalloc uint[]
ReadOnlySpan<uint> color_set = stackalloc uint[]
{
ApplicateColor(c, 0, d),
ApplicateColor(c, 0, -d),
@@ -519,9 +569,9 @@ namespace TextureDecoder.Etc
{
for (int x = 0; x < 4; x++, i++)
{
int ri = Clamp255((x * (c[1 * 3 + 0] - c[0 * 3 + 0]) + y * (c[2 * 3 + 0] - c[0 * 3 + 0]) + 4 * c[0 * 3 + 0] + 2) >> 2);
int gi = Clamp255((x * (c[1 * 3 + 1] - c[0 * 3 + 1]) + y * (c[2 * 3 + 1] - c[0 * 3 + 1]) + 4 * c[0 * 3 + 1] + 2) >> 2);
int bi = Clamp255((x * (c[1 * 3 + 2] - c[0 * 3 + 2]) + y * (c[2 * 3 + 2] - c[0 * 3 + 2]) + 4 * c[0 * 3 + 2] + 2) >> 2);
byte ri = Clamp255((x * (c[1 * 3 + 0] - c[0 * 3 + 0]) + y * (c[2 * 3 + 0] - c[0 * 3 + 0]) + 4 * c[0 * 3 + 0] + 2) >> 2);
byte gi = Clamp255((x * (c[1 * 3 + 1] - c[0 * 3 + 1]) + y * (c[2 * 3 + 1] - c[0 * 3 + 1]) + 4 * c[0 * 3 + 1] + 2) >> 2);
byte bi = Clamp255((x * (c[1 * 3 + 2] - c[0 * 3 + 2]) + y * (c[2 * 3 + 2] - c[0 * 3 + 2]) + 4 * c[0 * 3 + 2] + 2) >> 2);
output[i] = Color(ri, gi, bi, 255);
}
}
@@ -529,7 +579,7 @@ namespace TextureDecoder.Etc
else
{
// differential
int* code = stackalloc int[2];
Span<int> code = stackalloc int[2];
code[0] = (input[3] >> 5) * 4;
code[1] = (input[3] >> 2 & 7) * 4;
int ti = (input[3] & 1) * 16;
@@ -562,9 +612,11 @@ namespace TextureDecoder.Etc
else
{
// individual
int* code = stackalloc int[2];
code[0] = (input[3] >> 5) * 4;
code[1] = (input[3] >> 2 & 7) * 4;
ReadOnlySpan<int> code = stackalloc int[2]
{
(input[3] >> 5) * 4,
(input[3] >> 2 & 7) * 4
};
int ti = (input[3] & 1) * 16;
unchecked
{
@@ -589,7 +641,7 @@ namespace TextureDecoder.Etc
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void DecodeEtc2a1Block(byte* input, uint* output)
private static void DecodeEtc2a1Block(ReadOnlySpan<byte> input, Span<uint> output)
{
if ((input[3] & 2) != 0)
{
@@ -602,11 +654,11 @@ namespace TextureDecoder.Etc
}
}
private unsafe static void DecodeEtc2PunchThrowBlock(byte* input, uint* output)
private static void DecodeEtc2PunchThrowBlock(ReadOnlySpan<byte> input, Span<uint> output)
{
int j = input[6] << 8 | input[7];
int k = input[4] << 8 | input[5];
byte* c = stackalloc byte[3 * 3];
Span<byte> c = stackalloc byte[3 * 3];
int r = input[0] & 0xf8;
int dr = (input[0] << 3 & 0x18) - (input[0] << 3 & 0x20);
if (r + dr < 0 || r + dr > 255)
@@ -623,7 +675,7 @@ namespace TextureDecoder.Etc
}
int ti = input[3] >> 1 & 6 | input[3] & 1;
byte d = Etc2DistanceTable[ti];
uint* color_set = stackalloc uint[]
ReadOnlySpan<uint> color_set = stackalloc uint[4]
{
ApplicateColorRaw(c, 0),
ApplicateColor(c, 1, d),
@@ -665,7 +717,7 @@ namespace TextureDecoder.Etc
++di;
}
byte d = Etc2DistanceTable[di];
uint* color_set = stackalloc uint[]
ReadOnlySpan<uint> color_set = stackalloc uint[4]
{
ApplicateColor(c, 0, d),
ApplicateColor(c, 0, -d),
@@ -706,9 +758,9 @@ namespace TextureDecoder.Etc
{
for (int x = 0; x < 4; x++, i++)
{
int ri = Clamp255((x * (c[1 * 3 + 0] - c[0 * 3 + 0]) + y * (c[2 * 3 + 0] - c[0 * 3 + 0]) + 4 * c[0 * 3 + 0] + 2) >> 2);
int gi = Clamp255((x * (c[1 * 3 + 1] - c[0 * 3 + 1]) + y * (c[2 * 3 + 1] - c[0 * 3 + 1]) + 4 * c[0 * 3 + 1] + 2) >> 2);
int bi = Clamp255((x * (c[1 * 3 + 2] - c[0 * 3 + 2]) + y * (c[2 * 3 + 2] - c[0 * 3 + 2]) + 4 * c[0 * 3 + 2] + 2) >> 2);
byte ri = Clamp255((x * (c[1 * 3 + 0] - c[0 * 3 + 0]) + y * (c[2 * 3 + 0] - c[0 * 3 + 0]) + 4 * c[0 * 3 + 0] + 2) >> 2);
byte gi = Clamp255((x * (c[1 * 3 + 1] - c[0 * 3 + 1]) + y * (c[2 * 3 + 1] - c[0 * 3 + 1]) + 4 * c[0 * 3 + 1] + 2) >> 2);
byte bi = Clamp255((x * (c[1 * 3 + 2] - c[0 * 3 + 2]) + y * (c[2 * 3 + 2] - c[0 * 3 + 2]) + 4 * c[0 * 3 + 2] + 2) >> 2);
output[i] = Color(ri, gi, bi, 255);
}
}
@@ -716,9 +768,11 @@ namespace TextureDecoder.Etc
else
{
// differential (Etc1Block + mask + specific mod table)
int* code = stackalloc int[2];
code[0] = (input[3] >> 5) * 4;
code[1] = (input[3] >> 2 & 7) * 4;
ReadOnlySpan<int> code = stackalloc int[2]
{
(input[3] >> 5) * 4,
(input[3] >> 2 & 7) * 4
};
int ti = (input[3] & 1) * 16;
unchecked
{
@@ -748,7 +802,7 @@ namespace TextureDecoder.Etc
}
}
private unsafe static void DecodeEtc2a8Block(byte* input, uint* output)
private static void DecodeEtc2a8Block(ReadOnlySpan<byte> input, Span<uint> output)
{
int @base = input[0];
int data1 = input[1];
@@ -757,53 +811,53 @@ namespace TextureDecoder.Etc
{
for (int i = 0; i < 16; i++)
{
DecodeEac11Block((byte*)output + 3, @base);
DecodeEac11Block(MemoryMarshal.Cast<uint, byte>(output).Slice(3), @base);
}
}
else
{
int table = data1 & 0xF;
ulong l = Get6SwapedBytes(input);
DecodeEac11Block((byte*)output + 3, @base, table, mul, l);
DecodeEac11Block(MemoryMarshal.Cast<uint, byte>(output).Slice(3), @base, table, mul, l);
}
}
private unsafe static void DecodeEacUnsignedBlock(byte* input, uint* output, int channel)
private static void DecodeEacUnsignedBlock(ReadOnlySpan<byte> input, Span<uint> output, int channel)
{
int @base = input[0];
int data1 = input[1];
int mul = data1 >> 4;
if (mul == 0)
{
DecodeEac11Block((byte*)output + channel, @base);
DecodeEac11Block(MemoryMarshal.Cast<uint, byte>(output).Slice(channel), @base);
}
else
{
int table = data1 & 0xF;
ulong l = Get6SwapedBytes(input);
DecodeEac11Block((byte*)output + channel, @base, table, mul, l);
DecodeEac11Block(MemoryMarshal.Cast<uint, byte>(output).Slice(channel), @base, table, mul, l);
}
}
private unsafe static void DecodeEacSignedBlock(byte* input, uint* output, int channel)
private static void DecodeEacSignedBlock(ReadOnlySpan<byte> input, Span<uint> output, int channel)
{
int @base = 127 + unchecked((sbyte)input[0]);
int data1 = input[1];
int mul = data1 >> 4;
if (mul == 0)
{
DecodeEac11Block((byte*)output + channel, @base);
DecodeEac11Block(MemoryMarshal.Cast<uint, byte>(output).Slice(channel), @base);
}
else
{
int table = data1 & 0xF;
ulong l = Get6SwapedBytes(input);
DecodeEac11Block((byte*)output + channel, @base, table, mul, l);
DecodeEac11Block(MemoryMarshal.Cast<uint, byte>(output).Slice(channel), @base, table, mul, l);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void DecodeEac11Block(byte* output, int @base)
private static void DecodeEac11Block(Span<byte> output, int @base)
{
for (int i = 0; i < 16; i++)
{
@@ -812,15 +866,13 @@ namespace TextureDecoder.Etc
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void DecodeEac11Block(byte* output, int @base, int ti, int mul, ulong l)
private static void DecodeEac11Block(Span<byte> output, int @base, int ti, int mul, ulong l)
{
fixed (sbyte* table = &Etc2AlphaModTable[ti * 8])
ReadOnlySpan<sbyte> table = Etc2AlphaModTable.AsSpan(ti * 8, 8);
for (int i = 0; i < 16; i++, l >>= 3)
{
for (int i = 0; i < 16; i++, l >>= 3)
{
int val = @base + mul * table[l & 7];
output[WriteOrderTableRev[i] * 4] = (byte)(Clamp255(val));
}
int val = @base + mul * table[unchecked((int)(l & 0b111))];
output[WriteOrderTableRev[i] * 4] = Clamp255(val);
}
}
@@ -831,31 +883,31 @@ namespace TextureDecoder.Etc
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Clamp255(int n)
private static byte Clamp255(int n)
{
return n < 0 ? 0 : n > 255 ? 255 : n;
return n < 0 ? (byte)0 : n > 255 ? (byte)255 : unchecked((byte)n);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static uint ApplicateColor(byte* c, int o, int m)
private static uint ApplicateColor(ReadOnlySpan<byte> c, int o, int m)
{
return Color(Clamp255(c[o * 3 + 0] + m), Clamp255(c[o * 3 + 1] + m), Clamp255(c[o * 3 + 2] + m), 255);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static uint ApplicateColor(int* c, int o, int m)
private static uint ApplicateColor(ReadOnlySpan<int> c, int o, int m)
{
return Color(Clamp255(c[o * 3 + 0] + m), Clamp255(c[o * 3 + 1] + m), Clamp255(c[o * 3 + 2] + m), 255);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static uint ApplicateColorRaw(byte* c, int o)
private static uint ApplicateColorRaw(ReadOnlySpan<byte> c, int o)
{
return Color(c[o * 3 + 0], c[o * 3 + 1], c[o * 3 + 2], 255);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static ulong Get6SwapedBytes(byte* data)
private static ulong Get6SwapedBytes(ReadOnlySpan<byte> data)
{
return data[7] | (uint)data[6] << 8 | (uint)data[5] << 16 | (uint)data[4] << 24 | (ulong)data[3] << 32 | (ulong)data[2] << 40;
}
@@ -0,0 +1,2 @@
global using System;
global using System.Runtime.CompilerServices;
@@ -0,0 +1,11 @@
namespace AssetRipper.TextureDecoder
{
internal static class OptimizationConstants
{
#if NETCOREAPP
internal const MethodImplOptions AggressiveInliningAndOptimization = MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization;
#else
internal const MethodImplOptions AggressiveInliningAndOptimization = MethodImplOptions.AggressiveInlining;
#endif
}
}
@@ -0,0 +1,25 @@
//#define DISABLE_TWINDDLING_ROUTINE
#define ASSUME_IMAGE_TILING
namespace AssetRipper.TextureDecoder.Pvrtc
{
public static partial class PvrtcDecoder
{
/// <summary>
/// 8 bytes
/// </summary>
private struct AmtcBlock
{
public AmtcBlock(uint v0, uint v1)
{
PackedData0 = v0;
PackedData1 = v1;
}
// Uses 64 bits pre block
public readonly uint PackedData0;
public readonly uint PackedData1;
}
}
}
@@ -0,0 +1,17 @@
//#define DISABLE_TWINDDLING_ROUTINE
#define ASSUME_IMAGE_TILING
namespace AssetRipper.TextureDecoder.Pvrtc
{
public static partial class PvrtcDecoder
{
/// <summary>
/// Low precision colours extracted from the blocks
/// </summary>
private unsafe struct Colours5554
{
public fixed int Reps[2 * 4];
}
}
}
@@ -1,34 +1,26 @@
//#define DISABLE_TWINDDLING_ROUTINE
#define ASSUME_IMAGE_TILING
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace TextureDecoder.Pvrtc
namespace AssetRipper.TextureDecoder.Pvrtc
{
public static class PvrtcDecoder
public static partial class PvrtcDecoder
{
private struct AmtcBlock
{
public AmtcBlock(uint v0, uint v1)
{
PackedData0 = v0;
PackedData1 = v1;
}
// Uses 64 bits pre block
public readonly uint PackedData0;
public readonly uint PackedData1;
}
/// <summary>
/// Low precision colours extracted from the blocks
/// Decompresses PVRTC to RGBA 8888
/// </summary>
private unsafe struct Colours5554
/// <param name="input">The PVRTC texture data to decompress</param>
/// <param name="xDim">X dimension (width) of the texture</param>
/// <param name="yDim">Y dimension (height) of the texture</param>
/// <param name="output">The decompressed texture data</param>
/// <param name="do2bitMode">Signifies whether the data is PVRTC2 or PVRTC4</param>
/// <returns>The number of bytes read from <paramref name="input"/></returns>
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
public static int DecompressPVRTC(ReadOnlySpan<byte> input, int xDim, int yDim, bool do2bitMode, out byte[] output)
{
public fixed int Reps[2 * 4];
output = new byte[xDim * yDim * sizeof(uint)];
return DecompressPVRTC(input, xDim, yDim, do2bitMode, output);
}
/// <summary>
@@ -39,16 +31,9 @@ namespace TextureDecoder.Pvrtc
/// <param name="yDim">Y dimension (height) of the texture</param>
/// <param name="output">The decompressed texture data</param>
/// <param name="do2bitMode">Signifies whether the data is PVRTC2 or PVRTC4</param>
/// <returns></returns>
public unsafe static void DecompressPVRTC(byte[] input, int xDim, int yDim, byte[] output, bool do2bitMode)
{
fixed (byte* inputPtr = input)
{
PVRDecompress(inputPtr, do2bitMode, xDim, yDim, output);
}
}
private unsafe static void PVRDecompress(byte* compressedData, bool do2bitMode, int xDim, int yDim, byte[] output)
/// <returns>The number of bytes read from <paramref name="input"/></returns>
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
public static int DecompressPVRTC(ReadOnlySpan<byte> input, int xDim, int yDim, bool do2bitMode, Span<byte> output)
{
int xBlockSize = do2bitMode ? BlockX2bpp : BlockX4bpp;
// for MBX don't allow the sizes to get too small
@@ -60,13 +45,17 @@ namespace TextureDecoder.Pvrtc
uint pblocki10 = uint.MaxValue;
uint pblocki11 = uint.MaxValue;
Colours5554* m_colors = stackalloc Colours5554[2 * 2];
uint maxBlockIndexRead = uint.MinValue;
Span<Colours5554> m_colors = stackalloc Colours5554[2 * 2];
// interpolated A colors for the pixel
int* aSig = stackalloc int[4];
Span<int> aSig = stackalloc int[4];
// interpolated B colors for the pixel
int* bSig = stackalloc int[4];
int* modulationVals = stackalloc int[8 * 16];
int* modulationModes = stackalloc int[8 * 16];
Span<int> bSig = stackalloc int[4];
Span<int> modulationVals = stackalloc int[8 * 16];
Span<int> modulationModes = stackalloc int[8 * 16];
ReadOnlySpan<AmtcBlock> blocks = MemoryMarshal.Cast<byte, AmtcBlock>(input);
// step through the pixels of the image decompressing each one in turn.
// Note that this is a hideously inefficient way to do this!
@@ -95,28 +84,30 @@ namespace TextureDecoder.Pvrtc
bool changed = blocki00 != pblocki00 || blocki01 != pblocki01 || blocki10 != pblocki10 || blocki11 != pblocki11;
if (changed)
{
AmtcBlock* block00 = &((AmtcBlock*)compressedData)[blocki00];
Unpack5554Colour(block00, m_colors[0].Reps);
AmtcBlock block00 = blocks[(int)blocki00];
Unpack5554Colour(block00, m_colors.GetIntSpanForColor(0));
UnpackModulations(block00, do2bitMode, modulationVals, modulationModes, 0, 0);
AmtcBlock* block01 = &((AmtcBlock*)compressedData)[blocki01];
Unpack5554Colour(block01, m_colors[1].Reps);
AmtcBlock block01 = blocks[(int)blocki01];
Unpack5554Colour(block01, m_colors.GetIntSpanForColor(1));
UnpackModulations(block01, do2bitMode, modulationVals, modulationModes, xBlockSize, 0);
AmtcBlock* block10 = &((AmtcBlock*)compressedData)[blocki10];
Unpack5554Colour(block10, m_colors[2].Reps);
AmtcBlock block10 = blocks[(int)blocki10];
Unpack5554Colour(block10, m_colors.GetIntSpanForColor(2));
UnpackModulations(block10, do2bitMode, modulationVals, modulationModes, 0, BlockYSize);
AmtcBlock* block11 = &((AmtcBlock*)compressedData)[blocki11];
Unpack5554Colour(block11, m_colors[3].Reps);
AmtcBlock block11 = blocks[(int)blocki11];
Unpack5554Colour(block11, m_colors.GetIntSpanForColor(3));
UnpackModulations(block11, do2bitMode, modulationVals, modulationModes, xBlockSize, BlockYSize);
pblocki00 = blocki00;
pblocki01 = blocki01;
pblocki10 = blocki10;
pblocki11 = blocki11;
maxBlockIndexRead = Math.Max(maxBlockIndexRead, Math.Max(Math.Max(blocki00, blocki01), Math.Max(blocki10, blocki11)));
}
// decompress the pixel. First compute the interpolated A and B signals
InterpolateColours(m_colors[0].Reps, m_colors[1].Reps, m_colors[2].Reps, m_colors[3].Reps, 0, do2bitMode, x, y, aSig);
InterpolateColours(m_colors[0].Reps, m_colors[1].Reps, m_colors[2].Reps, m_colors[3].Reps, 1, do2bitMode, x, y, bSig);
InterpolateColours(m_colors.GetIntSpanForColor(0), m_colors.GetIntSpanForColor(1), m_colors.GetIntSpanForColor(2), m_colors.GetIntSpanForColor(3), 0, do2bitMode, x, y, aSig);
InterpolateColours(m_colors.GetIntSpanForColor(0), m_colors.GetIntSpanForColor(1), m_colors.GetIntSpanForColor(2), m_colors.GetIntSpanForColor(3), 1, do2bitMode, x, y, bSig);
GetModulationValue(x, y, do2bitMode, modulationVals, modulationModes, out int mod, out bool doPT);
// compute the modulated color. Swap red and blue channel
@@ -127,6 +118,8 @@ namespace TextureDecoder.Pvrtc
output[position + 3] = doPT ? (byte)0 : (byte)((aSig[3] * 8 + mod * (bSig[3] - aSig[3])) >> 3);
}
}
return ((int)maxBlockIndexRead + 1) * Unsafe.SizeOf<AmtcBlock>();
}
/// <summary>
@@ -210,15 +203,14 @@ namespace TextureDecoder.Pvrtc
/// <summary>
/// Get the modulation value as a numerator of a fraction of 8ths
/// </summary>
private unsafe static void GetModulationValue(int x, int y, bool do2bitMode, int* modulationVals, int* modulationModes, out int mod, out bool doPT)
private static void GetModulationValue(int x, int y, bool do2bitMode, ReadOnlySpan<int> modulationVals, ReadOnlySpan<int> modulationModes, out int mod, out bool doPT)
{
// Map X and Y into the local 2x2 block
y = (y & 0x3) | ((~y & 0x2) << 1);
if (do2bitMode)
x = (x & 0x7) | ((~x & 0x4) << 1);
else
x = (x & 0x3) | ((~x & 0x2) << 1);
x = do2bitMode
? (x & 0x7) | ((~x & 0x4) << 1)
: (x & 0x3) | ((~x & 0x2) << 1);
// assume no PT for now
doPT = false;
@@ -267,7 +259,7 @@ namespace TextureDecoder.Pvrtc
/// This performs a HW bit accurate interpolation of either the A or B colours for a particular pixel
/// <para>NOTE: It is assumed that the source colours are in ARGB 5554 format - This means that some "preparation" of the values will be necessary</para>
/// </summary>
private unsafe static void InterpolateColours(int* colorP, int* colorQ, int* colorR, int* colorS, int ci, bool do2bitMode, int x, int y, int* result)
private static void InterpolateColours(ReadOnlySpan<int> colorP, ReadOnlySpan<int> colorQ, ReadOnlySpan<int> colorR, ReadOnlySpan<int> colorS, int ci, bool do2bitMode, int x, int y, Span<int> result)
{
// put the x and y values into the right range and get the u and v scale amounts
int v = ((y & 0x3) | ((~y & 0x2) << 1)) - BlockYSize / 2;
@@ -333,10 +325,10 @@ namespace TextureDecoder.Pvrtc
/// <summary>
/// Given the block and the texture type and it's relative position in the 2x2 group of blocks, extract the bit patterns for the fully defined pixels.
/// </summary>
private unsafe static void UnpackModulations(AmtcBlock* block, bool do2bitMode, int* modulationVals, int* modulationModes, int startX, int startY)
private static void UnpackModulations(AmtcBlock block, bool do2bitMode, Span<int> modulationVals, Span<int> modulationModes, int startX, int startY)
{
int blockModMode = (int)(block->PackedData1 & 1);
uint modulationBits = block->PackedData0;
int blockModMode = (int)(block.PackedData1 & 1);
uint modulationBits = block.PackedData0;
// if it's in an interpolated mode
if (do2bitMode && (blockModMode != 0))
@@ -404,14 +396,14 @@ namespace TextureDecoder.Pvrtc
/// <summary>
/// Given a block, extract the colour information and convert to 5554 formats
/// </summary>
private unsafe static void Unpack5554Colour(AmtcBlock* block, int* abColors)
private static void Unpack5554Colour(AmtcBlock block, Span<int> abColors)
{
uint* rawBits = stackalloc uint[2];
Span<uint> rawBits = stackalloc uint[2];
// extract A and B
// 15 bits (shifted up by one)
rawBits[0] = block->PackedData1 & (0xFFFE);
rawBits[0] = block.PackedData1 & (0xFFFE);
// 16 bits
rawBits[1] = block->PackedData1 >> 16;
rawBits[1] = block.PackedData1 >> 16;
// step through both colours
for (int i = 0; i < 2; i++)
@@ -463,12 +455,18 @@ namespace TextureDecoder.Pvrtc
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static Span<int> GetIntSpanForColor(this Span<Colours5554> colorSpan, int index)
{
return MemoryMarshal.Cast<Colours5554, int>(colorSpan.Slice(index, 1));
}
/// <summary>
/// Check that a number is an integer power of two, i.e. 1, 2, 4, 8, ... etc. Returns false for zero
/// </summary>
/// <param name="input">A number</param>
/// <returns>True if the number is an integer power of two, else false</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static bool IsPowerOf2(uint input)
{
if (input == 0)
@@ -483,7 +481,7 @@ namespace TextureDecoder.Pvrtc
/// <summary>
/// Define an expression to either wrap or clamp large or small vals to the legal coordinate range
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static int LimitCoord(int value, int size)
{
#if ASSUME_IMAGE_TILING
@@ -0,0 +1,352 @@
namespace AssetRipper.TextureDecoder.Rgb
{
internal static class ConversionUtilities
{
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
internal static TTo ConvertValue<TFrom, TTo>(TFrom value)
where TFrom : unmanaged
where TTo : unmanaged
{
if (typeof(TFrom) == typeof(TTo))
{
return Unsafe.As<TFrom, TTo>(ref value);
}
else if (typeof(TFrom) == typeof(sbyte))
{
byte converted = ChangeSign(Unsafe.As<TFrom, sbyte>(ref value));
return ConvertUInt8<TTo>(converted);
}
else if(typeof(TFrom) == typeof(byte))
{
return ConvertUInt8<TTo>(Unsafe.As<TFrom, byte>(ref value));
}
else if (typeof(TFrom) == typeof(short))
{
ushort converted = ChangeSign(Unsafe.As<TFrom, short>(ref value));
return ConvertUInt16<TTo>(converted);
}
else if (typeof(TFrom) == typeof(ushort))
{
return ConvertUInt16<TTo>(Unsafe.As<TFrom, ushort>(ref value));
}
else if (typeof(TFrom) == typeof(Half))
{
return ConvertHalf<TTo>(Unsafe.As<TFrom, Half>(ref value));
}
else if (typeof(TFrom) == typeof(float))
{
return ConvertSingle<TTo>(Unsafe.As<TFrom, float>(ref value));
}
else if (typeof(TFrom) == typeof(double))
{
return ConvertDouble<TTo>(Unsafe.As<TFrom, double>(ref value));
}
else
{
return ThrowOrReturnDefault<TTo>();
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertUInt8<TTo>(byte value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(value);
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
return Unsafe.As<byte, TTo>(ref value);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(ConvertUInt8ToUInt16(value));
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
ushort converted = ConvertUInt8ToUInt16(value);
return Unsafe.As<ushort, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(Half))
{
Half converted = (Half)(value / (float)byte.MaxValue);
return Unsafe.As<Half, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(float))
{
float converted = (float)(value / (float)byte.MaxValue);
return Unsafe.As<float, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(double))
{
double converted = (double)(value / (double)byte.MaxValue);
return Unsafe.As<double, TTo>(ref converted);
}
else
{
return ThrowOrReturnDefault<TTo>();
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
static ushort ConvertUInt8ToUInt16(byte value)
{
return unchecked((ushort)(((uint)value << 8) | value));//See https://github.com/AssetRipper/TextureDecoder/issues/19
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertUInt16<TTo>(ushort value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(ConvertUInt16ToUInt8(value));
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
byte converted = ConvertUInt16ToUInt8(value);
return Unsafe.As<byte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(value);
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
return Unsafe.As<ushort, TTo>(ref value);
}
else if (typeof(TTo) == typeof(Half))
{
Half converted = (Half)(value / (float)ushort.MaxValue);
return Unsafe.As<Half, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(float))
{
float converted = (float)(value / (float)ushort.MaxValue);
return Unsafe.As<float, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(double))
{
double converted = (double)(value / (double)ushort.MaxValue);
return Unsafe.As<double, TTo>(ref converted);
}
else
{
return ThrowOrReturnDefault<TTo>();
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
static byte ConvertUInt16ToUInt8(ushort value)
{
uint result = (value * 255u + 32895u) >> 16;//See https://github.com/AssetRipper/TextureDecoder/issues/19
return unchecked((byte)result);
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertHalf<TTo>(Half value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(ClampUInt8((float)value * byte.MaxValue));
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
byte converted = ClampUInt8((float)value * byte.MaxValue);
return Unsafe.As<byte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(ClampUInt16((float)value * ushort.MaxValue));
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
ushort converted = ClampUInt16((float)value * ushort.MaxValue);
return Unsafe.As<ushort, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(Half))
{
return Unsafe.As<Half, TTo>(ref value);
}
else if (typeof(TTo) == typeof(float))
{
float converted = (float)value;
return Unsafe.As<float, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(double))
{
double converted = (double)value;
return Unsafe.As<double, TTo>(ref converted);
}
else
{
return ThrowOrReturnDefault<TTo>();
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertSingle<TTo>(float value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(ClampUInt8(value * byte.MaxValue));
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
byte converted = ClampUInt8(value * byte.MaxValue);
return Unsafe.As<byte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(ClampUInt16(value * ushort.MaxValue));
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
ushort converted = ClampUInt16(value * ushort.MaxValue);
return Unsafe.As<ushort, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(Half))
{
Half converted = (Half)value;
return Unsafe.As<Half, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(float))
{
return Unsafe.As<float, TTo>(ref value);
}
else if (typeof(TTo) == typeof(double))
{
double converted = (double)value;
return Unsafe.As<double, TTo>(ref converted);
}
else
{
return ThrowOrReturnDefault<TTo>();
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static TTo ConvertDouble<TTo>(double value) where TTo : unmanaged
{
if (typeof(TTo) == typeof(sbyte))
{
sbyte converted = ChangeSign(ClampUInt8(value * byte.MaxValue));
return Unsafe.As<sbyte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(byte))
{
byte converted = ClampUInt8(value * byte.MaxValue);
return Unsafe.As<byte, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(short))
{
short converted = ChangeSign(ClampUInt16(value * ushort.MaxValue));
return Unsafe.As<short, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(ushort))
{
ushort converted = ClampUInt16(value * ushort.MaxValue);
return Unsafe.As<ushort, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(Half))
{
Half converted = (Half)value;
return Unsafe.As<Half, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(float))
{
float converted = (float)value;
return Unsafe.As<float, TTo>(ref converted);
}
else if (typeof(TTo) == typeof(double))
{
return Unsafe.As<double, TTo>(ref value);
}
else
{
return ThrowOrReturnDefault<TTo>();
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static T ThrowOrReturnDefault<T>() where T : unmanaged
{
#if DEBUG
throw new InvalidCastException();
#else
return default; //exceptions prevent inlining
#endif
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static byte ClampUInt8(float x)
{
return byte.MaxValue < x ? byte.MaxValue : (x > byte.MinValue ? (byte)x : byte.MinValue);
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static byte ClampUInt8(double x)
{
return byte.MaxValue < x ? byte.MaxValue : (x > byte.MinValue ? (byte)x : byte.MinValue);
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static ushort ClampUInt16(float x)
{
return ushort.MaxValue < x ? ushort.MaxValue : (x > ushort.MinValue ? (ushort)x : ushort.MinValue);
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static ushort ClampUInt16(double x)
{
return ushort.MaxValue < x ? ushort.MaxValue : (x > ushort.MinValue ? (ushort)x : ushort.MinValue);
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static byte ChangeSign(sbyte x)
{
unchecked
{
const uint SignBit = 0x80;
return (byte)((uint)x ^ SignBit);
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static sbyte ChangeSign(byte x)
{
unchecked
{
const uint SignBit = 0x80;
return (sbyte)(x ^ SignBit);
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static ushort ChangeSign(short x)
{
unchecked
{
const uint SignBit = 0x8000;
return (ushort)((uint)x ^ SignBit);
}
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
private static short ChangeSign(ushort x)
{
unchecked
{
const uint SignBit = 0x8000;
return (short)(x ^ SignBit);
}
}
}
}
@@ -0,0 +1,27 @@
namespace AssetRipper.TextureDecoder.Rgb
{
internal static class DefaultColorMethods
{
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
internal static void GetChannels<T, TArg>(T color, out TArg r, out TArg g, out TArg b, out TArg a)
where TArg : unmanaged
where T : unmanaged, IColor<TArg>
{
r = color.R;
g = color.G;
b = color.B;
a = color.A;
}
[MethodImpl(OptimizationConstants.AggressiveInliningAndOptimization)]
internal static void SetChannels<T, TArg>(ref T color, TArg r, TArg g, TArg b, TArg a)
where TArg : unmanaged
where T : unmanaged, IColor<TArg>
{
color.R = r;
color.G = g;
color.B = b;
color.A = a;
}
}
}
@@ -0,0 +1,43 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Attributes;
namespace AssetRipper.TextureDecoder.Rgb.Formats
{
[RgbaAttribute(RedChannel = false, GreenChannel = false, BlueChannel = false, AlphaChannel = true, FullyUtilizedChannels = true)]
public partial struct ColorA8 : IColor<byte>
{
public byte R
{
get => byte.MinValue;
set { }
}
public byte G
{
get => byte.MinValue;
set { }
}
public byte B
{
get => byte.MinValue;
set { }
}
public byte A { get; set; }
public void GetChannels(out byte r, out byte g, out byte b, out byte a)
{
r = R;
g = G;
b = B;
a = A;
}
public void SetChannels(byte r, byte g, byte b, byte a)
{
A = a;
}
}
}
@@ -0,0 +1,42 @@
namespace AssetRipper.TextureDecoder.Rgb.Formats
{
public partial struct ColorARGB16 : IColor<byte>
{
private UInt4Pair gb;
private UInt4Pair ar;
public byte B
{
get => gb.LowValue;
set => gb.LowValue = value;
}
public byte G
{
get => gb.HighValue;
set => gb.HighValue = value;
}
public byte R
{
get => ar.LowValue;
set => ar.LowValue = value;
}
public byte A
{
get => ar.HighValue;
set => ar.HighValue = value;
}
public void GetChannels(out byte r, out byte g, out byte b, out byte a)
{
DefaultColorMethods.GetChannels(this, out r, out g, out b, out a);
}
public void SetChannels(byte r, byte g, byte b, byte a)
{
DefaultColorMethods.SetChannels(ref this, r, g, b, a);
}
}
}
@@ -0,0 +1,11 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Attributes;
namespace AssetRipper.TextureDecoder.Rgb.Formats
{
[RgbaAttribute(RedChannel = true, GreenChannel = true, BlueChannel = true, AlphaChannel = true, FullyUtilizedChannels = false)]
public partial struct ColorARGB16 : IColor<byte>
{
}
}
@@ -0,0 +1,20 @@
namespace AssetRipper.TextureDecoder.Rgb.Formats
{
public partial struct ColorARGB32 : IColor<byte>
{
public byte A { get; set; }
public byte R { get; set; }
public byte G { get; set; }
public byte B { get; set; }
public void GetChannels(out byte r, out byte g, out byte b, out byte a)
{
DefaultColorMethods.GetChannels(this, out r, out g, out b, out a);
}
public void SetChannels(byte r, byte g, byte b, byte a)
{
DefaultColorMethods.SetChannels(ref this, r, g, b, a);
}
}
}
@@ -0,0 +1,11 @@
//This code is source generated. Do not edit manually.
using AssetRipper.TextureDecoder.Attributes;
namespace AssetRipper.TextureDecoder.Rgb.Formats
{
[RgbaAttribute(RedChannel = true, GreenChannel = true, BlueChannel = true, AlphaChannel = true, FullyUtilizedChannels = true)]
public partial struct ColorARGB32 : IColor<byte>
{
}
}
Loaded 100 of 220 files, more files were not shown because too many files have changed in this diff. Show more