mirror of
https://github.com/DarthAffe/HPPH.git
synced 2025-12-12 13:28:37 +00:00
Initial commit (WIP)
This commit is contained in:
parent
5474273e70
commit
696f3b955f
19
HPPH.Benchmark/HPPH.Benchmark.csproj
Normal file
19
HPPH.Benchmark/HPPH.Benchmark.csproj
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HPPH.Reference\HPPH.Reference.csproj" />
|
||||||
|
<ProjectReference Include="..\HPPH\HPPH.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
1
HPPH.Benchmark/Program.cs
Normal file
1
HPPH.Benchmark/Program.cs
Normal file
@ -0,0 +1 @@
|
|||||||
|
Console.WriteLine("Empty");
|
||||||
3
HPPH.DotSettings
Normal file
3
HPPH.DotSettings
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BGR/@EntryIndexedValue">BGR</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BGRA/@EntryIndexedValue">BGRA</s:String></wpf:ResourceDictionary>
|
||||||
50
HPPH.Generators/ColorFormatData.cs
Normal file
50
HPPH.Generators/ColorFormatData.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
internal readonly struct ColorFormatData(string typeName, int bpp, char firstEntry, char secondEntry, char thirdEntry, char fourthEntry)
|
||||||
|
{
|
||||||
|
public readonly string TypeName = typeName;
|
||||||
|
public readonly int Bpp = bpp;
|
||||||
|
public readonly string FirstEntry = firstEntry.ToString().ToLowerInvariant();
|
||||||
|
public readonly string SecondEntry = secondEntry.ToString().ToLowerInvariant();
|
||||||
|
public readonly string ThirdEntry = thirdEntry.ToString().ToLowerInvariant();
|
||||||
|
public readonly string FourthEntry = fourthEntry.ToString().ToLowerInvariant();
|
||||||
|
|
||||||
|
public string FirstEntryName => GetEntryName(FirstEntry);
|
||||||
|
public string SecondEntryName => GetEntryName(SecondEntry);
|
||||||
|
public string ThirdEntryName => GetEntryName(ThirdEntry);
|
||||||
|
public string FourthEntryName => GetEntryName(FourthEntry);
|
||||||
|
|
||||||
|
public string Format
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
StringBuilder sb = new();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(FirstEntry))
|
||||||
|
sb.Append(FirstEntry);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(SecondEntry))
|
||||||
|
sb.Append(SecondEntry);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(ThirdEntry))
|
||||||
|
sb.Append(ThirdEntry);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(FourthEntry))
|
||||||
|
sb.Append(FourthEntry);
|
||||||
|
|
||||||
|
return sb.ToString().ToUpper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetEntryName(string entry)
|
||||||
|
=> entry switch
|
||||||
|
{
|
||||||
|
"a" => "Alpha",
|
||||||
|
"r" => "Red",
|
||||||
|
"g" => "Green",
|
||||||
|
"b" => "Blue",
|
||||||
|
_ => string.Empty
|
||||||
|
};
|
||||||
|
}
|
||||||
90
HPPH.Generators/ColorFormatSourceGenerator.cs
Normal file
90
HPPH.Generators/ColorFormatSourceGenerator.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
[Generator(LanguageNames.CSharp)]
|
||||||
|
public class ColorSourceGenerator : IIncrementalGenerator
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private static readonly Regex COLOR_FORMAT_REGEX = new("^Color(?<colorFormat>[ARGB]{3,4})$", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private static readonly IGeneratorFeature[] FEATURES =
|
||||||
|
[
|
||||||
|
new Colors(),
|
||||||
|
new Average(),
|
||||||
|
new MinMax(),
|
||||||
|
new Sum(),
|
||||||
|
new Quantize()
|
||||||
|
];
|
||||||
|
|
||||||
|
private const string COLOR_GENERATOR_ATTRIBUTE_SOURCE = """
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Struct)]
|
||||||
|
internal class ColorGeneratorAttribute : Attribute;
|
||||||
|
""";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
|
{
|
||||||
|
// if (!Debugger.IsAttached)
|
||||||
|
// Debugger.Launch();
|
||||||
|
|
||||||
|
context.RegisterPostInitializationOutput(ctx => ctx.AddSource("ColorGeneratorAttribute.g.cs", SourceText.From(COLOR_GENERATOR_ATTRIBUTE_SOURCE, Encoding.UTF8)));
|
||||||
|
|
||||||
|
IncrementalValueProvider<ImmutableArray<ColorFormatData>> classes = context.SyntaxProvider
|
||||||
|
.ForAttributeWithMetadataName("HPPH.ColorGeneratorAttribute", static (_, __) => true, Transform)
|
||||||
|
.Where(type => type.HasValue)
|
||||||
|
.Select((data, _) => data!.Value)
|
||||||
|
.Collect();
|
||||||
|
context.RegisterSourceOutput(classes, GenerateCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ColorFormatData? Transform(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (context.TargetNode is not StructDeclarationSyntax structDeclaration) return null;
|
||||||
|
if (context.SemanticModel.GetDeclaredSymbol(structDeclaration, cancellationToken) is not ITypeSymbol type) return null;
|
||||||
|
|
||||||
|
Match m = COLOR_FORMAT_REGEX.Match(type.Name);
|
||||||
|
if (!m.Success) return null;
|
||||||
|
|
||||||
|
string colorFormat = m.Groups["colorFormat"].Value;
|
||||||
|
if (colorFormat.Distinct().Count() != colorFormat.Length) return null;
|
||||||
|
|
||||||
|
return new ColorFormatData(type.Name,
|
||||||
|
colorFormat.Length,
|
||||||
|
colorFormat.Length > 0 ? colorFormat[0] : ' ',
|
||||||
|
colorFormat.Length > 1 ? colorFormat[1] : ' ',
|
||||||
|
colorFormat.Length > 2 ? colorFormat[2] : ' ',
|
||||||
|
colorFormat.Length > 3 ? colorFormat[3] : ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateCode(SourceProductionContext context, ImmutableArray<ColorFormatData> colorFormats)
|
||||||
|
{
|
||||||
|
if (colorFormats.IsDefaultOrEmpty) return;
|
||||||
|
|
||||||
|
foreach (ColorFormatData formatData in colorFormats)
|
||||||
|
{
|
||||||
|
foreach (IGeneratorFeature feature in FEATURES)
|
||||||
|
foreach ((string name, string source) in feature.GenerateFor(formatData))
|
||||||
|
context.AddSource($"{name}.g.cs", SourceText.From(source, Encoding.UTF8));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (IGeneratorFeature feature in FEATURES)
|
||||||
|
foreach ((string name, string source) in feature.GenerateFor(colorFormats))
|
||||||
|
context.AddSource($"{name}.g.cs", SourceText.From(source, Encoding.UTF8));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
3
HPPH.Generators/ColorSortData.cs
Normal file
3
HPPH.Generators/ColorSortData.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
internal record struct ColorSortData(string Namespace, string Class, string ClassModifiers, string Signature, string DataTypeName, string SortValueName);
|
||||||
135
HPPH.Generators/ColorSortSourceGenerator.cs
Normal file
135
HPPH.Generators/ColorSortSourceGenerator.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
[Generator(LanguageNames.CSharp)]
|
||||||
|
public class ColorSortSourceGenerator : IIncrementalGenerator
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private const string SORT_GENERATOR_ATTRIBUTE_SOURCE = """
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
internal class ColorSortGeneratorAttribute(string dataTypeName, string sortValueName) : Attribute
|
||||||
|
{
|
||||||
|
public string DataTypeName { get; } = dataTypeName;
|
||||||
|
public string SortValueName { get; } = sortValueName;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
|
{
|
||||||
|
//if (!Debugger.IsAttached)
|
||||||
|
// Debugger.Launch();
|
||||||
|
|
||||||
|
context.RegisterPostInitializationOutput(ctx => ctx.AddSource("ColorSortGeneratorAttribute.g.cs", SourceText.From(SORT_GENERATOR_ATTRIBUTE_SOURCE, Encoding.UTF8)));
|
||||||
|
|
||||||
|
IncrementalValueProvider<ImmutableArray<ColorSortData>> classes = context.SyntaxProvider
|
||||||
|
.ForAttributeWithMetadataName("HPPH.ColorSortGeneratorAttribute", static (_, __) => true, Transform)
|
||||||
|
.Where(type => type.HasValue)
|
||||||
|
.Select((data, _) => data!.Value)
|
||||||
|
.Collect();
|
||||||
|
context.RegisterSourceOutput(classes, GenerateCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ColorSortData? Transform(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (context.TargetNode is not MethodDeclarationSyntax methodDeclaration) return null;
|
||||||
|
if (context.SemanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken) is not IMethodSymbol method) return null;
|
||||||
|
if (!method.IsPartialDefinition) return null;
|
||||||
|
|
||||||
|
foreach (AttributeData attribute in method.GetAttributes())
|
||||||
|
{
|
||||||
|
if (attribute.AttributeClass?.Name != "ColorSortGeneratorAttribute")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!attribute.ConstructorArguments.IsEmpty)
|
||||||
|
{
|
||||||
|
ImmutableArray<TypedConstant> args = attribute.ConstructorArguments;
|
||||||
|
if (args.Any(arg => arg.Kind == TypedConstantKind.Error)) break;
|
||||||
|
|
||||||
|
return new ColorSortData(method.ContainingNamespace.Name, method.ContainingType.Name, ((ClassDeclarationSyntax)methodDeclaration.Parent!).Modifiers.ToString(), $"{methodDeclaration.Modifiers} {methodDeclaration.ReturnType} {methodDeclaration.Identifier}{methodDeclaration.TypeParameterList}{methodDeclaration.ParameterList} {methodDeclaration.ConstraintClauses}", args[0].Value!.ToString(), args[1].Value!.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateCode(SourceProductionContext context, ImmutableArray<ColorSortData> colorSorts)
|
||||||
|
{
|
||||||
|
if (colorSorts.IsDefaultOrEmpty) return;
|
||||||
|
|
||||||
|
Dictionary<(string, string, string), string> sourceMapping = colorSorts.Select(x => (x.Namespace, x.Class, x.ClassModifiers)).Distinct().ToDictionary(x => x, _ => string.Empty);
|
||||||
|
|
||||||
|
foreach (ColorSortData colorSort in colorSorts)
|
||||||
|
sourceMapping[(colorSort.Namespace, colorSort.Class, colorSort.ClassModifiers)] += GenerateSortMethodSource(colorSort);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<(string @namespace, string @class, string classModifier), string> data in sourceMapping)
|
||||||
|
{
|
||||||
|
context.AddSource($"{data.Key.@class}.g.cs", SourceText.From($$"""
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
|
namespace {{data.Key.@namespace}};
|
||||||
|
|
||||||
|
{{data.Key.classModifier}} class {{data.Key.@class}}
|
||||||
|
{
|
||||||
|
{{data.Value}}
|
||||||
|
}
|
||||||
|
""", Encoding.UTF8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateSortMethodSource(ColorSortData colorSort)
|
||||||
|
=> $$"""
|
||||||
|
{{colorSort.Signature}}
|
||||||
|
{
|
||||||
|
fixed ({{colorSort.DataTypeName}}* ptr = colors)
|
||||||
|
{
|
||||||
|
{{colorSort.DataTypeName}}* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for ({{colorSort.DataTypeName}}* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).{{colorSort.SortValueName}}]++;
|
||||||
|
|
||||||
|
{{colorSort.DataTypeName}}[] bucketsArray = ArrayPool<{{colorSort.DataTypeName}}>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<{{colorSort.DataTypeName}}> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for ({{colorSort.DataTypeName}}* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).{{colorSort.SortValueName}}]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<{{colorSort.DataTypeName}}>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
47
HPPH.Generators/Features/Average.cs
Normal file
47
HPPH.Generators/Features/Average.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
internal class Average : IGeneratorFeature
|
||||||
|
{
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
yield return ($"ColorFormat{colorFormat.Format}.Average", GenerateColorFormatAverage(colorFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ImmutableArray<ColorFormatData> colorFormats)
|
||||||
|
{
|
||||||
|
yield return ("IColorFormat.Average", GenerateColorFormatInterfaceAverage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateColorFormatAverage(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
return $$"""
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormat{{colorFormat.Format}}
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor IColorFormat.Average(ReadOnlySpan<byte> data) => PixelHelper.Average(MemoryMarshal.Cast<byte, Color{{colorFormat.Format}}>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateColorFormatInterfaceAverage()
|
||||||
|
{
|
||||||
|
return """
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
internal IColor Average(ReadOnlySpan<byte> data);
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
}
|
||||||
200
HPPH.Generators/Features/Colors.cs
Normal file
200
HPPH.Generators/Features/Colors.cs
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
internal class Colors : IGeneratorFeature
|
||||||
|
{
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
string colorStructCode = GenerateColorStructCode(colorFormat);
|
||||||
|
if (!string.IsNullOrWhiteSpace(colorStructCode))
|
||||||
|
{
|
||||||
|
yield return (colorFormat.TypeName, colorStructCode!);
|
||||||
|
yield return ($"ColorFormat{colorFormat.Format}", GenerateColorFormatCode(colorFormat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ImmutableArray<ColorFormatData> colorFormats)
|
||||||
|
{
|
||||||
|
yield return ("IColorFormat.Instances.cs", GenerateColorFormats(colorFormats));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateColorStructCode(ColorFormatData colorFormat)
|
||||||
|
=> colorFormat.Bpp switch
|
||||||
|
{
|
||||||
|
3 => $$"""
|
||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color in 24 bit {{colorFormat.Format}}-format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="{{colorFormat.TypeName}}"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="{{colorFormat.FirstEntry}}">The {{colorFormat.FirstEntryName}}-component of the color.</param>
|
||||||
|
/// <param name="{{colorFormat.SecondEntry}}">The {{colorFormat.SecondEntryName}}-component of the color.</param>
|
||||||
|
/// <param name="{{colorFormat.ThirdEntry}}">The {{colorFormat.ThirdEntryName}}-component of the color.</param>
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct {{colorFormat.TypeName}}(byte {{colorFormat.FirstEntry}}, byte {{colorFormat.SecondEntry}}, byte {{colorFormat.ThirdEntry}}): IColor
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColorFormat ColorFormat => IColorFormat.{{colorFormat.Format}};
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.FirstEntry}} = {{colorFormat.FirstEntry}};
|
||||||
|
private readonly byte _{{colorFormat.SecondEntry}} = {{colorFormat.SecondEntry}};
|
||||||
|
private readonly byte _{{colorFormat.ThirdEntry}} = {{colorFormat.ThirdEntry}};
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte R => _r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte G => _g;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte B => _b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte A => byte.MaxValue;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColor Create(byte r, byte g, byte b, byte a) => new {{colorFormat.TypeName}}({{colorFormat.FirstEntry}}, {{colorFormat.SecondEntry}}, {{colorFormat.ThirdEntry}});
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
""",
|
||||||
|
|
||||||
|
4 => $$"""
|
||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color in 32 bit {{colorFormat.Format}}-format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="{{colorFormat.TypeName}}"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="{{colorFormat.FirstEntry}}">The {{colorFormat.FirstEntryName}}-component of the color.</param>
|
||||||
|
/// <param name="{{colorFormat.SecondEntry}}">The {{colorFormat.SecondEntryName}}-component of the color.</param>
|
||||||
|
/// <param name="{{colorFormat.ThirdEntry}}">The {{colorFormat.ThirdEntryName}}-component of the color.</param>
|
||||||
|
/// <param name="{{colorFormat.FourthEntry}}">The {{colorFormat.FourthEntryName}}-component of the color.</param>
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct {{colorFormat.TypeName}}(byte {{colorFormat.FirstEntry}}, byte {{colorFormat.SecondEntry}}, byte {{colorFormat.ThirdEntry}}, byte {{colorFormat.FourthEntry}}) : IColor
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColorFormat ColorFormat => IColorFormat.{{colorFormat.Format}};
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.FirstEntry}} = {{colorFormat.FirstEntry}};
|
||||||
|
private readonly byte _{{colorFormat.SecondEntry}} = {{colorFormat.SecondEntry}};
|
||||||
|
private readonly byte _{{colorFormat.ThirdEntry}} = {{colorFormat.ThirdEntry}};
|
||||||
|
private readonly byte _{{colorFormat.FourthEntry}} = {{colorFormat.FourthEntry}};
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte R => _r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte G => _g;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte B => _b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColor Create(byte r, byte g, byte b, byte a) => new {{colorFormat.TypeName}}({{colorFormat.FirstEntry}}, {{colorFormat.SecondEntry}}, {{colorFormat.ThirdEntry}}, {{colorFormat.FourthEntry}});
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
""",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string GenerateColorFormatCode(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
return $$"""
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormat{{colorFormat.Format}} : IColorFormat
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public static ColorFormat{{colorFormat.Format}} Instance { get; } = new();
|
||||||
|
|
||||||
|
public int BytesPerPixel => {{colorFormat.Bpp}};
|
||||||
|
|
||||||
|
public string Name => "{{colorFormat.Format}}";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
private ColorFormat{{colorFormat.Format}}() {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateColorFormats(ImmutableArray<ColorFormatData> colorFormats)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new();
|
||||||
|
sb.AppendLine("""
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
#region Instances
|
||||||
|
""");
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
|
||||||
|
foreach (ColorFormatData colorFormat in colorFormats)
|
||||||
|
sb.AppendLine($" public static ColorFormat{colorFormat.Format} {colorFormat.Format} => ColorFormat{colorFormat.Format}.Instance;");
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
|
||||||
|
sb.AppendLine("""
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
10
HPPH.Generators/Features/IGeneratorFeature.cs
Normal file
10
HPPH.Generators/Features/IGeneratorFeature.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
internal interface IGeneratorFeature
|
||||||
|
{
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ColorFormatData colorFormat);
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ImmutableArray<ColorFormatData> colorFormats);
|
||||||
|
}
|
||||||
162
HPPH.Generators/Features/MinMax.cs
Normal file
162
HPPH.Generators/Features/MinMax.cs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
internal class MinMax : IGeneratorFeature
|
||||||
|
{
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
yield return ($"MinMax{colorFormat.Format}", GenerateMinMaxStruct(colorFormat));
|
||||||
|
yield return ($"ColorFormat{colorFormat.Format}.MinMax", GenerateColorFormatMinMax(colorFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ImmutableArray<ColorFormatData> colorFormats)
|
||||||
|
{
|
||||||
|
yield return ("IColorFormat.MinMax", GenerateColorFormatInterfaceMinMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateMinMaxStruct(ColorFormatData colorFormat)
|
||||||
|
=> colorFormat.Bpp switch
|
||||||
|
{
|
||||||
|
3 => $$"""
|
||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct MinMax{{colorFormat.Format}}(byte {{colorFormat.FirstEntry}}Min, byte {{colorFormat.FirstEntry}}Max, byte {{colorFormat.SecondEntry}}Min, byte {{colorFormat.SecondEntry}}Max, byte {{colorFormat.ThirdEntry}}Min, byte {{colorFormat.ThirdEntry}}Max) : IMinMax
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.FirstEntry}}Min = {{colorFormat.FirstEntry}}Min;
|
||||||
|
private readonly byte _{{colorFormat.FirstEntry}}Max = {{colorFormat.FirstEntry}}Max;
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.SecondEntry}}Min = {{colorFormat.SecondEntry}}Min;
|
||||||
|
private readonly byte _{{colorFormat.SecondEntry}}Max = {{colorFormat.SecondEntry}}Max;
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.ThirdEntry}}Min = {{colorFormat.ThirdEntry}}Min;
|
||||||
|
private readonly byte _{{colorFormat.ThirdEntry}}Max = {{colorFormat.ThirdEntry}}Max;
|
||||||
|
|
||||||
|
public byte RedMin => _rMin;
|
||||||
|
public byte RedMax => _rMax;
|
||||||
|
|
||||||
|
public byte GreenMin => _gMin;
|
||||||
|
public byte GreenMax => _gMax;
|
||||||
|
|
||||||
|
public byte BlueMin => _bMin;
|
||||||
|
public byte BlueMax => _bMax;
|
||||||
|
|
||||||
|
public byte AlphaMin => byte.MaxValue;
|
||||||
|
public byte AlphaMax => byte.MaxValue;
|
||||||
|
|
||||||
|
public byte RedRange => (byte)(_rMax - _rMin);
|
||||||
|
public byte GreenRange => (byte)(_gMax - _gMin);
|
||||||
|
public byte BlueRange => (byte)(_bMax - _bMin);
|
||||||
|
public byte AlphaRange => 0;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
""",
|
||||||
|
|
||||||
|
4 => $$"""
|
||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct MinMax{{colorFormat.Format}}(byte {{colorFormat.FirstEntry}}Min, byte {{colorFormat.FirstEntry}}Max, byte {{colorFormat.SecondEntry}}Min, byte {{colorFormat.SecondEntry}}Max, byte {{colorFormat.ThirdEntry}}Min, byte {{colorFormat.ThirdEntry}}Max, byte {{colorFormat.FourthEntry}}Min, byte {{colorFormat.FourthEntry}}Max) : IMinMax
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.FirstEntry}}Min = {{colorFormat.FirstEntry}}Min;
|
||||||
|
private readonly byte _{{colorFormat.FirstEntry}}Max = {{colorFormat.FirstEntry}}Max;
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.SecondEntry}}Min = {{colorFormat.SecondEntry}}Min;
|
||||||
|
private readonly byte _{{colorFormat.SecondEntry}}Max = {{colorFormat.SecondEntry}}Max;
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.ThirdEntry}}Min = {{colorFormat.ThirdEntry}}Min;
|
||||||
|
private readonly byte _{{colorFormat.ThirdEntry}}Max = {{colorFormat.ThirdEntry}}Max;
|
||||||
|
|
||||||
|
private readonly byte _{{colorFormat.FourthEntry}}Min = {{colorFormat.FourthEntry}}Min;
|
||||||
|
private readonly byte _{{colorFormat.FourthEntry}}Max = {{colorFormat.FourthEntry}}Max;
|
||||||
|
|
||||||
|
public byte RedMin => _rMin;
|
||||||
|
public byte RedMax => _rMax;
|
||||||
|
|
||||||
|
public byte GreenMin => _gMin;
|
||||||
|
public byte GreenMax => _gMax;
|
||||||
|
|
||||||
|
public byte BlueMin => _bMin;
|
||||||
|
public byte BlueMax => _bMax;
|
||||||
|
|
||||||
|
public byte AlphaMin => _aMin;
|
||||||
|
public byte AlphaMax => _aMax;
|
||||||
|
|
||||||
|
public byte RedRange => (byte)(_rMax - _rMin);
|
||||||
|
public byte GreenRange => (byte)(_gMax - _gMin);
|
||||||
|
public byte BlueRange => (byte)(_bMax - _bMin);
|
||||||
|
public byte AlphaRange => (byte)(_aMax - _aMin);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
""",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string GenerateColorFormatMinMax(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
return $$"""
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormat{{colorFormat.Format}}
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<Color{{colorFormat.Format}}, MinMax{{colorFormat.Format}}>(MemoryMarshal.Cast<byte, Color{{colorFormat.Format}}>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateColorFormatInterfaceMinMax()
|
||||||
|
{
|
||||||
|
return """
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
internal IMinMax MinMax(ReadOnlySpan<byte> data);
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
}
|
||||||
56
HPPH.Generators/Features/Quantize.cs
Normal file
56
HPPH.Generators/Features/Quantize.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
internal class Quantize : IGeneratorFeature
|
||||||
|
{
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
yield return ($"ColorFormat{colorFormat.Format}.Quantize", GenerateColorFormatQuantize(colorFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ImmutableArray<ColorFormatData> colorFormats)
|
||||||
|
{
|
||||||
|
yield return ("IColorFormat.Quantize", GenerateColorFormatInterfaceQuantize());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateColorFormatQuantize(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
return $$"""
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormat{{colorFormat.Format}}
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor[] IColorFormat.CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize)
|
||||||
|
{
|
||||||
|
Color{{colorFormat.Format}}[] colors = PixelHelper.CreateColorPalette<Color{{colorFormat.Format}}>(MemoryMarshal.Cast<byte, Color{{colorFormat.Format}}>(data), paletteSize);
|
||||||
|
|
||||||
|
IColor[] result = new IColor[colors.Length];
|
||||||
|
for(int i = 0; i < colors.Length; i++)
|
||||||
|
result[i] = colors[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateColorFormatInterfaceQuantize()
|
||||||
|
{
|
||||||
|
return """
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
internal IColor[] CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize);
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
}
|
||||||
129
HPPH.Generators/Features/Sum.cs
Normal file
129
HPPH.Generators/Features/Sum.cs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace HPPH.Generators;
|
||||||
|
|
||||||
|
internal class Sum : IGeneratorFeature
|
||||||
|
{
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
yield return ($"Sum{colorFormat.Format}", GenerateSumStruct(colorFormat));
|
||||||
|
yield return ($"ColorFormat{colorFormat.Format}.Sum", GenerateColorFormatSum(colorFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<(string name, string source)> GenerateFor(ImmutableArray<ColorFormatData> colorFormats)
|
||||||
|
{
|
||||||
|
yield return ("IColorFormat.Sum", GenerateColorFormatInterfaceSum());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateSumStruct(ColorFormatData colorFormat)
|
||||||
|
=> colorFormat.Bpp switch
|
||||||
|
{
|
||||||
|
3 => $$"""
|
||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct Sum{{colorFormat.Format}}(long {{colorFormat.FirstEntry}}, long {{colorFormat.SecondEntry}}, long {{colorFormat.ThirdEntry}}, long a) : ISum
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly long _{{colorFormat.FirstEntry}} = {{colorFormat.FirstEntry}};
|
||||||
|
private readonly long _{{colorFormat.SecondEntry}} = {{colorFormat.SecondEntry}};
|
||||||
|
private readonly long _{{colorFormat.ThirdEntry}} = {{colorFormat.ThirdEntry}};
|
||||||
|
private readonly long _a = a;
|
||||||
|
|
||||||
|
public long A => _a;
|
||||||
|
public long R => _r;
|
||||||
|
public long G => _g;
|
||||||
|
public long B => _b;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
""",
|
||||||
|
|
||||||
|
4 => $$"""
|
||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct Sum{{colorFormat.Format}}(long {{colorFormat.FirstEntry}}, long {{colorFormat.SecondEntry}}, long {{colorFormat.ThirdEntry}}, long {{colorFormat.FourthEntry}}) : ISum
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly long _{{colorFormat.FirstEntry}} = {{colorFormat.FirstEntry}};
|
||||||
|
private readonly long _{{colorFormat.SecondEntry}} = {{colorFormat.SecondEntry}};
|
||||||
|
private readonly long _{{colorFormat.ThirdEntry}} = {{colorFormat.ThirdEntry}};
|
||||||
|
private readonly long _{{colorFormat.FourthEntry}} = {{colorFormat.FourthEntry}};
|
||||||
|
|
||||||
|
public long R => _r;
|
||||||
|
public long G => _g;
|
||||||
|
public long B => _b;
|
||||||
|
public long A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
""",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string GenerateColorFormatSum(ColorFormatData colorFormat)
|
||||||
|
{
|
||||||
|
return $$"""
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormat{{colorFormat.Format}}
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<Color{{colorFormat.Format}}, Sum{{colorFormat.Format}}>(MemoryMarshal.Cast<byte, Color{{colorFormat.Format}}>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateColorFormatInterfaceSum()
|
||||||
|
{
|
||||||
|
return """
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
internal ISum Sum(ReadOnlySpan<byte> data);
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
}
|
||||||
21
HPPH.Generators/HPPH.Generators.csproj
Normal file
21
HPPH.Generators/HPPH.Generators.csproj
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<IsRoslynComponent>true</IsRoslynComponent>
|
||||||
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
|
<DevelopmentDependency>true</DevelopmentDependency>
|
||||||
|
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||||
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<SourceGenerator_EnableLogging>True</SourceGenerator_EnableLogging>
|
||||||
|
<SourceGenerator_EnableDebug>False</SourceGenerator_EnableDebug>
|
||||||
|
<SourceGenerator_DetailedLog>True</SourceGenerator_DetailedLog>
|
||||||
|
<SourceGenerator_IntellisenseFix>True</SourceGenerator_IntellisenseFix>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
2
HPPH.Generators/HPPH.Generators.csproj.DotSettings
Normal file
2
HPPH.Generators/HPPH.Generators.csproj.DotSettings
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=features/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
13
HPPH.Reference/HPPH.Reference.csproj
Normal file
13
HPPH.Reference/HPPH.Reference.csproj
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HPPH\HPPH.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
14
HPPH.Reference/HPPHExtensions.cs
Normal file
14
HPPH.Reference/HPPHExtensions.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace HPPH.Reference;
|
||||||
|
|
||||||
|
internal static class HPPHExtensions
|
||||||
|
{
|
||||||
|
public static byte GetByteValueFromPercentage(this float percentage)
|
||||||
|
{
|
||||||
|
if (float.IsNaN(percentage) || (percentage < 0)) return 0;
|
||||||
|
|
||||||
|
return (byte)(percentage >= 1.0f ? 255 : percentage * 256.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetPercentageFromByteValue(this byte value)
|
||||||
|
=> value == 255 ? 1.0f : (value / 256.0f);
|
||||||
|
}
|
||||||
43
HPPH.Reference/PixelHelper.Average.cs
Normal file
43
HPPH.Reference/PixelHelper.Average.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
namespace HPPH.Reference;
|
||||||
|
|
||||||
|
public static partial class ReferencePixelHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public static IColor Average(IImage image)
|
||||||
|
{
|
||||||
|
float count = image.Width * image.Height;
|
||||||
|
|
||||||
|
ISum sum = Sum(image);
|
||||||
|
return new ColorRGBA((sum.R / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.G / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.B / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.A / count).GetByteValueFromPercentage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Average<T>(RefImage<T> image)
|
||||||
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
float count = image.Width * image.Height;
|
||||||
|
|
||||||
|
ISum sum = Sum(image);
|
||||||
|
return (T)T.Create((sum.R / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.G / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.B / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.A / count).GetByteValueFromPercentage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Average<T>(ReadOnlySpan<T> colors)
|
||||||
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
float count = colors.Length;
|
||||||
|
|
||||||
|
ISum sum = Sum(colors);
|
||||||
|
return (T)T.Create((sum.R / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.G / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.B / count).GetByteValueFromPercentage(),
|
||||||
|
(sum.A / count).GetByteValueFromPercentage());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
73
HPPH.Reference/PixelHelper.MinMax.cs
Normal file
73
HPPH.Reference/PixelHelper.MinMax.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
namespace HPPH.Reference;
|
||||||
|
|
||||||
|
public static partial class ReferencePixelHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public static IMinMax MinMax(IImage image)
|
||||||
|
{
|
||||||
|
byte minR = byte.MaxValue, minG = byte.MaxValue, minB = byte.MaxValue, minA = byte.MaxValue;
|
||||||
|
byte maxR = byte.MinValue, maxG = byte.MinValue, maxB = byte.MinValue, maxA = byte.MinValue;
|
||||||
|
|
||||||
|
foreach (IColor color in image)
|
||||||
|
{
|
||||||
|
minR = Math.Min(minR, color.R);
|
||||||
|
minG = Math.Min(minG, color.G);
|
||||||
|
minB = Math.Min(minB, color.B);
|
||||||
|
minA = Math.Min(minA, color.A);
|
||||||
|
|
||||||
|
maxR = Math.Max(maxR, color.R);
|
||||||
|
maxG = Math.Max(maxG, color.G);
|
||||||
|
maxB = Math.Max(maxB, color.B);
|
||||||
|
maxA = Math.Max(maxA, color.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MinMaxRGBA(minR, maxR, minG, maxG, minB, maxB, minA, maxA);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IMinMax MinMax<T>(RefImage<T> image)
|
||||||
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
byte minR = byte.MaxValue, minG = byte.MaxValue, minB = byte.MaxValue, minA = byte.MaxValue;
|
||||||
|
byte maxR = byte.MinValue, maxG = byte.MinValue, maxB = byte.MinValue, maxA = byte.MinValue;
|
||||||
|
|
||||||
|
foreach (T color in image)
|
||||||
|
{
|
||||||
|
minR = Math.Min(minR, color.R);
|
||||||
|
minG = Math.Min(minG, color.G);
|
||||||
|
minB = Math.Min(minB, color.B);
|
||||||
|
minA = Math.Min(minA, color.A);
|
||||||
|
|
||||||
|
maxR = Math.Max(maxR, color.R);
|
||||||
|
maxG = Math.Max(maxG, color.G);
|
||||||
|
maxB = Math.Max(maxB, color.B);
|
||||||
|
maxA = Math.Max(maxA, color.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MinMaxRGBA(minR, maxR, minG, maxG, minB, maxB, minA, maxA);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IMinMax MinMax<T>(ReadOnlySpan<T> colors)
|
||||||
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
byte minR = byte.MaxValue, minG = byte.MaxValue, minB = byte.MaxValue, minA = byte.MaxValue;
|
||||||
|
byte maxR = byte.MinValue, maxG = byte.MinValue, maxB = byte.MinValue, maxA = byte.MinValue;
|
||||||
|
|
||||||
|
foreach (T color in colors)
|
||||||
|
{
|
||||||
|
minR = Math.Min(minR, color.R);
|
||||||
|
minG = Math.Min(minG, color.G);
|
||||||
|
minB = Math.Min(minB, color.B);
|
||||||
|
minA = Math.Min(minA, color.A);
|
||||||
|
|
||||||
|
maxR = Math.Max(maxR, color.R);
|
||||||
|
maxG = Math.Max(maxG, color.G);
|
||||||
|
maxB = Math.Max(maxB, color.B);
|
||||||
|
maxA = Math.Max(maxA, color.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MinMaxRGBA(minR, maxR, minG, maxG, minB, maxB, minA, maxA);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
8
HPPH.Reference/PixelHelper.Quantize.cs
Normal file
8
HPPH.Reference/PixelHelper.Quantize.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace HPPH.Reference;
|
||||||
|
|
||||||
|
public static partial class ReferencePixelHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
26
HPPH.Reference/PixelHelper.Sort.cs
Normal file
26
HPPH.Reference/PixelHelper.Sort.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
namespace HPPH.Reference;
|
||||||
|
|
||||||
|
public static partial class ReferencePixelHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
// DarthAffe 05.07.2024: LINQ OrderBy uses a stable sorting algorithm -> it's a good reference as the optimized sort is supposed to be stable.
|
||||||
|
|
||||||
|
public static void SortByRed<T>(Span<T> colors)
|
||||||
|
where T : unmanaged, IColor
|
||||||
|
=> colors.ToArray().OrderBy(x => x.R).ToArray().AsSpan().CopyTo(colors);
|
||||||
|
|
||||||
|
public static void SortByGreen<T>(Span<T> colors)
|
||||||
|
where T : unmanaged, IColor
|
||||||
|
=> colors.ToArray().OrderBy(x => x.G).ToArray().AsSpan().CopyTo(colors);
|
||||||
|
|
||||||
|
public static void SortByBlue<T>(Span<T> colors)
|
||||||
|
where T : unmanaged, IColor
|
||||||
|
=> colors.ToArray().OrderBy(x => x.B).ToArray().AsSpan().CopyTo(colors);
|
||||||
|
|
||||||
|
public static void SortByAlpha<T>(Span<T> colors)
|
||||||
|
where T : unmanaged, IColor
|
||||||
|
=> colors.ToArray().OrderBy(x => x.A).ToArray().AsSpan().CopyTo(colors);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
55
HPPH.Reference/PixelHelper.Sum.cs
Normal file
55
HPPH.Reference/PixelHelper.Sum.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
namespace HPPH.Reference;
|
||||||
|
|
||||||
|
public static partial class ReferencePixelHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public static ISum Sum(IImage image)
|
||||||
|
{
|
||||||
|
long sumR = 0, sumG = 0, sumB = 0, sumA = 0;
|
||||||
|
|
||||||
|
foreach (IColor color in image)
|
||||||
|
{
|
||||||
|
sumR += color.R;
|
||||||
|
sumG += color.G;
|
||||||
|
sumB += color.B;
|
||||||
|
sumA += color.A;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SumRGBA(sumR, sumG, sumB, sumA);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ISum Sum<T>(RefImage<T> image)
|
||||||
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
long sumR = 0, sumG = 0, sumB = 0, sumA = 0;
|
||||||
|
|
||||||
|
foreach (T color in image)
|
||||||
|
{
|
||||||
|
sumR += color.R;
|
||||||
|
sumG += color.G;
|
||||||
|
sumB += color.B;
|
||||||
|
sumA += color.A;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SumRGBA(sumR, sumG, sumB, sumA);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ISum Sum<T>(ReadOnlySpan<T> colors)
|
||||||
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
long sumR = 0, sumG = 0, sumB = 0, sumA = 0;
|
||||||
|
|
||||||
|
foreach (T color in colors)
|
||||||
|
{
|
||||||
|
sumR += color.R;
|
||||||
|
sumG += color.G;
|
||||||
|
sumB += color.B;
|
||||||
|
sumA += color.A;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SumRGBA(sumR, sumG, sumB, sumA);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
3
HPPH.Reference/PixelHelper.cs
Normal file
3
HPPH.Reference/PixelHelper.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace HPPH.Reference;
|
||||||
|
|
||||||
|
public static partial class ReferencePixelHelper;
|
||||||
65
HPPH.Test/AverageTests.cs
Normal file
65
HPPH.Test/AverageTests.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using HPPH.Reference;
|
||||||
|
|
||||||
|
namespace HPPH.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class AverageTests
|
||||||
|
{
|
||||||
|
private static IEnumerable<string> GetTestImages() => Directory.EnumerateFiles(@"..\..\..\..\sample_data", "*.png", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AverageImage3Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AverageRefImage3Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AverageReadOnlySpan3Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGB[] data = ImageHelper.Get3ByteColorsFromImage(image);
|
||||||
|
ReadOnlySpan<ColorRGB> span = data;
|
||||||
|
|
||||||
|
ColorRGB reference = ReferencePixelHelper.Average(span);
|
||||||
|
ColorRGB test = PixelHelper.Average(span);
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.R, test.R, "R differs");
|
||||||
|
Assert.AreEqual(reference.G, test.G, "G differs");
|
||||||
|
Assert.AreEqual(reference.B, test.B, "B differs");
|
||||||
|
Assert.AreEqual(reference.A, test.A, "A differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AverageImage4Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AverageRefImage4Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AverageReadOnlySpan4Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGBA[] data = ImageHelper.Get4ByteColorsFromImage(image);
|
||||||
|
ReadOnlySpan<ColorRGBA> span = data;
|
||||||
|
|
||||||
|
ColorRGBA reference = ReferencePixelHelper.Average(span);
|
||||||
|
ColorRGBA test = PixelHelper.Average(span);
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.R, test.R, "R differs");
|
||||||
|
Assert.AreEqual(reference.G, test.G, "G differs");
|
||||||
|
Assert.AreEqual(reference.B, test.B, "B differs");
|
||||||
|
Assert.AreEqual(reference.A, test.A, "A differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
HPPH.Test/HPPH.Test.csproj
Normal file
29
HPPH.Test/HPPH.Test.csproj
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="8.0.6" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HPPH.Reference\HPPH.Reference.csproj" />
|
||||||
|
<ProjectReference Include="..\HPPH\HPPH.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
44
HPPH.Test/ImageHelper.cs
Normal file
44
HPPH.Test/ImageHelper.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace HPPH.Test;
|
||||||
|
|
||||||
|
internal static class ImageHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public static ColorRGB[] Get3ByteColorsFromImage(string file)
|
||||||
|
{
|
||||||
|
using FileStream stream = File.OpenRead(file);
|
||||||
|
using Bitmap bmp = new(stream);
|
||||||
|
|
||||||
|
ColorRGB[] colors = new ColorRGB[bmp.Width * bmp.Height];
|
||||||
|
int i = 0;
|
||||||
|
for (int x = 0; x < bmp.Width; x++)
|
||||||
|
for (int y = 0; y < bmp.Height; y++)
|
||||||
|
{
|
||||||
|
Color color = bmp.GetPixel(x, y);
|
||||||
|
colors[i++] = new ColorRGB(color.R, color.G, color.B);
|
||||||
|
}
|
||||||
|
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ColorRGBA[] Get4ByteColorsFromImage(string file)
|
||||||
|
{
|
||||||
|
using FileStream stream = File.OpenRead(file);
|
||||||
|
using Bitmap bmp = new(stream);
|
||||||
|
|
||||||
|
ColorRGBA[] colors = new ColorRGBA[bmp.Width * bmp.Height];
|
||||||
|
int i = 0;
|
||||||
|
for (int x = 0; x < bmp.Width; x++)
|
||||||
|
for (int y = 0; y < bmp.Height; y++)
|
||||||
|
{
|
||||||
|
Color color = bmp.GetPixel(x, y);
|
||||||
|
colors[i++] = new ColorRGBA(color.R, color.G, color.B, color.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
85
HPPH.Test/MinMaxTests.cs
Normal file
85
HPPH.Test/MinMaxTests.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
using HPPH.Reference;
|
||||||
|
|
||||||
|
namespace HPPH.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class MinMaxTests
|
||||||
|
{
|
||||||
|
private static IEnumerable<string> GetTestImages() => Directory.EnumerateFiles(@"..\..\..\..\sample_data", "*.png", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxImage3Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxRefImage3Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxReadOnlySpan3Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGB[] data = ImageHelper.Get3ByteColorsFromImage(image);
|
||||||
|
ReadOnlySpan<ColorRGB> span = data;
|
||||||
|
|
||||||
|
IMinMax reference = ReferencePixelHelper.MinMax(span);
|
||||||
|
IMinMax test = PixelHelper.MinMax(span);
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.RedMin, test.RedMin, "RedMin differs");
|
||||||
|
Assert.AreEqual(reference.GreenMin, test.GreenMin, "GreenMin differs");
|
||||||
|
Assert.AreEqual(reference.BlueMin, test.BlueMin, "BlueMin differs");
|
||||||
|
Assert.AreEqual(reference.AlphaMin, test.AlphaMin, "AlphaMin differs");
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.RedMax, test.RedMax, "RedMax differs");
|
||||||
|
Assert.AreEqual(reference.GreenMax, test.GreenMax, "GreenMax differs");
|
||||||
|
Assert.AreEqual(reference.BlueMax, test.BlueMax, "BlueMax differs");
|
||||||
|
Assert.AreEqual(reference.AlphaMax, test.AlphaMax, "AlphaMax differs");
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.RedRange, test.RedRange, "RedRange differs");
|
||||||
|
Assert.AreEqual(reference.GreenRange, test.GreenRange, "GreenRange differs");
|
||||||
|
Assert.AreEqual(reference.BlueRange, test.BlueRange, "BlueRange differs");
|
||||||
|
Assert.AreEqual(reference.AlphaRange, test.AlphaRange, "AlphaRange differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxImage4Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxRefImage4Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void MinMaxReadOnlySpan4Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGBA[] data = ImageHelper.Get4ByteColorsFromImage(image);
|
||||||
|
ReadOnlySpan<ColorRGBA> span = data;
|
||||||
|
|
||||||
|
IMinMax reference = ReferencePixelHelper.MinMax(span);
|
||||||
|
IMinMax test = PixelHelper.MinMax(span);
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.RedMin, test.RedMin, "RedMin differs");
|
||||||
|
Assert.AreEqual(reference.GreenMin, test.GreenMin, "GreenMin differs");
|
||||||
|
Assert.AreEqual(reference.BlueMin, test.BlueMin, "BlueMin differs");
|
||||||
|
Assert.AreEqual(reference.AlphaMin, test.AlphaMin, "AlphaMin differs");
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.RedMax, test.RedMax, "RedMax differs");
|
||||||
|
Assert.AreEqual(reference.GreenMax, test.GreenMax, "GreenMax differs");
|
||||||
|
Assert.AreEqual(reference.BlueMax, test.BlueMax, "BlueMax differs");
|
||||||
|
Assert.AreEqual(reference.AlphaMax, test.AlphaMax, "AlphaMax differs");
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.RedRange, test.RedRange, "RedRange differs");
|
||||||
|
Assert.AreEqual(reference.GreenRange, test.GreenRange, "GreenRange differs");
|
||||||
|
Assert.AreEqual(reference.BlueRange, test.BlueRange, "BlueRange differs");
|
||||||
|
Assert.AreEqual(reference.AlphaRange, test.AlphaRange, "AlphaRange differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
143
HPPH.Test/SortTests.cs
Normal file
143
HPPH.Test/SortTests.cs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
using HPPH.Reference;
|
||||||
|
|
||||||
|
namespace HPPH.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class SortTests
|
||||||
|
{
|
||||||
|
private static IEnumerable<string> GetTestImages() => Directory.EnumerateFiles(@"..\..\..\..\sample_data", "*.png", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SortByRed3Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGB[] referenceData = ImageHelper.Get3ByteColorsFromImage(image);
|
||||||
|
ColorRGB[] testData = new ColorRGB[referenceData.Length];
|
||||||
|
Span<ColorRGB> referenceSpan = referenceData;
|
||||||
|
Span<ColorRGB> testSpan = testData;
|
||||||
|
referenceSpan.CopyTo(testSpan);
|
||||||
|
|
||||||
|
ReferencePixelHelper.SortByRed(referenceSpan);
|
||||||
|
PixelHelper.SortByRed(testSpan);
|
||||||
|
|
||||||
|
for (int i = 0; i < referenceData.Length; i++)
|
||||||
|
Assert.AreEqual(referenceSpan[i], testSpan[i], $"Index {i} differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SortByGreen3Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGB[] referenceData = ImageHelper.Get3ByteColorsFromImage(image);
|
||||||
|
ColorRGB[] testData = new ColorRGB[referenceData.Length];
|
||||||
|
Span<ColorRGB> referenceSpan = referenceData;
|
||||||
|
Span<ColorRGB> testSpan = testData;
|
||||||
|
referenceSpan.CopyTo(testSpan);
|
||||||
|
|
||||||
|
ReferencePixelHelper.SortByGreen(referenceSpan);
|
||||||
|
PixelHelper.SortByGreen(testSpan);
|
||||||
|
|
||||||
|
for (int i = 0; i < referenceData.Length; i++)
|
||||||
|
Assert.AreEqual(referenceSpan[i], testSpan[i], $"Index {i} differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SortByBlue3Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGB[] referenceData = ImageHelper.Get3ByteColorsFromImage(image);
|
||||||
|
ColorRGB[] testData = new ColorRGB[referenceData.Length];
|
||||||
|
Span<ColorRGB> referenceSpan = referenceData;
|
||||||
|
Span<ColorRGB> testSpan = testData;
|
||||||
|
referenceSpan.CopyTo(testSpan);
|
||||||
|
|
||||||
|
ReferencePixelHelper.SortByBlue(referenceSpan);
|
||||||
|
PixelHelper.SortByBlue(testSpan);
|
||||||
|
|
||||||
|
for (int i = 0; i < referenceData.Length; i++)
|
||||||
|
Assert.AreEqual(referenceSpan[i], testSpan[i], $"Index {i} differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SortByRed4Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGBA[] referenceData = ImageHelper.Get4ByteColorsFromImage(image);
|
||||||
|
ColorRGBA[] testData = new ColorRGBA[referenceData.Length];
|
||||||
|
Span<ColorRGBA> referenceSpan = referenceData;
|
||||||
|
Span<ColorRGBA> testSpan = testData;
|
||||||
|
referenceSpan.CopyTo(testSpan);
|
||||||
|
|
||||||
|
ReferencePixelHelper.SortByRed(referenceSpan);
|
||||||
|
PixelHelper.SortByRed(testSpan);
|
||||||
|
|
||||||
|
for (int i = 0; i < referenceData.Length; i++)
|
||||||
|
Assert.AreEqual(referenceSpan[i], testSpan[i], $"Index {i} differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SortByGreen4Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGBA[] referenceData = ImageHelper.Get4ByteColorsFromImage(image);
|
||||||
|
ColorRGBA[] testData = new ColorRGBA[referenceData.Length];
|
||||||
|
Span<ColorRGBA> referenceSpan = referenceData;
|
||||||
|
Span<ColorRGBA> testSpan = testData;
|
||||||
|
referenceSpan.CopyTo(testSpan);
|
||||||
|
|
||||||
|
ReferencePixelHelper.SortByGreen(referenceSpan);
|
||||||
|
PixelHelper.SortByGreen(testSpan);
|
||||||
|
|
||||||
|
for (int i = 0; i < referenceData.Length; i++)
|
||||||
|
Assert.AreEqual(referenceSpan[i], testSpan[i], $"Index {i} differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SortByBlue4Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGBA[] referenceData = ImageHelper.Get4ByteColorsFromImage(image);
|
||||||
|
ColorRGBA[] testData = new ColorRGBA[referenceData.Length];
|
||||||
|
Span<ColorRGBA> referenceSpan = referenceData;
|
||||||
|
Span<ColorRGBA> testSpan = testData;
|
||||||
|
referenceSpan.CopyTo(testSpan);
|
||||||
|
|
||||||
|
ReferencePixelHelper.SortByBlue(referenceSpan);
|
||||||
|
PixelHelper.SortByBlue(testSpan);
|
||||||
|
|
||||||
|
for (int i = 0; i < referenceData.Length; i++)
|
||||||
|
Assert.AreEqual(referenceSpan[i], testSpan[i], $"Index {i} differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SortByAlpha4Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGBA[] referenceData = ImageHelper.Get4ByteColorsFromImage(image);
|
||||||
|
ColorRGBA[] testData = new ColorRGBA[referenceData.Length];
|
||||||
|
Span<ColorRGBA> referenceSpan = referenceData;
|
||||||
|
Span<ColorRGBA> testSpan = testData;
|
||||||
|
referenceSpan.CopyTo(testSpan);
|
||||||
|
|
||||||
|
ReferencePixelHelper.SortByAlpha(referenceSpan);
|
||||||
|
PixelHelper.SortByAlpha(testSpan);
|
||||||
|
|
||||||
|
for (int i = 0; i < referenceData.Length; i++)
|
||||||
|
Assert.AreEqual(referenceSpan[i], testSpan[i], $"Index {i} differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
HPPH.Test/SumTests.cs
Normal file
65
HPPH.Test/SumTests.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using HPPH.Reference;
|
||||||
|
|
||||||
|
namespace HPPH.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class SumTests
|
||||||
|
{
|
||||||
|
private static IEnumerable<string> GetTestImages() => Directory.EnumerateFiles(@"..\..\..\..\sample_data", "*.png", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SumImage3Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SumRefImage3Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SumReadOnlySpan3Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGB[] data = ImageHelper.Get3ByteColorsFromImage(image);
|
||||||
|
ReadOnlySpan<ColorRGB> span = data;
|
||||||
|
|
||||||
|
ISum reference = ReferencePixelHelper.Sum(span);
|
||||||
|
ISum test = PixelHelper.Sum(span);
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.R, test.R, "R differs");
|
||||||
|
Assert.AreEqual(reference.G, test.G, "G differs");
|
||||||
|
Assert.AreEqual(reference.B, test.B, "B differs");
|
||||||
|
Assert.AreEqual(reference.A, test.A, "A differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SumImage4Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SumRefImage4Byte()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SumReadOnlySpan4Byte()
|
||||||
|
{
|
||||||
|
foreach (string image in GetTestImages())
|
||||||
|
{
|
||||||
|
ColorRGBA[] data = ImageHelper.Get4ByteColorsFromImage(image);
|
||||||
|
ReadOnlySpan<ColorRGBA> span = data;
|
||||||
|
|
||||||
|
ISum reference = ReferencePixelHelper.Sum(span);
|
||||||
|
ISum test = PixelHelper.Sum(span);
|
||||||
|
|
||||||
|
Assert.AreEqual(reference.R, test.R, "R differs");
|
||||||
|
Assert.AreEqual(reference.G, test.G, "G differs");
|
||||||
|
Assert.AreEqual(reference.B, test.B, "B differs");
|
||||||
|
Assert.AreEqual(reference.A, test.A, "A differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
HPPH.sln
Normal file
49
HPPH.sln
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.9.34714.143
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HPPH", "HPPH\HPPH.csproj", "{FDC79AD8-26FF-4EA4-B1FF-7D4818F57A79}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HPPH.Test", "HPPH.Test\HPPH.Test.csproj", "{11795808-7916-4EAA-A69A-B09FEF46F71D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HPPH.Benchmark", "HPPH.Benchmark\HPPH.Benchmark.csproj", "{233CFF7C-DDA4-4450-AB88-17C1B58EBFB5}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HPPH.Reference", "HPPH.Reference\HPPH.Reference.csproj", "{1675FE68-1F51-4202-9567-BB46215B2BBD}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HPPH.Generators", "HPPH.Generators\HPPH.Generators.csproj", "{C247512B-E6D2-4591-8AFA-F2268F1AEAB2}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{FDC79AD8-26FF-4EA4-B1FF-7D4818F57A79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FDC79AD8-26FF-4EA4-B1FF-7D4818F57A79}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FDC79AD8-26FF-4EA4-B1FF-7D4818F57A79}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FDC79AD8-26FF-4EA4-B1FF-7D4818F57A79}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{11795808-7916-4EAA-A69A-B09FEF46F71D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{11795808-7916-4EAA-A69A-B09FEF46F71D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{11795808-7916-4EAA-A69A-B09FEF46F71D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{11795808-7916-4EAA-A69A-B09FEF46F71D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{233CFF7C-DDA4-4450-AB88-17C1B58EBFB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{233CFF7C-DDA4-4450-AB88-17C1B58EBFB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{233CFF7C-DDA4-4450-AB88-17C1B58EBFB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{233CFF7C-DDA4-4450-AB88-17C1B58EBFB5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1675FE68-1F51-4202-9567-BB46215B2BBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1675FE68-1F51-4202-9567-BB46215B2BBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1675FE68-1F51-4202-9567-BB46215B2BBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1675FE68-1F51-4202-9567-BB46215B2BBD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C247512B-E6D2-4591-8AFA-F2268F1AEAB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C247512B-E6D2-4591-8AFA-F2268F1AEAB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C247512B-E6D2-4591-8AFA-F2268F1AEAB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C247512B-E6D2-4591-8AFA-F2268F1AEAB2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {EAF6CA55-D81E-4887-9FAC-8D633BBC0096}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
2
HPPH.sln.DotSettings
Normal file
2
HPPH.sln.DotSettings
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HPPH/@EntryIndexedValue">HPPH</s:String></wpf:ResourceDictionary>
|
||||||
22
HPPH/Colors/Colors.cs
Normal file
22
HPPH/Colors/Colors.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// ReSharper disable UnusedType.Global
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[ColorGenerator]
|
||||||
|
public readonly partial struct ColorRGB;
|
||||||
|
|
||||||
|
[ColorGenerator]
|
||||||
|
public readonly partial struct ColorBGR;
|
||||||
|
|
||||||
|
[ColorGenerator]
|
||||||
|
public readonly partial struct ColorARGB;
|
||||||
|
|
||||||
|
[ColorGenerator]
|
||||||
|
public readonly partial struct ColorABGR;
|
||||||
|
|
||||||
|
[ColorGenerator]
|
||||||
|
public readonly partial struct ColorRGBA;
|
||||||
|
|
||||||
|
[ColorGenerator]
|
||||||
|
public readonly partial struct ColorBGRA;
|
||||||
34
HPPH/Colors/IColor.cs
Normal file
34
HPPH/Colors/IColor.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a generic color made of 4 bytes (alpha, red, green and blue)
|
||||||
|
/// </summary>
|
||||||
|
public interface IColor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the red-component of this color.
|
||||||
|
/// </summary>
|
||||||
|
byte R { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the green-component of this color.
|
||||||
|
/// </summary>
|
||||||
|
byte G { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the blue-component of this color.
|
||||||
|
/// </summary>
|
||||||
|
byte B { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the alpha-component of this color.
|
||||||
|
/// </summary>
|
||||||
|
byte A { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the color-format of this color.
|
||||||
|
/// </summary>
|
||||||
|
public static virtual IColorFormat ColorFormat => throw new NotSupportedException();
|
||||||
|
|
||||||
|
public static virtual IColor Create(byte r, byte g, byte b, byte a) => throw new NotSupportedException();
|
||||||
|
}
|
||||||
15
HPPH/Colors/IColorFormat.cs
Normal file
15
HPPH/Colors/IColorFormat.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color format.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Bytes per pixel for this color-format.
|
||||||
|
/// </summary>
|
||||||
|
int BytesPerPixel { get; }
|
||||||
|
|
||||||
|
string Name { get; }
|
||||||
|
}
|
||||||
265
HPPH/CommunityToolkit.HighPerformance/ReadOnlyRefEnumerable.cs
Normal file
265
HPPH/CommunityToolkit.HighPerformance/ReadOnlyRefEnumerable.cs
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
// DarthAffe 05.09.2023: Based on https://github.com/CommunityToolkit/dotnet/blob/b0d6c4f9c0cfb5d860400abb00b0ca1b3e94dfa4/src/CommunityToolkit.HighPerformance/Enumerables/ReadOnlyRefEnumerable%7BT%7D.cs
|
||||||
|
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <see langword="ref"/> <see langword="struct"/> that iterates readonly items from arbitrary memory locations.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items to enumerate.</typeparam>
|
||||||
|
public readonly ref struct ReadOnlyRefEnumerable<T>
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="ReadOnlySpan{T}"/> instance pointing to the first item in the target memory area.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The <see cref="ReadOnlySpan{T}.Length"/> field maps to the total available length.</remarks>
|
||||||
|
private readonly ReadOnlySpan<T> _span;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The distance between items in the sequence to enumerate.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The distance refers to <typeparamref name="T"/> items, not byte offset.</remarks>
|
||||||
|
private readonly int _step;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the total available length for the sequence.
|
||||||
|
/// </summary>
|
||||||
|
public int Length
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _span.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the element at the specified zero-based index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index of the element.</param>
|
||||||
|
/// <returns>A reference to the element at the specified index.</returns>
|
||||||
|
/// <exception cref="IndexOutOfRangeException">
|
||||||
|
/// Thrown when <paramref name="index"/> is invalid.
|
||||||
|
/// </exception>
|
||||||
|
public ref readonly T this[int index]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ((uint)index >= (uint)Length) throw new IndexOutOfRangeException();
|
||||||
|
|
||||||
|
ref T r0 = ref MemoryMarshal.GetReference(_span);
|
||||||
|
nint offset = (nint)(uint)index * (nint)(uint)_step;
|
||||||
|
ref T ri = ref Unsafe.Add(ref r0, offset);
|
||||||
|
|
||||||
|
return ref ri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the element at the specified zero-based index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index of the element.</param>
|
||||||
|
/// <returns>A reference to the element at the specified index.</returns>
|
||||||
|
/// <exception cref="IndexOutOfRangeException">
|
||||||
|
/// Thrown when <paramref name="index"/> is invalid.
|
||||||
|
/// </exception>
|
||||||
|
public ref readonly T this[Index index]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => ref this[index.GetOffset(Length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ReadOnlyRefEnumerable{T}"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reference">A reference to the first item of the sequence.</param>
|
||||||
|
/// <param name="length">The number of items in the sequence.</param>
|
||||||
|
/// <param name="step">The distance between items in the sequence to enumerate.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal ReadOnlyRefEnumerable(in T reference, int length, int step)
|
||||||
|
{
|
||||||
|
this._step = step;
|
||||||
|
|
||||||
|
_span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in reference), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc cref="System.Collections.IEnumerable.GetEnumerator"/>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Enumerator GetEnumerator() => new(_span, _step);
|
||||||
|
|
||||||
|
public T[] ToArray()
|
||||||
|
{
|
||||||
|
int length = _span.Length;
|
||||||
|
|
||||||
|
// Empty array if no data is mapped
|
||||||
|
if (length == 0)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
T[] array = new T[length];
|
||||||
|
CopyTo(array);
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the contents of this <see cref="ReadOnlyRefEnumerable{T}"/> into a destination <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination">The destination <see cref="Span{T}"/> instance.</param>
|
||||||
|
/// <exception cref="ArgumentException">
|
||||||
|
/// Thrown when <paramref name="destination"/> is shorter than the source <see cref="ReadOnlyRefEnumerable{T}"/> instance.
|
||||||
|
/// </exception>
|
||||||
|
public void CopyTo(Span<T> destination)
|
||||||
|
{
|
||||||
|
if (_step == 1)
|
||||||
|
{
|
||||||
|
_span.CopyTo(destination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref T sourceRef = ref MemoryMarshal.GetReference(_span);
|
||||||
|
int length = _span.Length;
|
||||||
|
if ((uint)destination.Length < (uint)length)
|
||||||
|
throw new ArgumentException("The target span is too short to copy all the current items to.");
|
||||||
|
|
||||||
|
ref T destinationRef = ref MemoryMarshal.GetReference(destination);
|
||||||
|
|
||||||
|
CopyTo(ref sourceRef, ref destinationRef, (nint)(uint)length, (nint)(uint)_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to copy the current <see cref="ReadOnlyRefEnumerable{T}"/> instance to a destination <see cref="Span{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination">The target <see cref="Span{T}"/> of the copy operation.</param>
|
||||||
|
/// <returns>Whether or not the operation was successful.</returns>
|
||||||
|
public bool TryCopyTo(Span<T> destination)
|
||||||
|
{
|
||||||
|
if (destination.Length >= _span.Length)
|
||||||
|
{
|
||||||
|
CopyTo(destination);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyTo(ref T sourceRef, ref T destinationRef, nint length, nint sourceStep)
|
||||||
|
{
|
||||||
|
nint sourceOffset = 0;
|
||||||
|
nint destinationOffset = 0;
|
||||||
|
|
||||||
|
while (length >= 8)
|
||||||
|
{
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 0) = Unsafe.Add(ref sourceRef, sourceOffset);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 1) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 2) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 3) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 4) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 5) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 6) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 7) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
|
||||||
|
length -= 8;
|
||||||
|
sourceOffset += sourceStep;
|
||||||
|
destinationOffset += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length >= 4)
|
||||||
|
{
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 0) = Unsafe.Add(ref sourceRef, sourceOffset);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 1) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 2) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset + 3) = Unsafe.Add(ref sourceRef, sourceOffset += sourceStep);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
sourceOffset += sourceStep;
|
||||||
|
destinationOffset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
Unsafe.Add(ref destinationRef, destinationOffset) = Unsafe.Add(ref sourceRef, sourceOffset);
|
||||||
|
|
||||||
|
length -= 1;
|
||||||
|
sourceOffset += sourceStep;
|
||||||
|
destinationOffset += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A custom enumerator type to traverse items within a <see cref="ReadOnlyRefEnumerable{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public ref struct Enumerator
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ReadOnlyRefEnumerable{T}._span"/>
|
||||||
|
private readonly ReadOnlySpan<T> _span;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ReadOnlyRefEnumerable{T}._step"/>
|
||||||
|
private readonly int _step;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current position in the sequence.
|
||||||
|
/// </summary>
|
||||||
|
private int _position;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="System.Collections.Generic.IEnumerator{T}.Current"/>
|
||||||
|
public readonly ref readonly T Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ref T r0 = ref MemoryMarshal.GetReference(_span);
|
||||||
|
|
||||||
|
nint offset = (nint)(uint)_position * (nint)(uint)_step;
|
||||||
|
ref T ri = ref Unsafe.Add(ref r0, offset);
|
||||||
|
|
||||||
|
return ref ri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">The <see cref="ReadOnlySpan{T}"/> instance with the info on the items to traverse.</param>
|
||||||
|
/// <param name="step">The distance between items in the sequence to enumerate.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal Enumerator(ReadOnlySpan<T> span, int step)
|
||||||
|
{
|
||||||
|
this._span = span;
|
||||||
|
this._step = step;
|
||||||
|
|
||||||
|
_position = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext() => ++_position < _span.Length;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
8
HPPH/Data/Generic3ByteData.cs
Normal file
8
HPPH/Data/Generic3ByteData.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
internal readonly struct Generic3ByteData(byte b1, byte b2, byte b3)
|
||||||
|
{
|
||||||
|
public readonly byte B1 = b1;
|
||||||
|
public readonly byte B2 = b2;
|
||||||
|
public readonly byte B3 = b3;
|
||||||
|
}
|
||||||
17
HPPH/Data/Generic3ByteMinMax.cs
Normal file
17
HPPH/Data/Generic3ByteMinMax.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
internal readonly struct Generic3ByteMinMax(byte b1Min, byte b1Max, byte b2Min, byte b2Max, byte b3Min, byte b3Max)
|
||||||
|
{
|
||||||
|
public readonly byte B1Min = b1Min;
|
||||||
|
public readonly byte B1Max = b1Max;
|
||||||
|
|
||||||
|
public readonly byte B2Min = b2Min;
|
||||||
|
public readonly byte B2Max = b2Max;
|
||||||
|
|
||||||
|
public readonly byte B3Min = b3Min;
|
||||||
|
public readonly byte B3Max = b3Max;
|
||||||
|
|
||||||
|
public byte B1Range => (byte)(B1Max - B1Min);
|
||||||
|
public byte B2Range => (byte)(B2Max - B2Min);
|
||||||
|
public byte B3Range => (byte)(B3Max - B3Min);
|
||||||
|
}
|
||||||
9
HPPH/Data/Generic4ByteData.cs
Normal file
9
HPPH/Data/Generic4ByteData.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
internal readonly struct Generic4ByteData(byte b1, byte b2, byte b3, byte b4)
|
||||||
|
{
|
||||||
|
public readonly byte B1 = b1;
|
||||||
|
public readonly byte B2 = b2;
|
||||||
|
public readonly byte B3 = b3;
|
||||||
|
public readonly byte B4 = b4;
|
||||||
|
}
|
||||||
21
HPPH/Data/Generic4ByteMinMax.cs
Normal file
21
HPPH/Data/Generic4ByteMinMax.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
internal readonly struct Generic4ByteMinMax(byte b1Min, byte b1Max, byte b2Min, byte b2Max, byte b3Min, byte b3Max, byte b4Min, byte b4Max)
|
||||||
|
{
|
||||||
|
public readonly byte B1Min = b1Min;
|
||||||
|
public readonly byte B1Max = b1Max;
|
||||||
|
|
||||||
|
public readonly byte B2Min = b2Min;
|
||||||
|
public readonly byte B2Max = b2Max;
|
||||||
|
|
||||||
|
public readonly byte B3Min = b3Min;
|
||||||
|
public readonly byte B3Max = b3Max;
|
||||||
|
|
||||||
|
public readonly byte B4Min = b4Min;
|
||||||
|
public readonly byte B4Max = b4Max;
|
||||||
|
|
||||||
|
public byte B1Range => (byte)(B1Max - B1Min);
|
||||||
|
public byte B2Range => (byte)(B2Max - B2Min);
|
||||||
|
public byte B3Range => (byte)(B3Max - B3Min);
|
||||||
|
public byte B4Range => (byte)(B4Max - B4Min);
|
||||||
|
}
|
||||||
9
HPPH/Data/Generic4LongData.cs
Normal file
9
HPPH/Data/Generic4LongData.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
internal readonly struct Generic4LongData(long l1, long l2, long l3, long l4)
|
||||||
|
{
|
||||||
|
public readonly long L1 = l1;
|
||||||
|
public readonly long L2 = l2;
|
||||||
|
public readonly long L3 = l3;
|
||||||
|
public readonly long L4 = l4;
|
||||||
|
}
|
||||||
21
HPPH/Data/IMinMax.cs
Normal file
21
HPPH/Data/IMinMax.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public interface IMinMax
|
||||||
|
{
|
||||||
|
public byte RedMin { get; }
|
||||||
|
public byte RedMax { get; }
|
||||||
|
|
||||||
|
public byte GreenMin { get; }
|
||||||
|
public byte GreenMax { get; }
|
||||||
|
|
||||||
|
public byte BlueMin { get; }
|
||||||
|
public byte BlueMax { get; }
|
||||||
|
|
||||||
|
public byte AlphaMin { get; }
|
||||||
|
public byte AlphaMax { get; }
|
||||||
|
|
||||||
|
public byte RedRange { get; }
|
||||||
|
public byte GreenRange { get; }
|
||||||
|
public byte BlueRange { get; }
|
||||||
|
public byte AlphaRange { get; }
|
||||||
|
}
|
||||||
9
HPPH/Data/ISum.cs
Normal file
9
HPPH/Data/ISum.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public interface ISum
|
||||||
|
{
|
||||||
|
public long R { get; }
|
||||||
|
public long G { get; }
|
||||||
|
public long B { get; }
|
||||||
|
public long A { get; }
|
||||||
|
}
|
||||||
94
HPPH/Extensions/HPPHExtensions.cs
Normal file
94
HPPH/Extensions/HPPHExtensions.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Offers some extensions and helper-methods for the work with floats.
|
||||||
|
/// </summary>
|
||||||
|
internal static class HPPHExtensions
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the precision RGB.NET processes floating point comparisons in.
|
||||||
|
/// </summary>
|
||||||
|
public const float TOLERANCE = 1E-7f;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if two values are equal respecting the <see cref="TOLERANCE"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value1">The first value to compare.</param>
|
||||||
|
/// <param name="value2">The first value to compare.</param>
|
||||||
|
/// <returns><c>true</c> if the difference is smaller than the <see cref="TOLERANCE"/>; otherwise, <c>false</c>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool EqualsInTolerance(this float value1, float value2) => Math.Abs(value1 - value2) < TOLERANCE;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clamps the provided value to be bigger or equal min and smaller or equal max.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to clamp.</param>
|
||||||
|
/// <param name="min">The lower value of the range the value is clamped to.</param>
|
||||||
|
/// <param name="max">The higher value of the range the value is clamped to.</param>
|
||||||
|
/// <returns>The clamped value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T Clamp<T>(this T value, T min, T max)
|
||||||
|
where T : INumber<T>
|
||||||
|
{
|
||||||
|
// ReSharper disable ConvertIfStatementToReturnStatement - I'm not sure why, but inlining this statement reduces performance by ~10%
|
||||||
|
if (value < min) return min;
|
||||||
|
if (value > max) return max;
|
||||||
|
return value;
|
||||||
|
// ReSharper restore ConvertIfStatementToReturnStatement
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enforces the provided value to be in the specified range by wrapping it around the edges if it exceeds them.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to wrap.</param>
|
||||||
|
/// <param name="min">The lower value of the range the value is wrapped into.</param>
|
||||||
|
/// <param name="max">The higher value of the range the value is wrapped into.</param>
|
||||||
|
/// <returns>The wrapped value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T Wrap<T>(this T value, T min, T max)
|
||||||
|
where T : INumber<T>
|
||||||
|
{
|
||||||
|
T range = max - min;
|
||||||
|
|
||||||
|
while (value >= max)
|
||||||
|
value -= range;
|
||||||
|
|
||||||
|
while (value < min)
|
||||||
|
value += range;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a normalized float value in the range [0..1] to a byte [0..255].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="percentage">The normalized float value to convert.</param>
|
||||||
|
/// <returns>The byte value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static byte GetByteValueFromPercentage(this float percentage)
|
||||||
|
{
|
||||||
|
if (float.IsNaN(percentage) || (percentage < 0)) return 0;
|
||||||
|
|
||||||
|
return (byte)(percentage >= 1.0f ? 255 : percentage * 256.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a byte value [0..255] to a normalized float value in the range [0..1].
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The byte value to convert.</param>
|
||||||
|
/// <returns>The normalized float value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static float GetPercentageFromByteValue(this byte value)
|
||||||
|
=> value == 255 ? 1.0f : (value / 256.0f);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
internal class ColorSortGeneratorAttribute(string dataTypeName, string sortValueName) : Attribute
|
||||||
|
{
|
||||||
|
public string DataTypeName { get; } = dataTypeName;
|
||||||
|
public string SortValueName { get; } = sortValueName;
|
||||||
|
}
|
||||||
@ -0,0 +1,393 @@
|
|||||||
|
using System.Buffers;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public static unsafe partial class PixelHelper
|
||||||
|
{
|
||||||
|
public static partial void SortByRed<T>(Span<T> colors) where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
fixed (T* ptr = colors)
|
||||||
|
{
|
||||||
|
T* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (T* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).R]++;
|
||||||
|
|
||||||
|
T[] bucketsArray = ArrayPool<T>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<T> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (T* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).R]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<T>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static partial void SortByGreen<T>(Span<T> colors) where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
fixed (T* ptr = colors)
|
||||||
|
{
|
||||||
|
T* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (T* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).G]++;
|
||||||
|
|
||||||
|
T[] bucketsArray = ArrayPool<T>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<T> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (T* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).G]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<T>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static partial void SortByBlue<T>(Span<T> colors) where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
fixed (T* ptr = colors)
|
||||||
|
{
|
||||||
|
T* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (T* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).B]++;
|
||||||
|
|
||||||
|
T[] bucketsArray = ArrayPool<T>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<T> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (T* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).B]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<T>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static partial void SortByAlpha<T>(Span<T> colors) where T : unmanaged, IColor
|
||||||
|
{
|
||||||
|
fixed (T* ptr = colors)
|
||||||
|
{
|
||||||
|
T* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (T* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).A]++;
|
||||||
|
|
||||||
|
T[] bucketsArray = ArrayPool<T>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<T> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (T* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).A]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<T>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static partial void SortB1(Span<Generic3ByteData> colors)
|
||||||
|
{
|
||||||
|
fixed (Generic3ByteData* ptr = colors)
|
||||||
|
{
|
||||||
|
Generic3ByteData* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (Generic3ByteData* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).B1]++;
|
||||||
|
|
||||||
|
Generic3ByteData[] bucketsArray = ArrayPool<Generic3ByteData>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<Generic3ByteData> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Generic3ByteData* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).B1]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Generic3ByteData>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static partial void SortB2(Span<Generic3ByteData> colors)
|
||||||
|
{
|
||||||
|
fixed (Generic3ByteData* ptr = colors)
|
||||||
|
{
|
||||||
|
Generic3ByteData* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (Generic3ByteData* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).B2]++;
|
||||||
|
|
||||||
|
Generic3ByteData[] bucketsArray = ArrayPool<Generic3ByteData>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<Generic3ByteData> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Generic3ByteData* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).B2]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Generic3ByteData>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static partial void SortB3(Span<Generic3ByteData> colors)
|
||||||
|
{
|
||||||
|
fixed (Generic3ByteData* ptr = colors)
|
||||||
|
{
|
||||||
|
Generic3ByteData* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (Generic3ByteData* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).B3]++;
|
||||||
|
|
||||||
|
Generic3ByteData[] bucketsArray = ArrayPool<Generic3ByteData>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<Generic3ByteData> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Generic3ByteData* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).B3]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Generic3ByteData>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static partial void SortB1(Span<Generic4ByteData> colors)
|
||||||
|
{
|
||||||
|
fixed (Generic4ByteData* ptr = colors)
|
||||||
|
{
|
||||||
|
Generic4ByteData* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (Generic4ByteData* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).B1]++;
|
||||||
|
|
||||||
|
Generic4ByteData[] bucketsArray = ArrayPool<Generic4ByteData>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<Generic4ByteData> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Generic4ByteData* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).B1]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Generic4ByteData>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static partial void SortB2(Span<Generic4ByteData> colors)
|
||||||
|
{
|
||||||
|
fixed (Generic4ByteData* ptr = colors)
|
||||||
|
{
|
||||||
|
Generic4ByteData* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (Generic4ByteData* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).B2]++;
|
||||||
|
|
||||||
|
Generic4ByteData[] bucketsArray = ArrayPool<Generic4ByteData>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<Generic4ByteData> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Generic4ByteData* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).B2]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Generic4ByteData>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static partial void SortB3(Span<Generic4ByteData> colors)
|
||||||
|
{
|
||||||
|
fixed (Generic4ByteData* ptr = colors)
|
||||||
|
{
|
||||||
|
Generic4ByteData* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (Generic4ByteData* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).B3]++;
|
||||||
|
|
||||||
|
Generic4ByteData[] bucketsArray = ArrayPool<Generic4ByteData>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<Generic4ByteData> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Generic4ByteData* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).B3]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Generic4ByteData>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static partial void SortB4(Span<Generic4ByteData> colors)
|
||||||
|
{
|
||||||
|
fixed (Generic4ByteData* ptr = colors)
|
||||||
|
{
|
||||||
|
Generic4ByteData* end = ptr + colors.Length;
|
||||||
|
|
||||||
|
Span<int> histogram = stackalloc int[256];
|
||||||
|
histogram.Clear();
|
||||||
|
for (Generic4ByteData* color = ptr; color < end; color++)
|
||||||
|
histogram[(*color).B4]++;
|
||||||
|
|
||||||
|
Generic4ByteData[] bucketsArray = ArrayPool<Generic4ByteData>.Shared.Rent(colors.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Span<Generic4ByteData> buckets = bucketsArray.AsSpan()[..colors.Length];
|
||||||
|
Span<int> currentBucketIndex = stackalloc int[256];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0; i < histogram.Length; i++)
|
||||||
|
{
|
||||||
|
currentBucketIndex[i] = offset;
|
||||||
|
offset += histogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Generic4ByteData* color = ptr; color < end; color++)
|
||||||
|
buckets[currentBucketIndex[(*color).B4]++] = (*color);
|
||||||
|
|
||||||
|
buckets.CopyTo(colors);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Generic4ByteData>.Shared.Return(bucketsArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color in 32 bit ABGR-format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorABGR"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="a">The Alpha-component of the color.</param>
|
||||||
|
/// <param name="b">The Blue-component of the color.</param>
|
||||||
|
/// <param name="g">The Green-component of the color.</param>
|
||||||
|
/// <param name="r">The Red-component of the color.</param>
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct ColorABGR(byte a, byte b, byte g, byte r) : IColor
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColorFormat ColorFormat => IColorFormat.ABGR;
|
||||||
|
|
||||||
|
private readonly byte _a = a;
|
||||||
|
private readonly byte _b = b;
|
||||||
|
private readonly byte _g = g;
|
||||||
|
private readonly byte _r = r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte R => _r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte G => _g;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte B => _b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColor Create(byte r, byte g, byte b, byte a) => new ColorABGR(a, b, g, r);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color in 32 bit ARGB-format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorARGB"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="a">The Alpha-component of the color.</param>
|
||||||
|
/// <param name="r">The Red-component of the color.</param>
|
||||||
|
/// <param name="g">The Green-component of the color.</param>
|
||||||
|
/// <param name="b">The Blue-component of the color.</param>
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct ColorARGB(byte a, byte r, byte g, byte b) : IColor
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColorFormat ColorFormat => IColorFormat.ARGB;
|
||||||
|
|
||||||
|
private readonly byte _a = a;
|
||||||
|
private readonly byte _r = r;
|
||||||
|
private readonly byte _g = g;
|
||||||
|
private readonly byte _b = b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte R => _r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte G => _g;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte B => _b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColor Create(byte r, byte g, byte b, byte a) => new ColorARGB(a, r, g, b);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color in 24 bit BGR-format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorBGR"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="b">The Blue-component of the color.</param>
|
||||||
|
/// <param name="g">The Green-component of the color.</param>
|
||||||
|
/// <param name="r">The Red-component of the color.</param>
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct ColorBGR(byte b, byte g, byte r): IColor
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColorFormat ColorFormat => IColorFormat.BGR;
|
||||||
|
|
||||||
|
private readonly byte _b = b;
|
||||||
|
private readonly byte _g = g;
|
||||||
|
private readonly byte _r = r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte R => _r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte G => _g;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte B => _b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte A => byte.MaxValue;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColor Create(byte r, byte g, byte b, byte a) => new ColorBGR(b, g, r);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color in 32 bit BGRA-format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorBGRA"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="b">The Blue-component of the color.</param>
|
||||||
|
/// <param name="g">The Green-component of the color.</param>
|
||||||
|
/// <param name="r">The Red-component of the color.</param>
|
||||||
|
/// <param name="a">The Alpha-component of the color.</param>
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct ColorBGRA(byte b, byte g, byte r, byte a) : IColor
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColorFormat ColorFormat => IColorFormat.BGRA;
|
||||||
|
|
||||||
|
private readonly byte _b = b;
|
||||||
|
private readonly byte _g = g;
|
||||||
|
private readonly byte _r = r;
|
||||||
|
private readonly byte _a = a;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte R => _r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte G => _g;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte B => _b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColor Create(byte r, byte g, byte b, byte a) => new ColorBGRA(b, g, r, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatABGR
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor IColorFormat.Average(ReadOnlySpan<byte> data) => PixelHelper.Average(MemoryMarshal.Cast<byte, ColorABGR>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatABGR
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorABGR, MinMaxABGR>(MemoryMarshal.Cast<byte, ColorABGR>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatABGR
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor[] IColorFormat.CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize)
|
||||||
|
{
|
||||||
|
ColorABGR[] colors = PixelHelper.CreateColorPalette<ColorABGR>(MemoryMarshal.Cast<byte, ColorABGR>(data), paletteSize);
|
||||||
|
|
||||||
|
IColor[] result = new IColor[colors.Length];
|
||||||
|
for(int i = 0; i < colors.Length; i++)
|
||||||
|
result[i] = colors[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatABGR
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorABGR, SumABGR>(MemoryMarshal.Cast<byte, ColorABGR>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatABGR : IColorFormat
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public static ColorFormatABGR Instance { get; } = new();
|
||||||
|
|
||||||
|
public int BytesPerPixel => 4;
|
||||||
|
|
||||||
|
public string Name => "ABGR";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
private ColorFormatABGR() {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatARGB
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor IColorFormat.Average(ReadOnlySpan<byte> data) => PixelHelper.Average(MemoryMarshal.Cast<byte, ColorARGB>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatARGB
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorARGB, MinMaxARGB>(MemoryMarshal.Cast<byte, ColorARGB>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatARGB
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor[] IColorFormat.CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize)
|
||||||
|
{
|
||||||
|
ColorARGB[] colors = PixelHelper.CreateColorPalette<ColorARGB>(MemoryMarshal.Cast<byte, ColorARGB>(data), paletteSize);
|
||||||
|
|
||||||
|
IColor[] result = new IColor[colors.Length];
|
||||||
|
for(int i = 0; i < colors.Length; i++)
|
||||||
|
result[i] = colors[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatARGB
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorARGB, SumARGB>(MemoryMarshal.Cast<byte, ColorARGB>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatARGB : IColorFormat
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public static ColorFormatARGB Instance { get; } = new();
|
||||||
|
|
||||||
|
public int BytesPerPixel => 4;
|
||||||
|
|
||||||
|
public string Name => "ARGB";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
private ColorFormatARGB() {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGR
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor IColorFormat.Average(ReadOnlySpan<byte> data) => PixelHelper.Average(MemoryMarshal.Cast<byte, ColorBGR>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGR
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorBGR, MinMaxBGR>(MemoryMarshal.Cast<byte, ColorBGR>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGR
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor[] IColorFormat.CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize)
|
||||||
|
{
|
||||||
|
ColorBGR[] colors = PixelHelper.CreateColorPalette<ColorBGR>(MemoryMarshal.Cast<byte, ColorBGR>(data), paletteSize);
|
||||||
|
|
||||||
|
IColor[] result = new IColor[colors.Length];
|
||||||
|
for(int i = 0; i < colors.Length; i++)
|
||||||
|
result[i] = colors[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGR
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorBGR, SumBGR>(MemoryMarshal.Cast<byte, ColorBGR>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGR : IColorFormat
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public static ColorFormatBGR Instance { get; } = new();
|
||||||
|
|
||||||
|
public int BytesPerPixel => 3;
|
||||||
|
|
||||||
|
public string Name => "BGR";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
private ColorFormatBGR() {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGRA
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor IColorFormat.Average(ReadOnlySpan<byte> data) => PixelHelper.Average(MemoryMarshal.Cast<byte, ColorBGRA>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGRA
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorBGRA, MinMaxBGRA>(MemoryMarshal.Cast<byte, ColorBGRA>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGRA
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor[] IColorFormat.CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize)
|
||||||
|
{
|
||||||
|
ColorBGRA[] colors = PixelHelper.CreateColorPalette<ColorBGRA>(MemoryMarshal.Cast<byte, ColorBGRA>(data), paletteSize);
|
||||||
|
|
||||||
|
IColor[] result = new IColor[colors.Length];
|
||||||
|
for(int i = 0; i < colors.Length; i++)
|
||||||
|
result[i] = colors[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGRA
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorBGRA, SumBGRA>(MemoryMarshal.Cast<byte, ColorBGRA>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatBGRA : IColorFormat
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public static ColorFormatBGRA Instance { get; } = new();
|
||||||
|
|
||||||
|
public int BytesPerPixel => 4;
|
||||||
|
|
||||||
|
public string Name => "BGRA";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
private ColorFormatBGRA() {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGB
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor IColorFormat.Average(ReadOnlySpan<byte> data) => PixelHelper.Average(MemoryMarshal.Cast<byte, ColorRGB>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGB
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorRGB, MinMaxRGB>(MemoryMarshal.Cast<byte, ColorRGB>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGB
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor[] IColorFormat.CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize)
|
||||||
|
{
|
||||||
|
ColorRGB[] colors = PixelHelper.CreateColorPalette<ColorRGB>(MemoryMarshal.Cast<byte, ColorRGB>(data), paletteSize);
|
||||||
|
|
||||||
|
IColor[] result = new IColor[colors.Length];
|
||||||
|
for(int i = 0; i < colors.Length; i++)
|
||||||
|
result[i] = colors[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGB
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorRGB, SumRGB>(MemoryMarshal.Cast<byte, ColorRGB>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGB : IColorFormat
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public static ColorFormatRGB Instance { get; } = new();
|
||||||
|
|
||||||
|
public int BytesPerPixel => 3;
|
||||||
|
|
||||||
|
public string Name => "RGB";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
private ColorFormatRGB() {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGBA
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor IColorFormat.Average(ReadOnlySpan<byte> data) => PixelHelper.Average(MemoryMarshal.Cast<byte, ColorRGBA>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGBA
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorRGBA, MinMaxRGBA>(MemoryMarshal.Cast<byte, ColorRGBA>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGBA
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe IColor[] IColorFormat.CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize)
|
||||||
|
{
|
||||||
|
ColorRGBA[] colors = PixelHelper.CreateColorPalette<ColorRGBA>(MemoryMarshal.Cast<byte, ColorRGBA>(data), paletteSize);
|
||||||
|
|
||||||
|
IColor[] result = new IColor[colors.Length];
|
||||||
|
for(int i = 0; i < colors.Length; i++)
|
||||||
|
result[i] = colors[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGBA
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorRGBA, SumRGBA>(MemoryMarshal.Cast<byte, ColorRGBA>(data));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public sealed partial class ColorFormatRGBA : IColorFormat
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public static ColorFormatRGBA Instance { get; } = new();
|
||||||
|
|
||||||
|
public int BytesPerPixel => 4;
|
||||||
|
|
||||||
|
public string Name => "RGBA";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
private ColorFormatRGBA() {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Struct)]
|
||||||
|
internal class ColorGeneratorAttribute : Attribute;
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color in 24 bit RGB-format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorRGB"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="r">The Red-component of the color.</param>
|
||||||
|
/// <param name="g">The Green-component of the color.</param>
|
||||||
|
/// <param name="b">The Blue-component of the color.</param>
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct ColorRGB(byte r, byte g, byte b): IColor
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColorFormat ColorFormat => IColorFormat.RGB;
|
||||||
|
|
||||||
|
private readonly byte _r = r;
|
||||||
|
private readonly byte _g = g;
|
||||||
|
private readonly byte _b = b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte R => _r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte G => _g;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte B => _b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte A => byte.MaxValue;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColor Create(byte r, byte g, byte b, byte a) => new ColorRGB(r, g, b);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color in 32 bit RGBA-format.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Initializes a new instance of the <see cref="ColorRGBA"/> class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="r">The Red-component of the color.</param>
|
||||||
|
/// <param name="g">The Green-component of the color.</param>
|
||||||
|
/// <param name="b">The Blue-component of the color.</param>
|
||||||
|
/// <param name="a">The Alpha-component of the color.</param>
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct ColorRGBA(byte r, byte g, byte b, byte a) : IColor
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColorFormat ColorFormat => IColorFormat.RGBA;
|
||||||
|
|
||||||
|
private readonly byte _r = r;
|
||||||
|
private readonly byte _g = g;
|
||||||
|
private readonly byte _b = b;
|
||||||
|
private readonly byte _a = a;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte R => _r;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte G => _g;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte B => _b;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public static IColor Create(byte r, byte g, byte b, byte a) => new ColorRGBA(r, g, b, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
internal IColor Average(ReadOnlySpan<byte> data);
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
#region Instances
|
||||||
|
|
||||||
|
public static ColorFormatRGB RGB => ColorFormatRGB.Instance;
|
||||||
|
public static ColorFormatBGR BGR => ColorFormatBGR.Instance;
|
||||||
|
public static ColorFormatARGB ARGB => ColorFormatARGB.Instance;
|
||||||
|
public static ColorFormatABGR ABGR => ColorFormatABGR.Instance;
|
||||||
|
public static ColorFormatRGBA RGBA => ColorFormatRGBA.Instance;
|
||||||
|
public static ColorFormatBGRA BGRA => ColorFormatBGRA.Instance;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
internal IMinMax MinMax(ReadOnlySpan<byte> data);
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
internal IColor[] CreateColorPalette(ReadOnlySpan<byte> data, int paletteSize);
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
public partial interface IColorFormat
|
||||||
|
{
|
||||||
|
internal ISum Sum(ReadOnlySpan<byte> data);
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct MinMaxABGR(byte aMin, byte aMax, byte bMin, byte bMax, byte gMin, byte gMax, byte rMin, byte rMax) : IMinMax
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly byte _aMin = aMin;
|
||||||
|
private readonly byte _aMax = aMax;
|
||||||
|
|
||||||
|
private readonly byte _bMin = bMin;
|
||||||
|
private readonly byte _bMax = bMax;
|
||||||
|
|
||||||
|
private readonly byte _gMin = gMin;
|
||||||
|
private readonly byte _gMax = gMax;
|
||||||
|
|
||||||
|
private readonly byte _rMin = rMin;
|
||||||
|
private readonly byte _rMax = rMax;
|
||||||
|
|
||||||
|
public byte RedMin => _rMin;
|
||||||
|
public byte RedMax => _rMax;
|
||||||
|
|
||||||
|
public byte GreenMin => _gMin;
|
||||||
|
public byte GreenMax => _gMax;
|
||||||
|
|
||||||
|
public byte BlueMin => _bMin;
|
||||||
|
public byte BlueMax => _bMax;
|
||||||
|
|
||||||
|
public byte AlphaMin => _aMin;
|
||||||
|
public byte AlphaMax => _aMax;
|
||||||
|
|
||||||
|
public byte RedRange => (byte)(_rMax - _rMin);
|
||||||
|
public byte GreenRange => (byte)(_gMax - _gMin);
|
||||||
|
public byte BlueRange => (byte)(_bMax - _bMin);
|
||||||
|
public byte AlphaRange => (byte)(_aMax - _aMin);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct MinMaxARGB(byte aMin, byte aMax, byte rMin, byte rMax, byte gMin, byte gMax, byte bMin, byte bMax) : IMinMax
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly byte _aMin = aMin;
|
||||||
|
private readonly byte _aMax = aMax;
|
||||||
|
|
||||||
|
private readonly byte _rMin = rMin;
|
||||||
|
private readonly byte _rMax = rMax;
|
||||||
|
|
||||||
|
private readonly byte _gMin = gMin;
|
||||||
|
private readonly byte _gMax = gMax;
|
||||||
|
|
||||||
|
private readonly byte _bMin = bMin;
|
||||||
|
private readonly byte _bMax = bMax;
|
||||||
|
|
||||||
|
public byte RedMin => _rMin;
|
||||||
|
public byte RedMax => _rMax;
|
||||||
|
|
||||||
|
public byte GreenMin => _gMin;
|
||||||
|
public byte GreenMax => _gMax;
|
||||||
|
|
||||||
|
public byte BlueMin => _bMin;
|
||||||
|
public byte BlueMax => _bMax;
|
||||||
|
|
||||||
|
public byte AlphaMin => _aMin;
|
||||||
|
public byte AlphaMax => _aMax;
|
||||||
|
|
||||||
|
public byte RedRange => (byte)(_rMax - _rMin);
|
||||||
|
public byte GreenRange => (byte)(_gMax - _gMin);
|
||||||
|
public byte BlueRange => (byte)(_bMax - _bMin);
|
||||||
|
public byte AlphaRange => (byte)(_aMax - _aMin);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct MinMaxBGR(byte bMin, byte bMax, byte gMin, byte gMax, byte rMin, byte rMax) : IMinMax
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly byte _bMin = bMin;
|
||||||
|
private readonly byte _bMax = bMax;
|
||||||
|
|
||||||
|
private readonly byte _gMin = gMin;
|
||||||
|
private readonly byte _gMax = gMax;
|
||||||
|
|
||||||
|
private readonly byte _rMin = rMin;
|
||||||
|
private readonly byte _rMax = rMax;
|
||||||
|
|
||||||
|
public byte RedMin => _rMin;
|
||||||
|
public byte RedMax => _rMax;
|
||||||
|
|
||||||
|
public byte GreenMin => _gMin;
|
||||||
|
public byte GreenMax => _gMax;
|
||||||
|
|
||||||
|
public byte BlueMin => _bMin;
|
||||||
|
public byte BlueMax => _bMax;
|
||||||
|
|
||||||
|
public byte AlphaMin => byte.MaxValue;
|
||||||
|
public byte AlphaMax => byte.MaxValue;
|
||||||
|
|
||||||
|
public byte RedRange => (byte)(_rMax - _rMin);
|
||||||
|
public byte GreenRange => (byte)(_gMax - _gMin);
|
||||||
|
public byte BlueRange => (byte)(_bMax - _bMin);
|
||||||
|
public byte AlphaRange => 0;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct MinMaxBGRA(byte bMin, byte bMax, byte gMin, byte gMax, byte rMin, byte rMax, byte aMin, byte aMax) : IMinMax
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly byte _bMin = bMin;
|
||||||
|
private readonly byte _bMax = bMax;
|
||||||
|
|
||||||
|
private readonly byte _gMin = gMin;
|
||||||
|
private readonly byte _gMax = gMax;
|
||||||
|
|
||||||
|
private readonly byte _rMin = rMin;
|
||||||
|
private readonly byte _rMax = rMax;
|
||||||
|
|
||||||
|
private readonly byte _aMin = aMin;
|
||||||
|
private readonly byte _aMax = aMax;
|
||||||
|
|
||||||
|
public byte RedMin => _rMin;
|
||||||
|
public byte RedMax => _rMax;
|
||||||
|
|
||||||
|
public byte GreenMin => _gMin;
|
||||||
|
public byte GreenMax => _gMax;
|
||||||
|
|
||||||
|
public byte BlueMin => _bMin;
|
||||||
|
public byte BlueMax => _bMax;
|
||||||
|
|
||||||
|
public byte AlphaMin => _aMin;
|
||||||
|
public byte AlphaMax => _aMax;
|
||||||
|
|
||||||
|
public byte RedRange => (byte)(_rMax - _rMin);
|
||||||
|
public byte GreenRange => (byte)(_gMax - _gMin);
|
||||||
|
public byte BlueRange => (byte)(_bMax - _bMin);
|
||||||
|
public byte AlphaRange => (byte)(_aMax - _aMin);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct MinMaxRGB(byte rMin, byte rMax, byte gMin, byte gMax, byte bMin, byte bMax) : IMinMax
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly byte _rMin = rMin;
|
||||||
|
private readonly byte _rMax = rMax;
|
||||||
|
|
||||||
|
private readonly byte _gMin = gMin;
|
||||||
|
private readonly byte _gMax = gMax;
|
||||||
|
|
||||||
|
private readonly byte _bMin = bMin;
|
||||||
|
private readonly byte _bMax = bMax;
|
||||||
|
|
||||||
|
public byte RedMin => _rMin;
|
||||||
|
public byte RedMax => _rMax;
|
||||||
|
|
||||||
|
public byte GreenMin => _gMin;
|
||||||
|
public byte GreenMax => _gMax;
|
||||||
|
|
||||||
|
public byte BlueMin => _bMin;
|
||||||
|
public byte BlueMax => _bMax;
|
||||||
|
|
||||||
|
public byte AlphaMin => byte.MaxValue;
|
||||||
|
public byte AlphaMax => byte.MaxValue;
|
||||||
|
|
||||||
|
public byte RedRange => (byte)(_rMax - _rMin);
|
||||||
|
public byte GreenRange => (byte)(_gMax - _gMin);
|
||||||
|
public byte BlueRange => (byte)(_bMax - _bMin);
|
||||||
|
public byte AlphaRange => 0;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct MinMaxRGBA(byte rMin, byte rMax, byte gMin, byte gMax, byte bMin, byte bMax, byte aMin, byte aMax) : IMinMax
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly byte _rMin = rMin;
|
||||||
|
private readonly byte _rMax = rMax;
|
||||||
|
|
||||||
|
private readonly byte _gMin = gMin;
|
||||||
|
private readonly byte _gMax = gMax;
|
||||||
|
|
||||||
|
private readonly byte _bMin = bMin;
|
||||||
|
private readonly byte _bMax = bMax;
|
||||||
|
|
||||||
|
private readonly byte _aMin = aMin;
|
||||||
|
private readonly byte _aMax = aMax;
|
||||||
|
|
||||||
|
public byte RedMin => _rMin;
|
||||||
|
public byte RedMax => _rMax;
|
||||||
|
|
||||||
|
public byte GreenMin => _gMin;
|
||||||
|
public byte GreenMax => _gMax;
|
||||||
|
|
||||||
|
public byte BlueMin => _bMin;
|
||||||
|
public byte BlueMax => _bMax;
|
||||||
|
|
||||||
|
public byte AlphaMin => _aMin;
|
||||||
|
public byte AlphaMax => _aMax;
|
||||||
|
|
||||||
|
public byte RedRange => (byte)(_rMax - _rMin);
|
||||||
|
public byte GreenRange => (byte)(_gMax - _gMin);
|
||||||
|
public byte BlueRange => (byte)(_bMax - _bMin);
|
||||||
|
public byte AlphaRange => (byte)(_aMax - _aMin);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {AlphaMin}-{AlphaMax}, R: {RedMin}-{RedMax}, G: {GreenMin}-{GreenMax}, B: {BlueMin}-{BlueMax}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct SumABGR(long a, long b, long g, long r) : ISum
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly long _a = a;
|
||||||
|
private readonly long _b = b;
|
||||||
|
private readonly long _g = g;
|
||||||
|
private readonly long _r = r;
|
||||||
|
|
||||||
|
public long R => _r;
|
||||||
|
public long G => _g;
|
||||||
|
public long B => _b;
|
||||||
|
public long A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct SumARGB(long a, long r, long g, long b) : ISum
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly long _a = a;
|
||||||
|
private readonly long _r = r;
|
||||||
|
private readonly long _g = g;
|
||||||
|
private readonly long _b = b;
|
||||||
|
|
||||||
|
public long R => _r;
|
||||||
|
public long G => _g;
|
||||||
|
public long B => _b;
|
||||||
|
public long A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct SumBGR(long b, long g, long r, long a) : ISum
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly long _b = b;
|
||||||
|
private readonly long _g = g;
|
||||||
|
private readonly long _r = r;
|
||||||
|
private readonly long _a = a;
|
||||||
|
|
||||||
|
public long A => _a;
|
||||||
|
public long R => _r;
|
||||||
|
public long G => _g;
|
||||||
|
public long B => _b;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct SumBGRA(long b, long g, long r, long a) : ISum
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly long _b = b;
|
||||||
|
private readonly long _g = g;
|
||||||
|
private readonly long _r = r;
|
||||||
|
private readonly long _a = a;
|
||||||
|
|
||||||
|
public long R => _r;
|
||||||
|
public long G => _g;
|
||||||
|
public long B => _b;
|
||||||
|
public long A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct SumRGB(long r, long g, long b, long a) : ISum
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly long _r = r;
|
||||||
|
private readonly long _g = g;
|
||||||
|
private readonly long _b = b;
|
||||||
|
private readonly long _a = a;
|
||||||
|
|
||||||
|
public long A => _a;
|
||||||
|
public long R => _r;
|
||||||
|
public long G => _g;
|
||||||
|
public long B => _b;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
// ReSharper disable ConvertToAutoProperty
|
||||||
|
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||||
|
// ReSharper disable ReplaceWithPrimaryConstructorParameter
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace HPPH;
|
||||||
|
|
||||||
|
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct SumRGBA(long r, long g, long b, long a) : ISum
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
private readonly long _r = r;
|
||||||
|
private readonly long _g = g;
|
||||||
|
private readonly long _b = b;
|
||||||
|
private readonly long _a = a;
|
||||||
|
|
||||||
|
public long R => _r;
|
||||||
|
public long G => _g;
|
||||||
|
public long B => _b;
|
||||||
|
public long A => _a;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"[A: {A}, R: {R}, G: {G}, B: {B}]";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
20
HPPH/HPPH.csproj
Normal file
20
HPPH/HPPH.csproj
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
|
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HPPH.Generators\HPPH.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user