tools/generate-swizzles.ps1 writes the checked-in src/CultMath/Swizzles.g.cs as partial structs plus a partial math: for float2/3/4, int2/3/4 and bool2/3/4 every swizzle of length 2-4 including repeats, in xyzw and rgba naming, with setters only on non-repeating masks, plus single-component r/g/b/a. double2/3 get lengths 2-3 (there is no double4). Every HLSL mixed constructor (float4(float2, float2), float4(float, float2, float), copy forms, ...) exists as a struct constructor and, for float/int/bool, a math function. The hand-written swizzles and mixed constructors it supersedes are deleted. Matrices store private rows and return ref float2/float3 from the row indexer ([UnscopedRef], polyfilled for netstandard2.1), so m[1][2] = s compiles as in HLSL; _mRC are get/set properties over the rows. Equality and hashing stay value-based. Intrinsics follow HLSL: sign returns int/intN and yields 0 for NaN; step is x >= y ? 1 : 0 so NaN yields 0; any/all accept float and int vectors; min/max/abs on int vectors return int vectors, and abs(int) returns int. Strips the UTF-8 BOMs this branch added to math.cs, CultMath.csproj and HlslSemanticsTests.cs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
132 lines
5.3 KiB
PowerShell
132 lines
5.3 KiB
PowerShell
param(
|
|
[string]$OutputPath = ""
|
|
)
|
|
|
|
# Writes src\CultMath\Swizzles.g.cs: HLSL swizzles and mixed constructors for
|
|
# CultMath's vector types. The output is checked in; rerun after changing the
|
|
# family table below and commit both files together.
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
if (-not $OutputPath) {
|
|
$OutputPath = Join-Path $PSScriptRoot "..\src\CultMath\Swizzles.g.cs"
|
|
}
|
|
|
|
# Functions: emit math.<type>(...) constructor functions. double has none because
|
|
# a math.double3 method group would hide the double3 type name under
|
|
# `using static CultMath.math;` and HLSL shader code does not construct doubles.
|
|
$families = @(
|
|
@{ Scalar = "float"; Sizes = @(2, 3, 4); Functions = $true },
|
|
@{ Scalar = "int"; Sizes = @(2, 3, 4); Functions = $true },
|
|
@{ Scalar = "bool"; Sizes = @(2, 3, 4); Functions = $true },
|
|
@{ Scalar = "double"; Sizes = @(2, 3); Functions = $false }
|
|
)
|
|
$componentFields = @("x", "y", "z", "w")
|
|
$namings = @(@("x", "y", "z", "w"), @("r", "g", "b", "a"))
|
|
|
|
function Get-Compositions([int]$total) {
|
|
# Ordered part sizes summing to $total, excluding the all-scalar form that the
|
|
# hand-written base constructor already owns.
|
|
$results = [System.Collections.Generic.List[object]]::new()
|
|
function Expand([int]$remaining, [int[]]$prefix) {
|
|
if ($remaining -eq 0) {
|
|
if (@($prefix | Where-Object { $_ -ne 1 }).Count -gt 0) {
|
|
$results.Add($prefix)
|
|
}
|
|
return
|
|
}
|
|
for ($part = 1; $part -le $remaining; $part++) {
|
|
Expand ($remaining - $part) ($prefix + $part)
|
|
}
|
|
}
|
|
Expand $total @()
|
|
return , $results
|
|
}
|
|
|
|
$builder = [System.Text.StringBuilder]::new()
|
|
function Line([string]$text = "") { [void]$builder.Append($text).Append("`n") }
|
|
|
|
Line "// <auto-generated>"
|
|
Line "// Generated by tools/generate-swizzles.ps1. Do not edit by hand."
|
|
Line "// </auto-generated>"
|
|
Line ""
|
|
Line "namespace CultMath;"
|
|
|
|
$functionLines = [System.Collections.Generic.List[string]]::new()
|
|
|
|
foreach ($family in $families) {
|
|
$scalar = $family.Scalar
|
|
$maxSize = ($family.Sizes | Measure-Object -Maximum).Maximum
|
|
foreach ($size in $family.Sizes) {
|
|
$type = "$scalar$size"
|
|
Line ""
|
|
Line "public partial struct $type"
|
|
Line "{"
|
|
|
|
foreach ($composition in (Get-Compositions $size)) {
|
|
$parameters = @()
|
|
$arguments = @()
|
|
$offset = 0
|
|
foreach ($part in $composition) {
|
|
$name = -join $componentFields[$offset..($offset + $part - 1)]
|
|
if ($part -eq 1) {
|
|
$parameters += "$scalar $name"
|
|
$arguments += $name
|
|
} else {
|
|
$parameters += "$scalar$part $name"
|
|
for ($i = 0; $i -lt $part; $i++) { $arguments += "$name.$($componentFields[$i])" }
|
|
}
|
|
$offset += $part
|
|
}
|
|
$parameterList = $parameters -join ", "
|
|
Line " public $type($parameterList) : this($($arguments -join ', ')) { }"
|
|
if ($family.Functions) {
|
|
$names = @($parameters | ForEach-Object { ($_ -split " ")[1] })
|
|
$functionLines.Add(" public static $type $type($parameterList) => new($($names -join ', '));")
|
|
}
|
|
}
|
|
|
|
# Single-component color aliases; x/y/z/w are the fields themselves.
|
|
$letters = $namings[1]
|
|
for ($i = 0; $i -lt $size; $i++) {
|
|
Line " public $scalar $($letters[$i]) { readonly get => $($componentFields[$i]); set => $($componentFields[$i]) = value; }"
|
|
}
|
|
|
|
foreach ($letters in $namings) {
|
|
for ($length = 2; $length -le $maxSize; $length++) {
|
|
$count = [math]::Pow($size, $length)
|
|
for ($index = 0; $index -lt $count; $index++) {
|
|
[int[]]$digits = @()
|
|
[int]$remainder = $index
|
|
for ($d = 0; $d -lt $length; $d++) {
|
|
$digits = @([int]($remainder % $size)) + $digits
|
|
$remainder = [int][math]::Floor($remainder / $size)
|
|
}
|
|
$name = -join ($digits | ForEach-Object { $letters[$_] })
|
|
$getter = ($digits | ForEach-Object { $componentFields[$_] }) -join ", "
|
|
$resultType = "$scalar$length"
|
|
$unique = @($digits | Select-Object -Unique).Count -eq $length
|
|
if ($unique) {
|
|
$assignments = for ($d = 0; $d -lt $length; $d++) { "$($componentFields[$digits[$d]]) = value.$($componentFields[$d]);" }
|
|
Line " public $resultType $name { readonly get => new($getter); set { $($assignments -join ' ') } }"
|
|
} else {
|
|
Line " public readonly $resultType $name => new($getter);"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Line "}"
|
|
}
|
|
}
|
|
|
|
Line ""
|
|
Line "public static partial class math"
|
|
Line "{"
|
|
foreach ($functionLine in $functionLines) { Line $functionLine }
|
|
Line "}"
|
|
|
|
$fullPath = [System.IO.Path]::GetFullPath($OutputPath)
|
|
$content = $builder.ToString() -replace "`n", "`r`n"
|
|
[System.IO.File]::WriteAllText($fullPath, $content, [System.Text.UTF8Encoding]::new($false))
|
|
Write-Host "Wrote $fullPath ($((Get-Item -LiteralPath $fullPath).Length) bytes)"
|