Hello Triangle!
This commit is contained in:
parent
c16eb13ba1
commit
7700000bd7
11 changed files with 414 additions and 3 deletions
|
|
@ -7,8 +7,14 @@ paru -S --needed sdl3 wgpu-native
|
||||||
```
|
```
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
|
### Core
|
||||||
- [x] Platform
|
- [x] Platform
|
||||||
- [x] Window
|
- [x] Window
|
||||||
- [x] Device
|
- [x] Device
|
||||||
- [x] Cache
|
- [x] Cache
|
||||||
- [ ] Renderer
|
- [ ] Renderer
|
||||||
|
|
||||||
|
### Engine
|
||||||
|
- [ ] ClassDB
|
||||||
|
- [ ] UI
|
||||||
|
|
|
||||||
18
src/main.zig
18
src/main.zig
|
|
@ -18,6 +18,7 @@ const platform = @import("plugins/platform/root.zig");
|
||||||
const device = @import("plugins/device/root.zig");
|
const device = @import("plugins/device/root.zig");
|
||||||
const window = @import("plugins/window/root.zig");
|
const window = @import("plugins/window/root.zig");
|
||||||
const cache = @import("plugins/cache/root.zig");
|
const cache = @import("plugins/cache/root.zig");
|
||||||
|
const input = @import("plugins/input/root.zig");
|
||||||
const renderer = @import("plugins/renderer/root.zig");
|
const renderer = @import("plugins/renderer/root.zig");
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
|
|
@ -33,6 +34,7 @@ pub fn main(init: std.process.Init) !void {
|
||||||
device.plugin,
|
device.plugin,
|
||||||
window.plugin,
|
window.plugin,
|
||||||
cache.plugin,
|
cache.plugin,
|
||||||
|
input.plugin,
|
||||||
renderer.plugin,
|
renderer.plugin,
|
||||||
});
|
});
|
||||||
try app.plugins.build(&app);
|
try app.plugins.build(&app);
|
||||||
|
|
@ -48,4 +50,20 @@ pub fn main(init: std.process.Init) !void {
|
||||||
// --- LIFETIME ---
|
// --- LIFETIME ---
|
||||||
try app.schedules.run(App.stage.init, &app);
|
try app.schedules.run(App.stage.init, &app);
|
||||||
defer app.schedules.runReversed(App.stage.deinit, &app) catch unreachable;
|
defer app.schedules.runReversed(App.stage.deinit, &app) catch unreachable;
|
||||||
|
|
||||||
|
// --- MAIN LOOP ---
|
||||||
|
while (true) {
|
||||||
|
// --- # ---
|
||||||
|
if (app.events.consume(App.event.AppExit)) |_| break;
|
||||||
|
|
||||||
|
// --- # ---
|
||||||
|
try app.schedules.runMany(&.{
|
||||||
|
App.stage.begin_frame,
|
||||||
|
App.stage.inputs,
|
||||||
|
App.stage.fixed_update,
|
||||||
|
App.stage.update,
|
||||||
|
App.stage.draw,
|
||||||
|
App.stage.end_frame,
|
||||||
|
}, &app);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
29
src/plugins/input/root.zig
Normal file
29
src/plugins/input/root.zig
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
|
||||||
|
//
|
||||||
|
// PRIVATE
|
||||||
|
//
|
||||||
|
|
||||||
|
const App = @import("app");
|
||||||
|
const input = @import("system/input.zig");
|
||||||
|
|
||||||
|
//
|
||||||
|
// PUBLIC
|
||||||
|
//
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const plugin: App.plugin.Plugin = .{
|
||||||
|
.name = "Input",
|
||||||
|
.build = build,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn build(
|
||||||
|
_: *App.plugin.Plugin,
|
||||||
|
app: *App,
|
||||||
|
) !void {
|
||||||
|
try app.schedules.add(App.stage.inputs, input.pollEvents);
|
||||||
|
}
|
||||||
17
src/plugins/input/system/input.zig
Normal file
17
src/plugins/input/system/input.zig
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
|
||||||
|
const sdl = @import("sdl");
|
||||||
|
const App = @import("app");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn pollEvents(app: *App) !void {
|
||||||
|
var event: sdl.SDL_Event = undefined;
|
||||||
|
while (sdl.SDL_PollEvent(&event)) {
|
||||||
|
switch (event.type) {
|
||||||
|
sdl.SDL_EVENT_QUIT => try app.events.send(App.event.AppExit{}),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/plugins/renderer/resource/renderer.zig
Normal file
73
src/plugins/renderer/resource/renderer.zig
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const gtl = @import("gtl");
|
||||||
|
const Material = @import("../../common/component/material.zig");
|
||||||
|
const Handle = gtl.Handle;
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
const Mesh = struct {};
|
||||||
|
const Camera = struct {};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const DrawCMD = union(enum) {
|
||||||
|
draw: struct {
|
||||||
|
mesh: Handle(Mesh),
|
||||||
|
material: Material.Unique,
|
||||||
|
},
|
||||||
|
|
||||||
|
draw_indexed: struct {
|
||||||
|
mesh: Handle(Mesh),
|
||||||
|
material: Material.Unique,
|
||||||
|
},
|
||||||
|
|
||||||
|
begin_pass: struct {
|
||||||
|
camera: Handle(Camera),
|
||||||
|
color: [4]f32 = .{ 0, 0, 0, 255 },
|
||||||
|
},
|
||||||
|
|
||||||
|
end_pass,
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// FIELDS
|
||||||
|
//
|
||||||
|
|
||||||
|
commands: std.ArrayList(DrawCMD),
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn init(alloc: std.mem.Allocator) Self {
|
||||||
|
return .{
|
||||||
|
.commands = .empty,
|
||||||
|
.alloc = alloc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self.commands.deinit(self.alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn clear(self: *Self) void {
|
||||||
|
self.commands.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn draw(
|
||||||
|
self: *Self,
|
||||||
|
cmd: DrawCMD,
|
||||||
|
) !void {
|
||||||
|
try self.commands.append(
|
||||||
|
self.alloc,
|
||||||
|
cmd,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -7,10 +7,16 @@
|
||||||
|
|
||||||
const App = @import("app");
|
const App = @import("app");
|
||||||
|
|
||||||
|
const lifetime = @import("system/lifetime.zig");
|
||||||
|
const frame = @import("system/frame.zig");
|
||||||
|
const present = @import("system/present.zig");
|
||||||
|
|
||||||
//
|
//
|
||||||
// PUBLIC
|
// PUBLIC
|
||||||
//
|
//
|
||||||
|
|
||||||
|
const Renderer = @import("resource/renderer.zig");
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub const plugin: App.plugin.Plugin = .{
|
pub const plugin: App.plugin.Plugin = .{
|
||||||
|
|
@ -24,5 +30,14 @@ fn build(
|
||||||
_: *App.plugin.Plugin,
|
_: *App.plugin.Plugin,
|
||||||
app: *App,
|
app: *App,
|
||||||
) !void {
|
) !void {
|
||||||
_ = app;
|
// --- LIFETIME ---
|
||||||
|
try app.schedules.add(App.stage.init, lifetime.init);
|
||||||
|
try app.schedules.add(App.stage.deinit, lifetime.deinit);
|
||||||
|
|
||||||
|
// --- FRAME ---
|
||||||
|
try app.schedules.add(App.stage.begin_frame, frame.begin);
|
||||||
|
try app.schedules.add(App.stage.end_frame, frame.end);
|
||||||
|
|
||||||
|
// --- DRAW ---
|
||||||
|
try app.schedules.add(App.stage.draw, present.draw);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
src/plugins/renderer/system/frame.zig
Normal file
39
src/plugins/renderer/system/frame.zig
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
|
||||||
|
const App = @import("app");
|
||||||
|
const Renderer = @import("../resource/renderer.zig");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn begin(app: *App) !void {
|
||||||
|
// --- # ---
|
||||||
|
const res = try app.resources.getMany(struct {
|
||||||
|
renderer: *Renderer,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- # ---
|
||||||
|
res.renderer.clear();
|
||||||
|
|
||||||
|
{ // TEST
|
||||||
|
try res.renderer.draw(.{
|
||||||
|
.begin_pass = .{
|
||||||
|
.camera = undefined,
|
||||||
|
.color = .{ 0.2, 0.8, 0.2, 1.0 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
try res.renderer.draw(.{
|
||||||
|
.draw = .{
|
||||||
|
.mesh = undefined,
|
||||||
|
.material = .{},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
try res.renderer.draw(.end_pass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn end(app: *App) !void {
|
||||||
|
_ = app;
|
||||||
|
}
|
||||||
20
src/plugins/renderer/system/lifetime.zig
Normal file
20
src/plugins/renderer/system/lifetime.zig
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
|
||||||
|
const App = @import("app");
|
||||||
|
const Renderer = @import("../resource/renderer.zig");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn init(app: *App) !void {
|
||||||
|
try app.resources.set(Renderer.init(
|
||||||
|
app.alloc,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn deinit(app: *App) !void {
|
||||||
|
const renderer = app.resources.getPtr(Renderer) orelse return error.RendererNotSet;
|
||||||
|
renderer.deinit();
|
||||||
|
}
|
||||||
114
src/plugins/renderer/system/present.zig
Normal file
114
src/plugins/renderer/system/present.zig
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
//! ----------------------------------------------------
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const wgpu = @import("wgpu");
|
||||||
|
const App = @import("app");
|
||||||
|
|
||||||
|
const Window = @import("../../window/resource/window.zig");
|
||||||
|
const Device = @import("../../device/resource/wgpu_device.zig");
|
||||||
|
const Renderer = @import("../resource/renderer.zig");
|
||||||
|
const PipelineCache = @import("../../cache/resource/pipeline_cache.zig");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn draw(app: *App) !void {
|
||||||
|
// --- # ---
|
||||||
|
const res = try app.resources.getMany(struct {
|
||||||
|
window: *Window,
|
||||||
|
device: *Device,
|
||||||
|
renderer: *Renderer,
|
||||||
|
pipeline_cache: *PipelineCache,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- SURFACE TEXTURE ---
|
||||||
|
var surface_texture: wgpu.WGPUSurfaceTexture = .{};
|
||||||
|
defer wgpu.wgpuTextureRelease(surface_texture.texture);
|
||||||
|
|
||||||
|
// --- GET SURFACE TEXTURE ---
|
||||||
|
wgpu.wgpuSurfaceGetCurrentTexture(
|
||||||
|
@ptrCast(res.window.surface),
|
||||||
|
&surface_texture,
|
||||||
|
);
|
||||||
|
|
||||||
|
// --- GET SURFACE COLOR VIEW ---
|
||||||
|
const target_view = wgpu.wgpuTextureCreateView(surface_texture.texture, &wgpu.WGPUTextureViewDescriptor{
|
||||||
|
.format = wgpu.wgpuTextureGetFormat(surface_texture.texture),
|
||||||
|
.dimension = wgpu.WGPUTextureViewDimension_2D,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.mipLevelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.arrayLayerCount = 1,
|
||||||
|
.aspect = wgpu.WGPUTextureAspect_All,
|
||||||
|
});
|
||||||
|
defer wgpu.wgpuTextureViewRelease(target_view);
|
||||||
|
|
||||||
|
// --- ENCODER ---
|
||||||
|
const encoder = wgpu.wgpuDeviceCreateCommandEncoder(
|
||||||
|
res.device.raw,
|
||||||
|
&wgpu.WGPUCommandEncoderDescriptor{},
|
||||||
|
);
|
||||||
|
defer wgpu.wgpuCommandEncoderRelease(encoder);
|
||||||
|
|
||||||
|
// --- FRAME ---
|
||||||
|
var render_pass: ?*wgpu.WGPURenderPassEncoderImpl = null;
|
||||||
|
|
||||||
|
for (res.renderer.commands.items) |cmd| {
|
||||||
|
switch (cmd) {
|
||||||
|
.begin_pass => |v| {
|
||||||
|
// --- END PREV PASS ---
|
||||||
|
if (render_pass) |rp| {
|
||||||
|
wgpu.wgpuRenderPassEncoderEnd(rp);
|
||||||
|
wgpu.wgpuRenderPassEncoderRelease(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- NEW RENDER PASS ---
|
||||||
|
render_pass = wgpu.wgpuCommandEncoderBeginRenderPass(
|
||||||
|
encoder,
|
||||||
|
&wgpu.WGPURenderPassDescriptor{
|
||||||
|
.colorAttachmentCount = 1,
|
||||||
|
.colorAttachments = &wgpu.WGPURenderPassColorAttachment{
|
||||||
|
.view = target_view,
|
||||||
|
.resolveTarget = null,
|
||||||
|
.loadOp = wgpu.WGPULoadOp_Clear,
|
||||||
|
.storeOp = wgpu.WGPUStoreOp_Store,
|
||||||
|
.clearValue = .{
|
||||||
|
.r = v.color[0],
|
||||||
|
.g = v.color[1],
|
||||||
|
.b = v.color[2],
|
||||||
|
.a = v.color[3],
|
||||||
|
},
|
||||||
|
.depthSlice = wgpu.WGPU_DEPTH_SLICE_UNDEFINED,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
.end_pass => {
|
||||||
|
if (render_pass) |rp| {
|
||||||
|
wgpu.wgpuRenderPassEncoderEnd(rp);
|
||||||
|
wgpu.wgpuRenderPassEncoderRelease(rp);
|
||||||
|
render_pass = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.draw => |v| {
|
||||||
|
// --- ENSURE PIPELINE ---
|
||||||
|
const pipeline = try res.pipeline_cache.getOrCreate(
|
||||||
|
v.material,
|
||||||
|
);
|
||||||
|
|
||||||
|
// --- DRAW ---
|
||||||
|
wgpu.wgpuRenderPassEncoderSetPipeline(render_pass, pipeline.raw);
|
||||||
|
wgpu.wgpuRenderPassEncoderDraw(render_pass, 3, 1, 0, 0);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FINISH ENCODER | CMD BUFFER ---
|
||||||
|
const cmd_buff = wgpu.wgpuCommandEncoderFinish(encoder, &.{});
|
||||||
|
defer wgpu.wgpuCommandBufferRelease(cmd_buff);
|
||||||
|
|
||||||
|
// --- SUBMIT AND PRESENT ---
|
||||||
|
wgpu.wgpuQueueSubmit(res.device.queue, 1, &cmd_buff);
|
||||||
|
_ = wgpu.wgpuSurfacePresent(@ptrCast(res.window.surface));
|
||||||
|
}
|
||||||
5
src/plugins/window/resource/window.zig
Normal file
5
src/plugins/window/resource/window.zig
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
const sdl = @import("sdl");
|
||||||
|
const sdl_glue = @import("sdl_glue");
|
||||||
|
|
||||||
|
raw: *sdl.SDL_Window,
|
||||||
|
surface: *sdl_glue.WGPUSurfaceImpl,
|
||||||
|
|
@ -5,12 +5,19 @@
|
||||||
// PRIVATE
|
// PRIVATE
|
||||||
//
|
//
|
||||||
|
|
||||||
|
const sdl = @import("sdl");
|
||||||
|
const sdl_glue = @import("sdl_glue");
|
||||||
|
|
||||||
const App = @import("app");
|
const App = @import("app");
|
||||||
|
const WGPUInstance = @import("../platform/resource/wgpu_instance.zig");
|
||||||
|
const WGPUDevice = @import("../device/resource/wgpu_device.zig");
|
||||||
|
|
||||||
//
|
//
|
||||||
// PUBLIC
|
// PUBLIC
|
||||||
//
|
//
|
||||||
|
|
||||||
|
pub const Window = @import("resource/window.zig");
|
||||||
|
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
/// ----------------------------------------------------
|
/// ----------------------------------------------------
|
||||||
pub const plugin: App.plugin.Plugin = .{
|
pub const plugin: App.plugin.Plugin = .{
|
||||||
|
|
@ -24,5 +31,73 @@ fn build(
|
||||||
_: *App.plugin.Plugin,
|
_: *App.plugin.Plugin,
|
||||||
app: *App,
|
app: *App,
|
||||||
) !void {
|
) !void {
|
||||||
_ = app;
|
try app.schedules.add(App.stage.init, init);
|
||||||
|
try app.schedules.add(App.stage.deinit, deinit);
|
||||||
|
|
||||||
|
try app.schedules.addAfter(App.stage.init, App.stage.init, configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn init(app: *App) !void {
|
||||||
|
// --- GET WGPU INSTANCE ---
|
||||||
|
const instance = app.resources.getPtr(
|
||||||
|
WGPUInstance,
|
||||||
|
) orelse return error.WGPUInstanceNotSet;
|
||||||
|
|
||||||
|
// --- WINDOW ---
|
||||||
|
const raw_window = sdl.SDL_CreateWindow(
|
||||||
|
"NYXEngine",
|
||||||
|
800,
|
||||||
|
600,
|
||||||
|
0,
|
||||||
|
) orelse return error.CreateWindow;
|
||||||
|
|
||||||
|
// --- SURFACE ---
|
||||||
|
const raw_surface = sdl_glue.SDL_GetWGPUSurface(
|
||||||
|
@ptrCast(instance.raw),
|
||||||
|
@ptrCast(raw_window),
|
||||||
|
) orelse return error.GetSurface;
|
||||||
|
|
||||||
|
// --- RESOURCE ---
|
||||||
|
try app.resources.set(Window{
|
||||||
|
.raw = raw_window,
|
||||||
|
.surface = raw_surface,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn deinit(app: *App) !void {
|
||||||
|
// --- # ---
|
||||||
|
const res = try app.resources.getMany(struct {
|
||||||
|
window: *Window,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- # ---
|
||||||
|
sdl_glue.wgpuSurfaceUnconfigure(res.window.surface);
|
||||||
|
sdl_glue.wgpuSurfaceRelease(res.window.surface);
|
||||||
|
sdl.SDL_DestroyWindow(res.window.raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn configure(app: *App) !void {
|
||||||
|
// --- # ---
|
||||||
|
const res = try app.resources.getMany(struct {
|
||||||
|
window: *Window,
|
||||||
|
device: *WGPUDevice,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- CONFIGURE SURFACE ---
|
||||||
|
sdl_glue.wgpuSurfaceConfigure(
|
||||||
|
res.window.surface,
|
||||||
|
&sdl_glue.WGPUSurfaceConfiguration{
|
||||||
|
.device = @ptrCast(res.device.raw),
|
||||||
|
.format = 28, // TODO: Get format properly, idk, store it somewhere
|
||||||
|
.width = 800,
|
||||||
|
.height = 600,
|
||||||
|
.usage = sdl_glue.WGPUTextureUsage_RenderAttachment,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue