Start using ECS by creating a camera entity

main
copygirl 5 months ago
parent 10c44e989a
commit 1c97d66cea
  1. 1
      libs/flecs-zig-ble
  2. 17
      src/main.zig
  3. 40
      src/renderer.zig

@ -0,0 +1 @@
Subproject commit f48a6884caf656b49f416abdd3ce078fc93b1504

@ -4,10 +4,14 @@ const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator(.{});
const core = @import("mach").core;
const Renderer = @import("./renderer.zig");
const flecszigble = @import("flecs-zig-ble");
const World = flecszigble.World(void);
pub const App = @This();
gpa: GeneralPurposeAllocator,
allocator: std.mem.Allocator,
world: *World,
random: std.rand.Random,
renderer: *Renderer,
@ -31,6 +35,18 @@ pub fn init(app: *App) !void {
app.gpa = GeneralPurposeAllocator{};
app.allocator = app.gpa.allocator();
// Initialize flecs-zig-ble and create a new Flecs world.
//
// Flecs is a library for using Entity Component System (ECS) design
// intuitively and efficiently. Entities can be created and have various
// components and relationships to other entities added to them.
//
// This data is stored in an in-memory database, which can be queried
// and modified. For example by using systems, you are able to get
// entities that match a set of components, and modify their values.
flecszigble.init(app.allocator);
app.world = try World.init();
// Create a pseudo-random number generator, but initialize it with
// a constant seed so we always get the same result when launching.
var prng = std.rand.DefaultPrng.init(0);
@ -47,6 +63,7 @@ pub fn deinit(app: *App) void {
// in the order they were created in `init`.
defer core.deinit();
defer _ = app.gpa.deinit(); // TODO: Check for memory leaks?
defer app.world.deinit();
defer app.renderer.deinit();
}

@ -17,6 +17,23 @@ const primitives = @import("./primitives.zig");
const VertexData = primitives.VertexData;
const PrimitiveData = primitives.PrimitiveData;
const flecszigble = @import("flecs-zig-ble");
const Entity = flecszigble.Entity(void);
const Transform = struct { value: Mat };
const CameraPerspective = struct {
/// Vertical field of view (in degrees).
field_of_view: f32,
/// The near clip plane distance. Objects closer than this value are
/// "cut off". Should be set to a positive value close to zero, depending
/// on how close rendered objects typically get to the camera.
near_plane: f32,
/// The far clip place distance. Objects further than this value are
/// "cut off" and therefore won't be visible. Should be set to a larger
/// positive value, depending on how far objects can get from the camera.
far_plane: f32,
};
/// Holds data needed to render an object in a rendering pass.
const ObjectData = struct {
/// Bind group which associates model-related buffers with parameters
@ -39,6 +56,7 @@ depth_texture_view: ?*gpu.TextureView = null,
primitive_data: []PrimitiveData,
object_data: []ObjectData,
camera_entity: Entity,
pub fn init(app: *App) !*Renderer {
// A string buffer used to format objects' labels.
@ -207,6 +225,12 @@ pub fn init(app: *App) !*Renderer {
};
}
_ = try app.world.component(Transform);
_ = try app.world.component(CameraPerspective);
const camera_entity = try app.world.entity(.{ .name = "Camera" }, .{ Transform, CameraPerspective });
camera_entity.set(CameraPerspective, .{ .field_of_view = 45.0, .near_plane = 0.05, .far_plane = 80.0 });
const result = try app.allocator.create(Renderer);
result.* = .{
.app = app,
@ -215,6 +239,7 @@ pub fn init(app: *App) !*Renderer {
.camera_bind_group = camera_bind_group,
.primitive_data = primitive_data,
.object_data = object_data,
.camera_entity = camera_entity,
};
// Initialize the depth texture.
@ -265,12 +290,23 @@ pub fn update(self: *Renderer) void {
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));
// 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
// outside of the rendering step, and then get and use it here, instead.
self.camera_entity.set(Transform, .{ .value = view_matrix });
// TODO: Not sure if this is the proper transform, or actually inverted.
// Set up a projection matrix using the size of the window.
// The perspective projection will make things further away appear smaller.
const width: f32 = @floatFromInt(core.descriptor.width);
const height: f32 = @floatFromInt(core.descriptor.height);
const field_of_view = std.math.degreesToRadians(f32, 45.0);
const proj_matrix = zm.perspectiveFovLh(field_of_view, width / height, 0.05, 80.0);
const perspective = self.camera_entity.get(CameraPerspective).?;
const proj_matrix = zm.perspectiveFovLh(
std.math.degreesToRadians(f32, perspective.field_of_view),
width / height,
perspective.near_plane,
perspective.far_plane,
);
const view_proj_matrix = zm.mul(view_matrix, proj_matrix);

Loading…
Cancel
Save