{Core,examples}: set window title via component
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
79dccb4d73
commit
68677b3448
5 changed files with 104 additions and 19 deletions
|
|
@ -51,7 +51,7 @@ fn init(game: *Mod, core: *mach.Core.Mod) !void {
|
||||||
.title_timer = try mach.Timer.start(),
|
.title_timer = try mach.Timer.start(),
|
||||||
.pipeline = pipeline,
|
.pipeline = pipeline,
|
||||||
});
|
});
|
||||||
try updateWindowTitle();
|
try updateWindowTitle(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(game: *Mod) void {
|
pub fn deinit(game: *Mod) void {
|
||||||
|
|
@ -109,13 +109,19 @@ fn tick(core: *mach.Core.Mod, game: *Mod) !void {
|
||||||
// update the window title every second
|
// update the window title every second
|
||||||
if (game.state().title_timer.read() >= 1.0) {
|
if (game.state().title_timer.read() >= 1.0) {
|
||||||
game.state().title_timer.reset();
|
game.state().title_timer.reset();
|
||||||
try updateWindowTitle();
|
try updateWindowTitle(core);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn updateWindowTitle() !void {
|
fn updateWindowTitle(core: *mach.Core.Mod) !void {
|
||||||
try mach.core.printTitle("mach.Core - custom entrypoint [ {d}fps ] [ Input {d}hz ]", .{
|
try mach.Core.printTitle(
|
||||||
mach.core.frameRate(),
|
core,
|
||||||
mach.core.inputRate(),
|
core.state().main_window,
|
||||||
});
|
"core-custom-entrypoint [ {d}fps ] [ Input {d}hz ]",
|
||||||
|
.{
|
||||||
|
mach.core.frameRate(),
|
||||||
|
mach.core.inputRate(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
core.send(.update, .{});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,6 @@ fn afterInit(
|
||||||
glyphs: *Glyphs.Mod,
|
glyphs: *Glyphs.Mod,
|
||||||
game: *Mod,
|
game: *Mod,
|
||||||
) !void {
|
) !void {
|
||||||
// The Mach .core is where we set window options, etc.
|
|
||||||
mach.core.setTitle("gfx.Sprite example");
|
|
||||||
|
|
||||||
// Create a sprite rendering pipeline
|
// Create a sprite rendering pipeline
|
||||||
const texture = glyphs.state().texture;
|
const texture = glyphs.state().texture;
|
||||||
const pipeline = try sprite_pipeline.newEntity();
|
const pipeline = try sprite_pipeline.newEntity();
|
||||||
|
|
@ -231,7 +228,7 @@ fn tick(
|
||||||
game.state().time += delta_time;
|
game.state().time += delta_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn endFrame(game: *Mod) !void {
|
fn endFrame(game: *Mod, core: *mach.Core.Mod) !void {
|
||||||
// Finish render pass
|
// Finish render pass
|
||||||
game.state().frame_render_pass.end();
|
game.state().frame_render_pass.end();
|
||||||
const label = @tagName(name) ++ ".endFrame";
|
const label = @tagName(name) ++ ".endFrame";
|
||||||
|
|
@ -245,7 +242,13 @@ fn endFrame(game: *Mod) !void {
|
||||||
|
|
||||||
// Every second, update the window title with the FPS
|
// Every second, update the window title with the FPS
|
||||||
if (game.state().fps_timer.read() >= 1.0) {
|
if (game.state().fps_timer.read() >= 1.0) {
|
||||||
try mach.core.printTitle("gfx.Sprite example [ FPS: {d} ] [ Sprites: {d} ]", .{ game.state().frame_count, game.state().sprites });
|
try mach.Core.printTitle(
|
||||||
|
core,
|
||||||
|
core.state().main_window,
|
||||||
|
"glyphs [ FPS: {d} ] [ Sprites: {d} ]",
|
||||||
|
.{ game.state().frame_count, game.state().sprites },
|
||||||
|
);
|
||||||
|
core.send(.update, .{});
|
||||||
game.state().fps_timer.reset();
|
game.state().fps_timer.reset();
|
||||||
game.state().frame_count = 0;
|
game.state().frame_count = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,6 @@ fn init(
|
||||||
sprite_pipeline: *gfx.SpritePipeline.Mod,
|
sprite_pipeline: *gfx.SpritePipeline.Mod,
|
||||||
game: *Mod,
|
game: *Mod,
|
||||||
) !void {
|
) !void {
|
||||||
// The Mach .core is where we set window options, etc.
|
|
||||||
mach.core.setTitle("gfx.Sprite example");
|
|
||||||
|
|
||||||
// We can create entities, and set components on them. Note that components live in a module
|
// We can create entities, and set components on them. Note that components live in a module
|
||||||
// namespace, e.g. the `.mach_gfx_sprite` module could have a 3D `.location` component with a different
|
// namespace, e.g. the `.mach_gfx_sprite` module could have a 3D `.location` component with a different
|
||||||
// type than the `.physics2d` module's `.location` component if you desire.
|
// type than the `.physics2d` module's `.location` component if you desire.
|
||||||
|
|
@ -215,7 +212,7 @@ fn tick(
|
||||||
game.state().time += delta_time;
|
game.state().time += delta_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn endFrame(game: *Mod) !void {
|
fn endFrame(game: *Mod, core: *mach.Core.Mod) !void {
|
||||||
// Finish render pass
|
// Finish render pass
|
||||||
game.state().frame_render_pass.end();
|
game.state().frame_render_pass.end();
|
||||||
const label = @tagName(name) ++ ".endFrame";
|
const label = @tagName(name) ++ ".endFrame";
|
||||||
|
|
@ -229,7 +226,13 @@ fn endFrame(game: *Mod) !void {
|
||||||
|
|
||||||
// Every second, update the window title with the FPS
|
// Every second, update the window title with the FPS
|
||||||
if (game.state().fps_timer.read() >= 1.0) {
|
if (game.state().fps_timer.read() >= 1.0) {
|
||||||
try mach.core.printTitle("gfx.Sprite example [ FPS: {d} ] [ Sprites: {d} ]", .{ game.state().frame_count, game.state().sprites });
|
try mach.Core.printTitle(
|
||||||
|
core,
|
||||||
|
core.state().main_window,
|
||||||
|
"sprite [ FPS: {d} ] [ Sprites: {d} ]",
|
||||||
|
.{ game.state().frame_count, game.state().sprites },
|
||||||
|
);
|
||||||
|
core.send(.update, .{});
|
||||||
game.state().fps_timer.reset();
|
game.state().fps_timer.reset();
|
||||||
game.state().frame_count = 0;
|
game.state().frame_count = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,7 @@ fn tick(
|
||||||
game.state().time += delta_time;
|
game.state().time += delta_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn endFrame(game: *Mod, text: *gfx.Text.Mod) !void {
|
fn endFrame(game: *Mod, text: *gfx.Text.Mod, core: *mach.Core.Mod) !void {
|
||||||
// Finish render pass
|
// Finish render pass
|
||||||
game.state().frame_render_pass.end();
|
game.state().frame_render_pass.end();
|
||||||
const label = @tagName(name) ++ ".tick";
|
const label = @tagName(name) ++ ".tick";
|
||||||
|
|
@ -288,7 +288,13 @@ fn endFrame(game: *Mod, text: *gfx.Text.Mod) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try mach.core.printTitle("gfx.Text example [ FPS: {d} ] [ Texts: {d} ] [ Glyphs: {d} ]", .{ game.state().frame_count, num_texts, num_glyphs });
|
try mach.Core.printTitle(
|
||||||
|
core,
|
||||||
|
core.state().main_window,
|
||||||
|
"text [ FPS: {d} ] [ Texts: {d} ] [ Glyphs: {d} ]",
|
||||||
|
.{ game.state().frame_count, num_texts, num_glyphs },
|
||||||
|
);
|
||||||
|
core.send(.update, .{});
|
||||||
game.state().fps_timer.reset();
|
game.state().fps_timer.reset();
|
||||||
game.state().frame_count = 0;
|
game.state().frame_count = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
67
src/Core.zig
67
src/Core.zig
|
|
@ -15,6 +15,10 @@ pub const global_events = .{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const local_events = .{
|
pub const local_events = .{
|
||||||
|
.update = .{ .handler = update, .description =
|
||||||
|
\\ Send this when window entities have been updated and you want the new values respected.
|
||||||
|
},
|
||||||
|
|
||||||
.init = .{ .handler = init },
|
.init = .{ .handler = init },
|
||||||
.init_done = .{ .handler = fn () void },
|
.init_done = .{ .handler = fn () void },
|
||||||
|
|
||||||
|
|
@ -26,10 +30,40 @@ pub const local_events = .{
|
||||||
.exit = .{ .handler = exit },
|
.exit = .{ .handler = exit },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const components = .{
|
||||||
|
.title = .{ .type = [:0]u8, .description =
|
||||||
|
\\ Window title slice. Can be set with a format string and arguments via:
|
||||||
|
\\
|
||||||
|
\\ ```
|
||||||
|
\\ try mach.Core.printTitle(core_mod, core_mod.state().main_window, "Hello, {s}!", .{"Mach"});
|
||||||
|
\\ ```
|
||||||
|
\\
|
||||||
|
\\ If setting this component yourself, ensure the buffer is allocated using core.state().allocator
|
||||||
|
\\ as it will be freed for you as part of the .deinit event.
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Prints into the window title buffer using a format string and arguments. e.g.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// try mach.Core.printTitle(core_mod, core_mod.state().main_window, "Hello, {s}!", .{"Mach"});
|
||||||
|
/// ```
|
||||||
|
pub fn printTitle(
|
||||||
|
core: *mach.Core.Mod,
|
||||||
|
window_id: mach.EntityID,
|
||||||
|
comptime fmt: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) !void {
|
||||||
|
const slice = try std.fmt.allocPrintZ(core.state().allocator, fmt, args);
|
||||||
|
try core.set(window_id, .title, slice);
|
||||||
|
}
|
||||||
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
device: *mach.gpu.Device,
|
device: *mach.gpu.Device,
|
||||||
queue: *mach.gpu.Queue,
|
queue: *mach.gpu.Queue,
|
||||||
|
main_window: mach.EntityID,
|
||||||
should_exit: bool = false,
|
should_exit: bool = false,
|
||||||
|
|
||||||
fn init(core: *Mod) !void {
|
fn init(core: *Mod) !void {
|
||||||
|
|
@ -41,19 +75,52 @@ fn init(core: *Mod) !void {
|
||||||
try mach.core.init(.{});
|
try mach.core.init(.{});
|
||||||
|
|
||||||
core.init(.{
|
core.init(.{
|
||||||
|
.allocator = mach.core.allocator,
|
||||||
.device = mach.core.device,
|
.device = mach.core.device,
|
||||||
.queue = mach.core.device.getQueue(),
|
.queue = mach.core.device.getQueue(),
|
||||||
|
.main_window = try core.newEntity(),
|
||||||
});
|
});
|
||||||
|
|
||||||
core.sendGlobal(.init, .{});
|
core.sendGlobal(.init, .{});
|
||||||
core.send(.init_done, .{});
|
core.send(.init_done, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update(core: *Mod) !void {
|
||||||
|
var archetypes_iter = core.entities.query(.{ .all = &.{
|
||||||
|
.{ .mach_core = &.{
|
||||||
|
.title,
|
||||||
|
} },
|
||||||
|
} });
|
||||||
|
|
||||||
|
var num_windows: usize = 0;
|
||||||
|
while (archetypes_iter.next()) |archetype| {
|
||||||
|
for (
|
||||||
|
archetype.slice(.entity, .id),
|
||||||
|
archetype.slice(.mach_core, .title),
|
||||||
|
) |window_id, title| {
|
||||||
|
num_windows += 1;
|
||||||
|
_ = window_id;
|
||||||
|
try mach.core.printTitle("{s}", .{title});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_windows > 1) @panic("mach: Core currently only supports a single window");
|
||||||
|
}
|
||||||
|
|
||||||
fn deinit(core: *Mod) void {
|
fn deinit(core: *Mod) void {
|
||||||
core.state().queue.release();
|
core.state().queue.release();
|
||||||
// TODO: this triggers a device loss error, which we should handle correctly
|
// TODO: this triggers a device loss error, which we should handle correctly
|
||||||
// core.state().device.release();
|
// core.state().device.release();
|
||||||
mach.core.deinit();
|
mach.core.deinit();
|
||||||
|
|
||||||
|
var archetypes_iter = core.entities.query(.{ .all = &.{
|
||||||
|
.{ .mach_core = &.{
|
||||||
|
.title,
|
||||||
|
} },
|
||||||
|
} });
|
||||||
|
while (archetypes_iter.next()) |archetype| {
|
||||||
|
for (archetype.slice(.mach_core, .title)) |title| core.state().allocator.free(title);
|
||||||
|
}
|
||||||
|
|
||||||
_ = gpa.deinit();
|
_ = gpa.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue