|
|
@ -18,7 +18,12 @@ const VertexData = primitives.VertexData; |
|
|
|
const PrimitiveData = primitives.PrimitiveData; |
|
|
|
const PrimitiveData = primitives.PrimitiveData; |
|
|
|
|
|
|
|
|
|
|
|
const flecszigble = @import("flecs-zig-ble"); |
|
|
|
const flecszigble = @import("flecs-zig-ble"); |
|
|
|
const Entity = flecszigble.Entity(void); |
|
|
|
const Context = flecszigble.Context(void); |
|
|
|
|
|
|
|
const Entity = Context.Entity; |
|
|
|
|
|
|
|
const Iter = Context.Iter; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const flecs = flecszigble.flecs; |
|
|
|
|
|
|
|
const OnStore = flecs.pipeline.OnStore; |
|
|
|
|
|
|
|
|
|
|
|
const Transform = struct { value: Mat }; |
|
|
|
const Transform = struct { value: Mat }; |
|
|
|
const CameraPerspective = struct { |
|
|
|
const CameraPerspective = struct { |
|
|
@ -46,6 +51,7 @@ const ObjectData = struct { |
|
|
|
const Renderer = @This(); |
|
|
|
const Renderer = @This(); |
|
|
|
|
|
|
|
|
|
|
|
app: *App, |
|
|
|
app: *App, |
|
|
|
|
|
|
|
time: f32 = 0.0, |
|
|
|
|
|
|
|
|
|
|
|
pipeline: *gpu.RenderPipeline, |
|
|
|
pipeline: *gpu.RenderPipeline, |
|
|
|
view_proj_buffer: *gpu.Buffer, |
|
|
|
view_proj_buffer: *gpu.Buffer, |
|
|
@ -56,7 +62,6 @@ depth_texture_view: ?*gpu.TextureView = null, |
|
|
|
|
|
|
|
|
|
|
|
primitive_data: []PrimitiveData, |
|
|
|
primitive_data: []PrimitiveData, |
|
|
|
object_data: []ObjectData, |
|
|
|
object_data: []ObjectData, |
|
|
|
camera_entity: Entity, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn init(app: *App) !*Renderer { |
|
|
|
pub fn init(app: *App) !*Renderer { |
|
|
|
// A string buffer used to format objects' labels. |
|
|
|
// A string buffer used to format objects' labels. |
|
|
@ -225,11 +230,22 @@ pub fn init(app: *App) !*Renderer { |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_ = try app.world.component(Transform); |
|
|
|
// Register components necessary for the camera. |
|
|
|
_ = try app.world.component(CameraPerspective); |
|
|
|
_ = try app.world.component("Transform", Transform); |
|
|
|
|
|
|
|
_ = try app.world.component("CameraPerspective", CameraPerspective); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const camera_entity = try app.world.entity( |
|
|
|
|
|
|
|
.{ .name = "Camera", .symbol = "Camera" }, |
|
|
|
|
|
|
|
.{ Transform, CameraPerspective }, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
camera_entity.set(CameraPerspective, .{ |
|
|
|
|
|
|
|
.field_of_view = 45.0, |
|
|
|
|
|
|
|
.near_plane = 0.05, |
|
|
|
|
|
|
|
.far_plane = 80.0, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const camera_entity = try app.world.entity(.{ .name = "Camera" }, .{ Transform, CameraPerspective }); |
|
|
|
const render_expr = "App, [in] CameraPerspective(Camera), [out] Transform(Camera)"; |
|
|
|
camera_entity.set(CameraPerspective, .{ .field_of_view = 45.0, .near_plane = 0.05, .far_plane = 80.0 }); |
|
|
|
_ = try app.world.system("Render", render, OnStore, render_expr); |
|
|
|
|
|
|
|
|
|
|
|
const result = try app.allocator.create(Renderer); |
|
|
|
const result = try app.allocator.create(Renderer); |
|
|
|
result.* = .{ |
|
|
|
result.* = .{ |
|
|
@ -239,7 +255,6 @@ pub fn init(app: *App) !*Renderer { |
|
|
|
.camera_bind_group = camera_bind_group, |
|
|
|
.camera_bind_group = camera_bind_group, |
|
|
|
.primitive_data = primitive_data, |
|
|
|
.primitive_data = primitive_data, |
|
|
|
.object_data = object_data, |
|
|
|
.object_data = object_data, |
|
|
|
.camera_entity = camera_entity, |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Initialize the depth texture. |
|
|
|
// Initialize the depth texture. |
|
|
@ -250,8 +265,8 @@ pub fn init(app: *App) !*Renderer { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn deinit(self: *Renderer) void { |
|
|
|
pub fn deinit(self: *Renderer) void { |
|
|
|
// Using `defer` here, so we can specify them |
|
|
|
// Using `defer` here, so we can specify resources we |
|
|
|
// in the order they were created in `init`. |
|
|
|
// want to free in the order they were created in `init`. |
|
|
|
defer self.app.allocator.destroy(self); |
|
|
|
defer self.app.allocator.destroy(self); |
|
|
|
|
|
|
|
|
|
|
|
defer self.pipeline.release(); |
|
|
|
defer self.pipeline.release(); |
|
|
@ -278,34 +293,39 @@ pub fn resize(self: *Renderer) void { |
|
|
|
self.recreateDepthTexture(); |
|
|
|
self.recreateDepthTexture(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn update(self: *Renderer) void { |
|
|
|
pub fn render(it: Iter) void { |
|
|
|
|
|
|
|
const app = it.field(*App, 1)[0]; |
|
|
|
|
|
|
|
const camera_perspective = it.field(CameraPerspective, 2)[0]; |
|
|
|
|
|
|
|
const camera_transform = &it.field(Transform, 3)[0]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const self = app.renderer; |
|
|
|
|
|
|
|
self.time += it.deltaTime(); |
|
|
|
|
|
|
|
|
|
|
|
// Set up a view matrix from the camera transform. |
|
|
|
// Set up a view matrix from the camera transform. |
|
|
|
// This moves everything to be relative to the camera. |
|
|
|
// This moves everything to be relative to the camera. |
|
|
|
// TODO: Actually implement camera transform instead of hardcoding a look-at matrix. |
|
|
|
// TODO: Actually implement camera transform instead of hardcoding a look-at matrix. |
|
|
|
// const view_matrix = zm.inverse(app.camera_transform); |
|
|
|
// const view_matrix = zm.inverse(app.camera_transform); |
|
|
|
const time = self.app.app_timer.read(); |
|
|
|
|
|
|
|
const camera_distance = 8.0; |
|
|
|
const camera_distance = 8.0; |
|
|
|
const x = @cos(time * std.math.tau / 20) * camera_distance; |
|
|
|
const x = @cos(self.time * std.math.tau / 20) * camera_distance; |
|
|
|
const z = @sin(time * std.math.tau / 20) * camera_distance; |
|
|
|
const z = @sin(self.time * std.math.tau / 20) * camera_distance; |
|
|
|
const camera_pos = vec(x, 2.0, z, 1.0); |
|
|
|
const camera_pos = vec(x, 2.0, z, 1.0); |
|
|
|
const view_matrix = zm.lookAtLh(camera_pos, vec(0, 0, 0, 1), vec(0, 1, 0, 1)); |
|
|
|
const view_matrix = zm.lookAtLh(camera_pos, vec(0, 0, 0, 1), vec(0, 1, 0, 1)); |
|
|
|
|
|
|
|
|
|
|
|
// Setting the transform here doesn't do anything because it's not used |
|
|
|
// Setting the transform here doesn't do anything because it's not used |
|
|
|
// anywhere. In the future we would want to set the camera transform |
|
|
|
// anywhere. In the future we would want to set the camera transform |
|
|
|
// outside of the rendering step, and then get and use it here, instead. |
|
|
|
// outside of the rendering step, and then get and use it here, instead. |
|
|
|
self.camera_entity.set(Transform, .{ .value = view_matrix }); |
|
|
|
camera_transform.* = .{ .value = view_matrix }; |
|
|
|
// TODO: Not sure if this is the proper transform, or actually inverted. |
|
|
|
// TODO: Not sure if this is the proper transform, or actually inverted. |
|
|
|
|
|
|
|
|
|
|
|
// Set up a projection matrix using the size of the window. |
|
|
|
// Set up a projection matrix using the size of the window. |
|
|
|
// The perspective projection will make things further away appear smaller. |
|
|
|
// The perspective projection will make things further away appear smaller. |
|
|
|
const width: f32 = @floatFromInt(core.descriptor.width); |
|
|
|
const width: f32 = @floatFromInt(core.descriptor.width); |
|
|
|
const height: f32 = @floatFromInt(core.descriptor.height); |
|
|
|
const height: f32 = @floatFromInt(core.descriptor.height); |
|
|
|
const perspective = self.camera_entity.get(CameraPerspective).?; |
|
|
|
|
|
|
|
const proj_matrix = zm.perspectiveFovLh( |
|
|
|
const proj_matrix = zm.perspectiveFovLh( |
|
|
|
std.math.degreesToRadians(f32, perspective.field_of_view), |
|
|
|
std.math.degreesToRadians(f32, camera_perspective.field_of_view), |
|
|
|
width / height, |
|
|
|
width / height, |
|
|
|
perspective.near_plane, |
|
|
|
camera_perspective.near_plane, |
|
|
|
perspective.far_plane, |
|
|
|
camera_perspective.far_plane, |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const view_proj_matrix = zm.mul(view_matrix, proj_matrix); |
|
|
|
const view_proj_matrix = zm.mul(view_matrix, proj_matrix); |
|
|
|