Skip to content

Commit ab400d3

Browse files
committed
Update bindings to r3d v0.9.1
- Regenerated bindings: GenMeshCylinder simplified, GenMeshCylinderEx added, shader alias functions, ShaderCustom opaque type, EnvDoF.NearScale field - Generator: support typedef aliases for opaque struct types, skip unused System.Text import for opaque types - TypeMapper: recursive opaque type detection through typedef chains - Examples: spawn child process per example to avoid rlgl state leakage between sequential runs (see #1)
1 parent e7cb43e commit ab400d3

18 files changed

Lines changed: 194 additions & 39 deletions

‎Examples/Decal.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static int Main()
2020
// Create meshes
2121
var plane = R3D.GenMeshPlane(5.0f, 5.0f, 1, 1);
2222
var sphere = R3D.GenMeshSphere(0.5f, 64, 64);
23-
var cylinder = R3D.GenMeshCylinder(0.5f, 0.5f, 1, 64);
23+
var cylinder = R3D.GenMeshCylinder(0.5f, 1, 64);
2424
var material = R3D.GetDefaultMaterial();
2525
material.Albedo.Color = Color.Gray;
2626

‎Examples/Program.cs‎

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Diagnostics;
3+
using System.Linq;
24
using Raylib_cs;
35

46
namespace Examples;
@@ -52,22 +54,24 @@ private static unsafe void Main(string[] args)
5254
{
5355
Raylib.SetTraceLogCallback(&Logging.LogConsole);
5456

55-
if (args.Length > 0)
57+
var examples = args.Length > 0
58+
? args.Select(ExampleList.GetExample).Where(e => e != null).ToArray()
59+
: ExampleList.AllExamples;
60+
61+
if (examples.Length <= 1)
5662
{
57-
var example = ExampleList.GetExample(args[0]);
58-
example?.Main.Invoke();
63+
examples.FirstOrDefault()?.Main.Invoke();
64+
return;
5965
}
60-
else
61-
RunExamples(ExampleList.AllExamples);
62-
}
6366

64-
private static void RunExamples(ExampleInfo[] examples)
65-
{
66-
var configFlags = Enum.GetValues<ConfigFlags>();
67+
var exe = Environment.ProcessPath!;
6768
foreach (var example in examples)
6869
{
69-
example.Main.Invoke();
70-
foreach (var flag in configFlags) Raylib.ClearWindowState(flag);
70+
var process = Process.Start(new ProcessStartInfo(exe, example.Name)
71+
{
72+
UseShellExecute = false
73+
})!;
74+
process.WaitForExit();
7175
}
7276
}
7377
}

‎R3D-cs.GenerateBindings/CodeGenerator.cs‎

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,16 +224,19 @@ private int GenerateStructsFiles(CppCompilation compilation)
224224
if (@class.ClassKind is not (CppClassKind.Struct or CppClassKind.Union))
225225
throw new Exception($"Unexpected class kind: {@class.ClassKind}");
226226

227+
bool isOpaque = TypeMapper.OpaqueTypes.Contains(@class.Name);
228+
227229
var sb = new StringBuilder();
228-
GenerateHeader(sb, ["System", "System.Numerics", "System.Runtime.InteropServices", "System.Text", "Raylib_cs"]);
230+
var usings = isOpaque
231+
? new List<string> { "System", "System.Numerics", "System.Runtime.InteropServices", "Raylib_cs" }
232+
: new List<string> { "System", "System.Numerics", "System.Runtime.InteropServices", "System.Text", "Raylib_cs" };
233+
GenerateHeader(sb, usings);
229234

230235
string className = StripR3DPrefix(@class.Name);
231236
bool needsUnsafe = @class.Fields.Select(f => MapType(f.Type)).Any(r => r.isUnsafe);
232237

233238
CommentGenerator.Generate(sb, @class.Comment, @class.Name);
234239

235-
bool isOpaque = TypeMapper.OpaqueTypes.Contains(@class.Name);
236-
237240
sb.AppendLine("[StructLayout(LayoutKind.Sequential)]");
238241
sb.Append($"public {(needsUnsafe ? "unsafe " : "")}struct {className}");
239242
sb.AppendLine();
@@ -434,6 +437,25 @@ private int GenerateMiscFiles(CppCompilation compilation)
434437
continue;
435438
}
436439

