220 lines
9.6 KiB
C#
220 lines
9.6 KiB
C#
//-----------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------
|
|
// file="UniformOverloadEmitter"
|
|
// Project: StgSharp
|
|
// Copyright (c) Nitload.
|
|
// SPDX-License-Identifier: MIT
|
|
// -----------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
#pragma warning disable CA1305
|
|
|
|
namespace GenerateGL.CodeGen
|
|
{
|
|
internal static partial class UniformOverloadEmitter
|
|
{
|
|
|
|
public static bool IsValueCommand(
|
|
GlCommand command
|
|
)
|
|
{
|
|
return ValueCommandRegex().IsMatch(command.Name);
|
|
}
|
|
|
|
public static bool IsSetterCommand(
|
|
GlCommand command
|
|
)
|
|
{
|
|
return IsValueCommand(command) || MatrixCommandRegex().IsMatch(command.Name);
|
|
}
|
|
|
|
public static void Write(
|
|
string outputRoot,
|
|
string version,
|
|
IReadOnlyList<GlCommand> commands
|
|
)
|
|
{
|
|
List<GlCommand> valueCommands = commands.Where(IsValueCommand)
|
|
.OrderBy(c => c.Name, StringComparer.Ordinal)
|
|
.ToList();
|
|
List<GlCommand> matrixConvenienceCommands = commands
|
|
.Where(c => Matrix4FloatCommandRegex().IsMatch(c.Name))
|
|
.OrderBy(c => c.Name, StringComparer.Ordinal)
|
|
.ToList();
|
|
|
|
if (valueCommands.Count == 0 && matrixConvenienceCommands.Count == 0) {
|
|
return;
|
|
}
|
|
|
|
StringBuilder sb = new();
|
|
sb.AppendLine("// <auto-generated>");
|
|
sb.AppendLine($"// Generated by StgSharp.GenerateGL on {DateTime.UtcNow.ToString("u", CultureInfo.InvariantCulture)}");
|
|
sb.AppendLine($"// Uniform overloads introduced in OpenGL {version}");
|
|
sb.AppendLine("// </auto-generated>");
|
|
sb.AppendLine("using System;");
|
|
sb.AppendLine("using System.Runtime.CompilerServices;");
|
|
sb.AppendLine("using StgSharp.Mathematics.Graphics;");
|
|
sb.AppendLine();
|
|
sb.AppendLine("namespace StgSharp.Graphics.OpenGL");
|
|
sb.AppendLine("{");
|
|
sb.AppendLine(" public unsafe partial class OpenGLFunction");
|
|
sb.AppendLine(" {");
|
|
|
|
foreach (GlCommand command in valueCommands) {
|
|
EmitValueOverload(sb, command);
|
|
}
|
|
foreach (GlCommand command in valueCommands.Where(IsFloatVectorCommand)) {
|
|
EmitVectorConvenienceOverload(sb, command);
|
|
}
|
|
foreach (GlCommand command in matrixConvenienceCommands) {
|
|
EmitMatrixConvenienceOverload(sb, command);
|
|
}
|
|
|
|
sb.AppendLine(" }");
|
|
sb.AppendLine("}");
|
|
|
|
string fileName = Path.Combine(
|
|
outputRoot,
|
|
$"OpenGLFunction.Uniform.v{version.Replace('.', '_')}.g.cs");
|
|
File.WriteAllText(fileName, sb.ToString(), Encoding.UTF8);
|
|
}
|
|
|
|
private static void EmitValueOverload(
|
|
StringBuilder sb,
|
|
GlCommand command
|
|
)
|
|
{
|
|
Match match = ValueCommandRegex().Match(command.Name);
|
|
bool hasProgram = match.Groups[1].Success;
|
|
int dimension = int.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture);
|
|
string scalarType = MapScalarType(match.Groups[3].Value);
|
|
bool isVector = match.Groups[4].Success;
|
|
string uniformType = $"Uniform<{string.Join(", ", Enumerable.Repeat(scalarType, dimension))}>";
|
|
|
|
sb.AppendLine(" [MethodImpl(MethodImplOptions.AggressiveInlining)]");
|
|
if (isVector)
|
|
{
|
|
string programParameter = hasProgram ? "GlHandle program, " : string.Empty;
|
|
sb.AppendLine($" public void SetUniformValue({programParameter}{uniformType} uniform, ReadOnlySpan<{scalarType}> values)");
|
|
sb.AppendLine(" {");
|
|
sb.AppendLine(" ArgumentNullException.ThrowIfNull(uniform);");
|
|
if (dimension > 1)
|
|
{
|
|
sb.AppendLine($" if ((values.Length % {dimension}) != 0) {{");
|
|
sb.AppendLine($" throw new ArgumentException(\"Uniform data length must be divisible by {dimension}.\", nameof(values));");
|
|
sb.AppendLine(" }");
|
|
}
|
|
sb.AppendLine($" fixed ({scalarType}* valuesPtr = values) {{");
|
|
string count = dimension == 1 ? "values.Length" : $"values.Length / {dimension}";
|
|
sb.AppendLine($" Context.{command.Name}({BuildPrefixArguments(hasProgram)}{count}, valuesPtr);");
|
|
sb.AppendLine(" }");
|
|
sb.AppendLine(" }");
|
|
} else
|
|
{
|
|
string programParameter = hasProgram ? "GlHandle program, " : string.Empty;
|
|
string values = string.Join(", ", Enumerable.Range(0, dimension)
|
|
.Select(i => $"{scalarType} v{i}"));
|
|
string valueArguments = string.Join(", ", Enumerable.Range(0, dimension)
|
|
.Select(i => $"v{i}"));
|
|
sb.AppendLine($" public void SetUniformValue({programParameter}{uniformType} uniform, {values})");
|
|
sb.AppendLine(" {");
|
|
sb.AppendLine(" ArgumentNullException.ThrowIfNull(uniform);");
|
|
sb.AppendLine($" Context.{command.Name}({BuildPrefixArguments(hasProgram)}{valueArguments});");
|
|
sb.AppendLine(" }");
|
|
}
|
|
sb.AppendLine();
|
|
}
|
|
|
|
private static void EmitVectorConvenienceOverload(
|
|
StringBuilder sb,
|
|
GlCommand command
|
|
)
|
|
{
|
|
Match match = ValueCommandRegex().Match(command.Name);
|
|
bool hasProgram = match.Groups[1].Success;
|
|
int dimension = int.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture);
|
|
if (dimension < 2) {
|
|
return;
|
|
}
|
|
|
|
string vectorType = $"Vec{dimension}";
|
|
string programParameter = hasProgram ? "GlHandle program, " : string.Empty;
|
|
sb.AppendLine(" [MethodImpl(MethodImplOptions.AggressiveInlining)]");
|
|
sb.AppendLine($" public void SetUniformValue({programParameter}Uniform<{vectorType}> uniform, {vectorType} value)");
|
|
sb.AppendLine(" {");
|
|
sb.AppendLine(" ArgumentNullException.ThrowIfNull(uniform);");
|
|
sb.AppendLine($" Context.{command.Name}({BuildPrefixArguments(hasProgram)}1, (float*)&value);");
|
|
sb.AppendLine(" }");
|
|
sb.AppendLine();
|
|
}
|
|
|
|
private static void EmitMatrixConvenienceOverload(
|
|
StringBuilder sb,
|
|
GlCommand command
|
|
)
|
|
{
|
|
bool hasProgram = command.Name.StartsWith("glProgram", StringComparison.Ordinal);
|
|
string programParameter = hasProgram ? "GlHandle program, " : string.Empty;
|
|
sb.AppendLine(" [MethodImpl(MethodImplOptions.AggressiveInlining)]");
|
|
sb.AppendLine($" public void SetUniformValue({programParameter}Uniform<GraphicsMatrix> uniform, GraphicsMatrix value, bool transpose = false)");
|
|
sb.AppendLine(" {");
|
|
sb.AppendLine(" ArgumentNullException.ThrowIfNull(uniform);");
|
|
sb.AppendLine($" Context.{command.Name}({BuildPrefixArguments(hasProgram)}1, transpose ? (byte)1 : (byte)0, (float*)&value);");
|
|
sb.AppendLine(" }");
|
|
sb.AppendLine();
|
|
}
|
|
|
|
private static string BuildPrefixArguments(
|
|
bool hasProgram
|
|
)
|
|
{
|
|
return hasProgram
|
|
? "program.Value, uniform.id.SignedValue, "
|
|
: "uniform.id.SignedValue, ";
|
|
}
|
|
|
|
private static bool IsFloatVectorCommand(
|
|
GlCommand command
|
|
)
|
|
{
|
|
Match match = ValueCommandRegex().Match(command.Name);
|
|
return match.Success && match.Groups[3].Value == "f" && match.Groups[4].Success;
|
|
}
|
|
|
|
private static string MapScalarType(
|
|
string suffix
|
|
)
|
|
{
|
|
return suffix switch
|
|
{
|
|
"f" => "float",
|
|
"d" => "double",
|
|
"i" => "int",
|
|
"ui" => "uint",
|
|
_ => throw new InvalidOperationException($"Unsupported uniform suffix: {suffix}")
|
|
};
|
|
}
|
|
|
|
[GeneratedRegex("^gl(Program)?Uniform([1-4])(ui|[fdi])(v)?$",
|
|
RegexOptions.CultureInvariant)]
|
|
private static partial Regex ValueCommandRegex();
|
|
|
|
[GeneratedRegex("^gl(?:Program)?UniformMatrix4fv$", RegexOptions.CultureInvariant)]
|
|
private static partial Regex Matrix4FloatCommandRegex();
|
|
|
|
[GeneratedRegex("^gl(?:Program)?UniformMatrix[234](?:x[234])?[fd]v$",
|
|
RegexOptions.CultureInvariant)]
|
|
private static partial Regex MatrixCommandRegex();
|
|
|
|
}
|
|
}
|
|
|
|
#pragma warning restore CA1305
|