const std = @import("std"); const mem = std.mem; fn getImports(headers: []const []const u8) type { return @cImport({ @cDefine("DILIGENT_C_API", "1"); @cDefine("PLATFORM_LINUX", "1"); @cInclude("vulkan/vulkan_core.h"); for (headers) |header| { @cInclude(header); } }); } fn generateCImport(writer: anytype, headers: []const []const u8) !void { try writer.writeAll( \\usingnamespace @cImport({ \\ @cDefine("DILIGENT_C_API", "1"); \\ @cDefine("PLATFORM_LINUX", "1"); \\ @cInclude("vulkan/vulkan_core.h"); ); for (headers) |header| { try writer.print("\n @cInclude(\"{}\");", .{header}); } try writer.writeAll("\n});\n"); } var buffer = [_]u8{0} ** 1024; fn formatTypename(comptime Type: type) ![]const u8 { const len = mem.replacementSize(u8, @typeName(Type), ".cimport:5:12.struct_", ""); if (len > buffer.len) return error.TypenameTooLong; _ = mem.replace(u8, @typeName(Type), ".cimport:5:12.struct_", "", buffer[0..]); return buffer[0..len]; } fn generateWrapper(comptime StructType: type, name: []const u8, writer: anytype) !void { comptime const VtblType = for (@typeInfo(StructType).Struct.fields) |field| { if (mem.eql(u8, field.name, "pVtbl")) { break @typeInfo(field.field_type); } } else { return error.NoVtbl; }; try writer.print( \\ \\pub const {0}_Wrapper = struct {{ \\ ptr: *{1}, \\ \\ pub fn wrap(ptr: [*c]{1}) @This() {{ \\ return .{{ .ptr = ptr }}; \\ }} \\ , .{ name, @typeName(StructType) }); inline for (@typeInfo(VtblType.Pointer.child).Struct.fields) |interface_field| { comptime const InterfaceType = @typeInfo(interface_field.field_type); inline for (InterfaceType.Struct.fields) |fp| { const FnType = @typeInfo(fp.field_type).Optional.child; const fn_id = @typeInfo(FnType).Fn; if (fn_id.is_var_args) return error.VarArgsUnsupported; try writer.print(" pub fn {}(self: @This()", .{fp.name}); var i: u8 = 'a'; inline for (fn_id.args[1..]) |arg| { const arg_type = arg.arg_type.?; try writer.print(", {c}: {}", .{ i, formatTypename(arg.arg_type.?) }); i += 1; } const return_type = formatTypename(fn_id.return_type orelse void); try writer.print(") {} {{", .{return_type}); const self_type = formatTypename(fn_id.args[0].arg_type.?); try writer.print( \\ \\ const fnp = self.ptr.*.pVtbl.*.{}.{} orelse unreachable; \\ return fnp(@ptrCast({}, self.ptr) , .{ interface_field.name, fp.name, self_type }); var ii: u8 = 'a'; while (ii < i) : (ii += 1) { try writer.print(", {c}", .{ii}); } try writer.writeAll( \\); \\ } \\ ); } } try writer.writeAll("};\n"); } pub fn generate( comptime headers: []const []const u8, comptime interfaces: []const []const u8, writer: anytype, ) !void { const c = getImports(headers); try generateCImport(writer, headers); inline for (interfaces) |interface| { @setEvalBranchQuota(10000); try generateWrapper(@field(c, interface), interface, writer); } } pub fn main() !void { comptime const headers = [_][]const u8{ "Graphics/GraphicsEngine/interface/DeviceContext.h", "Graphics/GraphicsEngine/interface/PipelineState.h", "Graphics/GraphicsEngine/interface/ShaderResourceVariable.h", "Graphics/GraphicsEngine/interface/ShaderResourceBinding.h", "Graphics/GraphicsEngine/interface/PipelineResourceSignature.h", "Graphics/GraphicsEngine/interface/Buffer.h", "Graphics/GraphicsEngine/interface/Texture.h", "Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h", "Graphics/GraphicsEngineVulkan/interface/EngineFactoryVk.h", "Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h", "TextureLoader/interface/TextureLoader.h", "TextureLoader/interface/TextureUtilities.h", "AssetLoader/interface/GLTFLoader.h", "GLTF_PBR_Renderer/interface/GLTF_PBR_Renderer.h", }; comptime const interfaces = [_][]const u8{ "IDeviceContext", "IPipelineState", "IShaderResourceVariable", "IShaderResourceBinding", "IPipelineResourceSignature", "IBuffer", "ITexture", "IRenderDeviceVk", "IEngineFactoryVk", "ISwapChainVk", "IGLTFModel", "IGLTF_PBR_Renderer", }; const first_arg = std.os.argv[1]; const output_file = try std.fs.createFileAbsolute(first_arg[0..mem.len(first_arg)], .{ .truncate = true }); defer output_file.close(); try generate(headers[0..], interfaces[0..], output_file.writer()); }