440+
// Typedef aliases for opaque struct types (e.g., typedef struct R3D_ShaderCustom R3D_ScreenShader)
441+
if (typedef.ElementType is CppClass aliasedClass && TypeMapper.OpaqueTypes.Contains(aliasedClass.Name))
442+
{
443+
var sb = new StringBuilder();
444+
GenerateHeader(sb, ["System", "System.Numerics", "System.Runtime.InteropServices", "Raylib_cs"]);
445+
446+
CommentGenerator.Generate(sb, typedef.Comment, typedef.Name);
447+
448+
sb.AppendLine("[StructLayout(LayoutKind.Sequential)]");
449+
sb.AppendLine($"public struct {name}");
450+
sb.AppendLine("{");
451+
sb.AppendLine(" private nint _handle;");
452+
sb.AppendLine("}");
453+
454+
File.WriteAllText(Path.Combine(outputDir, "types", $"{name}.g.cs"), sb.ToString());
455+
count++;
456+
continue;
457+
}
458+
437459
// Check for macro-based enums
438460
bool isBitflag = name.EndsWith("Flags");
439461
string enumName = isBitflag ? name[..^5] : name;

‎R3D-cs.GenerateBindings/TypeMapper.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ private static bool IsOpaqueType(CppType type)
9595
return unwrapped switch
9696
{
9797
CppClass cls => OpaqueTypes.Contains(cls.Name),
98-
CppTypedef td => OpaqueTypes.Contains(td.Name),
98+
CppTypedef td => OpaqueTypes.Contains(td.Name) || IsOpaqueType(td.ElementType),
9999
_ => false
100100
};
101101
}

‎R3D-cs/interop/R3D.core.g.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static unsafe partial class R3D
2424
/// </summary>
2525
public const string NativeLibName = "r3d";
2626

27-
public const string R3D_VERSION = "0.9.0";
27+
public const string R3D_VERSION = "0.9.1";
2828

2929
/// <summary>
3030
/// Initializes the rendering engine.

‎R3D-cs/interop/R3D.mesh.g.cs‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,32 @@ public static unsafe partial class R3D
171171
/// <summary>
172172
/// Generate a cylinder mesh.
173173
/// </summary>
174-
/// <param name="bottomRadius">Bottom radius.</param>
175-
/// <param name="topRadius">Top radius.</param>
174+
/// <param name="radius">Radius of the cylinder.</param>
176175
/// <param name="height">Height along Y axis.</param>
177176
/// <param name="slices">Radial subdivisions.</param>
178177
/// <returns>Mesh ready for rendering.</returns>
179178
/// <remarks>
180179
/// Native: <c>R3D_GenMeshCylinder</c>
181180
/// </remarks>
182181
[LibraryImport(NativeLibName, EntryPoint = "R3D_GenMeshCylinder")]
183-
public static partial Mesh GenMeshCylinder(float bottomRadius, float topRadius, float height, int slices);
182+
public static partial Mesh GenMeshCylinder(float radius, float height, int slices);
183+
184+
/// <summary>
185+
/// Generate a cylinder, cone or truncated cone mesh.
186+
/// </summary>
187+
/// <param name="bottomRadius">Bottom radius.</param>
188+
/// <param name="topRadius">Top radius.</param>
189+
/// <param name="height">Height along Y axis.</param>
190+
/// <param name="slices">Radial subdivisions.</param>
191+
/// <param name="stacks">Vertical subdivisions.</param>
192+
/// <param name="bottomCap">Generate bottom cap.</param>
193+
/// <param name="topCap">Generate top cap.</param>
194+
/// <returns>Mesh ready for rendering.</returns>
195+
/// <remarks>
196+
/// Native: <c>R3D_GenMeshCylinderEx</c>
197+
/// </remarks>
198+
[LibraryImport(NativeLibName, EntryPoint = "R3D_GenMeshCylinderEx")]
199+
public static partial Mesh GenMeshCylinderEx(float bottomRadius, float topRadius, float height, int slices, int stacks, [MarshalAs(UnmanagedType.I1)] bool bottomCap, [MarshalAs(UnmanagedType.I1)] bool topCap);
184200

185201
/// <summary>
186202
/// Generate a capsule mesh.

