Major update | Replaced previous renderer with a proper clean one
This commit is contained in:
parent
7a3fe658ef
commit
6fab7b5ead
76 changed files with 2999 additions and 783 deletions
|
|
@ -8,10 +8,8 @@ paru -S --needed sdl3 wgpu-native
|
|||
|
||||
## Architecture
|
||||
```bash
|
||||
[ENTITY]
|
||||
| mesh: Handle(Mesh)
|
||||
| material: Handle(Material)
|
||||
| transform: Transform2D or Transform3D
|
||||
RenderData -> RenderPhase -> RenderGraph
|
||||
Extract -> Prepare -> Queue -> Present
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
|
@ -21,7 +19,7 @@ paru -S --needed sdl3 wgpu-native
|
|||
- [x] Window
|
||||
- [x] Device
|
||||
- [x] Cache
|
||||
- [ ] Renderer
|
||||
- [x] RenderGraph
|
||||
- [ ] Hot Reloading
|
||||
|
||||
### Engine
|
||||
|
|
|
|||
|
|
@ -66,6 +66,12 @@ pub fn build(b: *std.Build) void {
|
|||
});
|
||||
exe.root_module.addImport("math", math.module("NYXMath"));
|
||||
|
||||
const world = b.dependency("NYXWorld", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe.root_module.addImport("world", world.module("NYXWorld"));
|
||||
|
||||
//
|
||||
// SYSTEM DEPENDENCIES
|
||||
//
|
||||
|
|
|
|||
|
|
@ -13,17 +13,21 @@
|
|||
.hash = "zla-0.0.0-z62_impQAABHbrWUmoFLsl_HuD8CNS-k91z6laMJEQ62",
|
||||
},
|
||||
.app = .{
|
||||
.url = "git+http://2.120.146.66:25569/abux/NYXA.git#9cbd0804a6008243b4cff387285a5e09cf1e03ed",
|
||||
.hash = "app-0.0.0-AOV9_YDvAAAjjuCldX-9p7mt3Oswbv8bTB2rvcZ67Fn1",
|
||||
.url = "git+http://192.168.0.11:25569/abux/NYXA.git#97c629a78b5a99860cd16405a8741ed91c2411ce",
|
||||
.hash = "app-0.0.0-AOV9_dxlAADNgU13ahJF7Qn934LLC-5M1KWAxVwDgaoW",
|
||||
},
|
||||
.gtl = .{
|
||||
.url = "git+http://192.168.0.11:25569/abux/GTL.git#f9772950b5097bbbda39cd68d86f6b6062c41fec",
|
||||
.hash = "gtl-0.0.0-e3QoJPNxAABpkY1nvYNN7r02CI4z2aki1_FHDPzdWi9P",
|
||||
.url = "git+http://192.168.0.11:25569/abux/GTL.git#3c411f25b9a60d4633fa283a076a1cc141eb9902",
|
||||
.hash = "gtl-0.0.0-e3QoJM_pAADNA1GlFiA-h7cRWuLH5rAspOCDy4aMXLd_",
|
||||
},
|
||||
.NYXMath = .{
|
||||
.url = "git+http://192.168.0.11:25569/abux/NYXMath.git#cb7b54995bdb46321f112bba2a704d58cf53aeb1",
|
||||
.hash = "NYXMath-0.0.0-BD6ST9rOAAA0uSpPK_woZrta3nTh0f5w7hFewJ-e2Kv1",
|
||||
},
|
||||
.NYXWorld = .{
|
||||
.url = "git+http://192.168.0.11:25569/abux/NYXWorld.git#e6c46e23716614473500931dbad16de9c7b36f3c",
|
||||
.hash = "NYXWorld-0.0.0-jIP7UtZ3AAB4FoXBjV1iAO-0EWFssFr-cxAnIK4Y7_LR",
|
||||
},
|
||||
},
|
||||
|
||||
.paths = .{
|
||||
|
|
|
|||
23
src/main.zig
23
src/main.zig
|
|
@ -15,6 +15,7 @@ const App = @import("app");
|
|||
//
|
||||
|
||||
const template = @import("plugins/template/root.zig");
|
||||
const world = @import("plugins/world/root.zig");
|
||||
const playground = @import("plugins/playground/root.zig");
|
||||
const lua = @import("plugins/lua/root.zig");
|
||||
const common = @import("plugins/common/root.zig");
|
||||
|
|
@ -32,8 +33,15 @@ pub fn main(init: std.process.Init) !void {
|
|||
var app: App = .init(init.gpa);
|
||||
defer app.deinit();
|
||||
|
||||
// --- # ---
|
||||
errdefer {
|
||||
app.schedules.runReversed(App.stage.deinit, &app) catch unreachable;
|
||||
app.deinit();
|
||||
}
|
||||
|
||||
// --- ADD PLUGINS ---
|
||||
try app.plugins.addMany(&.{
|
||||
world.plugin,
|
||||
lua.plugin,
|
||||
platform.plugin,
|
||||
device.plugin,
|
||||
|
|
@ -45,25 +53,10 @@ pub fn main(init: std.process.Init) !void {
|
|||
});
|
||||
try app.plugins.build(&app);
|
||||
|
||||
// DEBUG
|
||||
if (gtl.log.print(.debug, "PLUGINS", gtl.ansi.yellow)) |v| {
|
||||
defer v.end();
|
||||
|
||||
for (app.plugins.data.items) |plugin| {
|
||||
v.write("{s}", .{plugin.name});
|
||||
}
|
||||
}
|
||||
|
||||
// --- LIFETIME ---
|
||||
try app.schedules.run(App.stage.init, &app);
|
||||
defer app.schedules.runReversed(App.stage.deinit, &app) catch unreachable;
|
||||
|
||||
// --- # ---
|
||||
errdefer {
|
||||
app.schedules.runReversed(App.stage.deinit, &app) catch unreachable;
|
||||
app.deinit();
|
||||
}
|
||||
|
||||
// --- MAIN LOOP ---
|
||||
while (true) {
|
||||
// --- # ---
|
||||
|
|
|
|||
10
src/plugins.old/device/resource/gpu_device.zig
Normal file
10
src/plugins.old/device/resource/gpu_device.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const wgpu = @import("wgpu");
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
raw: *wgpu.WGPUDeviceImpl,
|
||||
30
src/plugins.old/device/root.zig
Normal file
30
src/plugins.old/device/root.zig
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
|
||||
const App = @import("app");
|
||||
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
|
||||
pub const GPUDevice = @import("resource/gpu_device.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Device",
|
||||
.build = build,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
_ = app;
|
||||
}
|
||||
3
src/plugins.old/platform/resource/wgpu_instance.zig
Normal file
3
src/plugins.old/platform/resource/wgpu_instance.zig
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
const wgpu = @import("wgpu");
|
||||
|
||||
raw: *wgpu.WGPUInstanceImpl,
|
||||
64
src/plugins.old/platform/root.zig
Normal file
64
src/plugins.old/platform/root.zig
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
|
||||
const std = @import("std");
|
||||
const sdl = @import("sdl");
|
||||
const wgpu = @import("wgpu");
|
||||
const App = @import("app");
|
||||
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
|
||||
pub const WGPUInstance = @import("resource/wgpu_instance.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
.name = "Platform",
|
||||
.build = build,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
try app.schedules.add(App.stage.init, init);
|
||||
try app.schedules.add(App.stage.deinit, deinit);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(app: *App) !void {
|
||||
// --- SDL3 INIT ---
|
||||
if (!sdl.SDL_Init(sdl.SDL_INIT_VIDEO)) {
|
||||
std.debug.print("[SDL_ERROR] SDL_Init: {s}\n", .{sdl.SDL_GetError()});
|
||||
return error.SDL_INIT;
|
||||
}
|
||||
|
||||
// --- WGPU INIT ---
|
||||
try app.resources.set(WGPUInstance{
|
||||
.raw = wgpu.wgpuCreateInstance(&wgpu.WGPUInstanceDescriptor{}) orelse return {
|
||||
return error.WGPU_Init;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
instance: *WGPUInstance,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
wgpu.wgpuInstanceRelease(res.instance.raw);
|
||||
sdl.SDL_Quit();
|
||||
}
|
||||
17
src/plugins.old/render/resource/render_graph.zig
Normal file
17
src/plugins.old/render/resource/render_graph.zig
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const gtl = @import("gtl");
|
||||
const Node = @import("../template/node.zig");
|
||||
const Slot = @import("../template/slot.zig");
|
||||
const Edge = @import("../template/edge.zig").Edge;
|
||||
const Handle = gtl.Handle;
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
nodes: gtl.SlotMap(Node),
|
||||
edges: gtl.SlotMap(Edge),
|
||||
slots: gtl.SlotMap(Slot),
|
||||
order: ?[]Handle(Node) = null,
|
||||
119
src/plugins.old/render/root.zig
Normal file
119
src/plugins.old/render/root.zig
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const App = @import("app");
|
||||
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
|
||||
pub const RenderGraph = @import("resource/render_graph.zig");
|
||||
pub const Node = @import("template/node.zig");
|
||||
pub const Edge = @import("template/edge.zig").Edge;
|
||||
pub const Slot = @import("template/slot.zig");
|
||||
pub const RenderCTX = @import("template/render_ctx.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Render",
|
||||
.build = build,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
try app.schedules.add(App.stage.init, init);
|
||||
try app.schedules.add(App.stage.deinit, deinit);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn init(app: *App) !void {
|
||||
const graph = try app.resources.getOrSet(RenderGraph{
|
||||
.edges = .init(app.alloc),
|
||||
.nodes = .init(app.alloc),
|
||||
.slots = .init(app.alloc),
|
||||
});
|
||||
|
||||
const main = try graph.nodes.put(.{
|
||||
.name = "main",
|
||||
.run = mainNode,
|
||||
});
|
||||
|
||||
const present = try graph.nodes.put(.{
|
||||
.name = "present",
|
||||
.run = presentNode,
|
||||
});
|
||||
|
||||
_ = try graph.edges.put(
|
||||
.{
|
||||
.order = .{
|
||||
.from = main,
|
||||
.to = present,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
var render_ctx: RenderCTX = .{
|
||||
.graph = graph,
|
||||
.device = undefined,
|
||||
.encoder = undefined,
|
||||
};
|
||||
|
||||
if (graph.order == null) {
|
||||
var order: std.ArrayList(gtl.Handle(Node)) = .empty;
|
||||
defer order.deinit(app.alloc);
|
||||
|
||||
try order.append(app.alloc, main);
|
||||
try order.append(app.alloc, present);
|
||||
|
||||
graph.order = try order.toOwnedSlice(app.alloc);
|
||||
}
|
||||
|
||||
if (graph.order) |order| {
|
||||
for (order) |node_id| {
|
||||
const node = graph.nodes.get(
|
||||
node_id,
|
||||
) orelse return error.MissingNode;
|
||||
|
||||
try node.run(&render_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn deinit(app: *App) !void {
|
||||
const graph = app.resources.getPtr(
|
||||
RenderGraph,
|
||||
) orelse return error.RenderGraphNotSet;
|
||||
|
||||
if (graph.order) |order| app.alloc.free(order);
|
||||
graph.nodes.deinit();
|
||||
graph.edges.deinit();
|
||||
graph.slots.deinit();
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn mainNode(ctx: *RenderCTX) !void {
|
||||
std.debug.print("[MAIN_PASS]\n", .{});
|
||||
_ = ctx;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn presentNode(ctx: *RenderCTX) !void {
|
||||
std.debug.print("[PRESENT_PASS]\n", .{});
|
||||
_ = ctx;
|
||||
}
|
||||
14
src/plugins.old/render/template/edge.zig
Normal file
14
src/plugins.old/render/template/edge.zig
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const gtl = @import("gtl");
|
||||
const Node = @import("node.zig");
|
||||
const Slot = @import("slot.zig");
|
||||
const Handle = gtl.Handle;
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Edge = union(enum) {
|
||||
data: struct { producer: Handle(Slot), consumer: Handle(Slot) },
|
||||
order: struct { from: Handle(Node), to: Handle(Node) },
|
||||
};
|
||||
16
src/plugins.old/render/template/node.zig
Normal file
16
src/plugins.old/render/template/node.zig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const gtl = @import("gtl");
|
||||
const Slot = @import("slot.zig");
|
||||
const RenderCTX = @import("render_ctx.zig");
|
||||
const Handle = gtl.Handle;
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
name: []const u8,
|
||||
inputs: []const Handle(Slot) = &.{},
|
||||
outputs: []const Handle(Slot) = &.{},
|
||||
run: *const fn (*RenderCTX) anyerror!void,
|
||||
14
src/plugins.old/render/template/render_ctx.zig
Normal file
14
src/plugins.old/render/template/render_ctx.zig
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const wgpu = @import("wgpu");
|
||||
const RenderGraph = @import("../resource/render_graph.zig");
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
device: *wgpu.WGPUDeviceImpl,
|
||||
encoder: *wgpu.WGPUCommandEncoderImpl,
|
||||
|
||||
graph: *const RenderGraph,
|
||||
19
src/plugins.old/render/template/slot.zig
Normal file
19
src/plugins.old/render/template/slot.zig
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const wgpu = @import("wgpu");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Value = union(enum) {
|
||||
buffer: *wgpu.WGPUBufferImpl,
|
||||
bind_group: *wgpu.WGPUBindGroupImpl,
|
||||
texture_view: *wgpu.WGPUTextureViewImpl,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
name: []const u8,
|
||||
value: ?Value = null,
|
||||
28
src/plugins.old/template/root.zig
Normal file
28
src/plugins.old/template/root.zig
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
|
||||
const App = @import("app");
|
||||
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Template",
|
||||
.build = build,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
_ = app;
|
||||
}
|
||||
6
src/plugins.old/window/resource/gpu_window.zig
Normal file
6
src/plugins.old/window/resource/gpu_window.zig
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const sdl = @import("sdl");
|
||||
|
||||
raw: *sdl.SDL_Window,
|
||||
8
src/plugins.old/window/resource/window.zig
Normal file
8
src/plugins.old/window/resource/window.zig
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
title: []const u8 = "NYXEngine",
|
||||
width: u32 = 800,
|
||||
height: u32 = 600,
|
||||
|
||||
resizeable: bool = true,
|
||||
33
src/plugins.old/window/root.zig
Normal file
33
src/plugins.old/window/root.zig
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
|
||||
const App = @import("app");
|
||||
const lifetime = @import("system/lifetime.zig");
|
||||
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
|
||||
pub const Window = @import("resource/window.zig");
|
||||
pub const GPUWindow = @import("resource/gpu_window.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Window",
|
||||
.build = build,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
try app.schedules.add(App.stage.init, lifetime.init);
|
||||
try app.schedules.add(App.stage.deinit, lifetime.deinit);
|
||||
}
|
||||
50
src/plugins.old/window/system/lifetime.zig
Normal file
50
src/plugins.old/window/system/lifetime.zig
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const sdl = @import("sdl");
|
||||
const gtl = @import("gtl");
|
||||
|
||||
const App = @import("app");
|
||||
const Window = @import("../resource/window.zig");
|
||||
const GPUWindow = @import("../resource/gpu_window.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(app: *App) !void {
|
||||
// --- ENSURE WINDOW ---
|
||||
const window = try app.resources.getOrSet(Window{});
|
||||
|
||||
// --- CREATE GPU WINDOW ---
|
||||
try app.resources.set(GPUWindow{
|
||||
.raw = sdl.SDL_CreateWindow(
|
||||
window.title.ptr,
|
||||
@intCast(window.width),
|
||||
@intCast(window.height),
|
||||
0,
|
||||
) orelse {
|
||||
gtl.log.err("{s}", .{sdl.SDL_GetError()}, @src());
|
||||
return error.SDLWindow;
|
||||
},
|
||||
});
|
||||
|
||||
// --- DEBUG ---
|
||||
if (gtl.log.print(.debug, "Window", gtl.ansi.blue)) |v| {
|
||||
defer v.end();
|
||||
|
||||
v.write("title: \"{s}\"", .{window.title});
|
||||
v.write("width: {}", .{window.width});
|
||||
v.write("height: {}", .{window.height});
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(app: *App) !void {
|
||||
// --- GET GPU WINDOW ---
|
||||
const gpu_window = app.resources.getPtr(
|
||||
GPUWindow,
|
||||
) orelse return error.GPUWindowNotSet;
|
||||
|
||||
// --- # ---
|
||||
sdl.SDL_DestroyWindow(gpu_window.raw);
|
||||
}
|
||||
7
src/plugins/cache/resource/mesh_cache.zig
vendored
7
src/plugins/cache/resource/mesh_cache.zig
vendored
|
|
@ -62,10 +62,11 @@ pub fn init(
|
|||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
// --- FREE BUFFERS ---
|
||||
for (self.data.items()) |entry| {
|
||||
wgpu.wgpuBufferRelease(entry.value.vbuf);
|
||||
var it = self.data.valueIterator();
|
||||
while (it.next()) |v| {
|
||||
wgpu.wgpuBufferRelease(v.vbuf);
|
||||
|
||||
if (entry.value.ibuf) |ibuf| {
|
||||
if (v.ibuf) |ibuf| {
|
||||
wgpu.wgpuBufferRelease(ibuf);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,3 +20,5 @@ target: union(enum) {
|
|||
|
||||
order: u32 = 0,
|
||||
priority: u32 = 0,
|
||||
|
||||
clear_color: math.Color = .black,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const gtl = @import("gtl");
|
||||
const Material = @import("../../renderer/template/material.zig");
|
||||
const MaterialAsset = @import("../../renderer/resource/material_assets.zig").Asset;
|
||||
const Handle = gtl.Handle;
|
||||
|
||||
value: Handle(Material),
|
||||
value: Handle(MaterialAsset),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
const MeshID = @import("../../cache/resource/mesh_cache.zig").MeshID;
|
||||
const gtl = @import("gtl");
|
||||
const MeshAssets = @import("../../renderer/resource/mesh_assets.zig");
|
||||
|
||||
value: MeshID,
|
||||
value: gtl.Handle(MeshAssets.Asset),
|
||||
|
||||
// const MeshID = @import("../../cache/resource/mesh_cache.zig").MeshID;
|
||||
// value: MeshID,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub const WGPUDevice = @import("resource/wgpu_device.zig");
|
|||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Device",
|
||||
.build = build,
|
||||
};
|
||||
|
|
@ -25,7 +25,7 @@ pub const plugin: App.plugin.Plugin = .{
|
|||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
try app.schedules.add(App.stage.init, lifetime.init);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ const input = @import("system/input.zig");
|
|||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Input",
|
||||
.build = build,
|
||||
};
|
||||
|
|
@ -22,7 +22,7 @@ pub const plugin: App.plugin.Plugin = .{
|
|||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
try app.schedules.add(App.stage.inputs, input.pollEvents);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ const wgpu = @import("wgpu");
|
|||
const App = @import("app");
|
||||
|
||||
const Window = @import("../../window/resource/window.zig");
|
||||
const GPUWindow = @import("../../window/resource/gpu_window.zig");
|
||||
const Resized = @import("../../window/event/resized.zig");
|
||||
const WGPUInstance = @import("../../platform/resource/wgpu_instance.zig");
|
||||
const WGPUDevice = @import("../../device/resource/wgpu_device.zig");
|
||||
|
|
@ -18,8 +19,9 @@ pub fn pollEvents(app: *App) !void {
|
|||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
instance: *WGPUInstance,
|
||||
window: *Window,
|
||||
device: *WGPUDevice,
|
||||
window: *Window,
|
||||
gpu_window: *GPUWindow,
|
||||
});
|
||||
|
||||
var event: sdl.SDL_Event = undefined;
|
||||
|
|
@ -33,12 +35,16 @@ pub fn pollEvents(app: *App) !void {
|
|||
.height = @intCast(event.window.data2),
|
||||
});
|
||||
|
||||
// --- SET SIZE ---
|
||||
res.window.width = @intCast(event.window.data1);
|
||||
res.window.height = @intCast(event.window.data2);
|
||||
|
||||
// --- RELEASE ---
|
||||
sdl_glue.wgpuSurfaceUnconfigure(res.window.surface);
|
||||
sdl_glue.wgpuSurfaceUnconfigure(res.gpu_window.surface);
|
||||
|
||||
// --- CONFIGURE SURFACE ---
|
||||
sdl_glue.wgpuSurfaceConfigure(
|
||||
res.window.surface,
|
||||
res.gpu_window.surface,
|
||||
&sdl_glue.WGPUSurfaceConfiguration{
|
||||
.device = @ptrCast(res.device.raw),
|
||||
.format = 28, // TODO: Get format properly, idk, store it somewhere
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ const Zla = @import("zla");
|
|||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "LUA",
|
||||
.build = build,
|
||||
};
|
||||
|
|
@ -22,7 +22,7 @@ pub const plugin: App.plugin.Plugin = .{
|
|||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
// --- LIFETIME ---
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub const WGPUInstance = @import("resource/wgpu_instance.zig");
|
|||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Platform",
|
||||
.build = build,
|
||||
};
|
||||
|
|
@ -26,7 +26,7 @@ pub const plugin: App.plugin.Plugin = .{
|
|||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
try app.schedules.add(App.stage.init, init);
|
||||
|
|
@ -54,11 +54,11 @@ pub fn init(app: *App) !void {
|
|||
/// ----------------------------------------------------
|
||||
pub fn deinit(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
instance: *WGPUInstance,
|
||||
});
|
||||
const instance = try app.resources.require(
|
||||
WGPUInstance,
|
||||
);
|
||||
|
||||
// --- # ---
|
||||
wgpu.wgpuInstanceRelease(res.instance.raw);
|
||||
wgpu.wgpuInstanceRelease(instance.raw);
|
||||
sdl.SDL_Quit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,17 @@
|
|||
|
||||
const std = @import("std");
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
|
||||
const MeshAssets = @import("../renderer/resource/mesh_assets.zig");
|
||||
const MaterialAssets = @import("../renderer/resource/material_assets.zig");
|
||||
|
||||
const Camera = @import("../common/component/camera.zig");
|
||||
const Mesh = @import("../common/component/mesh.zig");
|
||||
const Material = @import("../common/component/material.zig");
|
||||
const Transform3D = @import("../common/component/transform3D.zig");
|
||||
|
||||
const RenderWorld = @import("../renderer/resource/render_world.zig");
|
||||
// const RenderWorld = @import("../renderer/resource/render_world.zig");
|
||||
|
||||
//
|
||||
// PUBLIC
|
||||
|
|
@ -21,7 +25,7 @@ const RenderWorld = @import("../renderer/resource/render_world.zig");
|
|||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Playground",
|
||||
.build = build,
|
||||
};
|
||||
|
|
@ -29,10 +33,14 @@ pub const plugin: App.plugin.Plugin = .{
|
|||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
try app.schedules.addAfter(App.stage.init, App.stage.init, start);
|
||||
try app.schedules.addAfter(
|
||||
App.stage.init,
|
||||
App.stage.init,
|
||||
start,
|
||||
);
|
||||
}
|
||||
|
||||
const FlyCamera = struct {};
|
||||
|
|
@ -41,79 +49,62 @@ const FlyCamera = struct {};
|
|||
/// ----------------------------------------------------
|
||||
fn start(app: *App) !void {
|
||||
// --- # ---
|
||||
const render_world = app.resources.getPtr(
|
||||
RenderWorld,
|
||||
).?;
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
mesh_assets: *MeshAssets,
|
||||
material_assets: *MaterialAssets,
|
||||
});
|
||||
|
||||
// --- CAMERA ---
|
||||
try app.world.spawn(.{
|
||||
FlyCamera{},
|
||||
try res.world.spawn(.{
|
||||
Camera{
|
||||
.projection = .{
|
||||
.perspective = .{},
|
||||
},
|
||||
},
|
||||
Transform3D{
|
||||
.position = .new(.{ 0, -2.5, -6.5 }),
|
||||
.rotation = .fromEuler(.init(
|
||||
-std.math.degreesToRadians(30),
|
||||
0,
|
||||
0,
|
||||
)),
|
||||
},
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
try app.world.spawn(.{
|
||||
Mesh{ .value = .cube },
|
||||
Material{
|
||||
.value = try render_world.materials.put(.{
|
||||
.style = .{
|
||||
.albedo = .{ 0.8, 0.2, 0.2, 1.0 },
|
||||
},
|
||||
.unique = .{
|
||||
.cull_mode = .none,
|
||||
},
|
||||
}),
|
||||
},
|
||||
Transform3D{},
|
||||
});
|
||||
|
||||
const count: usize = 200;
|
||||
const radius: f32 = 5.0;
|
||||
try res.world.spawn(.{
|
||||
Mesh{ .value = try res.mesh_assets.put(.{}) },
|
||||
Material{ .value = try res.material_assets.put(.{}) },
|
||||
Transform3D{},
|
||||
});
|
||||
|
||||
for (0..count) |i| {
|
||||
const angle = (@as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(count))) * std.math.tau;
|
||||
|
||||
try app.world.spawn(.{
|
||||
Mesh{ .value = .cube },
|
||||
Material{
|
||||
.value = try render_world.materials.put(.{
|
||||
.style = .{
|
||||
.albedo = .{
|
||||
0.2,
|
||||
0.0 + (angle * std.math.pi) * 0.01,
|
||||
0.0 + (angle * std.math.pi) * 0.02,
|
||||
1,
|
||||
},
|
||||
},
|
||||
.unique = .{
|
||||
.cull_mode = .none,
|
||||
},
|
||||
}),
|
||||
},
|
||||
Transform3D{
|
||||
.position = .new(.{
|
||||
@cos(angle) * radius,
|
||||
0,
|
||||
@sin(angle) * radius,
|
||||
}),
|
||||
.rotation = .fromEuler(.init(
|
||||
std.math.degreesToRadians(180),
|
||||
0,
|
||||
0,
|
||||
)),
|
||||
},
|
||||
});
|
||||
}
|
||||
// const count: usize = 200;
|
||||
// const radius: f32 = 5.0;
|
||||
//
|
||||
// for (0..count) |i| {
|
||||
// const angle = (@as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(count))) * std.math.tau;
|
||||
//
|
||||
// try res.world.spawn(.{
|
||||
// Mesh{ .value = .cube },
|
||||
// Material{
|
||||
// .value = try res.render_world.materials.put(.{
|
||||
// .style = .{
|
||||
// .albedo = .{
|
||||
// 0.2,
|
||||
// 0.0 + (angle * std.math.pi) * 0.01,
|
||||
// 0.0 + (angle * std.math.pi) * 0.02,
|
||||
// 1,
|
||||
// },
|
||||
// },
|
||||
// .unique = .{
|
||||
// .cull_mode = .none,
|
||||
// },
|
||||
// }),
|
||||
// },
|
||||
// Transform3D{
|
||||
// .position = .new(.{
|
||||
// @cos(angle) * radius,
|
||||
// 0,
|
||||
// @sin(angle) * radius,
|
||||
// }),
|
||||
// .rotation = .fromEuler(.init(
|
||||
// std.math.degreesToRadians(180),
|
||||
// 0,
|
||||
// 0,
|
||||
// )),
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3f,
|
||||
@location(1) normal: vec3f,
|
||||
@location(2) uv: vec2f,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct VertexOutput {
|
||||
@builtin(position) position: vec4f,
|
||||
@location(0) uv: vec2f,
|
||||
@location(1) normal: vec3f,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct CameraUniform {
|
||||
view: mat4x4<f32>,
|
||||
projection: mat4x4<f32>,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct ModelUniform {
|
||||
data: mat4x4<f32>,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct Material {
|
||||
albedo: vec4f,
|
||||
metallic: f32,
|
||||
roughness: f32,
|
||||
_pad0: vec2f,
|
||||
};
|
||||
|
||||
//
|
||||
// UNIFORMS
|
||||
//
|
||||
|
||||
@group(0) @binding(0)
|
||||
var<uniform> camera: CameraUniform;
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> model: ModelUniform;
|
||||
|
||||
@group(2) @binding(0)
|
||||
var<uniform> material: Material;
|
||||
|
||||
//
|
||||
// VERTEX
|
||||
//
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
// --- # ---
|
||||
var out: VertexOutput;
|
||||
|
||||
// --- # ---
|
||||
out.position = camera.projection * camera.view * model.data * vec4f(in.position, 1.0);
|
||||
out.uv = in.uv;
|
||||
out.normal = in.normal;
|
||||
|
||||
// --- # ---
|
||||
return out;
|
||||
}
|
||||
|
||||
//
|
||||
// FRAGMENT
|
||||
//
|
||||
|
||||
@fragment
|
||||
fn fs_main(out: VertexOutput) -> @location(0) vec4f {
|
||||
var final_color: vec4f = material.albedo;
|
||||
final_color.x += out.uv.x * 0.2;
|
||||
final_color.y += out.uv.y * 0.2;
|
||||
return vec4f(final_color);
|
||||
}
|
||||
17
src/plugins/renderer.depricated/resource/render_graph.zig
Normal file
17
src/plugins/renderer.depricated/resource/render_graph.zig
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const gtl = @import("gtl");
|
||||
pub const Node = @import("../template/node.zig");
|
||||
pub const Slot = @import("../template/slot.zig");
|
||||
pub const Edge = @import("../template/edge.zig").Edge;
|
||||
const Handle = gtl.Handle;
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
nodes: gtl.FixedSlotMap(Node, 24),
|
||||
edges: gtl.FixedSlotMap(Edge, 24),
|
||||
slots: gtl.FixedSlotMap(Slot, 24),
|
||||
order: ?[]Handle(Node) = null,
|
||||
|
|
@ -5,7 +5,8 @@
|
|||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const wgpu = @import("wgpu");
|
||||
pub const Entity = u64; // TODO: You lazy retard
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
|
||||
// --- CAMERA ---
|
||||
pub const GPUCamera = @import("../template/gpu_camera.zig");
|
||||
|
|
@ -39,12 +40,12 @@ pub const UnlitCode = @embedFile("embeded/shaders/pbr.wgsl");
|
|||
// FIELDS
|
||||
//
|
||||
|
||||
gpu_cameras: gtl.KeyedSlotMap(Entity, GPUCamera),
|
||||
gpu_objects: gtl.KeyedSlotMap(Entity, GPUObject),
|
||||
gpu_cameras: gtl.KeyedSlotMap(World.Entity, GPUCamera),
|
||||
gpu_objects: gtl.KeyedSlotMap(World.Entity, GPUObject),
|
||||
gpu_shaders: gtl.KeyedSlotMap(ShaderID, GPUShader),
|
||||
gpu_pipelines: gtl.KeyedSlotMap(Pipeline, GPUPipeline),
|
||||
gpu_materials: gtl.KeyedSlotMap(gtl.Handle(Material), GPUMaterial),
|
||||
|
||||
frame_views: std.ArrayList(FrameView),
|
||||
frame_objects: std.ArrayList(FrameObject),
|
||||
frame_views: gtl.FixedArrayList(FrameView, 8),
|
||||
frame_objects: gtl.FixedArrayList(FrameObject, 256),
|
||||
materials: gtl.SlotMap(Material), // TODO: Move this to assets resource or sum
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
const Material = @import("../../common/component/material.zig");
|
||||
const Mesh = @import("../../cache/resource/mesh_cache.zig").MeshID;
|
||||
const Handle = gtl.Handle;
|
||||
|
|
@ -13,18 +15,18 @@ const Self = @This();
|
|||
pub const DrawCMD = union(enum) {
|
||||
draw: struct {
|
||||
mesh: Mesh,
|
||||
entity: u64,
|
||||
entity: World.Entity,
|
||||
material: Handle(Material),
|
||||
},
|
||||
|
||||
draw_indexed: struct {
|
||||
mesh: Mesh,
|
||||
entity: u64,
|
||||
entity: World.Entity,
|
||||
material: Handle(Material),
|
||||
},
|
||||
|
||||
begin_pass: struct {
|
||||
camera: u64, // TODO: Change it to Entity type instead
|
||||
camera: World.Entity,
|
||||
color: [4]f32 = .{ 0, 0, 0, 255 },
|
||||
load_op: enum {
|
||||
load,
|
||||
62
src/plugins/renderer.depricated/root.zig
Normal file
62
src/plugins/renderer.depricated/root.zig
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
|
||||
const App = @import("app");
|
||||
|
||||
const lifetime = @import("system/lifetime.zig");
|
||||
const frame = @import("system/frame.zig");
|
||||
const prepare = @import("system/prepare.zig");
|
||||
const present = @import("system/present.zig");
|
||||
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
|
||||
const Renderer = @import("resource/renderer.zig");
|
||||
const RenderWorld = @import("resource/render_world.zig");
|
||||
const RenderLayout = @import("resource/render_layout.zig");
|
||||
|
||||
pub const RenderGraph = @import("resource/render_graph.zig");
|
||||
pub const Node = @import("template/node.zig");
|
||||
pub const Slot = @import("template/slot.zig");
|
||||
pub const Edge = @import("template/edge.zig").Edge;
|
||||
pub const RenderCTX = @import("template/render_ctx.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Renderer",
|
||||
.build = build,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
// --- 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);
|
||||
|
||||
// --- PRE DRAW ---
|
||||
try app.schedules.addManyBefore(App.stage.draw, App.stage.draw, &.{
|
||||
prepare.shaders,
|
||||
prepare.pipelines,
|
||||
|
||||
prepare.cameras,
|
||||
prepare.objects,
|
||||
prepare.materials,
|
||||
});
|
||||
|
||||
// --- DRAW ---
|
||||
try app.schedules.add(App.stage.draw, present.draw);
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ pub fn begin(app: *App) !void {
|
|||
res.renderer.clear();
|
||||
|
||||
// --- # ---
|
||||
for (res.render_world.frame_views.items) |view| {
|
||||
for (res.render_world.frame_views.items()) |view| {
|
||||
// --- NEW PASS ---
|
||||
try res.renderer.draw(.{
|
||||
.begin_pass = .{
|
||||
|
|
@ -34,7 +34,7 @@ pub fn begin(app: *App) !void {
|
|||
defer res.renderer.draw(.end_pass) catch unreachable;
|
||||
|
||||
// --- DRAW ---
|
||||
for (res.render_world.frame_objects.items) |obj| {
|
||||
for (res.render_world.frame_objects.items()) |obj| {
|
||||
try res.renderer.draw(.{
|
||||
.draw = .{
|
||||
.material = obj.material,
|
||||
|
|
@ -46,8 +46,8 @@ pub fn begin(app: *App) !void {
|
|||
}
|
||||
|
||||
// --- YES ---
|
||||
res.render_world.frame_views.clearRetainingCapacity();
|
||||
res.render_world.frame_objects.clearRetainingCapacity();
|
||||
res.render_world.frame_views.clear();
|
||||
res.render_world.frame_objects.clear();
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
|
|
@ -6,6 +6,7 @@ const App = @import("app");
|
|||
const Zla = @import("zla");
|
||||
|
||||
const WGPUDevice = @import("../../device/resource/wgpu_device.zig");
|
||||
const RenderGraph = @import("../resource/render_graph.zig");
|
||||
const Renderer = @import("../resource/renderer.zig");
|
||||
const RenderWorld = @import("../resource/render_world.zig");
|
||||
const RenderLayout = @import("../resource/render_layout.zig");
|
||||
|
|
@ -23,6 +24,14 @@ pub fn init(app: *App) !void {
|
|||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
try app.resources.set(RenderGraph{
|
||||
.nodes = .empty,
|
||||
.edges = .empty,
|
||||
.slots = .empty,
|
||||
.order = null,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
try app.resources.set(Renderer.init(
|
||||
app.alloc,
|
||||
|
|
@ -97,10 +106,17 @@ pub fn deinit(app: *App) !void {
|
|||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
ren: *Renderer,
|
||||
ren_graph: *RenderGraph,
|
||||
ren_world: *RenderWorld,
|
||||
ren_layout: *RenderLayout,
|
||||
});
|
||||
|
||||
// --- FREE RENDER GRAPH ---
|
||||
// res.ren_graph.nodes.deinit();
|
||||
// res.ren_graph.edges.deinit();
|
||||
// res.ren_graph.slots.deinit();
|
||||
if (res.ren_graph.order) |v| app.alloc.free(v);
|
||||
|
||||
// --- FREE SHADERS ---
|
||||
for (res.ren_world.gpu_shaders.items()) |entry| {
|
||||
wgpu.wgpuShaderModuleRelease(entry.value.raw);
|
||||
|
|
@ -137,8 +153,6 @@ pub fn deinit(app: *App) !void {
|
|||
|
||||
// --- # ---
|
||||
res.ren_world.materials.deinit();
|
||||
res.ren_world.frame_views.deinit(app.alloc);
|
||||
res.ren_world.frame_objects.deinit(app.alloc);
|
||||
res.ren_world.gpu_cameras.deinit();
|
||||
res.ren_world.gpu_objects.deinit();
|
||||
res.ren_world.gpu_shaders.deinit();
|
||||
515
src/plugins/renderer.depricated/system/prepare.zig
Normal file
515
src/plugins/renderer.depricated/system/prepare.zig
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
// --- # ---
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const math = @import("math");
|
||||
const wgpu = @import("wgpu");
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
|
||||
// --- # ---
|
||||
const Vertex = @import("../../cache/resource/mesh_cache.zig").Vertex;
|
||||
const Window = @import("../../window/resource/window.zig");
|
||||
const WGPUDevice = @import("../../device/resource/wgpu_device.zig");
|
||||
const RenderWorld = @import("../resource/render_world.zig");
|
||||
const RenderLayout = @import("../resource/render_layout.zig");
|
||||
const RenderGraph = @import("../resource/render_graph.zig");
|
||||
|
||||
// --- # ---
|
||||
const Transform2D = @import("../../common/component/transform2D.zig");
|
||||
const Transform3D = @import("../../common/component/transform3D.zig");
|
||||
|
||||
// --- MESH ---
|
||||
const CMesh = @import("../../common/component/mesh.zig");
|
||||
const TMesh = @import("../template/gpu_object.zig");
|
||||
|
||||
// --- MATERIAL ---
|
||||
const CMaterial = @import("../../common/component/material.zig");
|
||||
const TMaterial = @import("../template/material.zig");
|
||||
|
||||
// --- CAMERA ---
|
||||
const CCamera = @import("../../common/component/camera.zig");
|
||||
const TCamera = @import("../template/gpu_camera.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn ensureGraph(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
device: *WGPUDevice,
|
||||
render_graph: *RenderGraph,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
if (res.render_graph.order == null) {
|
||||
const order: std.ArrayList(gtl.Handle(RenderGraph.Node)) = .empty;
|
||||
defer order.deinit(app.alloc);
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn cameras(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
render_world: *RenderWorld,
|
||||
render_layout: *RenderLayout,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = res.world.query(struct {
|
||||
camera: *const CCamera,
|
||||
transform2D: ?*const Transform2D,
|
||||
transform3D: ?*const Transform3D,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- GPU ---
|
||||
const raw = try res.render_world.gpu_cameras.getOrPut(query.entity(), blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_cameras.getByKey(
|
||||
query.entity(),
|
||||
)) |v| break :blk v.*;
|
||||
|
||||
// --- UNIFORM ---
|
||||
const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{
|
||||
.usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform,
|
||||
.size = @sizeOf(TCamera.Uniform),
|
||||
}) orelse return error.Buffer;
|
||||
|
||||
// --- VIEW ---
|
||||
const view: math.Mat4x4 = if (e.transform3D) |t3| cmp: { // 3D
|
||||
const eye = t3.position;
|
||||
const forward = t3.rotation.rotate(math.Vec3f.new(.{ 0, 0, 1 }));
|
||||
const up = t3.rotation.rotate(math.Vec3f.new(.{ 0, 1, 0 }));
|
||||
break :cmp math.Mat4x4.lookAt(eye, eye.add(forward), up);
|
||||
} else if (e.transform2D) |t2| cmp: { // 2D
|
||||
const eye: math.Vec3f = .new(.{ t2.position.value[0], t2.position.value[1], 0 });
|
||||
break :cmp math.Mat4x4.rotateZ(-t2.angle)
|
||||
.mul(math.Mat4x4.translate(-eye.value[0], -eye.value[1], 0));
|
||||
} else math.Mat4x4.identity();
|
||||
|
||||
// --- PROJECTION ---
|
||||
const projection: math.Mat4x4 = switch (e.camera.projection) {
|
||||
.perspective => |v| .perspective(std.math.degreesToRadians(v.fov), 800.0 / 600.0, v.near, v.far),
|
||||
.ortho => |v| .orthographic(800.0, 0, 600.0, 0, v.near, v.far),
|
||||
};
|
||||
|
||||
// --- WRITE TO UNIFORM ---
|
||||
wgpu.wgpuQueueWriteBuffer(
|
||||
res.device.queue,
|
||||
uniform,
|
||||
0,
|
||||
&TCamera.Uniform{
|
||||
.view = view.transpose(),
|
||||
.projection = projection.transpose(),
|
||||
},
|
||||
@sizeOf(TCamera.Uniform),
|
||||
);
|
||||
|
||||
// --- BIND GROUP ---
|
||||
const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{
|
||||
.layout = res.render_layout.camera,
|
||||
.entryCount = 1,
|
||||
.entries = &[_]wgpu.WGPUBindGroupEntry{
|
||||
.{
|
||||
.binding = 0,
|
||||
.buffer = uniform,
|
||||
.offset = 0,
|
||||
.size = @sizeOf(TCamera.Uniform),
|
||||
},
|
||||
},
|
||||
}) orelse return error.BindGroup;
|
||||
|
||||
break :blk .{
|
||||
.buffer = uniform,
|
||||
.bind_group = bind_group,
|
||||
.dirty = false,
|
||||
};
|
||||
});
|
||||
|
||||
// --- FRAME ---
|
||||
try res.render_world.frame_views.append(.{
|
||||
.order = e.camera.order,
|
||||
.priority = e.camera.priority,
|
||||
.camera = query.entity(),
|
||||
.raw = raw,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn objects(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
render_world: *RenderWorld,
|
||||
render_layout: *RenderLayout,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = res.world.query(struct {
|
||||
mesh: *const CMesh,
|
||||
material: *const CMaterial,
|
||||
transform2D: ?*const Transform2D,
|
||||
transform3D: ?*const Transform3D,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- ENSURE TRANSFORM ---
|
||||
if (e.transform2D == null and
|
||||
e.transform3D == null) continue;
|
||||
|
||||
// --- GPU ---
|
||||
_ = try res.render_world.gpu_objects.getOrPut(query.entity(), blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_objects.getByKey(
|
||||
query.entity(),
|
||||
)) |v| break :blk v.*;
|
||||
|
||||
// --- UNIFORM ---
|
||||
const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{
|
||||
.usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform,
|
||||
.size = @sizeOf(TMesh.Uniform),
|
||||
}) orelse return error.Buffer;
|
||||
|
||||
// --- MODEL ---
|
||||
const pos: math.Vec3f = e.transform3D.?.position;
|
||||
const scl: math.Vec3f = e.transform3D.?.scale;
|
||||
const rot: math.Quat = e.transform3D.?.rotation;
|
||||
|
||||
// --- FINAL MODEL ---
|
||||
const model =
|
||||
math.Mat4x4.translate(pos.value[0], pos.value[1], pos.value[2])
|
||||
.mul(rot.toMat4())
|
||||
.mul(math.Mat4x4.scale(scl.value[0], scl.value[1], scl.value[2]));
|
||||
|
||||
// --- WRITE TO UNIFORM ---
|
||||
wgpu.wgpuQueueWriteBuffer(
|
||||
res.device.queue,
|
||||
uniform,
|
||||
0,
|
||||
&TMesh.Uniform{
|
||||
.data = model.transpose(),
|
||||
},
|
||||
@sizeOf(TMesh.Uniform),
|
||||
);
|
||||
|
||||
// --- BIND GROUP ---
|
||||
const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{
|
||||
.layout = res.render_layout.model,
|
||||
.entryCount = 1,
|
||||
.entries = &[_]wgpu.WGPUBindGroupEntry{
|
||||
.{
|
||||
.binding = 0,
|
||||
.buffer = uniform,
|
||||
.offset = 0,
|
||||
.size = @sizeOf(TMesh.Uniform),
|
||||
},
|
||||
},
|
||||
}) orelse return error.BindGroup;
|
||||
|
||||
break :blk .{
|
||||
.buffer = uniform,
|
||||
.bind_group = bind_group,
|
||||
.dirty = false,
|
||||
};
|
||||
});
|
||||
|
||||
// --- FRAME ---
|
||||
try res.render_world.frame_objects.append(.{
|
||||
.mesh = e.mesh.value,
|
||||
.entity = query.entity(),
|
||||
.material = e.material.value,
|
||||
.transform = blk: {
|
||||
if (e.transform2D) |v| break :blk .{ .@"2D" = v.* };
|
||||
if (e.transform3D) |v| break :blk .{ .@"3D" = v.* };
|
||||
break :blk .{ .@"2D" = .{} };
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn shaders(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
render_world: *RenderWorld,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = res.world.query(struct {
|
||||
material: *const CMaterial,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- GET MATERIAL ---
|
||||
const material = res.render_world.materials.get(
|
||||
e.material.value,
|
||||
) orelse return error.MaterialNotFound;
|
||||
|
||||
// --- ENSURE SHADER ---
|
||||
_ = try res.render_world.gpu_shaders.getOrPut(material.unique.shader, blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_shaders.contains(
|
||||
material.unique.shader,
|
||||
)) return;
|
||||
|
||||
// --- CODE ---
|
||||
const code: []const u8 = switch (material.unique.shader) {
|
||||
.pbr => RenderWorld.PBRCode,
|
||||
.unlit => RenderWorld.UnlitCode,
|
||||
.custom => return error.TooLazyToImplement, // TODO: Yes
|
||||
};
|
||||
|
||||
// --- SOURCE ---
|
||||
var source: wgpu.WGPUShaderSourceWGSL = .{
|
||||
.chain = .{ .sType = wgpu.WGPUSType_ShaderSourceWGSL },
|
||||
.code = .{ .data = code.ptr, .length = wgpu.WGPU_STRLEN },
|
||||
};
|
||||
|
||||
// --- RESULT ---
|
||||
break :blk .{
|
||||
.raw = wgpu.wgpuDeviceCreateShaderModule(res.device.raw, &wgpu.WGPUShaderModuleDescriptor{
|
||||
.label = .{ .data = @tagName(material.unique.shader), .length = wgpu.WGPU_STRLEN },
|
||||
.nextInChain = &source.chain,
|
||||
}) orelse {
|
||||
return error.ShaderModuleCreationFailed;
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn pipelines(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
render_world: *RenderWorld,
|
||||
render_layout: *RenderLayout,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = res.world.query(struct {
|
||||
material: *const CMaterial,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- GET MATERIAL ---
|
||||
const material = res.render_world.materials.get(
|
||||
e.material.value,
|
||||
) orelse return error.MaterialNotFound;
|
||||
|
||||
// --- ENSURE PIPELINE ---
|
||||
_ = try res.render_world.gpu_pipelines.getOrPut(material.unique, blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_pipelines.contains(
|
||||
material.unique,
|
||||
)) return;
|
||||
|
||||
// --- LAYOUT ---
|
||||
var bind_group_layouts = [_]wgpu.WGPUBindGroupLayout{
|
||||
res.render_layout.camera,
|
||||
res.render_layout.model,
|
||||
res.render_layout.material,
|
||||
};
|
||||
|
||||
// --- PIPELINE LAYOUT ---
|
||||
const pipeline_layout = wgpu.wgpuDeviceCreatePipelineLayout(
|
||||
res.device.raw,
|
||||
&wgpu.WGPUPipelineLayoutDescriptor{
|
||||
.bindGroupLayoutCount = 3,
|
||||
.bindGroupLayouts = &bind_group_layouts,
|
||||
},
|
||||
) orelse return error.Layout;
|
||||
|
||||
// --- CREATE PIPELINE ---
|
||||
const pipeline = try createPipeline(
|
||||
material.unique,
|
||||
pipeline_layout,
|
||||
if (res.render_world.gpu_shaders.getByKey(
|
||||
material.unique.shader,
|
||||
)) |v| v.raw else return error.ShaderNotFound,
|
||||
res.device.raw,
|
||||
);
|
||||
|
||||
// --- RESULT ---
|
||||
break :blk .{
|
||||
.raw = pipeline,
|
||||
.layout = pipeline_layout,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn materials(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
render_world: *RenderWorld,
|
||||
render_layout: *RenderLayout,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = res.world.query(struct {
|
||||
material: *const CMaterial,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- ENSURE MATERIAL ---
|
||||
_ = try res.render_world.gpu_materials.getOrPut(
|
||||
e.material.value,
|
||||
blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_materials.contains(
|
||||
e.material.value,
|
||||
)) return;
|
||||
|
||||
// --- # ---
|
||||
const material = res.render_world.materials.get(
|
||||
e.material.value,
|
||||
) orelse return error.MaterialNotFound;
|
||||
|
||||
// --- UNIFORM ---
|
||||
const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{
|
||||
.usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform,
|
||||
.size = @sizeOf(TMaterial.Style),
|
||||
}) orelse return error.Buffer;
|
||||
|
||||
// --- WRITE TO UNIFORM ---
|
||||
wgpu.wgpuQueueWriteBuffer(
|
||||
res.device.queue,
|
||||
uniform,
|
||||
0,
|
||||
&material.style,
|
||||
@sizeOf(TMaterial.Style),
|
||||
);
|
||||
|
||||
// --- BIND GROUP ---
|
||||
const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{
|
||||
.layout = res.render_layout.material,
|
||||
.entryCount = 1,
|
||||
.entries = &[_]wgpu.WGPUBindGroupEntry{
|
||||
.{
|
||||
.binding = 0,
|
||||
.buffer = uniform,
|
||||
.offset = 0,
|
||||
.size = @sizeOf(TMaterial.Style),
|
||||
},
|
||||
},
|
||||
}) orelse return error.BindGroup;
|
||||
|
||||
// --- RESULT ---
|
||||
break :blk .{
|
||||
.buffer = uniform,
|
||||
.bind_group = bind_group,
|
||||
.dirty = false,
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn createPipeline(
|
||||
key: TMaterial.Unique,
|
||||
layout: *wgpu.WGPUPipelineLayoutImpl,
|
||||
shader: *wgpu.WGPUShaderModuleImpl,
|
||||
device: *wgpu.WGPUDeviceImpl,
|
||||
) !*wgpu.WGPURenderPipelineImpl {
|
||||
return wgpu.wgpuDeviceCreateRenderPipeline(device, &wgpu.WGPURenderPipelineDescriptor{
|
||||
.label = .{ .data = @tagName(key.shader), .length = wgpu.WGPU_STRLEN },
|
||||
.layout = layout,
|
||||
.vertex = .{
|
||||
.module = shader,
|
||||
.entryPoint = .{ .data = "vs_main", .length = wgpu.WGPU_STRLEN },
|
||||
.bufferCount = 1,
|
||||
.buffers = &wgpu.WGPUVertexBufferLayout{
|
||||
.attributeCount = 3,
|
||||
.attributes = &[_]wgpu.WGPUVertexAttribute{ // TODO: Mabe mabe allow for custom, mabe mabe later tho
|
||||
.{
|
||||
.format = wgpu.WGPUVertexFormat_Float32x3,
|
||||
.offset = @offsetOf(Vertex, "position"),
|
||||
.shaderLocation = 0,
|
||||
},
|
||||
.{
|
||||
.format = wgpu.WGPUVertexFormat_Float32x3,
|
||||
.offset = @offsetOf(Vertex, "normal"),
|
||||
.shaderLocation = 1,
|
||||
},
|
||||
.{
|
||||
.format = wgpu.WGPUVertexFormat_Float32x2,
|
||||
.offset = @offsetOf(Vertex, "uv"),
|
||||
.shaderLocation = 2,
|
||||
},
|
||||
},
|
||||
.arrayStride = @sizeOf(Vertex),
|
||||
.stepMode = wgpu.WGPUVertexStepMode_Vertex,
|
||||
},
|
||||
},
|
||||
.fragment = &wgpu.WGPUFragmentState{
|
||||
.module = shader,
|
||||
.entryPoint = .{ .data = "fs_main", .length = wgpu.WGPU_STRLEN },
|
||||
.targetCount = 1,
|
||||
.targets = &wgpu.WGPUColorTargetState{
|
||||
.format = 28, // FIX: Use proper format
|
||||
.blend = &wgpu.WGPUBlendState{
|
||||
.color = .{
|
||||
.srcFactor = wgpu.WGPUBlendFactor_SrcAlpha,
|
||||
.dstFactor = wgpu.WGPUBlendFactor_OneMinusSrcAlpha,
|
||||
.operation = wgpu.WGPUBlendOperation_Add,
|
||||
},
|
||||
.alpha = .{
|
||||
.srcFactor = wgpu.WGPUBlendFactor_Zero,
|
||||
.dstFactor = wgpu.WGPUBlendFactor_One,
|
||||
.operation = wgpu.WGPUBlendOperation_Add,
|
||||
},
|
||||
},
|
||||
.writeMask = wgpu.WGPUColorWriteMask_All,
|
||||
},
|
||||
},
|
||||
.primitive = .{
|
||||
.topology = switch (key.topology) {
|
||||
.triangle_list => wgpu.WGPUPrimitiveTopology_TriangleList,
|
||||
.point_list => wgpu.WGPUPrimitiveTopology_PointList,
|
||||
.line_list => wgpu.WGPUPrimitiveTopology_LineList,
|
||||
},
|
||||
.frontFace = switch (key.front_face) {
|
||||
.ccw => wgpu.WGPUFrontFace_CCW,
|
||||
.cw => wgpu.WGPUFrontFace_CW,
|
||||
},
|
||||
.cullMode = switch (key.cull_mode) {
|
||||
.back => wgpu.WGPUCullMode_Back,
|
||||
.front => wgpu.WGPUCullMode_Front,
|
||||
.none => wgpu.WGPUCullMode_None,
|
||||
},
|
||||
},
|
||||
.multisample = .{
|
||||
.count = 1,
|
||||
.mask = ~@as(u32, 0),
|
||||
.alphaToCoverageEnabled = 0,
|
||||
},
|
||||
// .depthStencil = &wgpu.WGPUDepthStencilState{
|
||||
// .format = wgpu.WGPUTextureFormat_Depth24Plus,
|
||||
// .depthCompare = wgpu.WGPUCompareFunction_Less,
|
||||
// .depthWriteEnabled = 1,
|
||||
//
|
||||
// .stencilReadMask = 0,
|
||||
// .stencilWriteMask = 0,
|
||||
// },
|
||||
}) orelse {
|
||||
return error.PipelineCreationFailed;
|
||||
};
|
||||
}
|
||||
160
src/plugins/renderer.depricated/system/present.zig
Normal file
160
src/plugins/renderer.depricated/system/present.zig
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const wgpu = @import("wgpu");
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
|
||||
const GPUWindow = @import("../../window/resource/gpu_window.zig");
|
||||
const Resized = @import("../../window/event/resized.zig");
|
||||
const Device = @import("../../device/resource/wgpu_device.zig");
|
||||
const Renderer = @import("../resource/renderer.zig");
|
||||
const RenderWorld = @import("../resource/render_world.zig");
|
||||
const MeshCache = @import("../../cache/resource/mesh_cache.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn draw(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
window: *GPUWindow,
|
||||
device: *Device,
|
||||
renderer: *Renderer,
|
||||
render_world: *RenderWorld,
|
||||
mesh_cache: *MeshCache,
|
||||
});
|
||||
|
||||
// --- DO NONE ON WINDOW RESIZE ---
|
||||
if (app.events.consume(Resized)) |_| {
|
||||
return;
|
||||
}
|
||||
|
||||
// --- SURFACE TEXTURE ---
|
||||
var surface_texture: wgpu.WGPUSurfaceTexture = .{};
|
||||
defer wgpu.wgpuTextureRelease(surface_texture.texture);
|
||||
|
||||
// --- GET SURFACE TEXTURE ---
|
||||
wgpu.wgpuSurfaceGetCurrentTexture(
|
||||
@ptrCast(res.window.surface),
|
||||
&surface_texture,
|
||||
);
|
||||
|
||||
// --- DEBUG ---
|
||||
switch (surface_texture.status) {
|
||||
wgpu.WGPUSurfaceGetCurrentTextureStatus_Error => {
|
||||
std.debug.print("\x1b[31m[SURFACE_TEXTURE_ERROR]\x1b[0m\n", .{});
|
||||
},
|
||||
wgpu.WGPUSurfaceGetCurrentTextureStatus_Outdated => {
|
||||
std.debug.print("\x1b[31m[SURFACE_TEXTURE_OUTDATED]\x1b[0m\n", .{});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
// --- 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;
|
||||
var camera: ?World.Entity = 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 = switch (v.load_op) {
|
||||
.load => wgpu.WGPULoadOp_Load,
|
||||
.clear => wgpu.WGPULoadOp_Clear,
|
||||
},
|
||||
.storeOp = switch (v.store_op) {
|
||||
.store => wgpu.WGPUStoreOp_Store,
|
||||
.discard => wgpu.WGPUStoreOp_Discard,
|
||||
},
|
||||
.clearValue = .{
|
||||
.r = v.color[0],
|
||||
.g = v.color[1],
|
||||
.b = v.color[2],
|
||||
.a = v.color[3],
|
||||
},
|
||||
.depthSlice = wgpu.WGPU_DEPTH_SLICE_UNDEFINED,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// --- SET CAMERA ---
|
||||
camera = v.camera;
|
||||
},
|
||||
.end_pass => {
|
||||
if (render_pass) |rp| {
|
||||
wgpu.wgpuRenderPassEncoderEnd(rp);
|
||||
wgpu.wgpuRenderPassEncoderRelease(rp);
|
||||
render_pass = null;
|
||||
}
|
||||
},
|
||||
.draw => |v| {
|
||||
// --- ENSURE ---
|
||||
const material = res.render_world.materials.get(v.material) orelse return error.MaterialNotFound;
|
||||
const gpu_material = res.render_world.gpu_materials.getByKey(v.material) orelse return error.GPUMaterialNotFound;
|
||||
const gpu_camera = res.render_world.gpu_cameras.getByKey(camera orelse return error.CameraNotSet) orelse return error.GPUCameraNotFound;
|
||||
const pipeline = res.render_world.gpu_pipelines.getByKey(material.unique) orelse return error.GPUPipelineNotFound;
|
||||
const gpu_mesh = res.render_world.gpu_objects.getByKey(v.entity) orelse return error.GPUMeshNotFound;
|
||||
const mesh = try res.mesh_cache.getOrCreate(v.mesh);
|
||||
|
||||
// --- BIND ---
|
||||
wgpu.wgpuRenderPassEncoderSetPipeline(render_pass, pipeline.raw);
|
||||
wgpu.wgpuRenderPassEncoderSetVertexBuffer(render_pass, 0, mesh.vbuf, 0, wgpu.wgpuBufferGetSize(mesh.vbuf));
|
||||
|
||||
// --- BIND SHADER GROUPS ---
|
||||
wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 0, gpu_camera.bind_group, 0, null);
|
||||
wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 1, gpu_mesh.bind_group, 0, null);
|
||||
wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 2, gpu_material.bind_group, 0, null);
|
||||
|
||||
// --- DRAW ---
|
||||
if (mesh.ibuf) |ibuf| {
|
||||
wgpu.wgpuRenderPassEncoderSetIndexBuffer(render_pass, ibuf, wgpu.WGPUIndexFormat_Uint32, 0, wgpu.wgpuBufferGetSize(ibuf));
|
||||
wgpu.wgpuRenderPassEncoderDrawIndexed(render_pass, mesh.index_count, 1, 0, 0, 0);
|
||||
} else {
|
||||
wgpu.wgpuRenderPassEncoderDraw(render_pass, mesh.vertex_count, 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));
|
||||
}
|
||||
14
src/plugins/renderer.depricated/template/edge.zig
Normal file
14
src/plugins/renderer.depricated/template/edge.zig
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const gtl = @import("gtl");
|
||||
const Node = @import("node.zig");
|
||||
const Slot = @import("slot.zig");
|
||||
const Handle = gtl.Handle;
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Edge = union(enum) {
|
||||
data: struct { producer: Handle(Slot), consumer: Handle(Slot) },
|
||||
order: struct { from: Handle(Node), to: Handle(Node) },
|
||||
};
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
//! ----------------------------------------------------
|
||||
|
||||
const gtl = @import("gtl");
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
const Material = @import("material.zig");
|
||||
const Transform2D = @import("../../common/component/transform2D.zig");
|
||||
const Transform3D = @import("../../common/component/transform3D.zig");
|
||||
|
|
@ -13,7 +15,7 @@ const Handle = gtl.Handle;
|
|||
//
|
||||
|
||||
mesh: MeshID,
|
||||
entity: u64, // TODO: Change to Entity type
|
||||
entity: World.Entity,
|
||||
material: Handle(Material),
|
||||
transform: union(enum) {
|
||||
@"2D": Transform2D,
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
const App = @import("app");
|
||||
const GPUCamera = @import("gpu_camera.zig");
|
||||
const World = @import("world");
|
||||
|
||||
raw: *GPUCamera,
|
||||
order: u32 = 0,
|
||||
priority: u32 = 0,
|
||||
camera: u64, // TODO: Change to ENTITY Type
|
||||
camera: World.Entity,
|
||||
16
src/plugins/renderer.depricated/template/node.zig
Normal file
16
src/plugins/renderer.depricated/template/node.zig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const gtl = @import("gtl");
|
||||
const Slot = @import("slot.zig");
|
||||
const RenderCTX = @import("render_ctx.zig");
|
||||
const Handle = gtl.Handle;
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
name: []const u8,
|
||||
inputs: []const Handle(Slot) = &.{},
|
||||
outputs: []const Handle(Slot) = &.{},
|
||||
run: *const fn (*RenderCTX) anyerror!void,
|
||||
14
src/plugins/renderer.depricated/template/render_ctx.zig
Normal file
14
src/plugins/renderer.depricated/template/render_ctx.zig
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const wgpu = @import("wgpu");
|
||||
const RenderGraph = @import("../resource/render_graph.zig");
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
device: *wgpu.WGPUDeviceImpl,
|
||||
encoder: *wgpu.WGPUCommandEncoderImpl,
|
||||
|
||||
graph: *const RenderGraph,
|
||||
19
src/plugins/renderer.depricated/template/slot.zig
Normal file
19
src/plugins/renderer.depricated/template/slot.zig
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const wgpu = @import("wgpu");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Value = union(enum) {
|
||||
buffer: *wgpu.WGPUBufferImpl,
|
||||
bind_group: *wgpu.WGPUBindGroupImpl,
|
||||
texture_view: *wgpu.WGPUTextureViewImpl,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
name: []const u8,
|
||||
value: ?Value = null,
|
||||
54
src/plugins/renderer/resource/bind_group_cache.zig
Normal file
54
src/plugins/renderer/resource/bind_group_cache.zig
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const wgpu = @import("wgpu");
|
||||
const MaterialAsset = @import("material_assets.zig").Asset;
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const GPUBindGroup = struct {
|
||||
raw: *wgpu.WGPUBindGroupImpl,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
const BindingRef = union(enum) {
|
||||
buffer: struct {},
|
||||
texture_view: u64,
|
||||
sampler: u64,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const BindGroup = struct {
|
||||
layout: u64,
|
||||
bindings: []const BindingRef,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
groups: std.AutoHashMap(BindGroup, GPUBindGroup),
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.groups = .init(alloc),
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
var it = self.groups.valueIterator();
|
||||
while (it.next()) |group| {
|
||||
wgpu.wgpuBindGroupRelease(group.raw);
|
||||
}
|
||||
self.groups.deinit();
|
||||
}
|
||||
|
|
@ -1,80 +1,17 @@
|
|||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3f,
|
||||
@location(1) normal: vec3f,
|
||||
@location(2) uv: vec2f,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct VertexOutput {
|
||||
@builtin(position) position: vec4f,
|
||||
@location(0) uv: vec2f,
|
||||
@location(1) normal: vec3f,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct CameraUniform {
|
||||
view: mat4x4<f32>,
|
||||
projection: mat4x4<f32>,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct ModelUniform {
|
||||
data: mat4x4<f32>,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct Material {
|
||||
albedo: vec4f,
|
||||
metallic: f32,
|
||||
roughness: f32,
|
||||
_pad0: vec2f,
|
||||
};
|
||||
|
||||
//
|
||||
// UNIFORMS
|
||||
//
|
||||
|
||||
@group(0) @binding(0)
|
||||
var<uniform> camera: CameraUniform;
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> model: ModelUniform;
|
||||
|
||||
@group(2) @binding(0)
|
||||
var<uniform> material: Material;
|
||||
|
||||
//
|
||||
// VERTEX
|
||||
//
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
// --- # ---
|
||||
var out: VertexOutput;
|
||||
|
||||
// --- # ---
|
||||
out.position = camera.projection * camera.view * model.data * vec4f(in.position, 1.0);
|
||||
out.uv = in.uv;
|
||||
out.normal = in.normal;
|
||||
|
||||
// --- # ---
|
||||
return out;
|
||||
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4f {
|
||||
var p = vec2f(0.0, 0.0);
|
||||
if in_vertex_index == 0u {
|
||||
p = vec2f(-0.5, -0.5);
|
||||
} else if in_vertex_index == 1u {
|
||||
p = vec2f(0.5, -0.5);
|
||||
} else {
|
||||
p = vec2f(0.0, 0.5);
|
||||
}
|
||||
return vec4f(p, 0.0, 1.0);
|
||||
}
|
||||
|
||||
//
|
||||
// FRAGMENT
|
||||
//
|
||||
|
||||
@fragment
|
||||
fn fs_main(out: VertexOutput) -> @location(0) vec4f {
|
||||
var final_color: vec4f = material.albedo;
|
||||
final_color.x += out.uv.x * 0.2;
|
||||
final_color.y += out.uv.y * 0.2;
|
||||
return vec4f(final_color);
|
||||
fn fs_main() -> @location(0) vec4f {
|
||||
return vec4f(0.0, 0.4, 1.0, 1.0);
|
||||
}
|
||||
|
|
|
|||
80
src/plugins/renderer/resource/embeded/shaders/pbr.wgsl.old
Normal file
80
src/plugins/renderer/resource/embeded/shaders/pbr.wgsl.old
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3f,
|
||||
@location(1) normal: vec3f,
|
||||
@location(2) uv: vec2f,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct VertexOutput {
|
||||
@builtin(position) position: vec4f,
|
||||
@location(0) uv: vec2f,
|
||||
@location(1) normal: vec3f,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct CameraUniform {
|
||||
view: mat4x4<f32>,
|
||||
projection: mat4x4<f32>,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct ModelUniform {
|
||||
data: mat4x4<f32>,
|
||||
};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ----------------------------------------------------
|
||||
struct Material {
|
||||
albedo: vec4f,
|
||||
metallic: f32,
|
||||
roughness: f32,
|
||||
_pad0: vec2f,
|
||||
};
|
||||
|
||||
//
|
||||
// UNIFORMS
|
||||
//
|
||||
|
||||
@group(0) @binding(0)
|
||||
var<uniform> camera: CameraUniform;
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> model: ModelUniform;
|
||||
|
||||
@group(2) @binding(0)
|
||||
var<uniform> material: Material;
|
||||
|
||||
//
|
||||
// VERTEX
|
||||
//
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
// --- # ---
|
||||
var out: VertexOutput;
|
||||
|
||||
// --- # ---
|
||||
out.position = camera.projection * camera.view * model.data * vec4f(in.position, 1.0);
|
||||
out.uv = in.uv;
|
||||
out.normal = in.normal;
|
||||
|
||||
// --- # ---
|
||||
return out;
|
||||
}
|
||||
|
||||
//
|
||||
// FRAGMENT
|
||||
//
|
||||
|
||||
@fragment
|
||||
fn fs_main(out: VertexOutput) -> @location(0) vec4f {
|
||||
var final_color: vec4f = material.albedo;
|
||||
final_color.x += out.uv.x * 0.2;
|
||||
final_color.y += out.uv.y * 0.2;
|
||||
return vec4f(final_color);
|
||||
}
|
||||
13
src/plugins/renderer/resource/gpu_frame.zig
Normal file
13
src/plugins/renderer/resource/gpu_frame.zig
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//! ----------------------------------------------------
|
||||
//! GPU Frame data
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const wgpu = @import("wgpu");
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
surface_texture: wgpu.WGPUSurfaceTexture = .{},
|
||||
target_view: *wgpu.WGPUTextureViewImpl = undefined,
|
||||
encoder: *wgpu.WGPUCommandEncoderImpl = undefined,
|
||||
89
src/plugins/renderer/resource/material_assets.zig
Normal file
89
src/plugins/renderer/resource/material_assets.zig
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const ShaderID = @import("shader_cache.zig").ShaderID;
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Asset = struct {
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Style = struct {
|
||||
albedo: @Vector(4, f32) = .{ 1, 1, 1, 1 },
|
||||
metallic: f32 = 0.0,
|
||||
roughness: f32 = 0.5,
|
||||
_pad0: [2]f32 = .{ 0, 0 },
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Unique = struct {
|
||||
shader: ShaderID = .pbr,
|
||||
|
||||
front_face: enum {
|
||||
cw,
|
||||
ccw,
|
||||
} = .ccw,
|
||||
|
||||
cull_mode: enum {
|
||||
back,
|
||||
front,
|
||||
none,
|
||||
} = .back,
|
||||
|
||||
topology: enum {
|
||||
triangle_list,
|
||||
point_list,
|
||||
line_list,
|
||||
} = .triangle_list,
|
||||
|
||||
blend_mode: enum {
|
||||
none,
|
||||
alpha,
|
||||
additive,
|
||||
multiply,
|
||||
} = .none,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
style: Style = .{},
|
||||
unique: Unique = .{},
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
assets: gtl.SlotMap(Asset),
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.assets = .init(alloc),
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.assets.deinit();
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn put(self: *Self, asset: Asset) !gtl.Handle(Asset) {
|
||||
return try self.assets.put(asset);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn get(self: *Self, handle: gtl.Handle(Asset)) ?*Asset {
|
||||
return self.assets.get(handle);
|
||||
}
|
||||
41
src/plugins/renderer/resource/material_cache.zig
Normal file
41
src/plugins/renderer/resource/material_cache.zig
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const wgpu = @import("wgpu");
|
||||
const MaterialAsset = @import("material_assets.zig").Asset;
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const GPUMaterial = struct {
|
||||
uniform_buffer: u64,
|
||||
bind_group: *wgpu.WGPUBindGroupImpl,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
map: std.AutoHashMap(gtl.Handle(MaterialAsset), GPUMaterial),
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.map = .init(alloc),
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
var it = self.map.valueIterator();
|
||||
while (it.next()) |gpu| {
|
||||
wgpu.wgpuBindGroupRelease(gpu.bind_group);
|
||||
}
|
||||
self.map.deinit();
|
||||
}
|
||||
52
src/plugins/renderer/resource/mesh_assets.zig
Normal file
52
src/plugins/renderer/resource/mesh_assets.zig
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Asset = struct {
|
||||
pub const MeshID = union(enum) {
|
||||
cube,
|
||||
quad,
|
||||
square,
|
||||
triangle,
|
||||
custom: u32, // TODO: idk, someday
|
||||
};
|
||||
|
||||
mesh: MeshID = .cube,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
assets: gtl.SlotMap(Asset),
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.assets = .init(alloc),
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.assets.deinit();
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn put(self: *Self, asset: Asset) !gtl.Handle(Asset) {
|
||||
return try self.assets.put(asset);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn get(self: *Self, handle: gtl.Handle(Asset)) ?*Asset {
|
||||
return self.assets.get(handle);
|
||||
}
|
||||
47
src/plugins/renderer/resource/pipeline_cache.zig
Normal file
47
src/plugins/renderer/resource/pipeline_cache.zig
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const wgpu = @import("wgpu");
|
||||
const ShaderID = @import("shader_cache.zig").ShaderID;
|
||||
const MaterialAsset = @import("material_assets.zig").Asset;
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const GPUPipeline = struct {
|
||||
raw: *wgpu.WGPURenderPipelineImpl,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// TODO: Add layout
|
||||
/// ----------------------------------------------------
|
||||
pub const Pipeline = struct {
|
||||
unique: MaterialAsset.Unique,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
data: std.AutoHashMap(Pipeline, GPUPipeline),
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.data = .init(alloc),
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
var it = self.data.valueIterator();
|
||||
while (it.next()) |pipe| {
|
||||
wgpu.wgpuRenderPipelineRelease(pipe.raw);
|
||||
}
|
||||
self.data.deinit();
|
||||
}
|
||||
47
src/plugins/renderer/resource/render_data.zig
Normal file
47
src/plugins/renderer/resource/render_data.zig
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
//! ----------------------------------------------------
|
||||
//! RenderData -> RenderPhase -> Present
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const math = @import("math");
|
||||
const World = @import("world");
|
||||
const MeshAsset = @import("mesh_assets.zig").Asset;
|
||||
const MaterialAsset = @import("material_assets.zig").Asset;
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const ExtractedMesh = struct {
|
||||
source: World.Entity,
|
||||
mesh: gtl.Handle(MeshAsset),
|
||||
material: gtl.Handle(MaterialAsset),
|
||||
transform: math.Mat4x4,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const ExtractedCamera = struct {
|
||||
source: World.Entity,
|
||||
|
||||
view: math.Mat4x4,
|
||||
projection: math.Mat4x4,
|
||||
clear_color: math.Color,
|
||||
|
||||
depth: struct { near: f32, far: f32 } = .{ .near = 0.05, .far = 4000.0 },
|
||||
active: bool = true,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
meshes: std.ArrayList(ExtractedMesh) = .empty,
|
||||
cameras: std.ArrayList(ExtractedCamera) = .empty,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn clear(self: *Self) void {
|
||||
self.meshes.clearRetainingCapacity();
|
||||
self.cameras.clearRetainingCapacity();
|
||||
}
|
||||
359
src/plugins/renderer/resource/render_graph.zig
Normal file
359
src/plugins/renderer/resource/render_graph.zig
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const math = @import("math");
|
||||
const wgpu = @import("wgpu");
|
||||
|
||||
const PipelineCache = @import("pipeline_cache.zig");
|
||||
|
||||
const Handle = gtl.Handle;
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Node = struct {
|
||||
name: []const u8,
|
||||
inputs: std.ArrayList(Handle(Slot)) = .empty,
|
||||
outputs: std.ArrayList(Handle(Slot)) = .empty,
|
||||
run: *const fn (*RenderCTX) anyerror!void,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Edge = union(enum) {
|
||||
data: struct {
|
||||
producer: Handle(Slot),
|
||||
consumer: Handle(Slot),
|
||||
},
|
||||
order: struct {
|
||||
from: Handle(Node),
|
||||
to: Handle(Node),
|
||||
},
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const Slot = struct {
|
||||
pub const Value = union(enum) {
|
||||
buffer: *wgpu.WGPUBufferImpl,
|
||||
sampler: *wgpu.WGPUSamplerImpl,
|
||||
texture_view: *wgpu.WGPUTextureViewImpl,
|
||||
};
|
||||
|
||||
name: []const u8,
|
||||
value: ?Value = null,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const RenderCTX = struct {
|
||||
// --- CORE ---
|
||||
app: *App,
|
||||
world: *World,
|
||||
graph: *Self,
|
||||
node: ?Handle(Node) = null,
|
||||
|
||||
// --- RAW ---
|
||||
device: *wgpu.WGPUDeviceImpl,
|
||||
encoder: *wgpu.WGPUCommandEncoderImpl,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn input(self: *RenderCTX, i: usize) !?Slot.Value {
|
||||
const n = self.node orelse return error.NodeNotSet;
|
||||
const node = self.graph.nodes.get(n) orelse return error.UnknownNode;
|
||||
if (i >= node.inputs.items.len) return error.SlotOutOfBounds;
|
||||
const slot = self.graph.slots.get(node.inputs.items[i]) orelse return error.UnknownSlot;
|
||||
return slot.value;
|
||||
}
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// TODO: create Encoder type instead that will return RenderPass
|
||||
/// ----------------------------------------------------
|
||||
pub const RenderPass = struct {
|
||||
raw: *wgpu.WGPURenderPassEncoderImpl,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn begin(
|
||||
view: *wgpu.WGPUTextureViewImpl,
|
||||
encoder: *wgpu.WGPUCommandEncoderImpl,
|
||||
color: math.Color,
|
||||
) !RenderPass {
|
||||
return .{
|
||||
.raw = wgpu.wgpuCommandEncoderBeginRenderPass(
|
||||
encoder,
|
||||
&wgpu.WGPURenderPassDescriptor{
|
||||
.colorAttachmentCount = 1,
|
||||
.colorAttachments = &wgpu.WGPURenderPassColorAttachment{
|
||||
.view = view,
|
||||
.resolveTarget = null,
|
||||
.loadOp = wgpu.WGPULoadOp_Clear,
|
||||
.storeOp = wgpu.WGPUStoreOp_Store,
|
||||
.clearValue = .{
|
||||
.r = color.r,
|
||||
.g = color.g,
|
||||
.b = color.b,
|
||||
.a = color.a,
|
||||
},
|
||||
.depthSlice = wgpu.WGPU_DEPTH_SLICE_UNDEFINED,
|
||||
},
|
||||
},
|
||||
) orelse return error.WGPURenderPassFailed,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn end(self: *const RenderPass) void {
|
||||
wgpu.wgpuRenderPassEncoderEnd(self.raw);
|
||||
wgpu.wgpuRenderPassEncoderRelease(self.raw);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn bindPipeline(self: *const RenderPass, pipe: *const PipelineCache.GPUPipeline) void {
|
||||
wgpu.wgpuRenderPassEncoderSetPipeline(self.raw, pipe.raw);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn draw(
|
||||
self: *const RenderPass,
|
||||
vertex_count: u32,
|
||||
instance_count: u32,
|
||||
) void {
|
||||
wgpu.wgpuRenderPassEncoderDraw(self.raw, vertex_count, instance_count, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
nodes: gtl.SlotMap(Node),
|
||||
edges: gtl.SlotMap(Edge),
|
||||
slots: gtl.SlotMap(Slot),
|
||||
|
||||
order: ?[]Handle(Node) = null,
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.nodes = .init(alloc),
|
||||
.edges = .init(alloc),
|
||||
.slots = .init(alloc),
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
var it = self.nodes.valueIterator();
|
||||
while (it.next()) |node| {
|
||||
node.inputs.deinit(self.alloc);
|
||||
node.outputs.deinit(self.alloc);
|
||||
}
|
||||
|
||||
self.nodes.deinit();
|
||||
self.edges.deinit();
|
||||
self.slots.deinit();
|
||||
|
||||
if (self.order) |order| {
|
||||
self.alloc.free(order);
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn run(
|
||||
self: *Self,
|
||||
ctx: *RenderCTX,
|
||||
) !void {
|
||||
if (self.order) |order| {
|
||||
for (order) |handle| {
|
||||
ctx.node = handle;
|
||||
const node = self.nodes.get(handle) orelse return error.UnknownNode;
|
||||
try node.run(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn addNode(self: *Self, node: Node) !Handle(Node) {
|
||||
self.order = null;
|
||||
return try self.nodes.put(node);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn addEdge(self: *Self, edge: Edge) !Handle(Edge) {
|
||||
self.order = null;
|
||||
return try self.edges.put(edge);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn addSlot(self: *Self, slot: Slot) !Handle(Slot) {
|
||||
self.order = null;
|
||||
return try self.slots.put(slot);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn addOrderEdge(self: *Self, from: Handle(Node), to: Handle(Node)) !void {
|
||||
_ = try self.addEdge(.{ .order = .{ .from = from, .to = to } });
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn addDataEdge(self: *Self, producer: Handle(Slot), consumer: Handle(Slot)) !void {
|
||||
_ = try self.addEdge(.{ .data = .{ .producer = producer, .consumer = consumer } });
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn addInput(self: *Self, node: Handle(Node), slot: Slot) !Handle(Slot) {
|
||||
const h = try self.slots.put(slot);
|
||||
try self.nodes.get(node).?.inputs.append(self.alloc, h);
|
||||
return h;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn compile(self: *Self) !void {
|
||||
if (self.order != null) return;
|
||||
|
||||
{ // --- VALIDATE EDGES ---
|
||||
var it = self.edges.valueIterator();
|
||||
while (it.next()) |edge| {
|
||||
switch (edge.*) {
|
||||
.data => |v| {
|
||||
if (!self.slots.contains(v.producer)) return error.UnknownSlot;
|
||||
if (!self.slots.contains(v.consumer)) return error.UnknownSlot;
|
||||
if (v.producer.eql(v.consumer)) return error.SelfLoop;
|
||||
},
|
||||
.order => |v| {
|
||||
if (!self.nodes.contains(v.from)) return error.UnknownNode;
|
||||
if (!self.nodes.contains(v.to)) return error.UnknownNode;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- SLOT OWNER ---
|
||||
var slot_owner = try self.buildSlotOwners();
|
||||
defer slot_owner.deinit();
|
||||
|
||||
// --- TOPO SORT ---
|
||||
var indegree: std.AutoHashMap(Handle(Node), u32) = .init(self.alloc);
|
||||
defer indegree.deinit();
|
||||
|
||||
var adj: std.AutoHashMap(Handle(Node), std.ArrayList(Handle(Node))) = .init(self.alloc);
|
||||
defer {
|
||||
var it = adj.valueIterator();
|
||||
while (it.next()) |l| l.deinit(self.alloc);
|
||||
adj.deinit();
|
||||
}
|
||||
|
||||
{
|
||||
var it = self.nodes.handleIterator();
|
||||
while (it.next()) |handle| {
|
||||
try indegree.put(handle, 0);
|
||||
try adj.put(handle, .empty);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var it = self.edges.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const from = switch (entry.value.*) {
|
||||
.data => |v| slot_owner.get(v.producer).?,
|
||||
.order => |v| v.from,
|
||||
};
|
||||
|
||||
const to = switch (entry.value.*) {
|
||||
.data => |v| slot_owner.get(v.consumer).?,
|
||||
.order => |v| v.to,
|
||||
};
|
||||
|
||||
const d = indegree.getPtr(to).?;
|
||||
d.* += 1;
|
||||
try adj.getPtr(from).?.append(self.alloc, to);
|
||||
}
|
||||
}
|
||||
|
||||
// --- NERDY SHIT ---
|
||||
|
||||
var order: std.ArrayList(Handle(Node)) = .empty;
|
||||
defer order.deinit(self.alloc);
|
||||
|
||||
var ready: std.ArrayList(Handle(Node)) = .empty;
|
||||
defer ready.deinit(self.alloc);
|
||||
|
||||
{
|
||||
var it = indegree.iterator();
|
||||
while (it.next()) |entry| {
|
||||
if (entry.value_ptr.* == 0) try ready.append(self.alloc, entry.key_ptr.*);
|
||||
}
|
||||
}
|
||||
|
||||
while (ready.pop()) |v| {
|
||||
try order.append(self.alloc, v);
|
||||
for (adj.get(v).?.items) |m| {
|
||||
const d = indegree.getPtr(m).?;
|
||||
d.* -= 1;
|
||||
if (d.* == 0) try ready.append(self.alloc, m);
|
||||
}
|
||||
}
|
||||
|
||||
if (order.items.len != self.nodes.len()) return error.CycleDetected;
|
||||
|
||||
// --- RESULT ---
|
||||
self.order = try order.toOwnedSlice(self.alloc);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn buildSlotOwners(self: *Self) !std.AutoHashMap(Handle(Slot), Handle(Node)) {
|
||||
// --- OWNERS ---
|
||||
var owners: std.AutoHashMap(Handle(Slot), Handle(Node)) = .init(self.alloc);
|
||||
errdefer owners.deinit();
|
||||
|
||||
{ // --- PORTS CHECK ---
|
||||
var it = self.nodes.iterator();
|
||||
while (it.next()) |entry| {
|
||||
// --- # ---
|
||||
const node_handle = entry.handle;
|
||||
const node: *const Node = entry.value;
|
||||
|
||||
// --- ENSURE STUFF ---
|
||||
const lists = [_][]const Handle(Slot){ node.inputs.items, node.outputs.items };
|
||||
for (lists) |list| for (list) |slot| {
|
||||
if (!self.slots.contains(slot)) return error.UnknownSlot;
|
||||
const gop = try owners.getOrPut(slot);
|
||||
if (gop.found_existing) return error.SlotHasMultipleOwners;
|
||||
gop.value_ptr.* = node_handle;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
{ // --- ORPHAN CHECK 🥀 ---
|
||||
var it = self.slots.handleIterator();
|
||||
while (it.next()) |handle| {
|
||||
if (!owners.contains(handle)) return error.OrphanSlot;
|
||||
}
|
||||
}
|
||||
|
||||
return owners;
|
||||
}
|
||||
33
src/plugins/renderer/resource/render_phase.zig
Normal file
33
src/plugins/renderer/resource/render_phase.zig
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
//! ----------------------------------------------------
|
||||
//! Final render data holder 💪
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const gtl = @import("gtl");
|
||||
const wgpu = @import("wgpu");
|
||||
const World = @import("world");
|
||||
const MaterialAsset = @import("material_assets.zig").Asset;
|
||||
const Self = @This();
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const DrawItem = struct {
|
||||
source: World.Entity,
|
||||
material: MaterialAsset.Unique,
|
||||
|
||||
// TODO: vbuf, ibuf, etc
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
opaques: std.ArrayList(DrawItem) = .empty,
|
||||
transparents: std.ArrayList(DrawItem) = .empty,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn clear(self: *Self) void {
|
||||
self.opaques.clearRetainingCapacity();
|
||||
self.transparents.clearRetainingCapacity();
|
||||
}
|
||||
35
src/plugins/renderer/resource/sampler_cache.zig
Normal file
35
src/plugins/renderer/resource/sampler_cache.zig
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const wgpu = @import("wgpu");
|
||||
const Self = @This();
|
||||
|
||||
pub const GPUSampler = struct { raw: *wgpu.WGPUSamplerImpl };
|
||||
pub const Sampler = struct { filter: u8, wrap: u8 };
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
map: std.AutoHashMap(Sampler, GPUSampler),
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.map = .init(alloc),
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
var it = self.map.valueIterator();
|
||||
while (it.next()) |sampler| {
|
||||
wgpu.wgpuSamplerRelease(sampler.raw);
|
||||
}
|
||||
self.map.deinit();
|
||||
}
|
||||
54
src/plugins/renderer/resource/shader_cache.zig
Normal file
54
src/plugins/renderer/resource/shader_cache.zig
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const wgpu = @import("wgpu");
|
||||
const Self = @This();
|
||||
|
||||
//
|
||||
// EMBEDED
|
||||
//
|
||||
|
||||
pub const PBRCode = @embedFile("embeded/shaders/pbr.wgsl");
|
||||
pub const UnlitCode = @embedFile("embeded/shaders/pbr.wgsl");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const ShaderID = union(enum) {
|
||||
pbr,
|
||||
unlit,
|
||||
custom: u32,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const GPUShader = struct {
|
||||
raw: *wgpu.WGPUShaderModuleImpl,
|
||||
};
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
modules: std.AutoHashMap(ShaderID, GPUShader),
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.modules = .init(alloc),
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
var it = self.modules.valueIterator();
|
||||
while (it.next()) |module| {
|
||||
wgpu.wgpuShaderModuleRelease(module.raw);
|
||||
}
|
||||
|
||||
self.modules.deinit();
|
||||
}
|
||||
26
src/plugins/renderer/resource/texture_cache.zig
Normal file
26
src/plugins/renderer/resource/texture_cache.zig
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
const std = @import("std");
|
||||
const wgpu = @import("wgpu");
|
||||
const Self = @This();
|
||||
|
||||
//
|
||||
// FIELDS
|
||||
//
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn deinit(self: *Self) void {
|
||||
_ = self;
|
||||
}
|
||||
|
|
@ -5,24 +5,44 @@
|
|||
// PRIVATE
|
||||
//
|
||||
|
||||
const App = @import("app");
|
||||
const std = @import("std");
|
||||
const wgpu = @import("wgpu");
|
||||
|
||||
const lifetime = @import("system/lifetime.zig");
|
||||
const frame = @import("system/frame.zig");
|
||||
const prepare = @import("system/prepare.zig");
|
||||
const present = @import("system/present.zig");
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
const Device = @import("../device/resource/wgpu_device.zig");
|
||||
const Window = @import("../window/resource/gpu_window.zig");
|
||||
|
||||
const extract_sys = @import("system/extract.zig");
|
||||
const prepare_sys = @import("system/prepare.zig");
|
||||
const present_sys = @import("system/present.zig");
|
||||
const queue_sys = @import("system/queue.zig");
|
||||
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
|
||||
const Renderer = @import("resource/renderer.zig");
|
||||
const RenderWorld = @import("resource/render_world.zig");
|
||||
const RenderLayout = @import("resource/render_layout.zig");
|
||||
// --- ASSETS ---
|
||||
pub const MeshAssets = @import("resource/mesh_assets.zig");
|
||||
pub const MaterialAssets = @import("resource/material_assets.zig");
|
||||
|
||||
// --- CACHE ---
|
||||
pub const SamplerCache = @import("resource/sampler_cache.zig");
|
||||
pub const TextureCache = @import("resource/texture_cache.zig");
|
||||
pub const MaterialCache = @import("resource/material_cache.zig");
|
||||
pub const ShaderCache = @import("resource/shader_cache.zig");
|
||||
pub const PipelineCache = @import("resource/pipeline_cache.zig");
|
||||
pub const BindGroupCache = @import("resource/bind_group_cache.zig");
|
||||
|
||||
// --- DRAW ---
|
||||
pub const GPUFrame = @import("resource/gpu_frame.zig");
|
||||
pub const RenderData = @import("resource/render_data.zig");
|
||||
pub const RenderPhase = @import("resource/render_phase.zig");
|
||||
pub const RenderGraph = @import("resource/render_graph.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Renderer",
|
||||
.build = build,
|
||||
};
|
||||
|
|
@ -30,27 +50,158 @@ pub const plugin: App.plugin.Plugin = .{
|
|||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
// --- LIFETIME ---
|
||||
try app.schedules.add(App.stage.init, lifetime.init);
|
||||
try app.schedules.add(App.stage.deinit, lifetime.deinit);
|
||||
try app.schedules.add(App.stage.init, init);
|
||||
try app.schedules.add(App.stage.deinit, deinit);
|
||||
try app.schedules.addMany(App.stage.update, &.{
|
||||
extract_sys.meshes,
|
||||
extract_sys.cameras,
|
||||
|
||||
// --- FRAME ---
|
||||
try app.schedules.add(App.stage.begin_frame, frame.begin);
|
||||
try app.schedules.add(App.stage.end_frame, frame.end);
|
||||
prepare_sys.shaders,
|
||||
prepare_sys.pipelines,
|
||||
|
||||
// --- PRE DRAW ---
|
||||
try app.schedules.addManyBefore(App.stage.draw, App.stage.draw, &.{
|
||||
prepare.shaders,
|
||||
prepare.pipelines,
|
||||
queue_sys.meshes,
|
||||
});
|
||||
try app.schedules.add(App.stage.draw, present_sys.draw);
|
||||
}
|
||||
|
||||
prepare.cameras,
|
||||
prepare.objects,
|
||||
prepare.materials,
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn init(app: *App) !void {
|
||||
// --- # ---
|
||||
try app.resources.set(MeshAssets.init(app.alloc));
|
||||
try app.resources.set(MaterialAssets.init(app.alloc));
|
||||
|
||||
// --- # ---
|
||||
try app.resources.set(SamplerCache.init(app.alloc));
|
||||
try app.resources.set(TextureCache.init(app.alloc));
|
||||
try app.resources.set(MaterialCache.init(app.alloc));
|
||||
try app.resources.set(ShaderCache.init(app.alloc));
|
||||
try app.resources.set(PipelineCache.init(app.alloc));
|
||||
try app.resources.set(BindGroupCache.init(app.alloc));
|
||||
|
||||
// --- # ---
|
||||
try app.resources.set(GPUFrame{});
|
||||
try app.resources.set(RenderData{});
|
||||
try app.resources.set(RenderPhase{});
|
||||
try app.resources.set(RenderGraph.init(app.alloc));
|
||||
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
device: *Device,
|
||||
window: *Window,
|
||||
render_graph: *RenderGraph,
|
||||
frame: *GPUFrame,
|
||||
});
|
||||
|
||||
// --- DRAW ---
|
||||
try app.schedules.add(App.stage.draw, present.draw);
|
||||
const clear = try res.render_graph.addNode(.{
|
||||
.name = "clear",
|
||||
.run = clearNode,
|
||||
});
|
||||
|
||||
// const main_color = try res.render_graph.addSlot(.{ .name = "main_color" });
|
||||
const main = try res.render_graph.addNode(.{
|
||||
.name = "main",
|
||||
// .outputs = &.{
|
||||
// main_color,
|
||||
// },
|
||||
.run = mainNode,
|
||||
});
|
||||
|
||||
// const present_target = try res.render_graph.addSlot(.{ .name = "present_target" });
|
||||
const present = try res.render_graph.addNode(.{
|
||||
.name = "present",
|
||||
// .inputs = &.{
|
||||
// present_target,
|
||||
// },
|
||||
.run = presentNode,
|
||||
});
|
||||
|
||||
try res.render_graph.addOrderEdge(clear, main);
|
||||
// try res.render_graph.addDataEdge(main_color, present_target);
|
||||
try res.render_graph.addOrderEdge(main, present);
|
||||
|
||||
// --- # ---
|
||||
try res.render_graph.compile();
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn deinit(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
mesh_assets: *MeshAssets,
|
||||
material_assets: *MaterialAssets,
|
||||
|
||||
shader_cache: *ShaderCache,
|
||||
pipeline_cache: *PipelineCache,
|
||||
|
||||
render_data: *RenderData,
|
||||
render_phase: *RenderPhase,
|
||||
render_graph: *RenderGraph,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
res.mesh_assets.deinit();
|
||||
res.material_assets.deinit();
|
||||
|
||||
// --- # ---
|
||||
res.shader_cache.deinit();
|
||||
res.pipeline_cache.deinit();
|
||||
|
||||
// --- # ---
|
||||
res.render_graph.deinit();
|
||||
res.render_data.meshes.deinit(app.alloc);
|
||||
res.render_data.cameras.deinit(app.alloc);
|
||||
res.render_phase.opaques.deinit(app.alloc);
|
||||
res.render_phase.transparents.deinit(app.alloc);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn clearNode(ctx: *RenderGraph.RenderCTX) !void {
|
||||
// --- # ---
|
||||
const res = try ctx.app.resources.getMany(struct {
|
||||
frame: *GPUFrame,
|
||||
pipelines: *PipelineCache,
|
||||
render_data: *RenderData,
|
||||
render_phase: *RenderPhase,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
for (res.render_data.cameras.items) |camera| {
|
||||
const pass: RenderGraph.RenderPass = try .begin(
|
||||
res.frame.target_view,
|
||||
res.frame.encoder,
|
||||
camera.clear_color,
|
||||
);
|
||||
defer pass.end();
|
||||
|
||||
// --- # ---
|
||||
for (res.render_phase.opaques.items) |draw_item| {
|
||||
// --- GET PIPELINE ---
|
||||
const pipeline = res.pipelines.data.getPtr(.{
|
||||
.unique = draw_item.material,
|
||||
}) orelse continue;
|
||||
|
||||
// --- DRAW ---
|
||||
pass.bindPipeline(pipeline);
|
||||
pass.draw(3, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn mainNode(ctx: *RenderGraph.RenderCTX) !void {
|
||||
_ = ctx;
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn presentNode(ctx: *RenderGraph.RenderCTX) !void {
|
||||
_ = ctx;
|
||||
}
|
||||
|
|
|
|||
100
src/plugins/renderer/system/extract.zig
Normal file
100
src/plugins/renderer/system/extract.zig
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
//! ----------------------------------------------------
|
||||
//! Extract -> Prepare -> Present
|
||||
//! ----------------------------------------------------
|
||||
|
||||
// --- # ---
|
||||
const std = @import("std");
|
||||
const math = @import("math");
|
||||
|
||||
// --- RESOURCES ---
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
const MeshAssets = @import("../resource/mesh_assets.zig");
|
||||
const MaterialAssets = @import("../resource/material_assets.zig");
|
||||
const RenderData = @import("../resource/render_data.zig");
|
||||
|
||||
// --- COMPONENTS ---
|
||||
const Mesh = @import("../../common/component/mesh.zig");
|
||||
const Camera = @import("../../common/component/camera.zig");
|
||||
const Material = @import("../../common/component/material.zig");
|
||||
const Transform3D = @import("../../common/component/transform3D.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn meshes(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
mesh_assets: *MeshAssets,
|
||||
material_assets: *MaterialAssets,
|
||||
render_data: *RenderData,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = res.world.query(struct {
|
||||
mesh: *Mesh,
|
||||
material: *Material,
|
||||
transform: *Transform3D,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
|
||||
// --- TRANSFORM ---
|
||||
const transform = math.Mat4x4.translate(
|
||||
e.transform.position.value[0],
|
||||
e.transform.position.value[1],
|
||||
e.transform.position.value[2],
|
||||
)
|
||||
.mul(e.transform.rotation.toMat4())
|
||||
.mul(math.Mat4x4.scale(
|
||||
e.transform.scale.value[0],
|
||||
e.transform.scale.value[1],
|
||||
e.transform.scale.value[2],
|
||||
));
|
||||
|
||||
// --- RESULT ---
|
||||
try res.render_data.meshes.append(app.alloc, .{
|
||||
.source = query.entity(),
|
||||
.transform = transform,
|
||||
|
||||
.mesh = e.mesh.value,
|
||||
.material = e.material.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn cameras(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
render_data: *RenderData,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = res.world.query(struct {
|
||||
camera: *Camera,
|
||||
transform: *Transform3D,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- VIEW ---
|
||||
const eye = e.transform.position;
|
||||
const forward = e.transform.rotation.rotate(math.Vec3f.new(.{ 0, 0, 1 }));
|
||||
const up = e.transform.rotation.rotate(math.Vec3f.new(.{ 0, 1, 0 }));
|
||||
const view: math.Mat4x4 = .lookAt(eye, eye.add(forward), up);
|
||||
|
||||
// --- PROJECTION ---
|
||||
const projection: math.Mat4x4 = switch (e.camera.projection) {
|
||||
.perspective => |v| .perspective(std.math.degreesToRadians(v.fov), 800.0 / 600.0, v.near, v.far),
|
||||
.ortho => |v| .orthographic(800.0, 0, 600.0, 0, v.near, v.far),
|
||||
};
|
||||
|
||||
// --- RESULT ---
|
||||
try res.render_data.cameras.append(app.alloc, .{
|
||||
.source = query.entity(),
|
||||
.projection = projection,
|
||||
.view = view,
|
||||
.clear_color = e.camera.clear_color,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,248 +1,51 @@
|
|||
//! ----------------------------------------------------
|
||||
//! Extract -> Prepare -> Present
|
||||
//! ----------------------------------------------------
|
||||
|
||||
// --- # ---
|
||||
const std = @import("std");
|
||||
const math = @import("math");
|
||||
const gtl = @import("gtl");
|
||||
const wgpu = @import("wgpu");
|
||||
|
||||
// --- RESOURCES ---
|
||||
const App = @import("app");
|
||||
const Zla = @import("zla");
|
||||
|
||||
// --- # ---
|
||||
const Vertex = @import("../../cache/resource/mesh_cache.zig").Vertex;
|
||||
const WGPUDevice = @import("../../device/resource/wgpu_device.zig");
|
||||
const RenderWorld = @import("../resource/render_world.zig");
|
||||
const RenderLayout = @import("../resource/render_layout.zig");
|
||||
|
||||
// --- # ---
|
||||
const Transform2D = @import("../../common/component/transform2D.zig");
|
||||
const Transform3D = @import("../../common/component/transform3D.zig");
|
||||
|
||||
// --- MESH ---
|
||||
const CMesh = @import("../../common/component/mesh.zig");
|
||||
const TMesh = @import("../template/gpu_object.zig");
|
||||
|
||||
// --- MATERIAL ---
|
||||
const CMaterial = @import("../../common/component/material.zig");
|
||||
const TMaterial = @import("../template/material.zig");
|
||||
|
||||
// --- CAMERA ---
|
||||
const CCamera = @import("../../common/component/camera.zig");
|
||||
const TCamera = @import("../template/gpu_camera.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn cameras(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
render_world: *RenderWorld,
|
||||
render_layout: *RenderLayout,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = app.world.query(struct {
|
||||
camera: *const CCamera,
|
||||
transform2D: ?*const Transform2D,
|
||||
transform3D: ?*const Transform3D,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- GPU ---
|
||||
const raw = try res.render_world.gpu_cameras.getOrPut(query.entity(), blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_cameras.getByKey(
|
||||
query.entity(),
|
||||
)) |v| break :blk v.*;
|
||||
|
||||
// --- UNIFORM ---
|
||||
const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{
|
||||
.usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform,
|
||||
.size = @sizeOf(TCamera.Uniform),
|
||||
}) orelse return error.Buffer;
|
||||
|
||||
// --- VIEW ---
|
||||
const view: math.Mat4x4 = if (e.transform3D) |t3| cmp: { // 3D
|
||||
const eye = t3.position;
|
||||
const forward = t3.rotation.rotate(math.Vec3f.new(.{ 0, 0, 1 }));
|
||||
const up = t3.rotation.rotate(math.Vec3f.new(.{ 0, 1, 0 }));
|
||||
break :cmp math.Mat4x4.lookAt(eye, eye.add(forward), up);
|
||||
} else if (e.transform2D) |t2| cmp: { // 2D
|
||||
const eye: math.Vec3f = .new(.{ t2.position.value[0], t2.position.value[1], 0 });
|
||||
break :cmp math.Mat4x4.rotateZ(-t2.angle)
|
||||
.mul(math.Mat4x4.translate(-eye.value[0], -eye.value[1], 0));
|
||||
} else math.Mat4x4.identity();
|
||||
|
||||
// --- PROJECTION ---
|
||||
const projection: math.Mat4x4 = switch (e.camera.projection) {
|
||||
.perspective => |v| .perspective(std.math.degreesToRadians(v.fov), 800.0 / 600.0, v.near, v.far),
|
||||
.ortho => |v| .orthographic(800.0, 0, 600.0, 0, v.near, v.far),
|
||||
};
|
||||
|
||||
// --- WRITE TO UNIFORM ---
|
||||
wgpu.wgpuQueueWriteBuffer(
|
||||
res.device.queue,
|
||||
uniform,
|
||||
0,
|
||||
&TCamera.Uniform{
|
||||
.view = view.transpose(),
|
||||
.projection = projection.transpose(),
|
||||
},
|
||||
@sizeOf(TCamera.Uniform),
|
||||
);
|
||||
|
||||
// --- BIND GROUP ---
|
||||
const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{
|
||||
.layout = res.render_layout.camera,
|
||||
.entryCount = 1,
|
||||
.entries = &[_]wgpu.WGPUBindGroupEntry{
|
||||
.{
|
||||
.binding = 0,
|
||||
.buffer = uniform,
|
||||
.offset = 0,
|
||||
.size = @sizeOf(TCamera.Uniform),
|
||||
},
|
||||
},
|
||||
}) orelse return error.BindGroup;
|
||||
|
||||
break :blk .{
|
||||
.buffer = uniform,
|
||||
.bind_group = bind_group,
|
||||
.dirty = false,
|
||||
};
|
||||
});
|
||||
|
||||
// --- FRAME ---
|
||||
try res.render_world.frame_views.append(app.alloc, .{
|
||||
.order = e.camera.order,
|
||||
.priority = e.camera.priority,
|
||||
.camera = query.entity(),
|
||||
.raw = raw,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn objects(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
render_world: *RenderWorld,
|
||||
render_layout: *RenderLayout,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = app.world.query(struct {
|
||||
mesh: *const CMesh,
|
||||
material: *const CMaterial,
|
||||
transform2D: ?*const Transform2D,
|
||||
transform3D: ?*const Transform3D,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- ENSURE TRANSFORM ---
|
||||
if (e.transform2D == null and
|
||||
e.transform3D == null) continue;
|
||||
|
||||
// --- GPU ---
|
||||
_ = try res.render_world.gpu_objects.getOrPut(query.entity(), blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_objects.getByKey(
|
||||
query.entity(),
|
||||
)) |v| break :blk v.*;
|
||||
|
||||
// --- UNIFORM ---
|
||||
const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{
|
||||
.usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform,
|
||||
.size = @sizeOf(TMesh.Uniform),
|
||||
}) orelse return error.Buffer;
|
||||
|
||||
// --- MODEL ---
|
||||
const pos: math.Vec3f = e.transform3D.?.position;
|
||||
const scl: math.Vec3f = e.transform3D.?.scale;
|
||||
const rot: math.Quat = e.transform3D.?.rotation;
|
||||
|
||||
// --- FINAL MODEL ---
|
||||
const model =
|
||||
math.Mat4x4.translate(pos.value[0], pos.value[1], pos.value[2])
|
||||
.mul(rot.toMat4())
|
||||
.mul(math.Mat4x4.scale(scl.value[0], scl.value[1], scl.value[2]));
|
||||
|
||||
// --- WRITE TO UNIFORM ---
|
||||
wgpu.wgpuQueueWriteBuffer(
|
||||
res.device.queue,
|
||||
uniform,
|
||||
0,
|
||||
&TMesh.Uniform{
|
||||
.data = model.transpose(),
|
||||
},
|
||||
@sizeOf(TMesh.Uniform),
|
||||
);
|
||||
|
||||
// --- BIND GROUP ---
|
||||
const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{
|
||||
.layout = res.render_layout.model,
|
||||
.entryCount = 1,
|
||||
.entries = &[_]wgpu.WGPUBindGroupEntry{
|
||||
.{
|
||||
.binding = 0,
|
||||
.buffer = uniform,
|
||||
.offset = 0,
|
||||
.size = @sizeOf(TMesh.Uniform),
|
||||
},
|
||||
},
|
||||
}) orelse return error.BindGroup;
|
||||
|
||||
break :blk .{
|
||||
.buffer = uniform,
|
||||
.bind_group = bind_group,
|
||||
.dirty = false,
|
||||
};
|
||||
});
|
||||
|
||||
// --- FRAME ---
|
||||
try res.render_world.frame_objects.append(app.alloc, .{
|
||||
.mesh = e.mesh.value,
|
||||
.entity = query.entity(),
|
||||
.material = e.material.value,
|
||||
.transform = blk: {
|
||||
if (e.transform2D) |v| break :blk .{ .@"2D" = v.* };
|
||||
if (e.transform3D) |v| break :blk .{ .@"3D" = v.* };
|
||||
break :blk .{ .@"2D" = .{} };
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
const World = @import("world");
|
||||
const GPUDevice = @import("../../device/resource/wgpu_device.zig");
|
||||
const MeshAssets = @import("../resource/mesh_assets.zig");
|
||||
const MaterialAssets = @import("../resource/material_assets.zig");
|
||||
const RenderData = @import("../resource/render_data.zig");
|
||||
const ShaderCache = @import("../resource/shader_cache.zig");
|
||||
const PipelineCache = @import("../resource/pipeline_cache.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn shaders(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
render_world: *RenderWorld,
|
||||
device: *WGPUDevice,
|
||||
world: *World,
|
||||
device: *GPUDevice,
|
||||
mesh_assets: *MeshAssets,
|
||||
material_assets: *MaterialAssets,
|
||||
render_data: *RenderData,
|
||||
shader_cache: *ShaderCache,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = app.world.query(struct {
|
||||
material: *const CMaterial,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
for (res.render_data.meshes.items) |extracted_mesh| {
|
||||
// --- GET MATERIAL ---
|
||||
const material = res.render_world.materials.get(
|
||||
e.material.value,
|
||||
const material = res.material_assets.get(
|
||||
extracted_mesh.material,
|
||||
) orelse return error.MaterialNotFound;
|
||||
|
||||
// --- ENSURE SHADER ---
|
||||
_ = try res.render_world.gpu_shaders.getOrPut(material.unique.shader, blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_shaders.contains(
|
||||
material.unique.shader,
|
||||
)) return;
|
||||
// --- GOP ---
|
||||
const entry = try res.shader_cache.modules.getOrPut(
|
||||
material.unique.shader,
|
||||
);
|
||||
|
||||
if (!entry.found_existing) {
|
||||
// --- CODE ---
|
||||
const code: []const u8 = switch (material.unique.shader) {
|
||||
.pbr => RenderWorld.PBRCode,
|
||||
.unlit => RenderWorld.UnlitCode,
|
||||
.pbr => ShaderCache.PBRCode,
|
||||
.unlit => ShaderCache.UnlitCode,
|
||||
.custom => return error.TooLazyToImplement, // TODO: Yes
|
||||
};
|
||||
|
||||
|
|
@ -253,7 +56,7 @@ pub fn shaders(app: *App) !void {
|
|||
};
|
||||
|
||||
// --- RESULT ---
|
||||
break :blk .{
|
||||
entry.value_ptr.* = .{
|
||||
.raw = wgpu.wgpuDeviceCreateShaderModule(res.device.raw, &wgpu.WGPUShaderModuleDescriptor{
|
||||
.label = .{ .data = @tagName(material.unique.shader), .length = wgpu.WGPU_STRLEN },
|
||||
.nextInChain = &source.chain,
|
||||
|
|
@ -261,7 +64,7 @@ pub fn shaders(app: *App) !void {
|
|||
return error.ShaderModuleCreationFailed;
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -270,221 +73,125 @@ pub fn shaders(app: *App) !void {
|
|||
pub fn pipelines(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
render_world: *RenderWorld,
|
||||
render_layout: *RenderLayout,
|
||||
device: *WGPUDevice,
|
||||
world: *World,
|
||||
device: *GPUDevice,
|
||||
mesh_assets: *MeshAssets,
|
||||
material_assets: *MaterialAssets,
|
||||
render_data: *RenderData,
|
||||
|
||||
shader_cache: *ShaderCache,
|
||||
pipeline_cache: *PipelineCache,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = app.world.query(struct {
|
||||
material: *const CMaterial,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
for (res.render_data.meshes.items) |extracted_mesh| {
|
||||
// --- GET MATERIAL ---
|
||||
const material = res.render_world.materials.get(
|
||||
e.material.value,
|
||||
const material = res.material_assets.get(
|
||||
extracted_mesh.material,
|
||||
) orelse return error.MaterialNotFound;
|
||||
|
||||
// --- ENSURE PIPELINE ---
|
||||
_ = try res.render_world.gpu_pipelines.getOrPut(material.unique, blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_pipelines.contains(
|
||||
material.unique,
|
||||
)) return;
|
||||
// --- GET SHADER ---
|
||||
const shader = res.shader_cache.modules.getPtr(
|
||||
material.unique.shader,
|
||||
) orelse return error.ShaderNotFound;
|
||||
|
||||
// --- LAYOUT ---
|
||||
var bind_group_layouts = [_]wgpu.WGPUBindGroupLayout{
|
||||
res.render_layout.camera,
|
||||
res.render_layout.model,
|
||||
res.render_layout.material,
|
||||
};
|
||||
|
||||
// --- PIPELINE LAYOUT ---
|
||||
const pipeline_layout = wgpu.wgpuDeviceCreatePipelineLayout(
|
||||
res.device.raw,
|
||||
&wgpu.WGPUPipelineLayoutDescriptor{
|
||||
.bindGroupLayoutCount = 3,
|
||||
.bindGroupLayouts = &bind_group_layouts,
|
||||
},
|
||||
) orelse return error.Layout;
|
||||
|
||||
// --- CREATE PIPELINE ---
|
||||
const pipeline = try createPipeline(
|
||||
material.unique,
|
||||
pipeline_layout,
|
||||
if (res.render_world.gpu_shaders.getByKey(
|
||||
material.unique.shader,
|
||||
)) |v| v.raw else return error.ShaderNotFound,
|
||||
res.device.raw,
|
||||
);
|
||||
|
||||
// --- RESULT ---
|
||||
break :blk .{
|
||||
.raw = pipeline,
|
||||
.layout = pipeline_layout,
|
||||
};
|
||||
// --- GOP ---
|
||||
const entry = try res.pipeline_cache.data.getOrPut(.{
|
||||
.unique = material.unique,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn materials(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
render_world: *RenderWorld,
|
||||
render_layout: *RenderLayout,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
var query = app.world.query(struct {
|
||||
material: *const CMaterial,
|
||||
}, .{});
|
||||
while (query.next()) |e| {
|
||||
// --- ENSURE MATERIAL ---
|
||||
_ = try res.render_world.gpu_materials.getOrPut(
|
||||
e.material.value,
|
||||
blk: {
|
||||
// --- # ---
|
||||
if (res.render_world.gpu_materials.contains(
|
||||
e.material.value,
|
||||
)) return;
|
||||
|
||||
// --- # ---
|
||||
const material = res.render_world.materials.get(
|
||||
e.material.value,
|
||||
) orelse return error.MaterialNotFound;
|
||||
|
||||
// --- UNIFORM ---
|
||||
const uniform = wgpu.wgpuDeviceCreateBuffer(res.device.raw, &wgpu.WGPUBufferDescriptor{
|
||||
.usage = wgpu.WGPUBufferUsage_CopyDst | wgpu.WGPUBufferUsage_Uniform,
|
||||
.size = @sizeOf(TMaterial.Style),
|
||||
}) orelse return error.Buffer;
|
||||
|
||||
// --- WRITE TO UNIFORM ---
|
||||
wgpu.wgpuQueueWriteBuffer(
|
||||
res.device.queue,
|
||||
uniform,
|
||||
0,
|
||||
&material.style,
|
||||
@sizeOf(TMaterial.Style),
|
||||
);
|
||||
|
||||
// --- BIND GROUP ---
|
||||
const bind_group = wgpu.wgpuDeviceCreateBindGroup(res.device.raw, &wgpu.WGPUBindGroupDescriptor{
|
||||
.layout = res.render_layout.material,
|
||||
.entryCount = 1,
|
||||
.entries = &[_]wgpu.WGPUBindGroupEntry{
|
||||
.{
|
||||
.binding = 0,
|
||||
.buffer = uniform,
|
||||
.offset = 0,
|
||||
.size = @sizeOf(TMaterial.Style),
|
||||
if (!entry.found_existing) {
|
||||
entry.value_ptr.* = .{
|
||||
.raw = wgpu.wgpuDeviceCreateRenderPipeline(res.device.raw, &wgpu.WGPURenderPipelineDescriptor{
|
||||
.label = .{ .data = @tagName(material.unique.shader), .length = wgpu.WGPU_STRLEN },
|
||||
// .layout = layout,
|
||||
.vertex = .{
|
||||
.module = shader.raw,
|
||||
.entryPoint = .{ .data = "vs_main", .length = wgpu.WGPU_STRLEN },
|
||||
// .bufferCount = 1,
|
||||
// .buffers = &wgpu.WGPUVertexBufferLayout{
|
||||
// .attributeCount = 3,
|
||||
// .attributes = &[_]wgpu.WGPUVertexAttribute{ // TODO: Mabe mabe allow for custom, mabe mabe later tho
|
||||
// .{
|
||||
// .format = wgpu.WGPUVertexFormat_Float32x3,
|
||||
// .offset = @offsetOf(Vertex, "position"),
|
||||
// .shaderLocation = 0,
|
||||
// },
|
||||
// .{
|
||||
// .format = wgpu.WGPUVertexFormat_Float32x3,
|
||||
// .offset = @offsetOf(Vertex, "normal"),
|
||||
// .shaderLocation = 1,
|
||||
// },
|
||||
// .{
|
||||
// .format = wgpu.WGPUVertexFormat_Float32x2,
|
||||
// .offset = @offsetOf(Vertex, "uv"),
|
||||
// .shaderLocation = 2,
|
||||
// },
|
||||
// },
|
||||
// .arrayStride = @sizeOf(Vertex),
|
||||
// .stepMode = wgpu.WGPUVertexStepMode_Vertex,
|
||||
// },
|
||||
},
|
||||
.fragment = &wgpu.WGPUFragmentState{
|
||||
.module = shader.raw,
|
||||
.entryPoint = .{ .data = "fs_main", .length = wgpu.WGPU_STRLEN },
|
||||
.targetCount = 1,
|
||||
.targets = &wgpu.WGPUColorTargetState{
|
||||
.format = 28, // FIX: Use proper format
|
||||
.blend = &wgpu.WGPUBlendState{
|
||||
.color = .{
|
||||
.srcFactor = wgpu.WGPUBlendFactor_SrcAlpha,
|
||||
.dstFactor = wgpu.WGPUBlendFactor_OneMinusSrcAlpha,
|
||||
.operation = wgpu.WGPUBlendOperation_Add,
|
||||
},
|
||||
.alpha = .{
|
||||
.srcFactor = wgpu.WGPUBlendFactor_Zero,
|
||||
.dstFactor = wgpu.WGPUBlendFactor_One,
|
||||
.operation = wgpu.WGPUBlendOperation_Add,
|
||||
},
|
||||
},
|
||||
.writeMask = wgpu.WGPUColorWriteMask_All,
|
||||
},
|
||||
},
|
||||
}) orelse return error.BindGroup;
|
||||
.primitive = .{
|
||||
.topology = switch (material.unique.topology) {
|
||||
.triangle_list => wgpu.WGPUPrimitiveTopology_TriangleList,
|
||||
.point_list => wgpu.WGPUPrimitiveTopology_PointList,
|
||||
.line_list => wgpu.WGPUPrimitiveTopology_LineList,
|
||||
},
|
||||
.frontFace = switch (material.unique.front_face) {
|
||||
.ccw => wgpu.WGPUFrontFace_CCW,
|
||||
.cw => wgpu.WGPUFrontFace_CW,
|
||||
},
|
||||
.cullMode = switch (material.unique.cull_mode) {
|
||||
.back => wgpu.WGPUCullMode_Back,
|
||||
.front => wgpu.WGPUCullMode_Front,
|
||||
.none => wgpu.WGPUCullMode_None,
|
||||
},
|
||||
},
|
||||
.multisample = .{
|
||||
.count = 1,
|
||||
.mask = ~@as(u32, 0),
|
||||
.alphaToCoverageEnabled = 0,
|
||||
},
|
||||
// .depthStencil = &wgpu.WGPUDepthStencilState{
|
||||
// .format = wgpu.WGPUTextureFormat_Depth24Plus,
|
||||
// .depthCompare = wgpu.WGPUCompareFunction_Less,
|
||||
// .depthWriteEnabled = 1,
|
||||
//
|
||||
// .stencilReadMask = 0,
|
||||
// .stencilWriteMask = 0,
|
||||
// },
|
||||
}) orelse {
|
||||
return error.PipelineCreationFailed;
|
||||
},
|
||||
};
|
||||
|
||||
// --- RESULT ---
|
||||
break :blk .{
|
||||
.buffer = uniform,
|
||||
.bind_group = bind_group,
|
||||
.dirty = false,
|
||||
};
|
||||
},
|
||||
);
|
||||
if (gtl.log.print(.debug, "PIPELINE", gtl.ansi.blue)) |v| {
|
||||
defer v.end();
|
||||
|
||||
v.write("shader: {s}", .{@tagName(material.unique.shader)});
|
||||
v.write("topology: {s}", .{@tagName(material.unique.topology)});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn createPipeline(
|
||||
key: TMaterial.Unique,
|
||||
layout: *wgpu.WGPUPipelineLayoutImpl,
|
||||
shader: *wgpu.WGPUShaderModuleImpl,
|
||||
device: *wgpu.WGPUDeviceImpl,
|
||||
) !*wgpu.WGPURenderPipelineImpl {
|
||||
return wgpu.wgpuDeviceCreateRenderPipeline(device, &wgpu.WGPURenderPipelineDescriptor{
|
||||
.label = .{ .data = @tagName(key.shader), .length = wgpu.WGPU_STRLEN },
|
||||
.layout = layout,
|
||||
.vertex = .{
|
||||
.module = shader,
|
||||
.entryPoint = .{ .data = "vs_main", .length = wgpu.WGPU_STRLEN },
|
||||
.bufferCount = 1,
|
||||
.buffers = &wgpu.WGPUVertexBufferLayout{
|
||||
.attributeCount = 3,
|
||||
.attributes = &[_]wgpu.WGPUVertexAttribute{ // TODO: Mabe mabe allow for custom, mabe mabe later tho
|
||||
.{
|
||||
.format = wgpu.WGPUVertexFormat_Float32x3,
|
||||
.offset = @offsetOf(Vertex, "position"),
|
||||
.shaderLocation = 0,
|
||||
},
|
||||
.{
|
||||
.format = wgpu.WGPUVertexFormat_Float32x3,
|
||||
.offset = @offsetOf(Vertex, "normal"),
|
||||
.shaderLocation = 1,
|
||||
},
|
||||
.{
|
||||
.format = wgpu.WGPUVertexFormat_Float32x2,
|
||||
.offset = @offsetOf(Vertex, "uv"),
|
||||
.shaderLocation = 2,
|
||||
},
|
||||
},
|
||||
.arrayStride = @sizeOf(Vertex),
|
||||
.stepMode = wgpu.WGPUVertexStepMode_Vertex,
|
||||
},
|
||||
},
|
||||
.fragment = &wgpu.WGPUFragmentState{
|
||||
.module = shader,
|
||||
.entryPoint = .{ .data = "fs_main", .length = wgpu.WGPU_STRLEN },
|
||||
.targetCount = 1,
|
||||
.targets = &wgpu.WGPUColorTargetState{
|
||||
.format = 28, // FIX: Use proper format
|
||||
.blend = &wgpu.WGPUBlendState{
|
||||
.color = .{
|
||||
.srcFactor = wgpu.WGPUBlendFactor_SrcAlpha,
|
||||
.dstFactor = wgpu.WGPUBlendFactor_OneMinusSrcAlpha,
|
||||
.operation = wgpu.WGPUBlendOperation_Add,
|
||||
},
|
||||
.alpha = .{
|
||||
.srcFactor = wgpu.WGPUBlendFactor_Zero,
|
||||
.dstFactor = wgpu.WGPUBlendFactor_One,
|
||||
.operation = wgpu.WGPUBlendOperation_Add,
|
||||
},
|
||||
},
|
||||
.writeMask = wgpu.WGPUColorWriteMask_All,
|
||||
},
|
||||
},
|
||||
.primitive = .{
|
||||
.topology = switch (key.topology) {
|
||||
.triangle_list => wgpu.WGPUPrimitiveTopology_TriangleList,
|
||||
.point_list => wgpu.WGPUPrimitiveTopology_PointList,
|
||||
.line_list => wgpu.WGPUPrimitiveTopology_LineList,
|
||||
},
|
||||
.frontFace = switch (key.front_face) {
|
||||
.ccw => wgpu.WGPUFrontFace_CCW,
|
||||
.cw => wgpu.WGPUFrontFace_CW,
|
||||
},
|
||||
.cullMode = switch (key.cull_mode) {
|
||||
.back => wgpu.WGPUCullMode_Back,
|
||||
.front => wgpu.WGPUCullMode_Front,
|
||||
.none => wgpu.WGPUCullMode_None,
|
||||
},
|
||||
},
|
||||
.multisample = .{
|
||||
.count = 1,
|
||||
.mask = ~@as(u32, 0),
|
||||
.alphaToCoverageEnabled = 0,
|
||||
},
|
||||
// .depthStencil = &wgpu.WGPUDepthStencilState{
|
||||
// .format = wgpu.WGPUTextureFormat_Depth24Plus,
|
||||
// .depthCompare = wgpu.WGPUCompareFunction_Less,
|
||||
// .depthWriteEnabled = 1,
|
||||
//
|
||||
// .stencilReadMask = 0,
|
||||
// .stencilWriteMask = 0,
|
||||
// },
|
||||
}) orelse {
|
||||
return error.PipelineCreationFailed;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,44 +3,46 @@
|
|||
|
||||
const std = @import("std");
|
||||
const wgpu = @import("wgpu");
|
||||
const App = @import("app");
|
||||
|
||||
const Window = @import("../../window/resource/window.zig");
|
||||
const Resized = @import("../../window/event/resized.zig");
|
||||
const Device = @import("../../device/resource/wgpu_device.zig");
|
||||
const Renderer = @import("../resource/renderer.zig");
|
||||
const RenderWorld = @import("../resource/render_world.zig");
|
||||
const MeshCache = @import("../../cache/resource/mesh_cache.zig");
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
|
||||
const GPUDevice = @import("../../device/resource/wgpu_device.zig");
|
||||
const GPUWindow = @import("../../window/resource/gpu_window.zig");
|
||||
const GPUFrame = @import("../resource/gpu_frame.zig");
|
||||
const RenderGraph = @import("../resource/render_graph.zig");
|
||||
|
||||
const RenderData = @import("../resource/render_data.zig");
|
||||
const RenderPhase = @import("../resource/render_phase.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn draw(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
window: *Window,
|
||||
device: *Device,
|
||||
renderer: *Renderer,
|
||||
render_world: *RenderWorld,
|
||||
mesh_cache: *MeshCache,
|
||||
world: *World,
|
||||
window: *GPUWindow,
|
||||
device: *GPUDevice,
|
||||
frame: *GPUFrame,
|
||||
|
||||
render_data: *RenderData,
|
||||
render_phase: *RenderPhase,
|
||||
render_graph: *RenderGraph,
|
||||
});
|
||||
|
||||
// --- DO NONE ON WINDOW RESIZE ---
|
||||
if (app.events.consume(Resized)) |_| {
|
||||
return;
|
||||
}
|
||||
|
||||
// --- SURFACE TEXTURE ---
|
||||
var surface_texture: wgpu.WGPUSurfaceTexture = .{};
|
||||
defer wgpu.wgpuTextureRelease(surface_texture.texture);
|
||||
defer wgpu.wgpuTextureRelease(
|
||||
res.frame.surface_texture.texture,
|
||||
);
|
||||
|
||||
// --- GET SURFACE TEXTURE ---
|
||||
wgpu.wgpuSurfaceGetCurrentTexture(
|
||||
@ptrCast(res.window.surface),
|
||||
&surface_texture,
|
||||
&res.frame.surface_texture,
|
||||
);
|
||||
|
||||
// --- DEBUG ---
|
||||
switch (surface_texture.status) {
|
||||
switch (res.frame.surface_texture.status) {
|
||||
wgpu.WGPUSurfaceGetCurrentTextureStatus_Error => {
|
||||
std.debug.print("\x1b[31m[SURFACE_TEXTURE_ERROR]\x1b[0m\n", .{});
|
||||
},
|
||||
|
|
@ -51,109 +53,47 @@ pub fn draw(app: *App) !void {
|
|||
}
|
||||
|
||||
// --- GET SURFACE COLOR VIEW ---
|
||||
const target_view = wgpu.wgpuTextureCreateView(surface_texture.texture, &wgpu.WGPUTextureViewDescriptor{
|
||||
.format = wgpu.wgpuTextureGetFormat(surface_texture.texture),
|
||||
res.frame.target_view = wgpu.wgpuTextureCreateView(res.frame.surface_texture.texture, &wgpu.WGPUTextureViewDescriptor{
|
||||
.format = wgpu.wgpuTextureGetFormat(res.frame.surface_texture.texture),
|
||||
.dimension = wgpu.WGPUTextureViewDimension_2D,
|
||||
.baseMipLevel = 0,
|
||||
.mipLevelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = 1,
|
||||
.aspect = wgpu.WGPUTextureAspect_All,
|
||||
});
|
||||
defer wgpu.wgpuTextureViewRelease(target_view);
|
||||
}) orelse return error.WGPUTargetView;
|
||||
defer wgpu.wgpuTextureViewRelease(res.frame.target_view);
|
||||
|
||||
// --- ENCODER ---
|
||||
const encoder = wgpu.wgpuDeviceCreateCommandEncoder(
|
||||
res.frame.encoder = wgpu.wgpuDeviceCreateCommandEncoder(
|
||||
res.device.raw,
|
||||
&wgpu.WGPUCommandEncoderDescriptor{},
|
||||
) orelse return error.WGPUEncoder;
|
||||
defer wgpu.wgpuCommandEncoderRelease(res.frame.encoder);
|
||||
|
||||
// --- # ---
|
||||
var render_ctx: RenderGraph.RenderCTX = .{
|
||||
.app = app,
|
||||
.world = res.world,
|
||||
.graph = res.render_graph,
|
||||
.device = res.device.raw,
|
||||
.encoder = res.frame.encoder,
|
||||
};
|
||||
|
||||
// --- # ---
|
||||
try res.render_graph.run(
|
||||
&render_ctx,
|
||||
);
|
||||
defer wgpu.wgpuCommandEncoderRelease(encoder);
|
||||
|
||||
// --- FRAME ---
|
||||
var render_pass: ?*wgpu.WGPURenderPassEncoderImpl = null;
|
||||
var camera: ?u64 = 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 = switch (v.load_op) {
|
||||
.load => wgpu.WGPULoadOp_Load,
|
||||
.clear => wgpu.WGPULoadOp_Clear,
|
||||
},
|
||||
.storeOp = switch (v.store_op) {
|
||||
.store => wgpu.WGPUStoreOp_Store,
|
||||
.discard => wgpu.WGPUStoreOp_Discard,
|
||||
},
|
||||
.clearValue = .{
|
||||
.r = v.color[0],
|
||||
.g = v.color[1],
|
||||
.b = v.color[2],
|
||||
.a = v.color[3],
|
||||
},
|
||||
.depthSlice = wgpu.WGPU_DEPTH_SLICE_UNDEFINED,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// --- SET CAMERA ---
|
||||
camera = v.camera;
|
||||
},
|
||||
.end_pass => {
|
||||
if (render_pass) |rp| {
|
||||
wgpu.wgpuRenderPassEncoderEnd(rp);
|
||||
wgpu.wgpuRenderPassEncoderRelease(rp);
|
||||
render_pass = null;
|
||||
}
|
||||
},
|
||||
.draw => |v| {
|
||||
// --- ENSURE ---
|
||||
const material = res.render_world.materials.get(v.material) orelse return error.MaterialNotFound;
|
||||
const gpu_material = res.render_world.gpu_materials.getByKey(v.material) orelse return error.GPUMaterialNotFound;
|
||||
const gpu_camera = res.render_world.gpu_cameras.getByKey(camera orelse return error.CameraNotSet) orelse return error.GPUCameraNotFound;
|
||||
const pipeline = res.render_world.gpu_pipelines.getByKey(material.unique) orelse return error.GPUPipelineNotFound;
|
||||
const gpu_mesh = res.render_world.gpu_objects.getByKey(v.entity) orelse return error.GPUMeshNotFound;
|
||||
const mesh = try res.mesh_cache.getOrCreate(v.mesh);
|
||||
|
||||
// --- BIND ---
|
||||
wgpu.wgpuRenderPassEncoderSetPipeline(render_pass, pipeline.raw);
|
||||
wgpu.wgpuRenderPassEncoderSetVertexBuffer(render_pass, 0, mesh.vbuf, 0, wgpu.wgpuBufferGetSize(mesh.vbuf));
|
||||
|
||||
// --- BIND SHADER GROUPS ---
|
||||
wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 0, gpu_camera.bind_group, 0, null);
|
||||
wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 1, gpu_mesh.bind_group, 0, null);
|
||||
wgpu.wgpuRenderPassEncoderSetBindGroup(render_pass, 2, gpu_material.bind_group, 0, null);
|
||||
|
||||
// --- DRAW ---
|
||||
if (mesh.ibuf) |ibuf| {
|
||||
wgpu.wgpuRenderPassEncoderSetIndexBuffer(render_pass, ibuf, wgpu.WGPUIndexFormat_Uint32, 0, wgpu.wgpuBufferGetSize(ibuf));
|
||||
wgpu.wgpuRenderPassEncoderDrawIndexed(render_pass, mesh.index_count, 1, 0, 0, 0);
|
||||
} else {
|
||||
wgpu.wgpuRenderPassEncoderDraw(render_pass, mesh.vertex_count, 1, 0, 0);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// --- FINISH ENCODER | CMD BUFFER ---
|
||||
const cmd_buff = wgpu.wgpuCommandEncoderFinish(encoder, &.{});
|
||||
const cmd_buff = wgpu.wgpuCommandEncoderFinish(res.frame.encoder, &.{});
|
||||
defer wgpu.wgpuCommandBufferRelease(cmd_buff);
|
||||
|
||||
// --- SUBMIT AND PRESENT ---
|
||||
wgpu.wgpuQueueSubmit(res.device.queue, 1, &cmd_buff);
|
||||
_ = wgpu.wgpuSurfacePresent(@ptrCast(res.window.surface));
|
||||
|
||||
// --- CLEAR ---
|
||||
res.render_data.clear();
|
||||
res.render_phase.clear();
|
||||
}
|
||||
|
|
|
|||
38
src/plugins/renderer/system/queue.zig
Normal file
38
src/plugins/renderer/system/queue.zig
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
// --- # ---
|
||||
const std = @import("std");
|
||||
const math = @import("math");
|
||||
|
||||
// --- RESOURCES ---
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
const RenderPhase = @import("../resource/render_phase.zig");
|
||||
const RenderData = @import("../resource/render_data.zig");
|
||||
const MaterialAssets = @import("../resource/material_assets.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub fn meshes(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
world: *World,
|
||||
render_data: *RenderData,
|
||||
render_phase: *RenderPhase,
|
||||
material_assets: *MaterialAssets,
|
||||
});
|
||||
|
||||
for (res.render_data.meshes.items) |mesh| {
|
||||
// --- GET MATERIAL ---
|
||||
const material = res.material_assets.get(
|
||||
mesh.material,
|
||||
) orelse return error.MaterialNotFound;
|
||||
|
||||
// --- # ---
|
||||
try res.render_phase.opaques.append(app.alloc, .{
|
||||
.source = mesh.source,
|
||||
.material = material.unique,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ const App = @import("app");
|
|||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.plugin.Plugin = .{
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "Template",
|
||||
.build = build,
|
||||
};
|
||||
|
|
@ -21,7 +21,7 @@ pub const plugin: App.plugin.Plugin = .{
|
|||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.plugin.Plugin,
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
_ = app;
|
||||
|
|
|
|||
5
src/plugins/window/resource/gpu_window.zig
Normal file
5
src/plugins/window/resource/gpu_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,
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
const sdl = @import("sdl");
|
||||
const sdl_glue = @import("sdl_glue");
|
||||
|
||||
raw: *sdl.SDL_Window,
|
||||
surface: *sdl_glue.WGPUSurfaceImpl,
|
||||
title: []const u8 = "NYXEngine",
|
||||
width: u32 = 800,
|
||||
height: u32 = 600,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// PRIVATE
|
||||
//
|
||||
|
||||
const gtl = @import("gtl");
|
||||
const sdl = @import("sdl");
|
||||
const sdl_glue = @import("sdl_glue");
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ const WGPUDevice = @import("../device/resource/wgpu_device.zig");
|
|||
//
|
||||
|
||||
pub const Window = @import("resource/window.zig");
|
||||
pub const GPUWindow = @import("resource/gpu_window.zig");
|
||||
pub const Resized = @import("event/resized.zig");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
|
|
@ -46,11 +48,25 @@ pub fn init(app: *App) !void {
|
|||
WGPUInstance,
|
||||
) orelse return error.WGPUInstanceNotSet;
|
||||
|
||||
// --- ENSURE WINDOW ---
|
||||
const window = try app.resources.getOrSet(
|
||||
Window{},
|
||||
);
|
||||
|
||||
// DEBUG
|
||||
if (gtl.log.print(.debug, "WINDOW", gtl.ansi.yellow)) |v| {
|
||||
defer v.end();
|
||||
|
||||
v.write("Title: \"{s}\"", .{window.title});
|
||||
v.write("Width: {}", .{window.width});
|
||||
v.write("Height: {}", .{window.height});
|
||||
}
|
||||
|
||||
// --- WINDOW ---
|
||||
const raw_window = sdl.SDL_CreateWindow(
|
||||
"NYXEngine",
|
||||
800,
|
||||
600,
|
||||
window.title.ptr,
|
||||
@intCast(window.width),
|
||||
@intCast(window.height),
|
||||
sdl.SDL_WINDOW_RESIZABLE | sdl.SDL_WINDOW_HIGH_PIXEL_DENSITY,
|
||||
) orelse return error.CreateWindow;
|
||||
|
||||
|
|
@ -61,7 +77,7 @@ pub fn init(app: *App) !void {
|
|||
) orelse return error.GetSurface;
|
||||
|
||||
// --- RESOURCE ---
|
||||
try app.resources.set(Window{
|
||||
try app.resources.set(GPUWindow{
|
||||
.raw = raw_window,
|
||||
.surface = raw_surface,
|
||||
});
|
||||
|
|
@ -72,7 +88,7 @@ pub fn init(app: *App) !void {
|
|||
pub fn deinit(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
window: *Window,
|
||||
window: *GPUWindow,
|
||||
});
|
||||
|
||||
// --- # ---
|
||||
|
|
@ -86,7 +102,7 @@ pub fn deinit(app: *App) !void {
|
|||
pub fn configure(app: *App) !void {
|
||||
// --- # ---
|
||||
const res = try app.resources.getMany(struct {
|
||||
window: *Window,
|
||||
window: *GPUWindow,
|
||||
device: *WGPUDevice,
|
||||
});
|
||||
|
||||
|
|
|
|||
40
src/plugins/world/root.zig
Normal file
40
src/plugins/world/root.zig
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
//! ----------------------------------------------------
|
||||
//! ----------------------------------------------------
|
||||
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
|
||||
const App = @import("app");
|
||||
const World = @import("world");
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
pub const plugin: App.Plugin = .{
|
||||
.name = "World",
|
||||
.build = build,
|
||||
};
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn build(
|
||||
_: *App.Plugin,
|
||||
app: *App,
|
||||
) !void {
|
||||
try app.schedules.add(App.stage.init, init);
|
||||
try app.schedules.add(App.stage.deinit, deinit);
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn init(app: *App) !void {
|
||||
try app.resources.set(World.init(app.alloc));
|
||||
}
|
||||
|
||||
/// ----------------------------------------------------
|
||||
/// ----------------------------------------------------
|
||||
fn deinit(app: *App) !void {
|
||||
// --- # ---
|
||||
const world = try app.resources.require(World);
|
||||
world.deinit();
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue