Native Code Interoperability #
Total Points: 8
Starting code #
- RayTracing/
- RayTracingDemo/
- RayTracingInterop.sln
- Windowing/
1. Overview #
In this assignment, you will implement a high-performance communication layer between a native C++ ray tracing engine and a managed C# application. You are provided with the core mathematics and physics code for “Ray Tracing in One Weekend” (including a progressive renderer in camera.h) and a pre-built Avalonia-based Windowing library (Windowing).
Your goal is to build the RayTracing library (containing both native C++ code and C# bindings) and the RayTracingDemo console application to drive the rendering process and visualize the results in real-time.
2. Requirements #
Part 1: The Native Export Layer (C++) [2 Points] #
File: RayTracing/native/export.cpp
You must create a C-compatible ABI to expose the provided C++ core classes and utilities.
- Opaque Handles: Create functions to instantiate (
CreateScene,CreateMaterial, etc.) and return pointers to these objects. Do not expose C++ class layouts directly to C#. - Memory Management: Implement corresponding
Destroy...functions for every creator function. - Render Function: Implement
RenderScenethat:- Accepts a
CameraConfigstruct (passed by value) containing all camera parameters. - Instantiates a local
cameraobject and populates it with the config data. - Calls the camera’s built-in
rendermethod, passing the scene world, the output buffer pointer, and the callback.
- Accepts a
- Callback Specification:
- The render function must accept a function pointer with the signature:
typedef void (*RenderCallback)(int samples, uint8_t* buffer); - Pass this callback to the camera’s render method.
- The render function must accept a function pointer with the signature:
- Image Output: Provide a
SavePngfunction that utilizes the includedstb_image_writelibrary to save the RGBA buffer to a file.
Part 2: Low-Level Bindings (C#) [2 Points] #
File: RayTracing/NativeMethods.cs
Bind the exported C functions to .NET.
- P/Invoke: Preferably use the
[LibraryImport]source generator. - SafeHandles: Use
SafeHandlefor all native resources requiring cleanup.- Implement
SceneSafeHandleandMaterialSafeHandle. - The runtime must automatically invoke the C++
Destroyfunctions via these handles.
- Implement
- Delegates: Define the
RenderCallbackdelegate matching the C++ signature. - String Marshalling: Ensure the
SavePngbinding correctly handles string marshalling for the filename.
Part 3: High-Level Safe API (C#) [2 Points] #
File: RayTracing/*.cs
Create an idiomatic C# object-oriented wrapper that ensures memory and type safety.
- Safety: The public API must never expose
IntPtr/nintor pointers to the consumer. - Resource Ownership: Implement the
IDisposablepattern to manage the lifetime of the native handles.
Part 4: Demo & Integration [2 Points] #
File: RayTracingDemo/Program.cs
Implement the main demo application using your library and the provided Windowing library.
- Scene Setup: Procedurally generate the iconic scene from the cover of the first book (Ray Tracing in One Weekend).
- Visual Integration: Use
Windowing.Viewer.Showto spawn the window and start the render loop. - Live Feedback:
- Update the window’s status text with the rendering progress (samples/time).
- Update the window’s image buffer in real-time using the data provided in the callback.
- Output: Once rendering is finished, use your
SavePngmethod to save the final image asoutput.png.
3. Build #
The project uses CMake integrated with MSBuild. Building the C# solution will automatically trigger the C++ build.
dotnet build -c Release
dotnet run -c Release --project RayTracingDemo/RayTracingDemo.csproj