Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions OpenXRGen/Evergine.Bindings.OpenXR/Generated/Structs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public unsafe partial struct XrApiLayerCreateInfo
public uint structVersion;
public UIntPtr structSize;
public void* loaderInstance;
public byte settings_file_location;
public fixed byte settings_file_location[512];
public XrApiLayerNextInfo* nextInfo;
}

Expand Down Expand Up @@ -5602,7 +5602,8 @@ public unsafe partial struct XrEyeGazesFB
{
public XrStructureType type;
public void* next;
public XrEyeGazeFB gaze;
public XrEyeGazeFB gaze_0;
public XrEyeGazeFB gaze_1;
public long time;
}

Expand Down Expand Up @@ -8823,7 +8824,7 @@ public unsafe partial struct XrFrustumf
[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct XrUuid
{
public byte data;
public fixed byte data[(int)OpenXRNative.XR_UUID_SIZE];
}

[StructLayout(LayoutKind.Sequential)]
Expand Down
2 changes: 1 addition & 1 deletion OpenXRGen/OpenXRGen/ConstantDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static ConstantDefinition FromXML(XElement elem)
return constant;
}

public static object NormalizeValue(string value)
public static string NormalizeValue(string value)
{
return value.Replace("ULL", "UL");
}
Expand Down
60 changes: 60 additions & 0 deletions OpenXRGen/OpenXRGen/Helpers.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -268,5 +269,64 @@ public static bool IsIntPtr(string type)
return false;
}
}

/// <summary>
/// Attempts to parse a raw C #define value string (e.g. "(512)", "0x10", "-1u") into an integer.
/// Returns false for complex expressions that cannot be reduced to a single integer.
/// </summary>
public static bool TryParseDefineIntValue(string rawValue, out int value)
{
value = 0;
if (string.IsNullOrWhiteSpace(rawValue))
{
return false;
}

string trimmed = rawValue.Trim();

// Strip a single layer of outer parentheses, e.g. "(512)" → "512".
// The trimmed.Length > 2 guard ensures this terminates.
while (trimmed.Length > 2 && trimmed.StartsWith("(") && trimmed.EndsWith(")"))
{
trimmed = trimmed.Substring(1, trimmed.Length - 2).Trim();
}

// Reject complex expressions: anything with whitespace, arithmetic operators, or parentheses.
// A leading '-' is handled separately as a sign for negative numbers.
string checkString = trimmed.StartsWith("-") ? trimmed.Substring(1) : trimmed;
if (checkString.Contains(" ") || checkString.Contains("(") || checkString.Contains(")") ||
checkString.Contains("*") || checkString.Contains("+") || checkString.Contains("-") ||
checkString.Contains("/"))
{
return false;
}

bool negative = trimmed.StartsWith("-");
if (negative)
{
trimmed = trimmed.Substring(1);
}

string normalized = trimmed.TrimEnd('u', 'U', 'l', 'L');

if (normalized.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
if (!int.TryParse(normalized.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out value))
{
return false;
}
}
else if (!int.TryParse(normalized, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
{
return false;
}

if (negative)
{
value = -value;
}

return true;
}
}
}
26 changes: 26 additions & 0 deletions OpenXRGen/OpenXRGen/OpenXRSpecification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;

Expand All @@ -22,6 +23,7 @@ public class OpenXRSpecification
public List<FeatureDefinition> Features = new List<FeatureDefinition>();
public Dictionary<string, string> BaseTypes = new Dictionary<string, string>();
public Dictionary<string, string> Alias = new Dictionary<string, string>();
public Dictionary<string, string> Defines = new Dictionary<string, string>();
public List<ExtensionDefinition> Extensions = new List<ExtensionDefinition>();

public static OpenXRSpecification FromFile(string xmlFile)
Expand Down Expand Up @@ -61,6 +63,30 @@ public static OpenXRSpecification FromFile(string xmlFile)

var types = registry.Elements("types");

// #define values are tracked for struct array sizing, not emitted as generated C# constants.
var defineTypes = types.Elements("type").Where(t => t.Attribute("category")?.Value == "define");
foreach (var defineType in defineTypes)
{
var name = defineType.Element("name")?.Value;
if (string.IsNullOrEmpty(name) || spec.Defines.ContainsKey(name))
{
continue;
}

// XElement.Value is like "#define XR_FOO 123" (without XML tags).
var valueMatch = Regex.Match(defineType.Value, $@"#define\s+{Regex.Escape(name)}\s+(?<value>.+)");
if (!valueMatch.Success)
{
continue;
}

var value = valueMatch.Groups["value"].Value.Trim();
if (!string.IsNullOrEmpty(value))
{
spec.Defines[name] = value;
}
}

