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)"
|