Skip to content

Commit

Permalink
all: update to global vs. local ECS change
Browse files Browse the repository at this point in the history
See hexops-graveyard/mach-ecs@ef06fb6

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
  • Loading branch information
emidoots committed Dec 17, 2023
1 parent 2464a23 commit b1364d0
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 95 deletions.
4 changes: 2 additions & 2 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
.hash = "12207d0872fdffc8f6755638a7a997f8ac77685df742366e88710e3b7ca0e3756f8b",
},
.mach = .{
.url = "https://pkg.machengine.org/mach/d48690fdca7e7d185536ca60a4000b5b06604048.tar.gz",
.hash = "1220a5f8b65fb7e0f897061e3fe51234bc615eaa719d607d2921f037c58a0ea7a5b1",
.url = "https://pkg.machengine.org/mach/8ff30c931f16d24e8801e5aa56c4974411427799.tar.gz",
.hash = "122023c305c28c287ddaf370cb0b5f1399d3554a7a5d9a44d35c7cf5a7356663f098",
},
.mach_freetype = .{
.url = "https://pkg.machengine.org/mach-freetype/a6d971285dfe731e49f82e81c81da2b7f5c6a442.tar.gz",
Expand Down
188 changes: 95 additions & 93 deletions examples/glyphs/Text.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,99 +15,6 @@ ft: ft.Library,
face: ft.Face,
regions: RegionMap = .{},

pub fn gameTextInit(
engine: *mach.Mod(.engine),
text_mod: *mach.Mod(.game_text),
) !void {
const device = engine.state.device;

// rgba32_pixels
const img_size = gpu.Extent3D{ .width = 1024, .height = 1024 };

// Create a GPU texture
const texture = device.createTexture(&.{
.size = img_size,
.format = .rgba8_unorm,
.usage = .{
.texture_binding = true,
.copy_dst = true,
.render_attachment = true,
},
});

var s = &text_mod.state;
s.texture = texture;
s.texture_atlas = try mach.gfx.Atlas.init(
engine.allocator,
img_size.width,
.rgba,
);

// TODO: state fields' default values do not work
s.regions = .{};

s.ft = try ft.Library.init();
s.face = try s.ft.createFaceMemory(assets.fonts.roboto_medium.bytes, 0);

try text_mod.send(.prepare, .{&[_]u21{ '?', '!', 'a', 'b', '#', '@', '%', '$', '&', '^', '*', '+', '=', '<', '>', '/', ':', ';', 'Q', '~' }});
}

pub fn gameTextPrepare(
engine: *mach.Mod(.engine),
text_mod: *mach.Mod(.game_text),
codepoints: []const u21,
) !void {
const device = engine.state.device;
const queue = device.getQueue();
var s = &text_mod.state;

for (codepoints) |codepoint| {
const font_size = 48 * 1;
try s.face.setCharSize(font_size * 64, 0, 50, 0);
try s.face.loadChar(codepoint, .{ .render = true });
const glyph = s.face.glyph();
const metrics = glyph.metrics();

const glyph_bitmap = glyph.bitmap();
const glyph_width = glyph_bitmap.width();
const glyph_height = glyph_bitmap.rows();

// Add 1 pixel padding to texture to avoid bleeding over other textures
const margin = 1;
var glyph_data = try engine.allocator.alloc([4]u8, (glyph_width + (margin * 2)) * (glyph_height + (margin * 2)));
defer engine.allocator.free(glyph_data);
const glyph_buffer = glyph_bitmap.buffer().?;
for (glyph_data, 0..) |*data, i| {
const x = i % (glyph_width + (margin * 2));
const y = i / (glyph_width + (margin * 2));
if (x < margin or x > (glyph_width + margin) or y < margin or y > (glyph_height + margin)) {
data.* = [4]u8{ 0, 0, 0, 0 };
} else {
const alpha = glyph_buffer[((y - margin) * glyph_width + (x - margin)) % glyph_buffer.len];
data.* = [4]u8{ 0, 0, 0, alpha };
}
}
var glyph_atlas_region = try s.texture_atlas.reserve(engine.allocator, glyph_width + (margin * 2), glyph_height + (margin * 2));
s.texture_atlas.set(glyph_atlas_region, @as([*]const u8, @ptrCast(glyph_data.ptr))[0 .. glyph_data.len * 4]);

glyph_atlas_region.x += margin;
glyph_atlas_region.y += margin;
glyph_atlas_region.width -= margin * 2;
glyph_atlas_region.height -= margin * 2;

try s.regions.put(engine.allocator, codepoint, glyph_atlas_region);
_ = metrics;
}

// rgba32_pixels
const img_size = gpu.Extent3D{ .width = 1024, .height = 1024 };
const data_layout = gpu.Texture.DataLayout{
.bytes_per_row = @as(u32, @intCast(img_size.width * 4)),
.rows_per_image = @as(u32, @intCast(img_size.height)),
};
queue.writeTexture(&.{ .texture = s.texture }, &data_layout, &img_size, s.texture_atlas.data);
}

pub fn deinit(
engine: *mach.Mod(.engine),
text_mod: *mach.Mod(.game_text),
Expand All @@ -118,3 +25,98 @@ pub fn deinit(
text_mod.state.ft.deinit();
text_mod.state.regions.deinit(engine.allocator);
}

pub const local = struct {
pub fn init(
engine: *mach.Mod(.engine),
text_mod: *mach.Mod(.game_text),
) !void {
const device = engine.state.device;

// rgba32_pixels
const img_size = gpu.Extent3D{ .width = 1024, .height = 1024 };

// Create a GPU texture
const texture = device.createTexture(&.{
.size = img_size,
.format = .rgba8_unorm,
.usage = .{
.texture_binding = true,
.copy_dst = true,
.render_attachment = true,
},
});

var s = &text_mod.state;
s.texture = texture;
s.texture_atlas = try mach.gfx.Atlas.init(
engine.allocator,
img_size.width,
.rgba,
);

// TODO: state fields' default values do not work
s.regions = .{};

s.ft = try ft.Library.init();
s.face = try s.ft.createFaceMemory(assets.fonts.roboto_medium.bytes, 0);

try text_mod.send(.prepare, .{&[_]u21{ '?', '!', 'a', 'b', '#', '@', '%', '$', '&', '^', '*', '+', '=', '<', '>', '/', ':', ';', 'Q', '~' }});
}

pub fn prepare(
engine: *mach.Mod(.engine),
text_mod: *mach.Mod(.game_text),
codepoints: []const u21,
) !void {
const device = engine.state.device;
const queue = device.getQueue();
var s = &text_mod.state;

for (codepoints) |codepoint| {
const font_size = 48 * 1;
try s.face.setCharSize(font_size * 64, 0, 50, 0);
try s.face.loadChar(codepoint, .{ .render = true });
const glyph = s.face.glyph();
const metrics = glyph.metrics();

const glyph_bitmap = glyph.bitmap();
const glyph_width = glyph_bitmap.width();
const glyph_height = glyph_bitmap.rows();

// Add 1 pixel padding to texture to avoid bleeding over other textures
const margin = 1;
var glyph_data = try engine.allocator.alloc([4]u8, (glyph_width + (margin * 2)) * (glyph_height + (margin * 2)));
defer engine.allocator.free(glyph_data);
const glyph_buffer = glyph_bitmap.buffer().?;
for (glyph_data, 0..) |*data, i| {
const x = i % (glyph_width + (margin * 2));
const y = i / (glyph_width + (margin * 2));
if (x < margin or x > (glyph_width + margin) or y < margin or y > (glyph_height + margin)) {
data.* = [4]u8{ 0, 0, 0, 0 };
} else {
const alpha = glyph_buffer[((y - margin) * glyph_width + (x - margin)) % glyph_buffer.len];
data.* = [4]u8{ 0, 0, 0, alpha };
}
}
var glyph_atlas_region = try s.texture_atlas.reserve(engine.allocator, glyph_width + (margin * 2), glyph_height + (margin * 2));
s.texture_atlas.set(glyph_atlas_region, @as([*]const u8, @ptrCast(glyph_data.ptr))[0 .. glyph_data.len * 4]);

glyph_atlas_region.x += margin;
glyph_atlas_region.y += margin;
glyph_atlas_region.width -= margin * 2;
glyph_atlas_region.height -= margin * 2;

try s.regions.put(engine.allocator, codepoint, glyph_atlas_region);
_ = metrics;
}

// rgba32_pixels
const img_size = gpu.Extent3D{ .width = 1024, .height = 1024 };
const data_layout = gpu.Texture.DataLayout{
.bytes_per_row = @as(u32, @intCast(img_size.width * 4)),
.rows_per_image = @as(u32, @intCast(img_size.height)),
};
queue.writeTexture(&.{ .texture = s.texture }, &data_layout, &img_size, s.texture_atlas.data);
}
};

0 comments on commit b1364d0

Please sign in to comment.