mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
font: add method for drawing atlas to canvas
This commit is contained in:
@ -30,6 +30,7 @@ fetch(url.href).then(response =>
|
|||||||
face_debug_canvas,
|
face_debug_canvas,
|
||||||
atlas_new,
|
atlas_new,
|
||||||
atlas_free,
|
atlas_free,
|
||||||
|
atlas_debug_canvas,
|
||||||
} = results.instance.exports;
|
} = results.instance.exports;
|
||||||
// Give us access to the zjs value for debugging.
|
// Give us access to the zjs value for debugging.
|
||||||
globalThis.zjs = zjs;
|
globalThis.zjs = zjs;
|
||||||
@ -47,14 +48,21 @@ fetch(url.href).then(response =>
|
|||||||
new Uint8Array(memory.buffer, font_ptr).set(font);
|
new Uint8Array(memory.buffer, font_ptr).set(font);
|
||||||
|
|
||||||
// Call whatever example you want:
|
// Call whatever example you want:
|
||||||
const face = face_new(font_ptr, font.byteLength, 144);
|
const face = face_new(font_ptr, font.byteLength, 72);
|
||||||
free(font_ptr);
|
free(font_ptr);
|
||||||
|
|
||||||
// Render a glyph
|
// Render a glyph
|
||||||
face_render_glyph(face, atlas, "A".codePointAt(0));
|
for (let i = 33; i <= 126; i++) {
|
||||||
|
face_render_glyph(face, atlas, i);
|
||||||
|
}
|
||||||
|
// face_render_glyph(face, atlas, "A".codePointAt(0));
|
||||||
|
|
||||||
// Debug our canvas
|
// Debug our canvas
|
||||||
face_debug_canvas(face);
|
face_debug_canvas(face);
|
||||||
|
|
||||||
|
// Debug our atlas canvas
|
||||||
|
const id = atlas_debug_canvas(atlas);
|
||||||
|
document.getElementById("atlas-canvas").append(zjs.deleteValue(id));
|
||||||
|
|
||||||
//face_free(face);
|
//face_free(face);
|
||||||
});
|
});
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
<body>
|
<body>
|
||||||
<p>Open your console, we are just debugging here.</p>
|
<p>Open your console, we are just debugging here.</p>
|
||||||
<p>The font rendering canvas should show below. This shows a single glyph.</p>
|
<p>The font rendering canvas should show below. This shows a single glyph.</p>
|
||||||
<div id="face-canvas" style="display: inline-block; border: 1px solid red;"></div>
|
<div><div id="face-canvas" style="display: inline-block; border: 1px solid red;"></div></div>
|
||||||
|
<p>The current font atlas is rendered below.</p>
|
||||||
|
<div><div id="atlas-canvas" style="display: inline-block; border: 1px solid green;"></div></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -21,6 +21,8 @@ const Allocator = std.mem.Allocator;
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const fastmem = @import("../fastmem.zig");
|
const fastmem = @import("../fastmem.zig");
|
||||||
|
|
||||||
|
const log = std.log.scoped(.atlas);
|
||||||
|
|
||||||
/// Data is the raw texture data.
|
/// Data is the raw texture data.
|
||||||
data: []u8,
|
data: []u8,
|
||||||
|
|
||||||
@ -309,6 +311,7 @@ pub const Wasm = struct {
|
|||||||
// just replace this with the allocator you want to use.
|
// just replace this with the allocator you want to use.
|
||||||
const wasm = @import("../os/wasm.zig");
|
const wasm = @import("../os/wasm.zig");
|
||||||
const alloc = wasm.alloc;
|
const alloc = wasm.alloc;
|
||||||
|
const js = @import("zig-js");
|
||||||
|
|
||||||
export fn atlas_new(size: u32, format: u8) ?*Atlas {
|
export fn atlas_new(size: u32, format: u8) ?*Atlas {
|
||||||
const atlas = init(
|
const atlas = init(
|
||||||
@ -321,6 +324,13 @@ pub const Wasm = struct {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export fn atlas_free(ptr: ?*Atlas) void {
|
||||||
|
if (ptr) |v| {
|
||||||
|
v.deinit(alloc);
|
||||||
|
alloc.destroy(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The return value for this should be freed by the caller with "free".
|
/// The return value for this should be freed by the caller with "free".
|
||||||
export fn atlas_reserve(self: *Atlas, width: u32, height: u32) ?*Region {
|
export fn atlas_reserve(self: *Atlas, width: u32, height: u32) ?*Region {
|
||||||
return atlas_reserve_(self, width, height) catch return null;
|
return atlas_reserve_(self, width, height) catch return null;
|
||||||
@ -348,11 +358,89 @@ pub const Wasm = struct {
|
|||||||
self.clear();
|
self.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn atlas_free(ptr: ?*Atlas) void {
|
/// This creates a Canvas element identified by the id returned that
|
||||||
if (ptr) |v| {
|
/// the caller can draw into the DOM to visualize the atlas. The returned
|
||||||
v.deinit(alloc);
|
/// ID must be freed from the JS runtime by calling "zigjs.deleteValue".
|
||||||
alloc.destroy(v);
|
export fn atlas_debug_canvas(self: *Atlas) u32 {
|
||||||
|
return atlas_debug_canvas_(self) catch |err| {
|
||||||
|
log.warn("error dumping atlas canvas err={}", .{err});
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atlas_debug_canvas_(self: *Atlas) !u32 {
|
||||||
|
// Create our canvas
|
||||||
|
const doc = try js.global.get(js.Object, "document");
|
||||||
|
defer doc.deinit();
|
||||||
|
const canvas = try doc.call(js.Object, "createElement", .{js.string("canvas")});
|
||||||
|
errdefer canvas.deinit();
|
||||||
|
|
||||||
|
// Setup our canvas size
|
||||||
|
{
|
||||||
|
try canvas.set("width", self.size);
|
||||||
|
try canvas.set("height", self.size);
|
||||||
|
|
||||||
|
const width_str = try std.fmt.allocPrint(alloc, "{d}px", .{self.size});
|
||||||
|
defer alloc.free(width_str);
|
||||||
|
|
||||||
|
const style = try canvas.get(js.Object, "style");
|
||||||
|
defer style.deinit();
|
||||||
|
try style.set("width", js.string(width_str));
|
||||||
|
try style.set("height", js.string(width_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This will return the same context on subsequent calls so it
|
||||||
|
// is important to reset it.
|
||||||
|
const ctx = try canvas.call(js.Object, "getContext", .{js.string("2d")});
|
||||||
|
errdefer ctx.deinit();
|
||||||
|
|
||||||
|
// We need to draw pixels so this is format dependent.
|
||||||
|
var buf: []u8 = switch (self.format) {
|
||||||
|
// RGBA is the native ImageData format
|
||||||
|
.rgba => self.data,
|
||||||
|
|
||||||
|
.greyscale => buf: {
|
||||||
|
// Convert from A8 to RGBA so every 4th byte is set to a value.
|
||||||
|
var buf: []u8 = try alloc.alloc(u8, self.data.len * 4);
|
||||||
|
errdefer alloc.free(buf);
|
||||||
|
std.mem.set(u8, buf, 0);
|
||||||
|
for (self.data) |value, i| {
|
||||||
|
buf[(i * 4) + 3] = value;
|
||||||
|
}
|
||||||
|
break :buf buf;
|
||||||
|
},
|
||||||
|
|
||||||
|
else => return error.UnsupportedAtlasFormat,
|
||||||
|
};
|
||||||
|
defer if (buf.ptr != self.data.ptr) alloc.free(buf);
|
||||||
|
|
||||||
|
// Create an ImageData from our buffer and then write it to the canvas
|
||||||
|
const image_data: js.Object = data: {
|
||||||
|
// Get our runtime memory
|
||||||
|
const mem = try js.runtime.get(js.Object, "memory");
|
||||||
|
defer mem.deinit();
|
||||||
|
const mem_buf = try mem.get(js.Object, "buffer");
|
||||||
|
defer mem_buf.deinit();
|
||||||
|
|
||||||
|
// Create an array that points to our buffer
|
||||||
|
const Uint8ClampedArray = try js.global.get(js.Object, "Uint8ClampedArray");
|
||||||
|
defer Uint8ClampedArray.deinit();
|
||||||
|
const arr = try Uint8ClampedArray.new(.{ mem_buf, buf.ptr, buf.len });
|
||||||
|
|
||||||
|
// Create the image data from our array
|
||||||
|
const ImageData = try js.global.get(js.Object, "ImageData");
|
||||||
|
defer ImageData.deinit();
|
||||||
|
const data = try ImageData.new(.{ arr, self.size, self.size });
|
||||||
|
errdefer data.deinit();
|
||||||
|
|
||||||
|
break :data data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Draw it
|
||||||
|
try ctx.call(void, "putImageData", .{ image_data, 0, 0 });
|
||||||
|
|
||||||
|
const id = @bitCast(js.Ref, @enumToInt(canvas.value)).id;
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "happy path" {
|
test "happy path" {
|
||||||
|
@ -215,7 +215,7 @@ pub const Face = struct {
|
|||||||
defer alloc.free(bitmap_a8);
|
defer alloc.free(bitmap_a8);
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < bitmap_a8.len) : (i += 1) {
|
while (i < bitmap_a8.len) : (i += 1) {
|
||||||
bitmap_a8[i] = bitmap[i * 4];
|
bitmap_a8[i] = bitmap[(i * 4) + 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put it in our atlas
|
// Put it in our atlas
|
||||||
|
2
vendor/zig-js
vendored
2
vendor/zig-js
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 00eb5166ea3a070ac985b2b4409f2e51877865f4
|
Subproject commit 52eed4daddcf9fa974ad4457691de26ef2351c56
|
Reference in New Issue
Block a user