‎R3D-cs/interop/R3D.mesh_data.g.cs‎

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,26 @@ public static unsafe partial class R3D
1818
{
1919

2020
/// <summary>
21-
/// Creates an empty mesh data container.
21+
/// Allocates a mesh data container with the given capacity.
2222
/// <para>
23-
/// Allocates memory for vertex and index buffers. All allocated buffers are zero-initialized.
23+
/// This function allocates CPU-side buffers for vertices and indices, but does NOT initialize the mesh with any actual data. The returned R3D_MeshData has:
24+
/// </para>
25+
/// <para>
26+
/// <list type="bullet">
27+
/// <item><description>vertexCapacity and indexCapacity set to the requested sizes</description></item>
28+
/// <item><description>vertexCount and indexCount set to 0</description></item>
29+
/// </list>
30+
/// </para>
31+
/// <para>
32+
/// You must manually set vertexCount/indexCount after filling the buffers, or use helper functions like R3D_AppendMeshData() to populate the mesh.
33+
/// </para>
34+
/// <para>
35+
/// All allocated memory is zero-initialized.
2436
/// </para>
2537
/// </summary>
26-
/// <param name="vertexCount">Number of vertices to allocate. Must be non-zero.</param>
27-
/// <param name="indexCount">Number of indices to allocate. May be zero. If zero, no index buffer is allocated.</param>
28-
/// <returns>A new R3D_MeshData instance with allocated memory.</returns>
38+
/// <param name="vertexCount">Number of vertices to allocate (capacity). Must be &gt; 0.</param>
39+
/// <param name="indexCount">Number of indices to allocate (capacity). May be 0. If 0, no index buffer is allocated.</param>
40+
/// <returns>A new R3D_MeshData with allocated buffers and zero element counts.</returns>
2941
/// <remarks>
3042
/// Native: <c>R3D_LoadMeshData</c>
3143
/// </remarks>
@@ -195,21 +207,40 @@ public static unsafe partial class R3D
195207
public static partial MeshData GenMeshDataHemiSphere(float radius, int rings, int slices);
196208

197209
/// <summary>
198-
/// Generate a cylinder mesh with specified parameters.
210+
/// Generates a cylinder mesh centered at the origin along the Y axis.
199211
/// <para>
200-
/// Creates a mesh centered at the origin, extending along the Y axis. The mesh includes top and bottom caps and smooth side surfaces. A cone is produced when bottomRadius and topRadius differ.
212+
/// Both caps are included. For a cone or truncated cone, use R3D_GenMeshDataCylinderEx.
201213
/// </para>
202214
/// </summary>
203-
/// <param name="bottomRadius">Radius of the bottom cap.</param>
204-
/// <param name="topRadius">Radius of the top cap.</param>
205-
/// <param name="height">Height of the shape along the Y axis.</param>
206-
/// <param name="slices">Number of radial subdivisions around the shape.</param>
207-
/// <returns>Generated mesh structure.</returns>
215+
/// <param name="radius">Radius of the cylinder. Must be &gt; 0.</param>
216+
/// <param name="height">Total height along the Y axis. Must be &gt; 0.</param>
217+
/// <param name="slices">Radial subdivisions around the circumference. Must be &gt;= 3.</param>
218+
/// <returns>The generated mesh data, or an empty mesh on invalid input.</returns>
208219
/// <remarks>
209220
/// Native: <c>R3D_GenMeshDataCylinder</c>
210221
/// </remarks>
211222
[LibraryImport(NativeLibName, EntryPoint = "R3D_GenMeshDataCylinder")]
212-
public static partial MeshData GenMeshDataCylinder(float bottomRadius, float topRadius, float height, int slices);
223+
public static partial MeshData GenMeshDataCylinder(float radius, float height, int slices);
224+
225+
/// <summary>
226+
/// Generates a cylinder, cone, or truncated cone mesh centered at the origin along the Y axis.
227+
/// <para>
228+
/// The bottom cap sits at Y = -height/2 and the top cap at Y = +height/2. Setting one radius to 0 produces a cone; caps can be toggled independently.
229+
/// </para>
230+
/// </summary>
231+
/// <param name="bottomRadius">Radius of the bottom end. Must be &gt;= 0. Cannot both be 0.</param>
232+
/// <param name="topRadius">Radius of the top end. Must be &gt;= 0. Cannot both be 0.</param>
233+
/// <param name="height">Total height along the Y axis. Must be &gt; 0.</param>
234+
/// <param name="slices">Radial subdivisions around the circumference. Must be &gt;= 3.</param>
235+
/// <param name="stacks">Vertical subdivisions along the height. Must be &gt;= 1. Higher values reduce faceting, especially on cones.</param>
236+
/// <param name="bottomCap">Whether to generate the bottom cap.</param>
237+
/// <param name="topCap">Whether to generate the top cap.</param>
238+
/// <returns>The generated mesh data, or an empty mesh on invalid input.</returns>
239+
/// <remarks>
240+
/// Native: <c>R3D_GenMeshDataCylinderEx</c>
241+
/// </remarks>
242+
[LibraryImport(NativeLibName, EntryPoint = "R3D_GenMeshDataCylinderEx")]
243+
public static partial MeshData GenMeshDataCylinderEx(float bottomRadius, float topRadius, float height, int slices, int stacks, [MarshalAs(UnmanagedType.I1)] bool bottomCap, [MarshalAs(UnmanagedType.I1)] bool topCap);
213244

214245
/// <summary>
215246
/// Generate a capsule mesh with specified parameters.

‎R3D-cs/interop/R3D.screen_shader.g.cs‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,29 @@ public static unsafe partial class R3D
4545
[LibraryImport(NativeLibName, EntryPoint = "R3D_LoadScreenShaderFromMemory", StringMarshalling = StringMarshalling.Utf8)]
4646
public static partial ScreenShader LoadScreenShaderFromMemory(string code);
4747

48+
/// <summary>
49+
/// Creates an alias of an existing screen shader.
50+
/// <para>
51+
/// The alias shares the same compiled program as the original but holds its own independent uniform and sampler state. Typical use cases include pre-configuring aliases for distinct effects (e.g. different convolution kernels), or running the same shader multiple times in a post-process chain with different parameters at each pass.
52+
/// </para>
53+
/// <para>
54+
/// Uniform and sampler state is copied from the original at the moment this function is called, not from the shader source defaults. Any values set on the original after compilation but before this call will be reflected in the alias; values set afterward will not.
55+
/// </para>
56+
/// </summary>
57+
/// <param name="shader">The original screen shader to alias.</param>
58+
/// <returns>Pointer to the alias, or NULL on failure.</returns>
59+
/// <remarks>
60+
/// The alias does not own the program. Always unload all aliases before unloading the original, or the alias program references become dangling.
61+
/// Native: <c>R3D_LoadScreenShaderAlias</c>
62+
/// </remarks>
63+
[LibraryImport(NativeLibName, EntryPoint = "R3D_LoadScreenShaderAlias")]
64+
public static partial ScreenShader LoadScreenShaderAlias(ScreenShader shader);
65+
4866
/// <summary>
4967
/// Unloads and destroys a screen shader.
68+
/// <para>
69+
/// If the shader owns its program shaders (i.e. it was created withR3D_LoadScreenShader orR3D_LoadScreenShaderFromMemory), they are deleted. Aliases created from this shader viaR3D_LoadScreenShaderAlias must be unloaded beforehand, as they share the same programs and will be left with dangling references.
70+
/// </para>
5071
/// </summary>
5172
/// <param name="shader">Screen shader to unload.</param>
5273
/// <remarks>

‎R3D-cs/interop/R3D.sky_shader.g.cs‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,29 @@ public static unsafe partial class R3D
4545
[LibraryImport(NativeLibName, EntryPoint = "R3D_LoadSkyShaderFromMemory", StringMarshalling = StringMarshalling.Utf8)]
4646
public static partial SkyShader LoadSkyShaderFromMemory(string code);
4747

48+
/// <summary>
49+
/// Creates an alias of an existing sky shader.
50+
/// <para>
51+
/// The alias shares the same compiled program as the original but holds its own independent uniform and sampler state. A typical use case is to pre-configure several aliases with different uniforms or textures, avoiding the need to reconfigure the shader on every skybox switch.
52+
/// </para>
53+
/// <para>
54+
/// Uniform and sampler state is copied from the original at the moment this function is called, not from the shader source defaults. Any values set on the original after compilation but before this call will be reflected in the alias; values set afterward will not.
55+
/// </para>
56+
/// </summary>
57+
/// <param name="shader">The original sky shader to alias.</param>
58+
/// <returns>Pointer to the alias, or NULL on failure.</returns>
59+
/// <remarks>
60+
/// The alias does not own the program. Always unload all aliases before unloading the original, or the alias program references become dangling.
61+
/// Native: <c>R3D_LoadSkyShaderAlias</c>
62+
/// </remarks>
63+
[LibraryImport(NativeLibName, EntryPoint = "R3D_LoadSkyShaderAlias")]
64+
public static partial SkyShader LoadSkyShaderAlias(SkyShader shader);
65+
4866
/// <summary>
4967
/// Unloads and destroys a sky shader.
68+
/// <para>
69+
/// If the shader owns its program shaders (i.e. it was created withR3D_LoadSkyShader orR3D_LoadSkyShaderFromMemory), they are deleted. Aliases created from this shader viaR3D_LoadSkyShaderAlias must be unloaded beforehand, as they share the same programs and will be left with dangling references.
70+
/// </para>
5071
/// </summary>
5172
/// <param name="shader">Sky shader to unload.</param>
5273
/// <remarks>

0 commit comments

Comments
 (0)