HelloWorld!
This commit is contained in:
commit
f2f4830d57
26 changed files with 9404 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.zig-cache/
|
||||
zig-pkg/
|
||||
69
build.zig
Normal file
69
build.zig
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const mod = b.addModule("platform", .{
|
||||
.root_source_file = b.path("src/renderer.zig"),
|
||||
|
||||
.link_libc = true,
|
||||
.link_libcpp = true,
|
||||
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const mod_tests = b.addTest(.{
|
||||
.root_module = mod,
|
||||
});
|
||||
|
||||
const run_mod_tests = b.addRunArtifact(mod_tests);
|
||||
|
||||
const test_step = b.step("test", "Run tests");
|
||||
test_step.dependOn(&run_mod_tests.step);
|
||||
|
||||
//
|
||||
// DEPENDENCIES
|
||||
//
|
||||
|
||||
const app = b.dependency("app", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
mod.addImport("app", app.module("app"));
|
||||
|
||||
const platform = b.dependency("platform", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
mod.addImport("platform_plugin", platform.module("platform"));
|
||||
|
||||
//
|
||||
// SYSTEM DEPENDENCIES
|
||||
//
|
||||
|
||||
const sdl = b.addTranslateC(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.root_source_file = b.path("./src/vendors/sdl3/sdl.h"),
|
||||
});
|
||||
mod.addImport("sdl", sdl.createModule());
|
||||
mod.linkSystemLibrary("SDL3", .{});
|
||||
|
||||
const sdl3_glue = b.addTranslateC(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.root_source_file = b.path("./src/vendors/sdl3_glue/sdl3webgpu.h"),
|
||||
});
|
||||
mod.addImport("sdl_glue", sdl3_glue.createModule());
|
||||
mod.addCSourceFile(.{ .file = b.path("./src/vendors/sdl3_glue/sdl3webgpu.c") });
|
||||
|
||||
const wgpu = b.addTranslateC(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.root_source_file = b.path("./src/vendors/wgpu/wgpu.h"),
|
||||
});
|
||||
mod.addImport("wgpu", wgpu.createModule());
|
||||
mod.linkSystemLibrary("wgpu_native", .{});
|
||||
}
|
||||
15
build.zig.zon
Normal file
15
build.zig.zon
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
.{
|
||||
.name = .renderer,
|
||||
.version = "0.0.1",
|
||||
.dependencies = .{
|
||||
.app = .{
|
||||
.path = "../../app",
|
||||
},
|
||||
.platform = .{
|
||||
.path = "../platform/",
|
||||
},
|
||||
},
|
||||
.minimum_zig_version = "0.16.0",
|
||||
.paths = .{""},
|
||||
.fingerprint = 0xf199a19cb1dc8f03,
|
||||
}
|
||||
0
src/component/camera.zig
Normal file
0
src/component/camera.zig
Normal file
1
src/component/root.zig
Normal file
1
src/component/root.zig
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub const Camera = @import("camera.zig");
|
||||
40
src/plugin.zig
Normal file
40
src/plugin.zig
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
const App = @import("app");
|
||||
const system = @import("system/root.zig");
|
||||
const resource = @import("resource/root.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
.name = "Renderer",
|
||||
.description = "WebGPU Renderer",
|
||||
.build = build,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
ctx: App.plugin.Context,
|
||||
) !void {
|
||||
// --- RESOURCES ---
|
||||
try ctx.app.resources.set(resource.Instance{});
|
||||
try ctx.app.resources.set(resource.Device{});
|
||||
try ctx.app.resources.set(resource.window{});
|
||||
|
||||
// --- INIT ---
|
||||
try ctx.app.schedules.addMany(App.stage.Init, &.{
|
||||
system.instance.init,
|
||||
system.window.init,
|
||||
system.device.init,
|
||||
});
|
||||
|
||||
// --- DEINIT ---
|
||||
try ctx.app.schedules.addMany(App.stage.Deinit, &.{
|
||||
system.device.deinit,
|
||||
system.window.deinit,
|
||||
system.instance.deinit,
|
||||
});
|
||||
|
||||
// --- INPUT ---
|
||||
try ctx.app.schedules.addMany(App.stage.Inputs, &.{});
|
||||
}
|
||||
45
src/renderer.zig
Normal file
45
src/renderer.zig
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
const std = @import("std");
|
||||
const App = @import("app");
|
||||
const Platform = @import("platform_plugin");
|
||||
|
||||
pub const plugin = @import("plugin.zig").plugin;
|
||||
pub const system = @import("system/root.zig");
|
||||
pub const resource = @import("resource/root.zig");
|
||||
|
||||
test "Main" {
|
||||
// --- APP ---
|
||||
var app: App = .init(std.testing.allocator);
|
||||
defer app.deinit();
|
||||
|
||||
// --- ON ERROR ---
|
||||
errdefer {
|
||||
app.schedules.run(App.stage.Deinit, .{ .app = &app }) catch unreachable;
|
||||
app.deinit();
|
||||
}
|
||||
|
||||
// --- ADD PLUGINS ---
|
||||
try app.plugins.addMany(&.{
|
||||
plugin,
|
||||
Platform.plugin,
|
||||
});
|
||||
|
||||
// --- BUILD ---
|
||||
try app.plugins.build(.{
|
||||
.app = &app,
|
||||
});
|
||||
|
||||
// --- LIFETIME ---
|
||||
try app.schedules.run(App.stage.Init, .{ .app = &app });
|
||||
defer app.schedules.run(App.stage.Deinit, .{ .app = &app }) catch unreachable;
|
||||
|
||||
// --- MAIN LOOP ---
|
||||
// while (!app.events.has(Platform.event.AppExit)) {
|
||||
// try app.schedules.runMany(&.{
|
||||
// App.stage.Inputs,
|
||||
// App.stage.Update,
|
||||
// App.stage.Draw,
|
||||
// }, .{
|
||||
// .app = &app,
|
||||
// });
|
||||
// }
|
||||
}
|
||||
4
src/resource/device.zig
Normal file
4
src/resource/device.zig
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
const wgpu = @import("wgpu");
|
||||
|
||||
raw: ?*wgpu.WGPUDeviceImpl = null,
|
||||
queue: ?*wgpu.WGPUQueueImpl = null,
|
||||
7
src/resource/instance.zig
Normal file
7
src/resource/instance.zig
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
const wgpu = @import("wgpu");
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
raw: ?*wgpu.WGPUInstanceImpl = null,
|
||||
4
src/resource/root.zig
Normal file
4
src/resource/root.zig
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// --- CORE ---
|
||||
pub const Instance = @import("instance.zig");
|
||||
pub const Device = @import("device.zig");
|
||||
pub const window = @import("window.zig");
|
||||
13
src/resource/window.zig
Normal file
13
src/resource/window.zig
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const sdl = @import("sdl");
|
||||
const sdl_glue = @import("sdl_glue");
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
title: []const u8 = "App",
|
||||
width: u32 = 1280,
|
||||
height: u32 = 720,
|
||||
|
||||
raw: ?*sdl.SDL_Window = null,
|
||||
surface: ?*sdl_glue.WGPUSurfaceImpl = null,
|
||||
233
src/system/device.zig
Normal file
233
src/system/device.zig
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
const std = @import("std");
|
||||
const App = @import("app");
|
||||
const wgpu = @import("wgpu");
|
||||
const sdl_glue = @import("sdl_glue");
|
||||
|
||||
const Instance = @import("../resource/instance.zig");
|
||||
const Device = @import("../resource/device.zig");
|
||||
const Window = @import("../resource/window.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
const AdapterUserdata = struct {
|
||||
adapter: ?*wgpu.WGPUAdapterImpl = null,
|
||||
ended: bool = false,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
const DeviceUserdata = struct {
|
||||
device: ?*wgpu.WGPUDeviceImpl = null,
|
||||
ended: bool = false,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(ctx: App.scheduler.Context) !void {
|
||||
// --- RESOURCES ---
|
||||
const res = try ctx.app.resources.getMany(struct {
|
||||
instance: *Instance,
|
||||
window: *Window,
|
||||
device: *Device,
|
||||
});
|
||||
|
||||
//
|
||||
// ADAPTER
|
||||
//
|
||||
|
||||
// TODO: Mabe Mabe add other backends n stuff
|
||||
var adapter_userdata: AdapterUserdata = .{};
|
||||
_ = wgpu.wgpuInstanceRequestAdapter(
|
||||
res.instance.raw,
|
||||
&wgpu.WGPURequestAdapterOptions{
|
||||
.backendType = wgpu.WGPUBackendType_Vulkan,
|
||||
},
|
||||
wgpu.WGPURequestAdapterCallbackInfo{
|
||||
.callback = adapterCallback,
|
||||
.userdata1 = &adapter_userdata,
|
||||
},
|
||||
);
|
||||
|
||||
// --- ADAPTER ---
|
||||
const adapter = if (adapter_userdata.adapter) |v| v else return error.NoAdapter;
|
||||
defer wgpu.wgpuAdapterRelease(adapter);
|
||||
|
||||
// --- ON ERROR ---
|
||||
errdefer {
|
||||
wgpu.wgpuAdapterRelease(adapter);
|
||||
}
|
||||
|
||||
// --- GET LIMITS ---
|
||||
var limits: wgpu.WGPULimits = .{};
|
||||
switch (wgpu.wgpuAdapterGetLimits(adapter, &limits)) {
|
||||
wgpu.WGPUStatus_Error => return error.FailedToGetAdapterLimits,
|
||||
else => {},
|
||||
}
|
||||
|
||||
// --- GET INFO ---
|
||||
var info: wgpu.WGPUAdapterInfo = .{};
|
||||
switch (wgpu.wgpuAdapterGetInfo(adapter, &info)) {
|
||||
wgpu.WGPUStatus_Error => return error.FailedToGetAdapterInfo,
|
||||
else => {},
|
||||
}
|
||||
|
||||
// --- DEBUG LIMITS ---
|
||||
std.debug.print("Adapter Limits:\n", .{});
|
||||
std.debug.print("| Texture Dimentions: ({})1D, ({})2D, ({})3D, ({})Array Layers\n", .{
|
||||
limits.maxTextureDimension1D,
|
||||
limits.maxTextureDimension2D,
|
||||
limits.maxTextureDimension3D,
|
||||
limits.maxTextureArrayLayers,
|
||||
});
|
||||
|
||||
// --- DEBUG INFO ---
|
||||
std.debug.print("Adapter Info:\n", .{});
|
||||
std.debug.print(
|
||||
\\| Device: {s}
|
||||
\\| Backend: {s}
|
||||
\\
|
||||
, .{
|
||||
info.device.data,
|
||||
switch (info.backendType) {
|
||||
wgpu.WGPUBackendType_Vulkan => "Vulkan",
|
||||
wgpu.WGPUBackendType_OpenGL => "OpenGL",
|
||||
wgpu.WGPUBackendType_D3D11 => "D3D11",
|
||||
wgpu.WGPUBackendType_D3D12 => "D3D12",
|
||||
else => "idk", // TODO: idk 🥀
|
||||
},
|
||||
});
|
||||
|
||||
//
|
||||
// DEVICE
|
||||
//
|
||||
|
||||
// --- REQUEST DEVICE ---
|
||||
var device_userdata: DeviceUserdata = .{};
|
||||
_ = wgpu.wgpuAdapterRequestDevice(
|
||||
adapter,
|
||||
&wgpu.WGPUDeviceDescriptor{
|
||||
.label = .{ .data = "MainDevice", .length = wgpu.WGPU_STRLEN },
|
||||
.uncapturedErrorCallbackInfo = .{
|
||||
.callback = uncapturedErrorCallback,
|
||||
},
|
||||
},
|
||||
.{
|
||||
.callback = deviceCallback,
|
||||
.userdata1 = &device_userdata,
|
||||
},
|
||||
);
|
||||
res.device.raw = device_userdata.device;
|
||||
|
||||
// --- ON ERROR ---
|
||||
errdefer {
|
||||
wgpu.wgpuDeviceRelease(res.device.raw);
|
||||
res.device.raw = null;
|
||||
}
|
||||
|
||||
// --- GET QUEUE ---
|
||||
res.device.queue = wgpu.wgpuDeviceGetQueue(
|
||||
res.device.raw,
|
||||
) orelse return error.FailedToGetDeviceQueue;
|
||||
|
||||
var caps: sdl_glue.WGPUSurfaceCapabilities = .{};
|
||||
_ = sdl_glue.wgpuSurfaceGetCapabilities(res.window.surface, @ptrCast(adapter), &caps); // TODO: Handle possible error
|
||||
defer sdl_glue.wgpuSurfaceCapabilitiesFreeMembers(caps);
|
||||
|
||||
// --- CONFIGURE SURFACE ---
|
||||
sdl_glue.wgpuSurfaceConfigure(
|
||||
res.window.surface,
|
||||
&sdl_glue.WGPUSurfaceConfiguration{
|
||||
.device = @ptrCast(res.device.raw),
|
||||
.format = caps.formats[0],
|
||||
.width = res.window.width,
|
||||
.height = res.window.height,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(ctx: App.scheduler.Context) !void {
|
||||
// --- RESOURCES ---
|
||||
const res = try ctx.app.resources.getMany(struct {
|
||||
instance: *Instance,
|
||||
device: *Device,
|
||||
});
|
||||
|
||||
if (res.device.queue) |queue| {
|
||||
wgpu.wgpuQueueRelease(queue);
|
||||
res.device.queue = null;
|
||||
}
|
||||
|
||||
if (res.device.raw) |raw| {
|
||||
wgpu.wgpuDeviceRelease(raw);
|
||||
res.device.raw = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn uncapturedErrorCallback(
|
||||
_: [*c]const wgpu.WGPUDevice,
|
||||
err_type: wgpu.WGPUErrorType,
|
||||
message: wgpu.WGPUStringView,
|
||||
_: ?*anyopaque,
|
||||
_: ?*anyopaque,
|
||||
) callconv(.c) void {
|
||||
std.debug.print("[{s}] {s}\n", .{
|
||||
switch (err_type) {
|
||||
wgpu.WGPUErrorType_Validation => "\x1b[33VALIDATION\x1b[0m",
|
||||
wgpu.WGPUErrorType_OutOfMemory => "\x1b[31OUT_OF_MEMORY\x1b[0m",
|
||||
else => "IDK",
|
||||
},
|
||||
message.data,
|
||||
});
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn adapterCallback(
|
||||
status: wgpu.WGPURequestAdapterStatus,
|
||||
adapter: wgpu.WGPUAdapter,
|
||||
message: wgpu.WGPUStringView,
|
||||
raw_userdata: ?*anyopaque,
|
||||
_: ?*anyopaque,
|
||||
) callconv(.c) void {
|
||||
// --- USERDATA ---
|
||||
const userdata: *AdapterUserdata = @ptrCast(@alignCast(raw_userdata));
|
||||
defer userdata.ended = true;
|
||||
|
||||
// --- STATUS ---
|
||||
switch (status) {
|
||||
wgpu.WGPURequestAdapterStatus_Success => userdata.adapter = adapter,
|
||||
else => {
|
||||
std.debug.print("Failed to get WebGPU adapter: {s}\n", .{
|
||||
message.data,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn deviceCallback(
|
||||
status: wgpu.WGPURequestDeviceStatus,
|
||||
device: wgpu.WGPUDevice,
|
||||
message: wgpu.WGPUStringView,
|
||||
raw_userdata: ?*anyopaque,
|
||||
_: ?*anyopaque,
|
||||
) callconv(.c) void {
|
||||
// --- USERDATA ---
|
||||
const userdata: *DeviceUserdata = @ptrCast(@alignCast(raw_userdata));
|
||||
defer userdata.ended = true;
|
||||
|
||||
// --- STATUS ---
|
||||
switch (status) {
|
||||
wgpu.WGPURequestDeviceStatus_Success => userdata.device = device,
|
||||
else => {
|
||||
std.debug.print("Failed to get WebGPU adapter: {s}\n", .{
|
||||
message.data,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
29
src/system/instance.zig
Normal file
29
src/system/instance.zig
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
const std = @import("std");
|
||||
const App = @import("app");
|
||||
const wgpu = @import("wgpu");
|
||||
const Instance = @import("../resource/instance.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(ctx: App.scheduler.Context) !void {
|
||||
const instance = ctx.app.resources.getPtr(
|
||||
Instance,
|
||||
) orelse return;
|
||||
|
||||
instance.raw = wgpu.wgpuCreateInstance(
|
||||
&wgpu.WGPUInstanceDescriptor{},
|
||||
) orelse return error.WGPUInstance;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(ctx: App.scheduler.Context) !void {
|
||||
const instance = ctx.app.resources.getPtr(
|
||||
Instance,
|
||||
) orelse return;
|
||||
|
||||
if (instance.raw) |raw| {
|
||||
wgpu.wgpuInstanceRelease(raw);
|
||||
instance.raw = null;
|
||||
}
|
||||
}
|
||||
4
src/system/root.zig
Normal file
4
src/system/root.zig
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// --- CORE ---
|
||||
pub const instance = @import("instance.zig");
|
||||
pub const device = @import("device.zig");
|
||||
pub const window = @import("window.zig");
|
||||
50
src/system/window.zig
Normal file
50
src/system/window.zig
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
const App = @import("app");
|
||||
const sdl = @import("sdl");
|
||||
const sdl_glue = @import("sdl_glue");
|
||||
|
||||
const Instance = @import("../resource/instance.zig");
|
||||
const Device = @import("../resource/device.zig");
|
||||
const Window = @import("../resource/window.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(ctx: App.scheduler.Context) !void {
|
||||
// --- WINDOW ---
|
||||
const res = try ctx.app.resources.getMany(struct {
|
||||
instance: *Instance,
|
||||
window: *Window,
|
||||
});
|
||||
|
||||
// --- HANDLE ---
|
||||
res.window.raw = sdl.SDL_CreateWindow(
|
||||
res.window.title.ptr,
|
||||
@intCast(res.window.width),
|
||||
@intCast(res.window.height),
|
||||
sdl.SDL_WINDOW_RESIZABLE,
|
||||
) orelse return error.CreateWindow;
|
||||
|
||||
// --- SURFACE ---
|
||||
res.window.surface = sdl_glue.SDL_GetWGPUSurface(
|
||||
@ptrCast(res.instance.raw),
|
||||
@ptrCast(res.window.raw),
|
||||
) orelse return error.GetSurface;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(ctx: App.scheduler.Context) !void {
|
||||
const win = ctx.app.resources.getPtr(
|
||||
Window,
|
||||
) orelse return;
|
||||
|
||||
if (win.surface) |surface| {
|
||||
sdl_glue.wgpuSurfaceUnconfigure(surface);
|
||||
sdl_glue.wgpuSurfaceRelease(surface);
|
||||
win.surface = null;
|
||||
}
|
||||
|
||||
if (win.raw) |raw| {
|
||||
sdl.SDL_DestroyWindow(raw);
|
||||
win.raw = null;
|
||||
}
|
||||
}
|
||||
0
src/template/asset.zig
Normal file
0
src/template/asset.zig
Normal file
0
src/template/camera_pass.zig
Normal file
0
src/template/camera_pass.zig
Normal file
0
src/template/draw_cmd.zig
Normal file
0
src/template/draw_cmd.zig
Normal file
286
src/template/registry.zig
Normal file
286
src/template/registry.zig
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
const std = @import("std");
|
||||
const App = @import("app");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn Registry(
|
||||
comptime K: type,
|
||||
comptime V: type,
|
||||
) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Metadata = struct {
|
||||
source: ?[]const u8 = null,
|
||||
reload: ?*const fn (*V, App.scheduler.Context) anyerror!void = null,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Entry = struct {
|
||||
key: K,
|
||||
value: V,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
meta: std.ArrayList(Metadata),
|
||||
lookup: std.AutoHashMap(K, usize),
|
||||
entries: std.ArrayList(Entry),
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
//
|
||||
// LIFECYCLE
|
||||
//
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.meta = .empty,
|
||||
.lookup = .init(alloc),
|
||||
.entries = .empty,
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.meta.deinit(self.alloc);
|
||||
self.lookup.deinit();
|
||||
self.entries.deinit(self.alloc);
|
||||
}
|
||||
|
||||
//
|
||||
// INSERTION
|
||||
//
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn put(
|
||||
self: *Self,
|
||||
key: K,
|
||||
value: V,
|
||||
) !void {
|
||||
if (self.lookup.contains(key)) return error.Duplicate;
|
||||
try self.putNoDup(key, value, .{});
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// Insert or replace
|
||||
/// ----------------------------------------------------
|
||||
pub fn upsert(
|
||||
self: *Self,
|
||||
key: K,
|
||||
value: V,
|
||||
) !?V {
|
||||
if (self.lookup.contains(key)) {
|
||||
const idx = self.lookup.get(key).?;
|
||||
const old = self.entries.items[idx].value;
|
||||
self.entries.items[idx].value = value;
|
||||
return old;
|
||||
}
|
||||
try self.putNoDup(key, value, .{});
|
||||
return null;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// Insert with metadata
|
||||
/// ----------------------------------------------------
|
||||
pub fn putWith(
|
||||
self: *Self,
|
||||
key: K,
|
||||
value: V,
|
||||
metadata: Metadata,
|
||||
) !void {
|
||||
if (self.lookup.contains(key)) return error.Duplicate;
|
||||
try self.putNoDup(key, value, metadata);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn putNoDup(
|
||||
self: *Self,
|
||||
key: K,
|
||||
value: V,
|
||||
metadata: Metadata,
|
||||
) !void {
|
||||
try self.entries.append(self.alloc, .{ .key = key, .value = value });
|
||||
errdefer _ = self.entries.swapRemove(self.entries.items.len - 1);
|
||||
|
||||
try self.meta.append(self.alloc, metadata);
|
||||
errdefer _ = self.meta.swapRemove(self.meta.items.len - 1);
|
||||
|
||||
try self.lookup.put(key, self.entries.items.len - 1);
|
||||
}
|
||||
|
||||
//
|
||||
// REMOVAL
|
||||
//
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn remove(self: *Self, key: K) bool {
|
||||
const idx = self.lookup.get(key) orelse return false;
|
||||
self.removeIndex(idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn removeLast(self: *Self) bool {
|
||||
if (self.entries.items.len == 0) return false;
|
||||
const last = self.entries.items.len - 1;
|
||||
_ = self.lookup.remove(self.entries.items[last].key);
|
||||
self.entries.swapRemove(last);
|
||||
self.meta.swapRemove(last);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn removeIndex(self: *Self, idx: usize) void {
|
||||
const last = self.entries.items.len - 1;
|
||||
|
||||
// --- UPDATE LOOKUP ---
|
||||
if (idx != last) {
|
||||
self.lookup.put(self.entries.items[last].key, idx) catch {};
|
||||
}
|
||||
|
||||
_ = self.meta.swapRemove(idx);
|
||||
_ = self.lookup.remove(self.entries.items[idx].key);
|
||||
_ = self.entries.swapRemove(idx);
|
||||
}
|
||||
|
||||
//
|
||||
// LOOKUP
|
||||
//
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn contains(self: Self, key: K) bool {
|
||||
return self.lookup.contains(key);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn get(self: Self, key: K) ?*const V {
|
||||
const idx = self.lookup.get(key) orelse return null;
|
||||
return &self.entries.items[idx].value;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn getPtr(self: *Self, key: K) ?*V {
|
||||
const idx = self.lookup.get(key) orelse return null;
|
||||
return &self.entries.items[idx].value;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn getEntry(self: Self, key: K) ?*const Entry {
|
||||
const idx = self.lookup.get(key) orelse return null;
|
||||
return &self.entries.items[idx];
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn getMetadata(self: Self, key: K) ?*const Metadata {
|
||||
const idx = self.lookup.get(key) orelse return null;
|
||||
return &self.meta.items[idx];
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn getPtrMetadata(self: *Self, key: K) ?*Metadata {
|
||||
const idx = self.lookup.get(key) orelse return null;
|
||||
return &self.meta.items[idx];
|
||||
}
|
||||
|
||||
//
|
||||
// ITERATION
|
||||
//
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn count(self: Self) usize {
|
||||
return self.entries.items.len;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn values(self: Self) []const Entry {
|
||||
return self.entries.items;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// Value, Metadata
|
||||
/// ----------------------------------------------------
|
||||
pub fn iterator(self: *Self) Iterator {
|
||||
return .{ .registry = self, .index = 0 };
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Iterator = struct {
|
||||
registry: *Self,
|
||||
index: usize,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn next(it: *Iterator) ?struct { value: *V, meta: *Metadata } {
|
||||
if (it.index >= it.registry.entries.items.len) return null;
|
||||
defer it.index += 1;
|
||||
return .{
|
||||
.value = &it.registry.entries.items[it.index].value,
|
||||
.meta = &it.registry.meta.items[it.index],
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// IDK
|
||||
//
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn reloadAll(
|
||||
self: *Self,
|
||||
ctx: App.scheduler.Context,
|
||||
) anyerror!void {
|
||||
var it = self.iterator();
|
||||
while (it.next()) |entry| {
|
||||
if (entry.meta.reload) |reload| try reload(entry.value, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinitReverse(self: *Self) void {
|
||||
while (self.entries.items.len > 0) {
|
||||
_ = self.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn clear(self: *Self) void {
|
||||
self.meta.clearRetainingCapacity();
|
||||
self.lookup.clearRetainingCapacity();
|
||||
self.entries.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn clearAndFree(self: *Self) void {
|
||||
self.meta.clearAndFree();
|
||||
self.lookup.clearAndFree();
|
||||
self.entries.clearAndFree();
|
||||
}
|
||||
};
|
||||
}
|
||||
3
src/template/root.zig
Normal file
3
src/template/root.zig
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pub const Registry = @import("registry.zig").Registry;
|
||||
pub const CameraPass = @import("camera_pass.zig");
|
||||
pub const DrawCMD = @import("draw_cmd.zig");
|
||||
1
src/vendors/sdl3/sdl.h
vendored
Normal file
1
src/vendors/sdl3/sdl.h
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include <SDL3/SDL.h>
|
||||
20
src/vendors/sdl3_glue/LICENSE.md
vendored
Normal file
20
src/vendors/sdl3_glue/LICENSE.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
MIT License
|
||||
Copyright (c) 2022-2024 Élie Michel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
174
src/vendors/sdl3_glue/sdl3webgpu.c
vendored
Normal file
174
src/vendors/sdl3_glue/sdl3webgpu.c
vendored
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/**
|
||||
* This is an extension of SDL3 for WebGPU, abstracting away the details of
|
||||
* OS-specific operations.
|
||||
*
|
||||
* This file is part of the "Learn WebGPU for C++" book.
|
||||
* https://eliemichel.github.io/LearnWebGPU
|
||||
*
|
||||
* Most of this code comes from the wgpu-native triangle example:
|
||||
* https://github.com/gfx-rs/wgpu-native/blob/master/examples/triangle/main.c
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2022-2024 Elie Michel and the wgpu-native authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sdl3webgpu.h"
|
||||
|
||||
#include "../wgpu/wgpu.h"
|
||||
|
||||
#if defined(SDL_PLATFORM_MACOS)
|
||||
# include <Cocoa/Cocoa.h>
|
||||
# include <Foundation/Foundation.h>
|
||||
# include <QuartzCore/CAMetalLayer.h>
|
||||
#elif defined(SDL_PLATFORM_IOS)
|
||||
# include <UIKit/UIKit.h>
|
||||
# include <Foundation/Foundation.h>
|
||||
# include <QuartzCore/CAMetalLayer.h>
|
||||
# include <Metal/Metal.h>
|
||||
#elif defined(SDL_PLATFORM_WIN32)
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
WGPUSurface SDL_GetWGPUSurface(WGPUInstance instance, SDL_Window* window) {
|
||||
SDL_PropertiesID props = SDL_GetWindowProperties(window);
|
||||
|
||||
#if defined(SDL_PLATFORM_MACOS)
|
||||
{
|
||||
id metal_layer = NULL;
|
||||
NSWindow *ns_window = (__bridge NSWindow *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
|
||||
if (!ns_window) return NULL;
|
||||
[ns_window.contentView setWantsLayer : YES];
|
||||
metal_layer = [CAMetalLayer layer];
|
||||
[ns_window.contentView setLayer : metal_layer];
|
||||
|
||||
WGPUSurfaceSourceMetalLayer fromMetalLayer;
|
||||
fromMetalLayer.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
|
||||
fromMetalLayer.chain.next = NULL;
|
||||
fromMetalLayer.layer = metal_layer;
|
||||
|
||||
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||
surfaceDescriptor.nextInChain = &fromMetalLayer.chain;
|
||||
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_IOS)
|
||||
{
|
||||
UIWindow *ui_window = (__bridge UIWindow *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, NULL);
|
||||
if (!uiwindow) return NULL;
|
||||
|
||||
UIView* ui_view = ui_window.rootViewController.view;
|
||||
CAMetalLayer* metal_layer = [CAMetalLayer new];
|
||||
metal_layer.opaque = true;
|
||||
metal_layer.frame = ui_view.frame;
|
||||
metal_layer.drawableSize = ui_view.frame.size;
|
||||
|
||||
[ui_view.layer addSublayer: metal_layer];
|
||||
|
||||
WGPUSurfaceSourceMetalLayer fromMetalLayer;
|
||||
fromMetalLayer.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
|
||||
fromMetalLayer.chain.next = NULL;
|
||||
fromMetalLayer.layer = metal_layer;
|
||||
|
||||
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||
surfaceDescriptor.nextInChain = &fromMetalLayer.chain;
|
||||
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_LINUX)
|
||||
if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
|
||||
void *x11_display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
|
||||
uint64_t x11_window = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
||||
if (!x11_display || !x11_window) return NULL;
|
||||
|
||||
WGPUSurfaceSourceXlibWindow fromXlibWindow;
|
||||
fromXlibWindow.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
|
||||
fromXlibWindow.chain.next = NULL;
|
||||
fromXlibWindow.display = x11_display;
|
||||
fromXlibWindow.window = x11_window;
|
||||
|
||||
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||
surfaceDescriptor.nextInChain = &fromXlibWindow.chain;
|
||||
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||
}
|
||||
else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
|
||||
void *wayland_display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
|
||||
void *wayland_surface = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL);
|
||||
if (!wayland_display || !wayland_surface) return NULL;
|
||||
|
||||
WGPUSurfaceSourceWaylandSurface fromWaylandSurface;
|
||||
fromWaylandSurface.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
|
||||
fromWaylandSurface.chain.next = NULL;
|
||||
fromWaylandSurface.display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
|
||||
fromWaylandSurface.surface = wayland_surface;
|
||||
|
||||
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||
surfaceDescriptor.nextInChain = &fromWaylandSurface.chain;
|
||||
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_WIN32)
|
||||
{
|
||||
HWND hwnd = (HWND)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
||||
if (!hwnd) return NULL;
|
||||
HINSTANCE hinstance = GetModuleHandle(NULL);
|
||||
|
||||
WGPUSurfaceSourceWindowsHWND fromWindowsHWND;
|
||||
fromWindowsHWND.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
|
||||
fromWindowsHWND.chain.next = NULL;
|
||||
fromWindowsHWND.hinstance = hinstance;
|
||||
fromWindowsHWND.hwnd = hwnd;
|
||||
|
||||
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||
surfaceDescriptor.nextInChain = &fromWindowsHWND.chain;
|
||||
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||
}
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
{
|
||||
# ifdef WEBGPU_BACKEND_EMDAWNWEBGPU
|
||||
WGPUEmscriptenSurfaceSourceCanvasHTMLSelector fromCanvasHTMLSelector;
|
||||
fromCanvasHTMLSelector.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
|
||||
# else
|
||||
WGPUSurfaceDescriptorFromCanvasHTMLSelector fromCanvasHTMLSelector;
|
||||
fromCanvasHTMLSelector.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
|
||||
# endif
|
||||
fromCanvasHTMLSelector.chain.next = NULL;
|
||||
fromCanvasHTMLSelector.selector = "canvas";
|
||||
|
||||
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||
surfaceDescriptor.nextInChain = &fromCanvasHTMLSelector.chain;
|
||||
surfaceDescriptor.label = NULL;
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||
}
|
||||
#else
|
||||
// TODO: See SDL_syswm.h for other possible enum values!
|
||||
#error "Unsupported WGPU_TARGET"
|
||||
#endif
|
||||
}
|
||||
49
src/vendors/sdl3_glue/sdl3webgpu.h
vendored
Normal file
49
src/vendors/sdl3_glue/sdl3webgpu.h
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* This is an extension of SDL3 for WebGPU, abstracting away the details of
|
||||
* OS-specific operations.
|
||||
*
|
||||
* This file is part of the "Learn WebGPU for C++" book.
|
||||
* https://eliemichel.github.io/LearnWebGPU
|
||||
*
|
||||
* MIT License
|
||||
* Copyright (c) 2022-2024 Elie Michel and the wgpu-native authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _sdl3_webgpu_h_
|
||||
#define _sdl3_webgpu_h_
|
||||
|
||||
#include "../wgpu/wgpu.h"
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get a WGPUSurface from a SDL3 window.
|
||||
*/
|
||||
WGPUSurface SDL_GetWGPUSurface(WGPUInstance instance, SDL_Window* window);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _sdl3_webgpu_h_
|
||||
6768
src/vendors/wgpu/webgpu.h
vendored
Normal file
6768
src/vendors/wgpu/webgpu.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1587
src/vendors/wgpu/wgpu.h
vendored
Normal file
1587
src/vendors/wgpu/wgpu.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue