1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
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());
}
|