// FuncPointers
var funcPointers = types.Elements("type").Where(f => f.Attribute("category")?.Value == "funcpointer");
foreach (var func in funcPointers)
Expand Down
74 changes: 63 additions & 11 deletions OpenXRGen/OpenXRGen/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,54 @@ namespace OpenXRGen
{
class Program
{
/// <summary>
/// Attempts to resolve a constant name to an integer array count by searching API Constants,
/// enum values, and #define entries in order.
/// </summary>
private static bool TryResolveArrayCount(
string constantName,
OpenXRVersion openXRVersion,
OpenXRSpecification openXRSpec,
out int count)
{
// Try API Constants first
var apiConstant = openXRVersion.Constants.FirstOrDefault(c => c.Name == constantName);
if (apiConstant != null)
{
if (apiConstant.Value == null)
{
var alias = openXRVersion.Constants.FirstOrDefault(c => c.Name == apiConstant.Alias);
count = int.Parse(alias.Value);
}
else
{
count = int.Parse(apiConstant.Value);
}

return true;
}

// Try enum values
var enumValue = openXRVersion.Enums
.SelectMany(e => e.Values)
.FirstOrDefault(v => v.Name == constantName);
if (enumValue != null)
{
count = enumValue.Value;
return true;
}

// Try #define values
if (openXRSpec.Defines.TryGetValue(constantName, out var defineValueRaw) &&
Helpers.TryParseDefineIntValue(defineValueRaw, out count))
{
return true;
}

count = 0;
return false;
}

static void Main(string[] args)
{
string vkFile = Path.Combine("..", "..", "..", "..", "..", "KhronosRegistry", "xr.xml");
Expand Down Expand Up @@ -164,24 +212,28 @@ static void Main(string[] args)
}
else if (member.ConstantValue != null)
{
var validConstant = openXRVersion.Constants.FirstOrDefault(c => c.Name == member.ConstantValue);
var apiConstant = openXRVersion.Constants.FirstOrDefault(c => c.Name == member.ConstantValue);

if (Helpers.SupportFixed(csType))
{
file.WriteLine($"\t\tpublic fixed {csType} {Helpers.ValidatedName(member.Name)}[(int)OpenXRNative.{validConstant.Name}];");
}
else
{
int count = 0;

if (validConstant.Value == null)
if (apiConstant != null)
{
var alias = openXRVersion.Constants.FirstOrDefault(c => c.Name == validConstant.Alias);
count = int.Parse(alias.Value);
file.WriteLine($"\t\tpublic fixed {csType} {Helpers.ValidatedName(member.Name)}[(int)OpenXRNative.{apiConstant.Name}];");
}
else if (TryResolveArrayCount(member.ConstantValue, openXRVersion, openXRSpec, out int count))
{
file.WriteLine($"\t\tpublic fixed {csType} {Helpers.ValidatedName(member.Name)}[{count}];");
}
else
{
count = int.Parse(validConstant.Value);
throw new InvalidOperationException($"Cannot resolve array size constant '{member.ConstantValue}' for member '{member.Name}' in struct '{structure.Name}'.");
}
}
else
{
if (!TryResolveArrayCount(member.ConstantValue, openXRVersion, openXRSpec, out int count))
{
throw new InvalidOperationException($"Cannot resolve array size constant '{member.ConstantValue}' for member '{member.Name}' in struct '{structure.Name}'.");
}

for (int i = 0; i < count; i++)
Expand Down
28 changes: 19 additions & 9 deletions OpenXRGen/OpenXRGen/StructureDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,29 @@ public static Member FromXML(XElement elem)

if (m.ConstantValue == null)
{
Match match = Regex.Match(m.Value, $@"{m.Name}\[(\d+)\](\[(\d+)\])?");
if (match.Captures.Count > 0)
Match match = Regex.Match(m.Value, $@"{Regex.Escape(m.Name)}\[(?<count1>[^\]]+)\](\[(?<count2>[^\]]+)\])?");
if (match.Success)
{
if (match.Groups[2].Value != string.Empty)
string count1 = match.Groups["count1"].Value;
string count2 = match.Groups["count2"].Value;

bool firstIsNumeric = int.TryParse(count1, out int value1);
bool secondIsPresent = !string.IsNullOrEmpty(count2);
int value2 = 0;
bool secondIsNumeric = secondIsPresent && int.TryParse(count2, out value2);

if (firstIsNumeric && !secondIsPresent)
{
m.ElementCount = value1;
}
else if (firstIsNumeric && secondIsNumeric)
{
string valueString1 = match.Groups[1].Value;
string valueString2 = match.Groups[3].Value;
m.ElementCount = int.Parse(valueString1) * int.Parse(valueString2);
m.ElementCount = value1 * value2;
}
else
else if (!secondIsPresent)
{
string valueString = match.Groups[1].Value;
m.ElementCount = int.Parse(valueString);
// Handles array declarations using symbolic constants in member text.
m.ConstantValue = count1;
}
}
}
Expand Down