From 7fdc7a9dfcb7e66c68b760bffac1045d595620c3 Mon Sep 17 00:00:00 2001 From: Louis Pearson Date: Fri, 16 Feb 2024 17:58:42 -0700 Subject: [PATCH] feat: add mach-freetype, render a glyph --- build.zig | 10 ++++++++++ build.zig.zon | 15 +++++++++++++++ src/main.zig | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 build.zig.zon diff --git a/build.zig b/build.zig index 121a518..c6673a5 100644 --- a/build.zig +++ b/build.zig @@ -24,5 +24,15 @@ pub fn build(b: *std.Build) void { exe.addIncludePath(.{ .path = "deps/font8x8/" }); + const mach_freetype_dep = b.dependency("mach_freetype", .{ + .target = target, + .optimize = optimize, + }); + exe.root_module.addImport("freetype", mach_freetype_dep.module("mach-freetype")); + exe.root_module.addImport("harfbuzz", mach_freetype_dep.module("mach-harfbuzz")); + + const font_assets_dep = b.dependency("font_assets", .{}); + exe.root_module.addImport("font-assets", font_assets_dep.module("font-assets")); + b.installArtifact(exe); } diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..5084e3b --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,15 @@ +.{ + .name = "pinephone-test", + .version = "0.0.0", + .paths = .{""}, + .dependencies = .{ + .mach_freetype = .{ + .url = "https://pkg.machengine.org/mach-freetype/dc4a5d8ce14f8678f35bdaf197303091e22b1f27.tar.gz", + .hash = "122070070dd2c402d94c279d64d4a4d154691ad49f46fa2c24ed7c6e4e4f5c531477", + }, + .font_assets = .{ + .url = "https://pkg.machengine.org/font-assets/6b43c160451e8fa5c64620ffb614929feacf2f5d.tar.gz", + .hash = "12202039304f0603a9706105788e450fd4f901c3e20eca28a52a2173879b14c606c7", + }, + }, +} diff --git a/src/main.zig b/src/main.zig index a805968..b627f14 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,5 +1,7 @@ const std = @import("std"); const wayland = @import("root.zig"); +const freetype = @import("freetype"); +const font_assets = @import("font-assets"); const Conn = wayland.Conn; const Context = wayland.Context(&.{ @@ -63,6 +65,12 @@ pub fn main() !void { var conn = try Conn.init(gpa, display_path); defer conn.deinit(); + const freetype_lib = try freetype.Library.init(); + defer freetype_lib.deinit(); + + const face = try freetype_lib.createFaceMemory(font_assets.fira_sans_regular_ttf, 0); + try face.setCharSize(60 * 48, 0, 50, 0); + // Register all globals var ctx = try Context.init(&conn); @@ -85,6 +93,8 @@ pub fn main() !void { .ctx = &ctx, .ally = gpa, .callbacks = std.AutoHashMap(u32, App.Callback).init(gpa), + .freetype_lib = freetype_lib, + .font_face = face, .state = .{ .init = .{} }, .display = display, .shm = shm, @@ -154,6 +164,8 @@ const App = struct { ctx: *Context, ally: std.mem.Allocator, callbacks: std.AutoHashMap(u32, Callback), + freetype_lib: freetype.Library, + font_face: freetype.Face, display: wayland.core.Display, shm: wayland.core.Shm, @@ -438,6 +450,33 @@ const Canvas = struct { } } } + + fn blitFreetypeBitmap(canvas: Canvas, bitmap: freetype.Bitmap, pos: [2]u32) void { + const fb = canvas.fb; + const width = canvas.size[0]; + const height = canvas.size[1]; + const rows = bitmap.rows(); + const cols = bitmap.width(); + const left = pos[0]; + const top = pos[1]; + const right = @min(left + cols, width); + const bottom = @min(top + rows, height); + const buffer = bitmap.buffer().?; + if (pos[0] > width or pos[1] > height) return; + for (top..bottom, 0..) |y, i| { + const row = fb[y * width .. (y + 1) * width]; + for (left..right, 0..) |x, a| { + const pixel = &row[x]; + const intensity = buffer[i * cols + a]; + pixel.* = .{ + intensity, + intensity, + intensity, + 0xFF, + }; + } + } + } }; fn wmbaseHandler(app: *App, header: wayland.Header, body: []const u32) !void { @@ -484,7 +523,10 @@ fn surfaceDesktopHandler(app: *App, header: wayland.Header, body: []const u32) ! // render const canvas = try pool.getFramebuffer(.{ width, height }); + try app.font_face.loadChar('H', .{ .render = true }); + const bitmap = app.font_face.glyph().bitmap(); canvas.renderGradient(); + canvas.blitFreetypeBitmap(bitmap, .{ 0, 0 }); try canvas.attach(app.surface); try app.callbacks.put(canvas.buffer.id, bufferHandler); },