mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Merge 1ece6f06b397c8853038b6fc3902529faeef04da into 4c2d4620007c4c774b7bc6fd282827c04c08686c
This commit is contained in:
99
build.zig
99
build.zig
@ -716,7 +716,8 @@ pub fn build(b: *std.Build) !void {
|
||||
// Build our Wasm target.
|
||||
const wasm_crosstarget: std.Target.Query = .{
|
||||
.cpu_arch = .wasm32,
|
||||
.os_tag = .freestanding,
|
||||
.os_tag = .wasi,
|
||||
.abi = .musl,
|
||||
.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
|
||||
.cpu_features_add = std.Target.wasm.featureSet(&.{
|
||||
// We use this to explicitly request shared memory.
|
||||
@ -748,7 +749,7 @@ pub fn build(b: *std.Build) !void {
|
||||
break :config copy;
|
||||
};
|
||||
|
||||
const wasm = b.addSharedLibrary(.{
|
||||
const wasm = b.addExecutable(.{
|
||||
.name = "ghostty-wasm",
|
||||
.root_source_file = b.path("src/main_wasm.zig"),
|
||||
.target = b.resolveTargetQuery(wasm_crosstarget),
|
||||
@ -757,9 +758,14 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// So that we can use web workers with our wasm binary
|
||||
wasm.import_memory = true;
|
||||
wasm.initial_memory = 65536 * 25;
|
||||
wasm.initial_memory = 65536 * 512;
|
||||
wasm.entry = .disabled;
|
||||
wasm.wasi_exec_model = .reactor;
|
||||
wasm.rdynamic = true;
|
||||
wasm.import_symbols = true;
|
||||
wasm.max_memory = 65536 * 65536; // Maximum number of pages in wasm32
|
||||
wasm.shared_memory = wasm_shared;
|
||||
wasm.root_module.single_threaded = false;
|
||||
|
||||
// Stack protector adds extern requirements that we don't satisfy.
|
||||
wasm.root_module.stack_protector = false;
|
||||
@ -769,10 +775,11 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
// Install
|
||||
const wasm_install = b.addInstallArtifact(wasm, .{});
|
||||
wasm_install.dest_dir = .{ .prefix = {} };
|
||||
const install = b.addInstallFile(wasm.getEmittedBin(), "../example/ghostty-wasm.wasm");
|
||||
wasm_install.step.dependOn(&install.step);
|
||||
|
||||
const step = b.step("wasm", "Build the wasm library");
|
||||
step.dependOn(&wasm_install.step);
|
||||
step.dependOn(&install.step);
|
||||
|
||||
// We support tests via wasmtime. wasmtime uses WASI so this
|
||||
// isn't an exact match to our freestanding target above but
|
||||
@ -1073,7 +1080,7 @@ fn addDeps(
|
||||
try static_libs.append(fontconfig_dep.artifact("fontconfig").getEmittedBin());
|
||||
}
|
||||
}
|
||||
|
||||
if (step.rootModuleTarget().cpu.arch != .wasm32) {
|
||||
// Libpng - Ghostty doesn't actually use this directly, its only used
|
||||
// through dependencies, so we only need to add it to our static
|
||||
// libs list if we're not using system integration. The dependencies
|
||||
@ -1149,6 +1156,7 @@ fn addDeps(
|
||||
step.linkLibrary(simdutf_dep.artifact("simdutf"));
|
||||
try static_libs.append(simdutf_dep.artifact("simdutf").getEmittedBin());
|
||||
}
|
||||
}
|
||||
|
||||
// Sentry
|
||||
const sentry_dep = b.dependency("sentry", .{
|
||||
@ -1157,7 +1165,7 @@ fn addDeps(
|
||||
.backend = .breakpad,
|
||||
});
|
||||
step.root_module.addImport("sentry", sentry_dep.module("sentry"));
|
||||
if (target.result.os.tag != .windows) {
|
||||
if (target.result.os.tag != .windows and target.result.cpu.arch != .wasm32) {
|
||||
// Sentry
|
||||
step.linkLibrary(sentry_dep.artifact("sentry"));
|
||||
try static_libs.append(sentry_dep.artifact("sentry").getEmittedBin());
|
||||
@ -1177,6 +1185,83 @@ fn addDeps(
|
||||
.optimize = optimize,
|
||||
});
|
||||
step.root_module.addImport("zig-js", js_dep.module("zig-js"));
|
||||
step.root_module.addImport("ziglyph", b.dependency("ziglyph", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}).module("ziglyph"));
|
||||
step.root_module.addImport("z2d", b.addModule("z2d", .{
|
||||
.root_source_file = b.dependency("z2d", .{}).path("src/z2d.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}));
|
||||
step.root_module.addImport("opengl", b.dependency(
|
||||
"opengl",
|
||||
.{},
|
||||
).module("opengl"));
|
||||
step.root_module.addImport("xev", b.dependency("libxev", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}).module("xev"));
|
||||
step.root_module.addImport("wuffs", b.dependency("wuffs", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}).module("wuffs"));
|
||||
const oniguruma_dep = b.dependency("oniguruma", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
step.root_module.addImport("oniguruma", oniguruma_dep.module("oniguruma"));
|
||||
step.linkLibrary(oniguruma_dep.artifact("oniguruma"));
|
||||
try static_libs.append(oniguruma_dep.artifact("oniguruma").getEmittedBin());
|
||||
const simdutf_dep = b.dependency("simdutf", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
const utfcpp_dep = b.dependency("utfcpp", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
step.linkLibrary(utfcpp_dep.artifact("utfcpp"));
|
||||
try static_libs.append(utfcpp_dep.artifact("utfcpp").getEmittedBin());
|
||||
step.linkLibrary(simdutf_dep.artifact("simdutf"));
|
||||
try static_libs.append(simdutf_dep.artifact("simdutf").getEmittedBin());
|
||||
step.linkLibC();
|
||||
step.linkLibCpp();
|
||||
step.addIncludePath(b.path("src"));
|
||||
{
|
||||
// From hwy/detect_targets.h
|
||||
const HWY_AVX3_SPR: c_int = 1 << 4;
|
||||
const HWY_AVX3_ZEN4: c_int = 1 << 6;
|
||||
const HWY_AVX3_DL: c_int = 1 << 7;
|
||||
const HWY_AVX3: c_int = 1 << 8;
|
||||
|
||||
// Zig 0.13 bug: https://github.com/ziglang/zig/issues/20414
|
||||
// To workaround this we just disable AVX512 support completely.
|
||||
// The performance difference between AVX2 and AVX512 is not
|
||||
// significant for our use case and AVX512 is very rare on consumer
|
||||
// hardware anyways.
|
||||
const HWY_DISABLED_TARGETS: c_int = HWY_AVX3_SPR | HWY_AVX3_ZEN4 | HWY_AVX3_DL | HWY_AVX3;
|
||||
|
||||
step.addCSourceFiles(.{
|
||||
.files = &.{
|
||||
"src/simd/base64.cpp",
|
||||
"src/simd/codepoint_width.cpp",
|
||||
"src/simd/index_of.cpp",
|
||||
"src/simd/vt.cpp",
|
||||
},
|
||||
.flags = if (step.rootModuleTarget().cpu.arch == .x86_64) &.{
|
||||
b.fmt("-DHWY_DISABLED_TARGETS={}", .{HWY_DISABLED_TARGETS}),
|
||||
} else &.{"-DSIMDUTF_NO_THREADS"},
|
||||
});
|
||||
}
|
||||
const highway_dep = b.dependency("highway", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
step.linkLibrary(highway_dep.artifact("highway"));
|
||||
try static_libs.append(highway_dep.artifact("highway").getEmittedBin());
|
||||
|
||||
try addUnicodeTables(b, step);
|
||||
|
||||
return static_libs;
|
||||
}
|
||||
|
@ -4,10 +4,7 @@
|
||||
.paths = .{""},
|
||||
.dependencies = .{
|
||||
// Zig libs
|
||||
.libxev = .{
|
||||
.url = "https://github.com/mitchellh/libxev/archive/b8d1d93e5c899b27abbaa7df23b496c3e6a178c7.tar.gz",
|
||||
.hash = "1220612bc023c21d75234882ec9a8c6a1cbd9d642da3dfb899297f14bb5bd7b6cd78",
|
||||
},
|
||||
.libxev = .{ .path = "../xev" },
|
||||
.mach_glfw = .{
|
||||
.url = "https://github.com/mitchellh/mach-glfw/archive/37c2995f31abcf7e8378fba68ddcf4a3faa02de0.tar.gz",
|
||||
.hash = "12206ed982e709e565d536ce930701a8c07edfd2cfdce428683f3f2a601d37696a62",
|
||||
|
10
example/.proxyrc.js
Normal file
10
example/.proxyrc.js
Normal file
@ -0,0 +1,10 @@
|
||||
module.exports = function (app) {
|
||||
app.use(
|
||||
(req, res, next) => {
|
||||
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
|
||||
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
|
||||
res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
|
||||
next();
|
||||
}
|
||||
);
|
||||
};
|
223
example/app.ts
223
example/app.ts
@ -1,65 +1,47 @@
|
||||
import { ZigJS } from "zig-js";
|
||||
|
||||
const zjs = new ZigJS();
|
||||
const importObject = {
|
||||
module: {},
|
||||
env: {
|
||||
memory: new WebAssembly.Memory({
|
||||
initial: 25,
|
||||
maximum: 65536,
|
||||
shared: true,
|
||||
}),
|
||||
log: (ptr: number, len: number) => {
|
||||
const arr = new Uint8ClampedArray(zjs.memory.buffer, ptr, len);
|
||||
const data = arr.slice();
|
||||
const str = new TextDecoder("utf-8").decode(data);
|
||||
console.log(str);
|
||||
},
|
||||
},
|
||||
|
||||
...zjs.importObject(),
|
||||
};
|
||||
import { importObject, setFiles, setStdin, setWasmModule, zjs } from "./imports";
|
||||
import { old } from "./old";
|
||||
|
||||
const url = new URL("ghostty-wasm.wasm", import.meta.url);
|
||||
fetch(url.href)
|
||||
.then((response) => response.arrayBuffer())
|
||||
.then((bytes) => WebAssembly.instantiate(bytes, importObject))
|
||||
.then((results) => {
|
||||
.then(async (results) => {
|
||||
const memory = importObject.env.memory;
|
||||
const {
|
||||
malloc,
|
||||
free,
|
||||
config_new,
|
||||
atlas_clear,
|
||||
atlas_debug_canvas,
|
||||
atlas_free,
|
||||
atlas_grow,
|
||||
atlas_new,
|
||||
atlas_reserve,
|
||||
atlas_set,
|
||||
config_finalize,
|
||||
config_free,
|
||||
config_load_string,
|
||||
config_finalize,
|
||||
face_new,
|
||||
face_free,
|
||||
face_render_glyph,
|
||||
face_debug_canvas,
|
||||
deferred_face_new,
|
||||
config_new,
|
||||
deferred_face_free,
|
||||
deferred_face_load,
|
||||
deferred_face_face,
|
||||
group_new,
|
||||
group_free,
|
||||
group_add_face,
|
||||
group_init_sprite_face,
|
||||
group_index_for_codepoint,
|
||||
group_render_glyph,
|
||||
group_cache_new,
|
||||
group_cache_free,
|
||||
group_cache_index_for_codepoint,
|
||||
group_cache_render_glyph,
|
||||
group_cache_atlas_grayscale,
|
||||
group_cache_atlas_color,
|
||||
atlas_new,
|
||||
atlas_free,
|
||||
atlas_debug_canvas,
|
||||
shaper_new,
|
||||
deferred_face_new,
|
||||
face_debug_canvas,
|
||||
face_free,
|
||||
face_new,
|
||||
face_render_glyph,
|
||||
free,
|
||||
malloc,
|
||||
shaper_free,
|
||||
shaper_new,
|
||||
shaper_test,
|
||||
collection_new,
|
||||
collection_add_deferred_face,
|
||||
shared_grid_new,
|
||||
shared_grid_atlas_grayscale,
|
||||
shared_grid_atlas_color,
|
||||
shared_grid_index_for_codepoint,
|
||||
shared_grid_render_glyph,
|
||||
run,
|
||||
draw,
|
||||
} = results.instance.exports;
|
||||
|
||||
// Give us access to the zjs value for debugging.
|
||||
globalThis.zjs = zjs;
|
||||
console.log(zjs);
|
||||
@ -76,114 +58,41 @@ fetch(url.href)
|
||||
};
|
||||
|
||||
// Create our config
|
||||
const config = config_new();
|
||||
const config_str = makeStr("font-family = monospace");
|
||||
config_load_string(config, config_str.ptr, config_str.len);
|
||||
config_finalize(config);
|
||||
free(config_str.ptr);
|
||||
|
||||
// Create our atlas
|
||||
// const atlas = atlas_new(512, 0 /* grayscale */);
|
||||
|
||||
// Create some memory for our string
|
||||
const font_name = makeStr("monospace");
|
||||
|
||||
// Initialize our deferred face
|
||||
// const df = deferred_face_new(font_ptr, font.byteLength, 0 /* text */);
|
||||
//deferred_face_load(df, 72 /* size */);
|
||||
//const face = deferred_face_face(df);
|
||||
|
||||
// Initialize our font face
|
||||
//const face = face_new(font_ptr, font.byteLength, 72 /* size in px */);
|
||||
//free(font_ptr);
|
||||
|
||||
// Create our group
|
||||
const group = group_new(32 /* size */);
|
||||
group_add_face(
|
||||
group,
|
||||
0 /* regular */,
|
||||
deferred_face_new(font_name.ptr, font_name.len, 0 /* text */),
|
||||
);
|
||||
group_add_face(
|
||||
group,
|
||||
0 /* regular */,
|
||||
deferred_face_new(font_name.ptr, font_name.len, 1 /* emoji */),
|
||||
);
|
||||
|
||||
// Initialize our sprite font, without this we just use the browser.
|
||||
group_init_sprite_face(group);
|
||||
|
||||
// Create our group cache
|
||||
const group_cache = group_cache_new(group);
|
||||
|
||||
// Render a glyph
|
||||
// for (let i = 33; i <= 126; i++) {
|
||||
// const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
|
||||
// group_cache_render_glyph(group_cache, font_idx, i, 0);
|
||||
// //face_render_glyph(face, atlas, i);
|
||||
// }
|
||||
//
|
||||
// const emoji = ["🐏","🌞","🌚","🍱","💿","🐈","📃","📀","🕡","🙃"];
|
||||
// for (let i = 0; i < emoji.length; i++) {
|
||||
// const cp = emoji[i].codePointAt(0);
|
||||
// const font_idx = group_cache_index_for_codepoint(group_cache, cp, 0, -1 /* best choice */);
|
||||
// group_cache_render_glyph(group_cache, font_idx, cp, 0);
|
||||
// }
|
||||
|
||||
for (let i = 0x2500; i <= 0x257f; i++) {
|
||||
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
|
||||
group_cache_render_glyph(group_cache, font_idx, i, 0);
|
||||
const config_str = makeStr("font-family = monospace\nfont-size = 32\n");
|
||||
// old(results);
|
||||
setWasmModule(results.module);
|
||||
const stdin = new SharedArrayBuffer(1024);
|
||||
const files = {
|
||||
nextFd: new SharedArrayBuffer(4),
|
||||
polling: new SharedArrayBuffer(4),
|
||||
has: new SharedArrayBuffer(1024),
|
||||
}
|
||||
for (let i = 0x2580; i <= 0x259f; i++) {
|
||||
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
|
||||
group_cache_render_glyph(group_cache, font_idx, i, 0);
|
||||
}
|
||||
for (let i = 0x2800; i <= 0x28ff; i++) {
|
||||
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
|
||||
group_cache_render_glyph(group_cache, font_idx, i, 0);
|
||||
}
|
||||
for (let i = 0x1fb00; i <= 0x1fb3b; i++) {
|
||||
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
|
||||
group_cache_render_glyph(group_cache, font_idx, i, 0);
|
||||
}
|
||||
for (let i = 0x1fb3c; i <= 0x1fb6b; i++) {
|
||||
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
|
||||
group_cache_render_glyph(group_cache, font_idx, i, 0);
|
||||
}
|
||||
|
||||
//face_render_glyph(face, atlas, "橋".codePointAt(0));
|
||||
//face_render_glyph(face, atlas, "p".codePointAt(0));
|
||||
|
||||
// Debug our canvas
|
||||
//face_debug_canvas(face);
|
||||
|
||||
// Let's try shaping
|
||||
const shaper = shaper_new(120);
|
||||
//const input = makeStr("hello🐏");
|
||||
const input = makeStr("hello🐏👍🏽");
|
||||
shaper_test(shaper, group_cache, input.ptr, input.len);
|
||||
|
||||
const cp = 1114112;
|
||||
const font_idx = group_cache_index_for_codepoint(
|
||||
group_cache,
|
||||
cp,
|
||||
0,
|
||||
-1 /* best choice */,
|
||||
);
|
||||
group_cache_render_glyph(group_cache, font_idx, cp, -1);
|
||||
|
||||
// Debug our atlas canvas
|
||||
{
|
||||
const atlas = group_cache_atlas_grayscale(group_cache);
|
||||
const id = atlas_debug_canvas(atlas);
|
||||
document.getElementById("atlas-canvas").append(zjs.deleteValue(id));
|
||||
}
|
||||
|
||||
{
|
||||
const atlas = group_cache_atlas_color(group_cache);
|
||||
const id = atlas_debug_canvas(atlas);
|
||||
document.getElementById("atlas-color-canvas").append(zjs.deleteValue(id));
|
||||
}
|
||||
|
||||
//face_free(face);
|
||||
new Int32Array(files.nextFd)[0] = 4;
|
||||
setFiles(files);
|
||||
setStdin(stdin);
|
||||
run(config_str.ptr, config_str.len);
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
const io = new Uint8ClampedArray(stdin, 4);
|
||||
const text = new TextEncoder().encode("hello world\r\n");
|
||||
io.set(text);
|
||||
const n = new Int32Array(stdin);
|
||||
Atomics.store(n, 0, text.length)
|
||||
Atomics.notify(n, 0);
|
||||
function drawing() {
|
||||
requestAnimationFrame(() => {
|
||||
draw();
|
||||
drawing();
|
||||
});
|
||||
|
||||
}
|
||||
drawing()
|
||||
setInterval(() => {
|
||||
// const text = new TextEncoder().encode("🐏\n\r👍🏽\n\rM_ghostty\033[2;2H\033[48;2;240;40;40m\033[38;2;23;255;80mhello");
|
||||
const text = new TextEncoder().encode("🐏\r\n👍🏽\r\nM_ghostty\033[48;2;240;40;40m\033[38;2;23;255;80mhello\r\n");
|
||||
const n = new Int32Array(stdin);
|
||||
const place = Atomics.add(n, 0, text.length)
|
||||
const io = new Uint8ClampedArray(stdin, 4 + place);
|
||||
io.set(text);
|
||||
Atomics.notify(n, 0);
|
||||
}, 10000)
|
||||
})
|
||||
|
1076
example/imports.ts
Normal file
1076
example/imports.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<p>Open your console, we are just debugging here.</p>
|
||||
<div><div style="display: inline-block; border: 1px solid green;"><canvas id="main-canvas" width="500px" height="500px"></canvas></div></div>
|
||||
<div><div style="display: inline-block; border: 1px solid green;"><canvas id="shaper-canvas" width="500px" height="500px"></canvas></div></div>
|
||||
<p>The current <b>grayscale</b> font atlas is rendered below.</p>
|
||||
<div><div id="atlas-canvas" style="display: inline-block; border: 1px solid green;"></div></div>
|
||||
<p>The current <b>color</b> font atlas is rendered below.</p>
|
||||
|
158
example/old.ts
Normal file
158
example/old.ts
Normal file
@ -0,0 +1,158 @@
|
||||
import { zjs } from "./imports";
|
||||
|
||||
export function old(results) {
|
||||
const {
|
||||
atlas_clear,
|
||||
atlas_debug_canvas,
|
||||
atlas_free,
|
||||
atlas_grow,
|
||||
atlas_new,
|
||||
atlas_reserve,
|
||||
atlas_set,
|
||||
config_finalize,
|
||||
config_free,
|
||||
config_load_string,
|
||||
config_new,
|
||||
deferred_face_free,
|
||||
deferred_face_load,
|
||||
deferred_face_new,
|
||||
face_debug_canvas,
|
||||
face_free,
|
||||
face_new,
|
||||
face_render_glyph,
|
||||
free,
|
||||
malloc,
|
||||
shaper_free,
|
||||
shaper_new,
|
||||
shaper_test,
|
||||
collection_new,
|
||||
collection_add_deferred_face,
|
||||
shared_grid_new,
|
||||
shared_grid_atlas_grayscale,
|
||||
shared_grid_atlas_color,
|
||||
shared_grid_index_for_codepoint,
|
||||
shared_grid_render_glyph,
|
||||
run,
|
||||
} = results.instance.exports;
|
||||
|
||||
|
||||
// Helpers
|
||||
const makeStr = (str) => {
|
||||
const utf8 = new TextEncoder().encode(str);
|
||||
const ptr = malloc(utf8.byteLength);
|
||||
new Uint8Array(zjs.memory.buffer, ptr).set(utf8);
|
||||
return { ptr: ptr, len: utf8.byteLength };
|
||||
};
|
||||
// Create our config
|
||||
const config_str = makeStr("font-family = monospace");
|
||||
|
||||
const config = config_new();
|
||||
config_load_string(config, config_str);
|
||||
config_finalize(config);
|
||||
free(config_str.ptr);
|
||||
// Create our atlas
|
||||
// const atlas = atlas_new(512, 0 /* grayscale */);
|
||||
|
||||
// Create some memory for our string
|
||||
const font_name = makeStr("monospace");
|
||||
|
||||
// Initialize our deferred face
|
||||
// const df = deferred_face_new(font_ptr, font.byteLength, 0 /* text */);
|
||||
//deferred_face_load(df, 72 /* size */);
|
||||
//const face = deferred_face_face(df);
|
||||
|
||||
// Initialize our font face
|
||||
//const face = face_new(font_ptr, font.byteLength, 72 /* size in px */);
|
||||
//free(font_ptr);
|
||||
|
||||
// Create our group
|
||||
const collection = collection_new(32);
|
||||
collection_add_deferred_face(
|
||||
collection,
|
||||
0 /* regular */,
|
||||
deferred_face_new(font_name.ptr, font_name.len, 0 /* text */),
|
||||
);
|
||||
collection_add_deferred_face(
|
||||
collection,
|
||||
0 /* regular */,
|
||||
deferred_face_new(font_name.ptr, font_name.len, 1 /* emoji */),
|
||||
);
|
||||
const grid = shared_grid_new(collection);
|
||||
|
||||
// Initialize our sprite font, without this we just use the browser.
|
||||
// group_init_sprite_face(group);
|
||||
|
||||
// // Create our group cache
|
||||
// const group_cache = group_cache_new(group);
|
||||
|
||||
// Render a glyph
|
||||
for (let i = 33; i <= 126; i++) {
|
||||
const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1);
|
||||
shared_grid_render_glyph(grid, font_idx, i, 0);
|
||||
//face_render_glyph(face, atlas, i);
|
||||
}
|
||||
//
|
||||
const emoji = ["🐏", "🌞", "🌚", "🍱", "💿", "🐈", "📃", "📀", "🕡", "🙃"];
|
||||
for (let i = 0; i < emoji.length; i++) {
|
||||
const cp = emoji[i].codePointAt(0);
|
||||
const font_idx = shared_grid_index_for_codepoint(grid, cp, 0, -1 /* best choice */);
|
||||
shared_grid_render_glyph(grid, font_idx, cp, 0);
|
||||
}
|
||||
|
||||
for (let i = 0x2500; i <= 0x257f; i++) {
|
||||
const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1);
|
||||
shared_grid_render_glyph(grid, font_idx, i, 0);
|
||||
}
|
||||
for (let i = 0x2580; i <= 0x259f; i++) {
|
||||
const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1);
|
||||
shared_grid_render_glyph(grid, font_idx, i, 0);
|
||||
}
|
||||
for (let i = 0x2800; i <= 0x28ff; i++) {
|
||||
const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1);
|
||||
shared_grid_render_glyph(grid, font_idx, i, 0);
|
||||
}
|
||||
for (let i = 0x1fb00; i <= 0x1fb3b; i++) {
|
||||
const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1);
|
||||
shared_grid_render_glyph(grid, font_idx, i, 0);
|
||||
}
|
||||
for (let i = 0x1fb3c; i <= 0x1fb6b; i++) {
|
||||
const font_idx = shared_grid_index_for_codepoint(grid, i, 0, -1);
|
||||
shared_grid_render_glyph(grid, font_idx, i, 0);
|
||||
}
|
||||
|
||||
//face_render_glyph(face, atlas, "橋".codePointAt(0));
|
||||
//face_render_glyph(face, atlas, "p".codePointAt(0));
|
||||
|
||||
// Debug our canvas
|
||||
//face_debug_canvas(face);
|
||||
|
||||
// Let's try shaping
|
||||
const shaper = shaper_new(120);
|
||||
//const input = makeStr("hello🐏");
|
||||
const input = makeStr("M_yhelloaaaaaaaaa\n🐏\n👍🏽\nM_ghostty");
|
||||
shaper_test(shaper, grid, input.ptr, input.len);
|
||||
|
||||
const cp = 1114112;
|
||||
const font_idx = shared_grid_index_for_codepoint(
|
||||
grid,
|
||||
cp,
|
||||
0,
|
||||
-1 /* best choice */,
|
||||
);
|
||||
shared_grid_render_glyph(grid, font_idx, cp, -1);
|
||||
|
||||
// Debug our atlas canvas
|
||||
{
|
||||
const atlas = shared_grid_atlas_grayscale(grid);
|
||||
const id = atlas_debug_canvas(atlas);
|
||||
document.getElementById("atlas-canvas").append(zjs.deleteValue(id));
|
||||
}
|
||||
|
||||
{
|
||||
const atlas = shared_grid_atlas_color(grid);
|
||||
const id = atlas_debug_canvas(atlas);
|
||||
document.getElementById("atlas-color-canvas").append(zjs.deleteValue(id));
|
||||
}
|
||||
|
||||
//face_free(face);
|
||||
}
|
1272
example/package-lock.json
generated
1272
example/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,10 +13,20 @@
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@parcel/transformer-inline-string": "^2.8.0",
|
||||
"buffer": "^5.7.1",
|
||||
"crypto-browserify": "^3.12.1",
|
||||
"events": "^3.3.0",
|
||||
"os-browserify": "^0.3.0",
|
||||
"parcel": "^2.8.0",
|
||||
"typescript": "^4.9.3"
|
||||
"path-browserify": "^1.0.1",
|
||||
"process": "^0.11.10",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"string_decoder": "^1.3.0",
|
||||
"typescript": "^4.9.3",
|
||||
"vm-browserify": "^1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"zig-js": "file:../vendor/zig-js/js"
|
||||
"glslog": "^0.0.10",
|
||||
"zig-js": "https://gitpkg.vercel.app/mitchellh/zig-js/js?main"
|
||||
}
|
||||
}
|
||||
|
431
example/wasi.ts
Normal file
431
example/wasi.ts
Normal file
@ -0,0 +1,431 @@
|
||||
/*
|
||||
|
||||
This project is based from the Node implementation made by Gus Caplan
|
||||
https://github.com/devsnek/node-wasi
|
||||
However, JavaScript WASI is focused on:
|
||||
* Bringing WASI to the Browsers
|
||||
* Make easy to plug different filesystems
|
||||
* Provide a type-safe api using Typescript
|
||||
|
||||
|
||||
Copyright 2019 Gus Caplan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
export const WASI_ESUCCESS = 0;
|
||||
export const WASI_E2BIG = 1;
|
||||
export const WASI_EACCES = 2;
|
||||
export const WASI_EADDRINUSE = 3;
|
||||
export const WASI_EADDRNOTAVAIL = 4;
|
||||
export const WASI_EAFNOSUPPORT = 5;
|
||||
export const WASI_EAGAIN = 6;
|
||||
export const WASI_EALREADY = 7;
|
||||
export const WASI_EBADF = 8;
|
||||
export const WASI_EBADMSG = 9;
|
||||
export const WASI_EBUSY = 10;
|
||||
export const WASI_ECANCELED = 11;
|
||||
export const WASI_ECHILD = 12;
|
||||
export const WASI_ECONNABORTED = 13;
|
||||
export const WASI_ECONNREFUSED = 14;
|
||||
export const WASI_ECONNRESET = 15;
|
||||
export const WASI_EDEADLK = 16;
|
||||
export const WASI_EDESTADDRREQ = 17;
|
||||
export const WASI_EDOM = 18;
|
||||
export const WASI_EDQUOT = 19;
|
||||
export const WASI_EEXIST = 20;
|
||||
export const WASI_EFAULT = 21;
|
||||
export const WASI_EFBIG = 22;
|
||||
export const WASI_EHOSTUNREACH = 23;
|
||||
export const WASI_EIDRM = 24;
|
||||
export const WASI_EILSEQ = 25;
|
||||
export const WASI_EINPROGRESS = 26;
|
||||
export const WASI_EINTR = 27;
|
||||
export const WASI_EINVAL = 28;
|
||||
export const WASI_EIO = 29;
|
||||
export const WASI_EISCONN = 30;
|
||||
export const WASI_EISDIR = 31;
|
||||
export const WASI_ELOOP = 32;
|
||||
export const WASI_EMFILE = 33;
|
||||
export const WASI_EMLINK = 34;
|
||||
export const WASI_EMSGSIZE = 35;
|
||||
export const WASI_EMULTIHOP = 36;
|
||||
export const WASI_ENAMETOOLONG = 37;
|
||||
export const WASI_ENETDOWN = 38;
|
||||
export const WASI_ENETRESET = 39;
|
||||
export const WASI_ENETUNREACH = 40;
|
||||
export const WASI_ENFILE = 41;
|
||||
export const WASI_ENOBUFS = 42;
|
||||
export const WASI_ENODEV = 43;
|
||||
export const WASI_ENOENT = 44;
|
||||
export const WASI_ENOEXEC = 45;
|
||||
export const WASI_ENOLCK = 46;
|
||||
export const WASI_ENOLINK = 47;
|
||||
export const WASI_ENOMEM = 48;
|
||||
export const WASI_ENOMSG = 49;
|
||||
export const WASI_ENOPROTOOPT = 50;
|
||||
export const WASI_ENOSPC = 51;
|
||||
export const WASI_ENOSYS = 52;
|
||||
export const WASI_ENOTCONN = 53;
|
||||
export const WASI_ENOTDIR = 54;
|
||||
export const WASI_ENOTEMPTY = 55;
|
||||
export const WASI_ENOTRECOVERABLE = 56;
|
||||
export const WASI_ENOTSOCK = 57;
|
||||
export const WASI_ENOTSUP = 58;
|
||||
export const WASI_ENOTTY = 59;
|
||||
export const WASI_ENXIO = 60;
|
||||
export const WASI_EOVERFLOW = 61;
|
||||
export const WASI_EOWNERDEAD = 62;
|
||||
export const WASI_EPERM = 63;
|
||||
export const WASI_EPIPE = 64;
|
||||
export const WASI_EPROTO = 65;
|
||||
export const WASI_EPROTONOSUPPORT = 66;
|
||||
export const WASI_EPROTOTYPE = 67;
|
||||
export const WASI_ERANGE = 68;
|
||||
export const WASI_EROFS = 69;
|
||||
export const WASI_ESPIPE = 70;
|
||||
export const WASI_ESRCH = 71;
|
||||
export const WASI_ESTALE = 72;
|
||||
export const WASI_ETIMEDOUT = 73;
|
||||
export const WASI_ETXTBSY = 74;
|
||||
export const WASI_EXDEV = 75;
|
||||
export const WASI_ENOTCAPABLE = 76;
|
||||
|
||||
export const WASI_SIGABRT = 0;
|
||||
export const WASI_SIGALRM = 1;
|
||||
export const WASI_SIGBUS = 2;
|
||||
export const WASI_SIGCHLD = 3;
|
||||
export const WASI_SIGCONT = 4;
|
||||
export const WASI_SIGFPE = 5;
|
||||
export const WASI_SIGHUP = 6;
|
||||
export const WASI_SIGILL = 7;
|
||||
export const WASI_SIGINT = 8;
|
||||
export const WASI_SIGKILL = 9;
|
||||
export const WASI_SIGPIPE = 10;
|
||||
export const WASI_SIGQUIT = 11;
|
||||
export const WASI_SIGSEGV = 12;
|
||||
export const WASI_SIGSTOP = 13;
|
||||
export const WASI_SIGTERM = 14;
|
||||
export const WASI_SIGTRAP = 15;
|
||||
export const WASI_SIGTSTP = 16;
|
||||
export const WASI_SIGTTIN = 17;
|
||||
export const WASI_SIGTTOU = 18;
|
||||
export const WASI_SIGURG = 19;
|
||||
export const WASI_SIGUSR1 = 20;
|
||||
export const WASI_SIGUSR2 = 21;
|
||||
export const WASI_SIGVTALRM = 22;
|
||||
export const WASI_SIGXCPU = 23;
|
||||
export const WASI_SIGXFSZ = 24;
|
||||
|
||||
export const WASI_FILETYPE_UNKNOWN = 0;
|
||||
export const WASI_FILETYPE_BLOCK_DEVICE = 1;
|
||||
export const WASI_FILETYPE_CHARACTER_DEVICE = 2;
|
||||
export const WASI_FILETYPE_DIRECTORY = 3;
|
||||
export const WASI_FILETYPE_REGULAR_FILE = 4;
|
||||
export const WASI_FILETYPE_SOCKET_DGRAM = 5;
|
||||
export const WASI_FILETYPE_SOCKET_STREAM = 6;
|
||||
export const WASI_FILETYPE_SYMBOLIC_LINK = 7;
|
||||
|
||||
export type WASI_FILETYPE =
|
||||
| typeof WASI_FILETYPE_UNKNOWN
|
||||
| typeof WASI_FILETYPE_BLOCK_DEVICE
|
||||
| typeof WASI_FILETYPE_CHARACTER_DEVICE
|
||||
| typeof WASI_FILETYPE_DIRECTORY
|
||||
| typeof WASI_FILETYPE_REGULAR_FILE
|
||||
| typeof WASI_FILETYPE_SOCKET_DGRAM
|
||||
| typeof WASI_FILETYPE_SOCKET_STREAM
|
||||
| typeof WASI_FILETYPE_SYMBOLIC_LINK;
|
||||
|
||||
export const WASI_FDFLAG_APPEND = 0x0001;
|
||||
export const WASI_FDFLAG_DSYNC = 0x0002;
|
||||
export const WASI_FDFLAG_NONBLOCK = 0x0004;
|
||||
export const WASI_FDFLAG_RSYNC = 0x0008;
|
||||
export const WASI_FDFLAG_SYNC = 0x0010;
|
||||
|
||||
export const WASI_RIGHT_FD_DATASYNC = BigInt(0x0000000000000001);
|
||||
export const WASI_RIGHT_FD_READ = BigInt(0x0000000000000002);
|
||||
export const WASI_RIGHT_FD_SEEK = BigInt(0x0000000000000004);
|
||||
export const WASI_RIGHT_FD_FDSTAT_SET_FLAGS = BigInt(0x0000000000000008);
|
||||
export const WASI_RIGHT_FD_SYNC = BigInt(0x0000000000000010);
|
||||
export const WASI_RIGHT_FD_TELL = BigInt(0x0000000000000020);
|
||||
export const WASI_RIGHT_FD_WRITE = BigInt(0x0000000000000040);
|
||||
export const WASI_RIGHT_FD_ADVISE = BigInt(0x0000000000000080);
|
||||
export const WASI_RIGHT_FD_ALLOCATE = BigInt(0x0000000000000100);
|
||||
export const WASI_RIGHT_PATH_CREATE_DIRECTORY = BigInt(0x0000000000000200);
|
||||
export const WASI_RIGHT_PATH_CREATE_FILE = BigInt(0x0000000000000400);
|
||||
export const WASI_RIGHT_PATH_LINK_SOURCE = BigInt(0x0000000000000800);
|
||||
export const WASI_RIGHT_PATH_LINK_TARGET = BigInt(0x0000000000001000);
|
||||
export const WASI_RIGHT_PATH_OPEN = BigInt(0x0000000000002000);
|
||||
export const WASI_RIGHT_FD_READDIR = BigInt(0x0000000000004000);
|
||||
export const WASI_RIGHT_PATH_READLINK = BigInt(0x0000000000008000);
|
||||
export const WASI_RIGHT_PATH_RENAME_SOURCE = BigInt(0x0000000000010000);
|
||||
export const WASI_RIGHT_PATH_RENAME_TARGET = BigInt(0x0000000000020000);
|
||||
export const WASI_RIGHT_PATH_FILESTAT_GET = BigInt(0x0000000000040000);
|
||||
export const WASI_RIGHT_PATH_FILESTAT_SET_SIZE = BigInt(0x0000000000080000);
|
||||
export const WASI_RIGHT_PATH_FILESTAT_SET_TIMES = BigInt(0x0000000000100000);
|
||||
export const WASI_RIGHT_FD_FILESTAT_GET = BigInt(0x0000000000200000);
|
||||
export const WASI_RIGHT_FD_FILESTAT_SET_SIZE = BigInt(0x0000000000400000);
|
||||
export const WASI_RIGHT_FD_FILESTAT_SET_TIMES = BigInt(0x0000000000800000);
|
||||
export const WASI_RIGHT_PATH_SYMLINK = BigInt(0x0000000001000000);
|
||||
export const WASI_RIGHT_PATH_REMOVE_DIRECTORY = BigInt(0x0000000002000000);
|
||||
export const WASI_RIGHT_PATH_UNLINK_FILE = BigInt(0x0000000004000000);
|
||||
export const WASI_RIGHT_POLL_FD_READWRITE = BigInt(0x0000000008000000);
|
||||
export const WASI_RIGHT_SOCK_SHUTDOWN = BigInt(0x0000000010000000);
|
||||
|
||||
export const RIGHTS_ALL =
|
||||
WASI_RIGHT_FD_DATASYNC |
|
||||
WASI_RIGHT_FD_READ |
|
||||
WASI_RIGHT_FD_SEEK |
|
||||
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||
WASI_RIGHT_FD_SYNC |
|
||||
WASI_RIGHT_FD_TELL |
|
||||
WASI_RIGHT_FD_WRITE |
|
||||
WASI_RIGHT_FD_ADVISE |
|
||||
WASI_RIGHT_FD_ALLOCATE |
|
||||
WASI_RIGHT_PATH_CREATE_DIRECTORY |
|
||||
WASI_RIGHT_PATH_CREATE_FILE |
|
||||
WASI_RIGHT_PATH_LINK_SOURCE |
|
||||
WASI_RIGHT_PATH_LINK_TARGET |
|
||||
WASI_RIGHT_PATH_OPEN |
|
||||
WASI_RIGHT_FD_READDIR |
|
||||
WASI_RIGHT_PATH_READLINK |
|
||||
WASI_RIGHT_PATH_RENAME_SOURCE |
|
||||
WASI_RIGHT_PATH_RENAME_TARGET |
|
||||
WASI_RIGHT_PATH_FILESTAT_GET |
|
||||
WASI_RIGHT_PATH_FILESTAT_SET_SIZE |
|
||||
WASI_RIGHT_PATH_FILESTAT_SET_TIMES |
|
||||
WASI_RIGHT_FD_FILESTAT_GET |
|
||||
WASI_RIGHT_FD_FILESTAT_SET_TIMES |
|
||||
WASI_RIGHT_FD_FILESTAT_SET_SIZE |
|
||||
WASI_RIGHT_PATH_SYMLINK |
|
||||
WASI_RIGHT_PATH_UNLINK_FILE |
|
||||
WASI_RIGHT_PATH_REMOVE_DIRECTORY |
|
||||
WASI_RIGHT_POLL_FD_READWRITE |
|
||||
WASI_RIGHT_SOCK_SHUTDOWN;
|
||||
|
||||
export const RIGHTS_BLOCK_DEVICE_BASE = RIGHTS_ALL;
|
||||
export const RIGHTS_BLOCK_DEVICE_INHERITING = RIGHTS_ALL;
|
||||
|
||||
export const RIGHTS_CHARACTER_DEVICE_BASE = RIGHTS_ALL;
|
||||
export const RIGHTS_CHARACTER_DEVICE_INHERITING = RIGHTS_ALL;
|
||||
|
||||
export const RIGHTS_REGULAR_FILE_BASE =
|
||||
WASI_RIGHT_FD_DATASYNC |
|
||||
WASI_RIGHT_FD_READ |
|
||||
WASI_RIGHT_FD_SEEK |
|
||||
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||
WASI_RIGHT_FD_SYNC |
|
||||
WASI_RIGHT_FD_TELL |
|
||||
WASI_RIGHT_FD_WRITE |
|
||||
WASI_RIGHT_FD_ADVISE |
|
||||
WASI_RIGHT_FD_ALLOCATE |
|
||||
WASI_RIGHT_FD_FILESTAT_GET |
|
||||
WASI_RIGHT_FD_FILESTAT_SET_SIZE |
|
||||
WASI_RIGHT_FD_FILESTAT_SET_TIMES |
|
||||
WASI_RIGHT_POLL_FD_READWRITE;
|
||||
export const RIGHTS_REGULAR_FILE_INHERITING = BigInt(0);
|
||||
|
||||
export const RIGHTS_DIRECTORY_BASE =
|
||||
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||
WASI_RIGHT_FD_SYNC |
|
||||
WASI_RIGHT_FD_ADVISE |
|
||||
WASI_RIGHT_PATH_CREATE_DIRECTORY |
|
||||
WASI_RIGHT_PATH_CREATE_FILE |
|
||||
WASI_RIGHT_PATH_LINK_SOURCE |
|
||||
WASI_RIGHT_PATH_LINK_TARGET |
|
||||
WASI_RIGHT_PATH_OPEN |
|
||||
WASI_RIGHT_FD_READDIR |
|
||||
WASI_RIGHT_PATH_READLINK |
|
||||
WASI_RIGHT_PATH_RENAME_SOURCE |
|
||||
WASI_RIGHT_PATH_RENAME_TARGET |
|
||||
WASI_RIGHT_PATH_FILESTAT_GET |
|
||||
WASI_RIGHT_PATH_FILESTAT_SET_SIZE |
|
||||
WASI_RIGHT_PATH_FILESTAT_SET_TIMES |
|
||||
WASI_RIGHT_FD_FILESTAT_GET |
|
||||
WASI_RIGHT_FD_FILESTAT_SET_TIMES |
|
||||
WASI_RIGHT_PATH_SYMLINK |
|
||||
WASI_RIGHT_PATH_UNLINK_FILE |
|
||||
WASI_RIGHT_PATH_REMOVE_DIRECTORY |
|
||||
WASI_RIGHT_POLL_FD_READWRITE;
|
||||
export const RIGHTS_DIRECTORY_INHERITING =
|
||||
RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE;
|
||||
|
||||
export const RIGHTS_SOCKET_BASE =
|
||||
WASI_RIGHT_FD_READ |
|
||||
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||
WASI_RIGHT_FD_WRITE |
|
||||
WASI_RIGHT_FD_FILESTAT_GET |
|
||||
WASI_RIGHT_POLL_FD_READWRITE |
|
||||
WASI_RIGHT_SOCK_SHUTDOWN;
|
||||
export const RIGHTS_SOCKET_INHERITING = RIGHTS_ALL;
|
||||
|
||||
export const RIGHTS_TTY_BASE =
|
||||
WASI_RIGHT_FD_READ |
|
||||
WASI_RIGHT_FD_FDSTAT_SET_FLAGS |
|
||||
WASI_RIGHT_FD_WRITE |
|
||||
WASI_RIGHT_FD_FILESTAT_GET |
|
||||
WASI_RIGHT_POLL_FD_READWRITE;
|
||||
export const RIGHTS_TTY_INHERITING = BigInt(0);
|
||||
|
||||
export const WASI_CLOCK_REALTIME = 0;
|
||||
export const WASI_CLOCK_MONOTONIC = 1;
|
||||
export const WASI_CLOCK_PROCESS_CPUTIME_ID = 2;
|
||||
export const WASI_CLOCK_THREAD_CPUTIME_ID = 3;
|
||||
|
||||
export const WASI_EVENTTYPE_CLOCK = 0;
|
||||
export const WASI_EVENTTYPE_FD_READ = 1;
|
||||
export const WASI_EVENTTYPE_FD_WRITE = 2;
|
||||
|
||||
export const WASI_FILESTAT_SET_ATIM = 1 << 0;
|
||||
export const WASI_FILESTAT_SET_ATIM_NOW = 1 << 1;
|
||||
export const WASI_FILESTAT_SET_MTIM = 1 << 2;
|
||||
export const WASI_FILESTAT_SET_MTIM_NOW = 1 << 3;
|
||||
|
||||
export const WASI_O_CREAT = 1 << 0;
|
||||
export const WASI_O_DIRECTORY = 1 << 1;
|
||||
export const WASI_O_EXCL = 1 << 2;
|
||||
export const WASI_O_TRUNC = 1 << 3;
|
||||
|
||||
export const WASI_PREOPENTYPE_DIR = 0;
|
||||
|
||||
export const WASI_DIRCOOKIE_START = 0;
|
||||
|
||||
export const WASI_STDIN_FILENO = 0;
|
||||
export const WASI_STDOUT_FILENO = 1;
|
||||
export const WASI_STDERR_FILENO = 2;
|
||||
|
||||
export const WASI_WHENCE_SET = 0;
|
||||
export const WASI_WHENCE_CUR = 1;
|
||||
export const WASI_WHENCE_END = 2;
|
||||
|
||||
// http://man7.org/linux/man-pages/man3/errno.3.html
|
||||
export const ERROR_MAP: { [key: string]: number } = {
|
||||
E2BIG: WASI_E2BIG,
|
||||
EACCES: WASI_EACCES,
|
||||
EADDRINUSE: WASI_EADDRINUSE,
|
||||
EADDRNOTAVAIL: WASI_EADDRNOTAVAIL,
|
||||
EAFNOSUPPORT: WASI_EAFNOSUPPORT,
|
||||
EALREADY: WASI_EALREADY,
|
||||
EAGAIN: WASI_EAGAIN,
|
||||
// EBADE: WASI_EBADE,
|
||||
EBADF: WASI_EBADF,
|
||||
// EBADFD: WASI_EBADFD,
|
||||
EBADMSG: WASI_EBADMSG,
|
||||
// EBADR: WASI_EBADR,
|
||||
// EBADRQC: WASI_EBADRQC,
|
||||
// EBADSLT: WASI_EBADSLT,
|
||||
EBUSY: WASI_EBUSY,
|
||||
ECANCELED: WASI_ECANCELED,
|
||||
ECHILD: WASI_ECHILD,
|
||||
// ECHRNG: WASI_ECHRNG,
|
||||
// ECOMM: WASI_ECOMM,
|
||||
ECONNABORTED: WASI_ECONNABORTED,
|
||||
ECONNREFUSED: WASI_ECONNREFUSED,
|
||||
ECONNRESET: WASI_ECONNRESET,
|
||||
EDEADLOCK: WASI_EDEADLK,
|
||||
EDESTADDRREQ: WASI_EDESTADDRREQ,
|
||||
EDOM: WASI_EDOM,
|
||||
EDQUOT: WASI_EDQUOT,
|
||||
EEXIST: WASI_EEXIST,
|
||||
EFAULT: WASI_EFAULT,
|
||||
EFBIG: WASI_EFBIG,
|
||||
EHOSTDOWN: WASI_EHOSTUNREACH,
|
||||
EHOSTUNREACH: WASI_EHOSTUNREACH,
|
||||
// EHWPOISON: WASI_EHWPOISON,
|
||||
EIDRM: WASI_EIDRM,
|
||||
EILSEQ: WASI_EILSEQ,
|
||||
EINPROGRESS: WASI_EINPROGRESS,
|
||||
EINTR: WASI_EINTR,
|
||||
EINVAL: WASI_EINVAL,
|
||||
EIO: WASI_EIO,
|
||||
EISCONN: WASI_EISCONN,
|
||||
EISDIR: WASI_EISDIR,
|
||||
ELOOP: WASI_ELOOP,
|
||||
EMFILE: WASI_EMFILE,
|
||||
EMLINK: WASI_EMLINK,
|
||||
EMSGSIZE: WASI_EMSGSIZE,
|
||||
EMULTIHOP: WASI_EMULTIHOP,
|
||||
ENAMETOOLONG: WASI_ENAMETOOLONG,
|
||||
ENETDOWN: WASI_ENETDOWN,
|
||||
ENETRESET: WASI_ENETRESET,
|
||||
ENETUNREACH: WASI_ENETUNREACH,
|
||||
ENFILE: WASI_ENFILE,
|
||||
ENOBUFS: WASI_ENOBUFS,
|
||||
ENODEV: WASI_ENODEV,
|
||||
ENOENT: WASI_ENOENT,
|
||||
ENOEXEC: WASI_ENOEXEC,
|
||||
ENOLCK: WASI_ENOLCK,
|
||||
ENOLINK: WASI_ENOLINK,
|
||||
ENOMEM: WASI_ENOMEM,
|
||||
ENOMSG: WASI_ENOMSG,
|
||||
ENOPROTOOPT: WASI_ENOPROTOOPT,
|
||||
ENOSPC: WASI_ENOSPC,
|
||||
ENOSYS: WASI_ENOSYS,
|
||||
ENOTCONN: WASI_ENOTCONN,
|
||||
ENOTDIR: WASI_ENOTDIR,
|
||||
ENOTEMPTY: WASI_ENOTEMPTY,
|
||||
ENOTRECOVERABLE: WASI_ENOTRECOVERABLE,
|
||||
ENOTSOCK: WASI_ENOTSOCK,
|
||||
ENOTTY: WASI_ENOTTY,
|
||||
ENXIO: WASI_ENXIO,
|
||||
EOVERFLOW: WASI_EOVERFLOW,
|
||||
EOWNERDEAD: WASI_EOWNERDEAD,
|
||||
EPERM: WASI_EPERM,
|
||||
EPIPE: WASI_EPIPE,
|
||||
EPROTO: WASI_EPROTO,
|
||||
EPROTONOSUPPORT: WASI_EPROTONOSUPPORT,
|
||||
EPROTOTYPE: WASI_EPROTOTYPE,
|
||||
ERANGE: WASI_ERANGE,
|
||||
EROFS: WASI_EROFS,
|
||||
ESPIPE: WASI_ESPIPE,
|
||||
ESRCH: WASI_ESRCH,
|
||||
ESTALE: WASI_ESTALE,
|
||||
ETIMEDOUT: WASI_ETIMEDOUT,
|
||||
ETXTBSY: WASI_ETXTBSY,
|
||||
EXDEV: WASI_EXDEV
|
||||
};
|
||||
|
||||
export const SIGNAL_MAP: { [key: string]: string } = {
|
||||
[WASI_SIGHUP]: "SIGHUP",
|
||||
[WASI_SIGINT]: "SIGINT",
|
||||
[WASI_SIGQUIT]: "SIGQUIT",
|
||||
[WASI_SIGILL]: "SIGILL",
|
||||
[WASI_SIGTRAP]: "SIGTRAP",
|
||||
[WASI_SIGABRT]: "SIGABRT",
|
||||
[WASI_SIGBUS]: "SIGBUS",
|
||||
[WASI_SIGFPE]: "SIGFPE",
|
||||
[WASI_SIGKILL]: "SIGKILL",
|
||||
[WASI_SIGUSR1]: "SIGUSR1",
|
||||
[WASI_SIGSEGV]: "SIGSEGV",
|
||||
[WASI_SIGUSR2]: "SIGUSR2",
|
||||
[WASI_SIGPIPE]: "SIGPIPE",
|
||||
[WASI_SIGALRM]: "SIGALRM",
|
||||
[WASI_SIGTERM]: "SIGTERM",
|
||||
[WASI_SIGCHLD]: "SIGCHLD",
|
||||
[WASI_SIGCONT]: "SIGCONT",
|
||||
[WASI_SIGSTOP]: "SIGSTOP",
|
||||
[WASI_SIGTSTP]: "SIGTSTP",
|
||||
[WASI_SIGTTIN]: "SIGTTIN",
|
||||
[WASI_SIGTTOU]: "SIGTTOU",
|
||||
[WASI_SIGURG]: "SIGURG",
|
||||
[WASI_SIGXCPU]: "SIGXCPU",
|
||||
[WASI_SIGXFSZ]: "SIGXFSZ",
|
||||
[WASI_SIGVTALRM]: "SIGVTALRM"
|
||||
};
|
14
example/worker.ts
Normal file
14
example/worker.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { importObject, setFiles, setMainThread, setStdin, zjs } from "./imports";
|
||||
|
||||
onmessage = async (e) => {
|
||||
console.log("module received from main thread");
|
||||
const [memory, instance, stdin, wasmModule, files, pid] = e.data;
|
||||
console.log(wasmModule)
|
||||
setStdin(stdin);
|
||||
setMainThread(false);
|
||||
setFiles(files);
|
||||
importObject.env.memory = memory;
|
||||
const results = await WebAssembly.instantiate(wasmModule, importObject);
|
||||
zjs.memory = memory;
|
||||
results.exports.wasi_thread_start(pid, instance);
|
||||
};
|
285
pkg/opengl/c.zig
285
pkg/opengl/c.zig
@ -1,3 +1,284 @@
|
||||
pub const c = @cImport({
|
||||
const builtin = @import("builtin");
|
||||
pub const c = if (builtin.cpu.arch != .wasm32) @cImport({
|
||||
@cInclude("glad/gl.h");
|
||||
});
|
||||
}) else struct {
|
||||
pub extern fn glBindBufferBase(_: c_uint, _: c_uint, _: c_uint) void;
|
||||
pub extern fn glDrawElementsInstanced(_: GLenum, _: GLsizei, _: GLenum, _: ?*const anyopaque, _: GLsizei) void;
|
||||
pub extern fn glUniform4f(_: c_int, _: f32, _: f32, _: f32, _: f32) void;
|
||||
pub extern fn glUniform4fv(_: c_int, _: f32, _: f32, _: f32, _: f32) void;
|
||||
pub extern fn glBindFramebuffer(_: c_uint, _: c_uint) void;
|
||||
pub extern fn glGetIntegerv(_: GLenum, _: *GLint) void;
|
||||
pub extern fn glTexSubImage2D(_: c_uint, _: c_int, _: c_int, _: isize, _: isize, _: c_int, _: c_uint, _: c_uint, _: ?*const anyopaque) void;
|
||||
pub extern fn glDeleteFramebuffers(_: c_int, _: [*c]const c_uint) void;
|
||||
pub extern fn glGenFramebuffers(_: c_int, _: [*c]c_uint) void;
|
||||
pub extern fn glVertexAttribDivisor(_: c_uint, _: c_uint) void;
|
||||
pub extern fn glVertexAttribIPointer(_: c_uint, _: c_int, _: c_uint, _: isize, _: ?*const anyopaque) void;
|
||||
pub extern fn glBufferSubData(_: GLenum, _: isize, _: isize, _: ?*const anyopaque) void;
|
||||
pub extern fn glViewport(_: c_int, _: c_int, _: isize, _: isize) void;
|
||||
pub extern fn glClearColor(_: f32, _: f32, _: f32, _: f32) void;
|
||||
pub extern fn glEnable(_: c_uint) void;
|
||||
pub extern fn glDisable(_: c_uint) void;
|
||||
pub extern fn glDepthFunc(_: c_uint) void;
|
||||
pub extern fn glBlendFunc(_: c_uint, _: c_uint) void;
|
||||
pub extern fn glClear(_: c_uint) void;
|
||||
pub extern fn glGetAttribLocation(_: c_uint, _: [*]const u8, _: c_uint) c_int;
|
||||
pub extern fn glGetUniformLocation(_: c_uint, _: [*]const u8) c_int;
|
||||
pub extern fn glUniform1i(_: c_int, _: c_int) void;
|
||||
pub extern fn glUniform1f(_: c_int, _: f32) void;
|
||||
pub extern fn glUniformMatrix4fv(_: c_int, _: c_int, _: c_uint, _: *const f32) void;
|
||||
pub extern fn glCreateVertexArray() c_uint;
|
||||
pub extern fn glGenVertexArrays(_: c_int, [*c]c_uint) void;
|
||||
pub extern fn glDeleteVertexArrays(_: c_int, [*c]const c_uint) void;
|
||||
pub extern fn glBindVertexArray(_: c_uint) void;
|
||||
pub extern fn glCreateBuffer() c_uint;
|
||||
pub extern fn glGenBuffers(_: c_int, _: [*c]c_uint) void;
|
||||
pub extern fn glDeleteBuffers(_: c_int, _: [*c]const c_uint) void;
|
||||
pub extern fn glDeleteBuffer(_: c_uint) void;
|
||||
pub extern fn glBindBuffer(_: c_uint, _: c_uint) void;
|
||||
pub extern fn glBufferData(_: c_uint, _: isize, _: ?*const anyopaque, _: c_uint) void;
|
||||
pub extern fn glPixelStorei(_: c_uint, _: c_int) void;
|
||||
pub extern fn glAttachShader(_: c_uint, _: c_uint) void;
|
||||
pub extern fn glDetachShader(_: c_uint, _: c_uint) void;
|
||||
pub extern fn glDeleteShader(_: c_uint) void;
|
||||
pub extern fn glCreateShader(_: c_uint) c_uint;
|
||||
pub extern fn glCompileShader(_: c_uint) void;
|
||||
pub extern fn glShaderSource(_: c_uint, _: c_uint, _: *const [*c]const u8, _: ?*GLint) void;
|
||||
pub extern fn glCreateProgram() c_uint;
|
||||
pub extern fn glGetShaderiv(_: c_uint, _: c_uint, _: [*c]c_int) void;
|
||||
pub extern fn glGetShaderInfoLog(_: c_uint, _: c_int, _: [*c]c_int, _: [*c]u8) void;
|
||||
pub extern fn glGetProgramiv(_: c_uint, _: c_uint, _: [*c]c_int) void;
|
||||
pub extern fn glLinkProgram(_: c_uint) void;
|
||||
pub extern fn glUseProgram(_: c_uint) void;
|
||||
pub extern fn glGetProgramInfoLog(_: c_uint, _: c_int, _: [*c]c_int, _: [*c]u8) void;
|
||||
pub extern fn glDeleteProgram(_: c_uint) void;
|
||||
pub extern fn glEnableVertexAttribArray(_: c_uint) void;
|
||||
pub extern fn glVertexAttribPointer(_: c_uint, _: c_int, _: c_uint, _: c_uint, _: isize, _: ?*const anyopaque) void;
|
||||
pub extern fn glDrawArrays(_: c_uint, _: c_uint, _: c_int) void;
|
||||
pub extern fn glCreateTexture() c_uint;
|
||||
pub extern fn glGenTextures(_: c_int, _: [*c]c_uint) void;
|
||||
pub extern fn glDeleteTextures(_: c_int, _: [*c]const c_uint) void;
|
||||
pub extern fn glDeleteTexture(_: c_uint) void;
|
||||
pub extern fn glBindTexture(_: c_uint, _: c_uint) void;
|
||||
pub extern fn glTexImage2D(_: GLenum, _: GLint, _: c_int, _: c_int, _: c_int, _: c_int, _: c_uint, _: c_uint, _: ?*const anyopaque) void;
|
||||
pub extern fn glTexParameteri(_: c_uint, _: c_uint, _: c_int) void;
|
||||
pub extern fn glActiveTexture(_: c_uint) void;
|
||||
pub extern fn glGenerateMipmap(_: c_uint) void;
|
||||
pub extern fn glGetError() c_int;
|
||||
pub extern fn glGetString(_: c_int) c_int;
|
||||
pub extern fn glGetShaderParameter(_: c_uint, _: c_uint) c_int;
|
||||
pub extern fn glUniform2f(_: c_int, _: f32, _: f32) void;
|
||||
|
||||
// Types.
|
||||
pub const GLuint = c_uint;
|
||||
pub const GLenum = c_uint;
|
||||
pub const GLbitfield = c_uint;
|
||||
pub const GLint = c_int;
|
||||
pub const GLsizei = isize;
|
||||
pub const GLfloat = f32;
|
||||
pub const GLboolean = u8;
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants
|
||||
pub const GL_FALSE = 0;
|
||||
pub const GL_TRUE = 1;
|
||||
pub const GL_TRIANGLES = 4;
|
||||
pub const GL_DEPTH_BUFFER_BIT = 256;
|
||||
pub const GL_SRC_ALPHA = 770;
|
||||
pub const GL_ONE_MINUS_SRC_ALPHA = 771;
|
||||
pub const GL_FLOAT = 5126;
|
||||
pub const GL_CULL_FACE = 2884;
|
||||
pub const GL_DEPTH_TEST = 2929;
|
||||
pub const GL_BLEND = 3042;
|
||||
pub const GL_TEXTURE_2D = 3553;
|
||||
pub const GL_UNSIGNED_BYTE = 5121;
|
||||
pub const GL_RED = 6403;
|
||||
pub const GL_RGBA = 6408;
|
||||
pub const GL_VERSION = 7938;
|
||||
pub const GL_LINEAR: GLint = 9729;
|
||||
pub const GL_TEXTURE_MAG_FILTER = 10240;
|
||||
pub const GL_TEXTURE_MIN_FILTER = 10241;
|
||||
pub const GL_TEXTURE_WRAP_S = 10242;
|
||||
pub const GL_TEXTURE_WRAP_T = 10243;
|
||||
pub const GL_COLOR_BUFFER_BIT = 16384;
|
||||
pub const GL_CLAMP_TO_EDGE: GLint = 33071;
|
||||
pub const GL_RG = 33319;
|
||||
pub const GL_RG32F = 33327;
|
||||
pub const GL_TEXTURE0 = 33984;
|
||||
pub const GL_TEXTURE1 = 33985;
|
||||
pub const GL_TEXTURE2 = 33986;
|
||||
pub const GL_TEXTURE3 = 33987;
|
||||
pub const GL_TEXTURE4 = 33988;
|
||||
pub const GL_TEXTURE5 = 33989;
|
||||
pub const GL_RGBA32F = 34836;
|
||||
pub const GL_ARRAY_BUFFER = 34962;
|
||||
pub const GL_STATIC_DRAW = 35044;
|
||||
pub const GL_FRAGMENT_SHADER = 35632;
|
||||
pub const GL_VERTEX_SHADER = 35633;
|
||||
pub const GL_COMPILE_STATUS = 35713;
|
||||
pub const GL_LINK_STATUS = 35714;
|
||||
pub const GL_FRAMEBUFFER_COMPLETE = 36053;
|
||||
pub const GL_COLOR_ATTACHMENT0 = 36064;
|
||||
pub const GL_COLOR_ATTACHMENT1 = 36065;
|
||||
pub const GL_COLOR_ATTACHMENT2 = 36066;
|
||||
pub const GL_DEPTH_ATTACHMENT = 36096;
|
||||
pub const GL_FRAMEBUFFER = 36160;
|
||||
pub const GL_RENDERBUFFER = 36161;
|
||||
|
||||
pub const GL_NO_ERROR = 0;
|
||||
pub const GL_INVALID_ENUM = 0x0500;
|
||||
pub const GL_INVALID_FRAMEBUFFER_OPERATION = 0x0506;
|
||||
pub const GL_INVALID_OPERATION = 0x0502;
|
||||
pub const GL_INVALID_VALUE = 0x0501;
|
||||
pub const GL_OUT_OF_MEMORY = 0x0505;
|
||||
pub const GL_ONE = 1;
|
||||
|
||||
pub const GL_TEXTURE_1D = 0x0DE0;
|
||||
pub const GL_TEXTURE_2D_ARRAY = 0x8C1A;
|
||||
pub const GL_TEXTURE_1D_ARRAY = 0x8C18;
|
||||
pub const GL_TEXTURE_3D = 0x806F;
|
||||
pub const GL_TEXTURE_RECTANGLE = 0x84F5;
|
||||
pub const GL_TEXTURE_CUBE_MAP = 0x8513;
|
||||
pub const GL_TEXTURE_BUFFER = 0x8C2A;
|
||||
pub const GL_TEXTURE_2D_MULTISAMPLE = 0x9100;
|
||||
pub const GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 0x9102;
|
||||
pub const GL_TEXTURE_BASE_LEVEL = 0x813C;
|
||||
pub const GL_TEXTURE_SWIZZLE_A = 0x8E45;
|
||||
pub const GL_TEXTURE_SWIZZLE_B = 0x8E44;
|
||||
pub const GL_TEXTURE_SWIZZLE_G = 0x8E43;
|
||||
pub const GL_TEXTURE_SWIZZLE_R = 0x8E42;
|
||||
pub const GL_TEXTURE_COMPARE_FUNC = 0x884D;
|
||||
pub const GL_TEXTURE_COMPARE_MODE = 0x884C;
|
||||
pub const GL_TEXTURE_LOD_BIAS = 0x8501;
|
||||
pub const GL_TEXTURE_MIN_LOD = 0x813A;
|
||||
pub const GL_TEXTURE_MAX_LOD = 0x813B;
|
||||
pub const GL_TEXTURE_MAX_LEVEL = 0x813D;
|
||||
pub const GL_TEXTURE_WRAP_R = 0x8072;
|
||||
pub const GL_RGB = 0x1907;
|
||||
pub const GL_BGRA = 0x80E1;
|
||||
pub const GL_ELEMENT_ARRAY_BUFFER = 0x8893;
|
||||
pub const GL_UNIFORM_BUFFER = 0x8A11;
|
||||
pub const GL_STREAM_COPY = 0x88E2;
|
||||
pub const GL_STREAM_DRAW = 0x88E0;
|
||||
pub const GL_STREAM_READ = 0x88E1;
|
||||
pub const GL_STATIC_COPY = 0x88E6;
|
||||
pub const GL_STATIC_READ = 0x88E5;
|
||||
pub const GL_DYNAMIC_COPY = 0x88EA;
|
||||
pub const GL_DYNAMIC_DRAW = 0x88E8;
|
||||
pub const GL_DYNAMIC_READ = 0x88E9;
|
||||
pub const GL_UNSIGNED_SHORT = 0x1403;
|
||||
pub const GL_INT = 0x1404;
|
||||
pub const GL_UNSIGNED_INT = 0x1405;
|
||||
pub const GL_DRAW_FRAMEBUFFER = 0x8CA9;
|
||||
pub const GL_READ_FRAMEBUFFER_BINDING = 0x8CAA;
|
||||
pub const GL_READ_FRAMEBUFFER = 0x8CA8;
|
||||
pub const GL_FRAMEBUFFER_BINDING = 0x8CA6;
|
||||
pub const GladGLContext = struct {
|
||||
pub fn init(self: *GladGLContext) void {
|
||||
self.* = .{
|
||||
.Enable = glEnable,
|
||||
.GetError = glGetError,
|
||||
.BlendFunc = glBlendFunc,
|
||||
.BindTexture = glBindTexture,
|
||||
.GenTextures = glGenTextures,
|
||||
.DeleteTextures = glDeleteTextures,
|
||||
.TexImage2D = glTexImage2D,
|
||||
.CreateShader = glCreateShader,
|
||||
.CompileShader = glCompileShader,
|
||||
.DeleteShader = glDeleteShader,
|
||||
.AttachShader = glAttachShader,
|
||||
.ShaderSource = glShaderSource,
|
||||
.GetShaderiv = glGetShaderiv,
|
||||
.GetShaderInfoLog = glGetShaderInfoLog,
|
||||
.CreateProgram = glCreateProgram,
|
||||
.LinkProgram = glLinkProgram,
|
||||
.GetProgramiv = glGetProgramiv,
|
||||
.GetProgramInfoLog = glGetProgramInfoLog,
|
||||
.UseProgram = glUseProgram,
|
||||
.DeleteProgram = glDeleteProgram,
|
||||
.GetUniformLocation = glGetUniformLocation,
|
||||
.Uniform4fv = glUniform4fv,
|
||||
.Uniform1i = glUniform1i,
|
||||
.Uniform1f = glUniform1f,
|
||||
.Uniform2f = glUniform2f,
|
||||
.UniformMatrix4fv = glUniformMatrix4fv,
|
||||
.GenVertexArrays = glGenVertexArrays,
|
||||
.DeleteVertexArrays = glDeleteVertexArrays,
|
||||
.BindVertexArray = glBindVertexArray,
|
||||
.GenBuffers = glGenBuffers,
|
||||
.DeleteBuffers = glDeleteBuffers,
|
||||
.DeleteBuffer = glDeleteBuffer,
|
||||
.BindBuffer = glBindBuffer,
|
||||
.BufferData = glBufferData,
|
||||
.BufferSubData = glBufferSubData,
|
||||
.VertexAttribPointer = glVertexAttribPointer,
|
||||
.VertexAttribIPointer = glVertexAttribIPointer,
|
||||
.EnableVertexAttribArray = glEnableVertexAttribArray,
|
||||
.VertexAttribDivisor = glVertexAttribDivisor,
|
||||
.GenFramebuffers = glGenFramebuffers,
|
||||
.DeleteFramebuffers = glDeleteFramebuffers,
|
||||
.TexSubImage2D = glTexSubImage2D,
|
||||
.GetIntegerv = glGetIntegerv,
|
||||
.BindFramebuffer = glBindFramebuffer,
|
||||
.ClearColor = glClearColor,
|
||||
.Clear = glClear,
|
||||
.Viewport = glViewport,
|
||||
.Uniform4f = glUniform4f,
|
||||
.ActiveTexture = glActiveTexture,
|
||||
.DrawElementsInstanced = glDrawElementsInstanced,
|
||||
.BindBufferBase = glBindBufferBase,
|
||||
.TexParameteri = glTexParameteri,
|
||||
};
|
||||
}
|
||||
Enable: ?*const fn (_: GLenum) callconv(.C) void,
|
||||
GetError: ?*const fn () callconv(.C) c_int,
|
||||
BlendFunc: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void,
|
||||
BindTexture: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void,
|
||||
GenTextures: ?*const fn (_: c_int, _: [*c]c_uint) callconv(.C) void,
|
||||
DeleteTextures: ?*const fn (_: c_int, _: [*c]const c_uint) callconv(.C) void,
|
||||
TexImage2D: ?*const fn (_: GLenum, _: GLint, _: c_int, _: c_int, _: c_int, _: c_int, _: c_uint, _: c_uint, _: ?*const anyopaque) callconv(.C) void,
|
||||
CreateShader: ?*const fn (_: GLenum) callconv(.C) GLuint,
|
||||
CompileShader: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
DeleteShader: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
AttachShader: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void,
|
||||
ShaderSource: ?*const fn (_: c_uint, _: c_uint, _: *const [*c]const u8, _: ?*GLint) callconv(.C) void,
|
||||
GetShaderiv: ?*const fn (_: c_uint, _: c_uint, _: [*c]c_int) callconv(.C) void,
|
||||
GetShaderInfoLog: ?*const fn (_: c_uint, _: c_int, _: [*c]c_int, _: [*c]u8) callconv(.C) void,
|
||||
CreateProgram: ?*const fn () callconv(.C) c_uint,
|
||||
LinkProgram: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
GetProgramiv: ?*const fn (_: c_uint, _: c_uint, _: [*c]c_int) callconv(.C) void,
|
||||
GetProgramInfoLog: ?*const fn (_: c_uint, _: c_int, _: [*c]c_int, _: [*c]u8) callconv(.C) void,
|
||||
UseProgram: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
DeleteProgram: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
GetUniformLocation: ?*const fn (_: c_uint, _: [*]const u8) callconv(.C) c_int,
|
||||
Uniform4fv: ?*const fn (_: c_int, _: f32, _: f32, _: f32, _: f32) callconv(.C) void,
|
||||
Uniform1i: ?*const fn (_: c_int, _: c_int) callconv(.C) void,
|
||||
Uniform1f: ?*const fn (_: c_int, _: f32) callconv(.C) void,
|
||||
Uniform2f: ?*const fn (_: c_int, _: f32, _: f32) callconv(.C) void,
|
||||
UniformMatrix4fv: ?*const fn (_: c_int, _: c_int, _: c_uint, _: *const f32) callconv(.C) void,
|
||||
GenVertexArrays: ?*const fn (_: c_int, [*c]c_uint) callconv(.C) void,
|
||||
DeleteVertexArrays: ?*const fn (_: c_int, [*c]const c_uint) callconv(.C) void,
|
||||
BindVertexArray: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
GenBuffers: ?*const fn (_: c_int, _: [*c]c_uint) callconv(.C) void,
|
||||
DeleteBuffers: ?*const fn (_: c_int, _: [*c]const c_uint) callconv(.C) void,
|
||||
DeleteBuffer: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
BindBuffer: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void,
|
||||
BufferData: ?*const fn (_: c_uint, _: isize, _: ?*const anyopaque, _: c_uint) callconv(.C) void,
|
||||
BufferSubData: ?*const fn (_: GLenum, _: isize, _: isize, _: ?*const anyopaque) callconv(.C) void,
|
||||
VertexAttribPointer: ?*const fn (_: c_uint, _: c_int, _: c_uint, _: c_uint, _: isize, _: ?*const anyopaque) callconv(.C) void,
|
||||
VertexAttribIPointer: ?*const fn (_: c_uint, _: c_int, _: c_uint, _: isize, _: ?*const anyopaque) callconv(.C) void,
|
||||
EnableVertexAttribArray: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
VertexAttribDivisor: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void,
|
||||
GenFramebuffers: ?*const fn (_: c_int, _: [*c]c_uint) callconv(.C) void,
|
||||
DeleteFramebuffers: ?*const fn (_: c_int, _: [*c]const c_uint) callconv(.C) void,
|
||||
TexSubImage2D: ?*const fn (_: c_uint, _: c_int, _: c_int, _: isize, _: isize, _: c_int, _: c_uint, _: c_uint, _: ?*const anyopaque) callconv(.C) void,
|
||||
GetIntegerv: ?*const fn (_: GLenum, _: *GLint) callconv(.C) void,
|
||||
BindFramebuffer: ?*const fn (_: c_uint, _: c_uint) callconv(.C) void,
|
||||
ClearColor: ?*const fn (_: f32, _: f32, _: f32, _: f32) callconv(.C) void,
|
||||
Clear: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
Viewport: ?*const fn (_: c_int, _: c_int, _: isize, _: isize) callconv(.C) void,
|
||||
Uniform4f: ?*const fn (_: c_int, _: f32, _: f32, _: f32, _: f32) callconv(.C) void,
|
||||
ActiveTexture: ?*const fn (_: c_uint) callconv(.C) void,
|
||||
DrawElementsInstanced: ?*const fn (_: GLenum, _: GLsizei, _: GLenum, _: ?*const anyopaque, _: GLsizei) callconv(.C) void,
|
||||
BindBufferBase: ?*const fn (_: c_uint, _: c_uint, _: c_uint) callconv(.C) void,
|
||||
TexParameteri: ?*const fn (_: c_uint, _: c_uint, _: c_int) callconv(.C) void,
|
||||
};
|
||||
};
|
||||
|
@ -116,7 +116,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.flags = flags.items,
|
||||
}),
|
||||
|
||||
.freestanding => {},
|
||||
.freestanding, .wasi => {},
|
||||
|
||||
else => {
|
||||
std.log.warn("target={} not supported", .{target.result.os.tag});
|
||||
|
@ -22,6 +22,7 @@ pub fn build(b: *std.Build) !void {
|
||||
// Zig 0.13 bug: https://github.com/ziglang/zig/issues/20414
|
||||
// (See root Ghostty build.zig on why we do this)
|
||||
try flags.appendSlice(&.{"-DSIMDUTF_IMPLEMENTATION_ICELAKE=0"});
|
||||
try flags.appendSlice(&.{"-DSIMDUTF_NO_THREADS"});
|
||||
|
||||
lib.addCSourceFiles(.{
|
||||
.flags = flags.items,
|
||||
|
@ -73,7 +73,8 @@ pseudo_console: if (builtin.os.tag == .windows) ?windows.exp.HPCON else void =
|
||||
data: ?*anyopaque = null,
|
||||
|
||||
/// Process ID is set after start is called.
|
||||
pid: ?posix.pid_t = null,
|
||||
pid: ?PidT = null,
|
||||
pub const PidT = if (builtin.cpu.arch != .wasm32) posix.pid_t else i32;
|
||||
|
||||
/// LinuxCGroup type depends on our target OS
|
||||
pub const LinuxCgroup = if (builtin.os.tag == .linux) ?[]const u8 else void;
|
||||
@ -122,6 +123,7 @@ pub fn start(self: *Command, alloc: Allocator) !void {
|
||||
|
||||
switch (builtin.os.tag) {
|
||||
.windows => try self.startWindows(arena),
|
||||
.wasi => try self.startWasi(arena),
|
||||
else => try self.startPosix(arena),
|
||||
}
|
||||
}
|
||||
@ -187,6 +189,26 @@ fn startPosix(self: *Command, arena: Allocator) !void {
|
||||
return error.ExecFailedInChild;
|
||||
}
|
||||
|
||||
fn startWasi(self: *Command, arena: Allocator) !void {
|
||||
// Null-terminate all our arguments
|
||||
const pathZ = try arena.dupeZ(u8, self.path);
|
||||
const argsZ = try arena.allocSentinel(?[*:0]u8, self.args.len, null);
|
||||
for (self.args, 0..) |arg, i| argsZ[i] = (try arena.dupeZ(u8, arg)).ptr;
|
||||
|
||||
// Determine our env vars
|
||||
const envp = if (self.env) |env_map|
|
||||
(try createNullDelimitedEnvMap(arena, env_map)).ptr
|
||||
else if (builtin.link_libc)
|
||||
std.c.environ
|
||||
else
|
||||
@compileError("missing env vars");
|
||||
|
||||
self.pid = 100;
|
||||
|
||||
std.log.err("need to fork {s} {*}", .{ pathZ, envp });
|
||||
return;
|
||||
}
|
||||
|
||||
fn startWindows(self: *Command, arena: Allocator) !void {
|
||||
const application_w = try std.unicode.utf8ToUtf16LeWithNull(arena, self.path);
|
||||
const cwd_w = if (self.cwd) |cwd| try std.unicode.utf8ToUtf16LeWithNull(arena, cwd) else null;
|
||||
@ -324,6 +346,7 @@ fn setupFd(src: File.Handle, target: i32) !void {
|
||||
|
||||
try posix.dup2(src, target);
|
||||
},
|
||||
.wasi => {},
|
||||
else => @compileError("unsupported platform"),
|
||||
}
|
||||
}
|
||||
|
@ -592,7 +592,7 @@ pub fn init(
|
||||
|
||||
// Start our renderer thread
|
||||
self.renderer_thr = try std.Thread.spawn(
|
||||
.{},
|
||||
.{ .allocator = alloc },
|
||||
renderer.Thread.threadMain,
|
||||
.{&self.renderer_thread},
|
||||
);
|
||||
@ -600,7 +600,7 @@ pub fn init(
|
||||
|
||||
// Start our IO thread
|
||||
self.io_thr = try std.Thread.spawn(
|
||||
.{},
|
||||
.{ .allocator = alloc },
|
||||
termio.Thread.threadMain,
|
||||
.{ &self.io_thread, &self.io },
|
||||
);
|
||||
|
@ -1,2 +1,101 @@
|
||||
pub const App = struct {};
|
||||
const CoreSurface = @import("../Surface.zig");
|
||||
const CoreApp = @import("../App.zig");
|
||||
const apprt = @import("../apprt.zig");
|
||||
const std = @import("std");
|
||||
const log = std.log;
|
||||
|
||||
pub const App = struct {
|
||||
app: *CoreApp,
|
||||
|
||||
pub const Options = struct {};
|
||||
pub fn init(core_app: *CoreApp, _: Options) !App {
|
||||
return .{ .app = core_app };
|
||||
}
|
||||
pub fn performAction(
|
||||
self: *App,
|
||||
target: apprt.Target,
|
||||
comptime action: apprt.Action.Key,
|
||||
value: apprt.Action.Value(action),
|
||||
) !void {
|
||||
switch (action) {
|
||||
.new_window => _ = try self.newSurface(switch (target) {
|
||||
.app => null,
|
||||
.surface => |v| v,
|
||||
}),
|
||||
|
||||
.new_tab => try self.newTab(switch (target) {
|
||||
.app => null,
|
||||
.surface => |v| v,
|
||||
}),
|
||||
|
||||
.initial_size => switch (target) {
|
||||
.app => {},
|
||||
.surface => |surface| try surface.rt_surface.setInitialWindowSize(
|
||||
value.width,
|
||||
value.height,
|
||||
),
|
||||
},
|
||||
|
||||
// Unimplemented
|
||||
.size_limit,
|
||||
.toggle_fullscreen,
|
||||
.set_title,
|
||||
.mouse_shape,
|
||||
.mouse_visibility,
|
||||
.open_config,
|
||||
.new_split,
|
||||
.goto_split,
|
||||
.resize_split,
|
||||
.equalize_splits,
|
||||
.toggle_split_zoom,
|
||||
.present_terminal,
|
||||
.close_all_windows,
|
||||
.toggle_tab_overview,
|
||||
.toggle_window_decorations,
|
||||
.toggle_quick_terminal,
|
||||
.toggle_visibility,
|
||||
.goto_tab,
|
||||
.move_tab,
|
||||
.inspector,
|
||||
.render_inspector,
|
||||
.quit_timer,
|
||||
.secure_input,
|
||||
.key_sequence,
|
||||
.desktop_notification,
|
||||
.mouse_over_link,
|
||||
.cell_size,
|
||||
.renderer_health,
|
||||
.color_change,
|
||||
.pwd,
|
||||
.reload_config,
|
||||
.config_change,
|
||||
=> log.info("unimplemented action={}", .{action}),
|
||||
}
|
||||
}
|
||||
pub fn wakeup(self: *const App) void {
|
||||
_ = self;
|
||||
}
|
||||
};
|
||||
pub const Window = struct {};
|
||||
pub const Surface = struct {
|
||||
pub const opengl_single_threaded_draw = true;
|
||||
/// The app we're part of
|
||||
app: *App,
|
||||
|
||||
/// A core surface
|
||||
core_surface: CoreSurface,
|
||||
pub fn init(self: *Surface, app: *App) !void {
|
||||
self.app = app;
|
||||
}
|
||||
pub fn getContentScale(_: *const Surface) !apprt.ContentScale {
|
||||
return apprt.ContentScale{ .x = 1, .y = 1 };
|
||||
}
|
||||
pub fn getSize(_: *const Surface) !apprt.SurfaceSize {
|
||||
return apprt.SurfaceSize{ .width = 500, .height = 500 };
|
||||
}
|
||||
fn setInitialWindowSize(self: *const Surface, width: u32, height: u32) !void {
|
||||
_ = height; // autofix
|
||||
_ = self; // autofix
|
||||
_ = width; // autofix
|
||||
}
|
||||
};
|
||||
|
@ -128,8 +128,8 @@ pub const Artifact = enum {
|
||||
|
||||
pub fn detect() Artifact {
|
||||
if (builtin.target.isWasm()) {
|
||||
assert(builtin.output_mode == .Obj);
|
||||
assert(builtin.link_mode == .Static);
|
||||
// assert(builtin.output_mode == .Obj);
|
||||
// assert(builtin.link_mode == .Static);
|
||||
return .wasm_module;
|
||||
}
|
||||
|
||||
|
@ -1275,7 +1275,7 @@ pub fn LineIterator(comptime ReaderType: type) type {
|
||||
}
|
||||
|
||||
// Constructs a LineIterator (see docs for that).
|
||||
fn lineIterator(reader: anytype) LineIterator(@TypeOf(reader)) {
|
||||
pub fn lineIterator(reader: anytype) LineIterator(@TypeOf(reader)) {
|
||||
return .{ .r = reader };
|
||||
}
|
||||
|
||||
|
@ -2638,6 +2638,7 @@ pub fn changeConditionalState(
|
||||
/// Expand the relative paths in config-files to be absolute paths
|
||||
/// relative to the base directory.
|
||||
fn expandPaths(self: *Config, base: []const u8) !void {
|
||||
if (builtin.cpu.arch == .wasm32) return error.WasmCannotExpandPaths;
|
||||
const arena_alloc = self._arena.?.allocator();
|
||||
|
||||
// Keep track of this step for replays
|
||||
@ -2752,6 +2753,7 @@ fn loadTheme(self: *Config, theme: Theme) !void {
|
||||
pub fn finalize(self: *Config) !void {
|
||||
// We always load the theme first because it may set other fields
|
||||
// in our config.
|
||||
if (builtin.cpu.arch != .wasm32) {
|
||||
if (self.theme) |theme| {
|
||||
const different = !std.mem.eql(u8, theme.light, theme.dark);
|
||||
|
||||
@ -2767,6 +2769,7 @@ pub fn finalize(self: *Config) !void {
|
||||
if (self.@"window-theme" == .auto) self.@"window-theme" = .system;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const alloc = self._arena.?.allocator();
|
||||
|
||||
|
@ -39,7 +39,7 @@ pub const Location = enum {
|
||||
// error set since some platforms don't support some
|
||||
// error types.
|
||||
const Error = @TypeOf(err) || switch (builtin.os.tag) {
|
||||
.ios => error{BufferTooSmall},
|
||||
.ios, .wasi => error{BufferTooSmall},
|
||||
else => error{},
|
||||
};
|
||||
|
||||
|
@ -659,6 +659,27 @@ pub const Index = packed struct(Index.Backing) {
|
||||
}
|
||||
};
|
||||
|
||||
/// The wasm-compatible API.
|
||||
pub const Wasm = struct {
|
||||
const wasm = @import("../os/wasm.zig");
|
||||
const alloc = wasm.alloc;
|
||||
export fn collection_new(points: f32) ?*Collection {
|
||||
const result = alloc.create(Collection) catch |err| {
|
||||
log.warn("error creating collection err={}", .{err});
|
||||
return null;
|
||||
};
|
||||
result.* = Collection.init();
|
||||
result.load_options = .{ .library = Library.init() catch unreachable, .size = .{ .points = points } };
|
||||
return result;
|
||||
}
|
||||
export fn collection_add_deferred_face(self: *Collection, style: u8, face: *DeferredFace) u16 {
|
||||
return @bitCast(self.add(alloc, @enumFromInt(style), .{ .deferred = face.* }) catch |err| {
|
||||
log.warn("error adding deferred face to collection err={}", .{err});
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
test init {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
@ -163,6 +163,7 @@ pub fn load(
|
||||
lib: Library,
|
||||
opts: font.face.Options,
|
||||
) !Face {
|
||||
log.err("load {}", .{opts.size});
|
||||
return switch (options.backend) {
|
||||
.fontconfig_freetype => try self.loadFontconfig(lib, opts),
|
||||
.coretext, .coretext_harfbuzz, .coretext_noshape => try self.loadCoreText(lib, opts),
|
||||
@ -254,7 +255,7 @@ fn loadWebCanvas(
|
||||
opts: font.face.Options,
|
||||
) !Face {
|
||||
const wc = self.wc.?;
|
||||
return try Face.initNamed(wc.alloc, wc.font_str, opts, wc.presentation);
|
||||
return try Face.initNamed(wc.alloc, wc.font_str, opts.size, wc.presentation);
|
||||
}
|
||||
|
||||
/// Returns true if this face can satisfy the given codepoint and
|
||||
@ -392,7 +393,7 @@ pub const Wasm = struct {
|
||||
}
|
||||
|
||||
export fn deferred_face_load(self: *DeferredFace, pts: f32) void {
|
||||
self.load(.{}, .{ .points = pts }) catch |err| {
|
||||
_ = self.load(.{}, .{ .size = .{ .points = pts } }) catch |err| {
|
||||
log.warn("error loading deferred face err={}", .{err});
|
||||
return;
|
||||
};
|
||||
|
@ -322,6 +322,54 @@ const GlyphKey = struct {
|
||||
|
||||
const TestMode = enum { normal };
|
||||
|
||||
/// The wasm-compatible API.
|
||||
pub const Wasm = struct {
|
||||
const wasm = @import("../os/wasm.zig");
|
||||
const alloc = wasm.alloc;
|
||||
export fn shared_grid_new(c: *Collection) ?*SharedGrid {
|
||||
const result = alloc.create(SharedGrid) catch |err| {
|
||||
log.warn("error creating SharedGrid err={}", .{err});
|
||||
return null;
|
||||
};
|
||||
result.* = SharedGrid.init(wasm.alloc, .{ .collection = c.* }) catch |err| {
|
||||
log.warn("error initializing SharedGrid err={}", .{err});
|
||||
return null;
|
||||
};
|
||||
return result;
|
||||
}
|
||||
export fn shared_grid_atlas_grayscale(self: *SharedGrid) ?*Atlas {
|
||||
return &self.atlas_grayscale;
|
||||
}
|
||||
export fn shared_grid_atlas_color(self: *SharedGrid) ?*Atlas {
|
||||
return &self.atlas_color;
|
||||
}
|
||||
export fn shared_grid_index_for_codepoint(self: *SharedGrid, code: u32, style: u8, presentation: i8) ?*Collection.Index {
|
||||
const get = self.getIndex(wasm.alloc, code, @enumFromInt(style), if (presentation < 0) null else @enumFromInt(presentation)) catch |err| {
|
||||
log.warn("error getting SharedGrid index for codepoint err={}", .{err});
|
||||
return null;
|
||||
};
|
||||
if (get) |thing| {
|
||||
const index = wasm.alloc.create(Collection.Index) catch unreachable;
|
||||
index.* = thing;
|
||||
return index;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export fn shared_grid_render_glyph(self: *SharedGrid, font_idx: *Collection.Index, code: u32, _: u8) void {
|
||||
const glyph_index = glyph_index: {
|
||||
if (font_idx.special()) |special| break :glyph_index switch (special) {
|
||||
.sprite => code,
|
||||
};
|
||||
self.lock.lockShared();
|
||||
defer self.lock.unlockShared();
|
||||
const face = self.resolver.collection.getFace(font_idx.*) catch unreachable;
|
||||
break :glyph_index face.glyphIndex(code) orelse return;
|
||||
};
|
||||
_ = self.renderGlyph(wasm.alloc, font_idx.*, glyph_index, .{}) catch unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
fn testGrid(mode: TestMode, alloc: Allocator, lib: Library) !SharedGrid {
|
||||
const testFont = font.embedded.regular;
|
||||
|
||||
|
@ -255,6 +255,7 @@ fn collection(
|
||||
try c.completeStyles(self.alloc, config.@"font-synthetic-style");
|
||||
|
||||
// Our built-in font will be used as a backup
|
||||
if (builtin.cpu.arch != .wasm32) {
|
||||
_ = try c.add(
|
||||
self.alloc,
|
||||
.regular,
|
||||
@ -291,6 +292,30 @@ fn collection(
|
||||
load_options.faceOptions(),
|
||||
) },
|
||||
);
|
||||
} else {
|
||||
const family = if (config.@"font-family".list.items.len > 0) config.@"font-family".list.items[0] else "monospace";
|
||||
|
||||
_ = try c.add(
|
||||
self.alloc,
|
||||
.regular,
|
||||
.{ .fallback_loaded = try Face.initNamed(
|
||||
self.alloc,
|
||||
family,
|
||||
load_options.size,
|
||||
.text,
|
||||
) },
|
||||
);
|
||||
_ = try c.add(
|
||||
self.alloc,
|
||||
.regular,
|
||||
.{ .fallback_loaded = try Face.initNamed(
|
||||
self.alloc,
|
||||
family,
|
||||
load_options.size,
|
||||
.emoji,
|
||||
) },
|
||||
);
|
||||
}
|
||||
|
||||
// On macOS, always search for and add the Apple Emoji font
|
||||
// as our preferred emoji font for fallback. We do this in case
|
||||
@ -314,7 +339,7 @@ fn collection(
|
||||
|
||||
// Emoji fallback. We don't include this on Mac since Mac is expected
|
||||
// to always have the Apple Emoji available on the system.
|
||||
if (comptime !builtin.target.isDarwin() or Discover == void) {
|
||||
if (builtin.cpu.arch != .wasm32 and comptime !builtin.target.isDarwin() or Discover == void) {
|
||||
_ = try c.add(
|
||||
self.alloc,
|
||||
.regular,
|
||||
|
@ -29,9 +29,6 @@ pub const Face = struct {
|
||||
/// Metrics for this font face. These are useful for renderers.
|
||||
metrics: font.face.Metrics,
|
||||
|
||||
/// The canvas element that we will reuse to render glyphs
|
||||
canvas: js.Object,
|
||||
|
||||
/// The map to store multi-codepoint grapheme clusters that are rendered.
|
||||
/// We use 1 above the maximum unicode codepoint up to the max 32-bit
|
||||
/// unsigned integer to store the "glyph index" for graphemes.
|
||||
@ -58,20 +55,12 @@ pub const Face = struct {
|
||||
const font_str = try alloc.dupe(u8, raw);
|
||||
errdefer alloc.free(font_str);
|
||||
|
||||
// Create our canvas that we're going to continue to reuse.
|
||||
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();
|
||||
|
||||
var result = Face{
|
||||
.alloc = alloc,
|
||||
.font_str = font_str,
|
||||
.size = size,
|
||||
.presentation = presentation,
|
||||
|
||||
.canvas = canvas,
|
||||
|
||||
// We're going to calculate these right after initialization.
|
||||
.metrics = undefined,
|
||||
};
|
||||
@ -89,7 +78,6 @@ pub const Face = struct {
|
||||
while (it.next()) |value| self.alloc.free(value.*);
|
||||
self.glyph_to_grapheme.deinit(self.alloc);
|
||||
}
|
||||
self.canvas.deinit();
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
@ -232,7 +220,7 @@ pub const Face = struct {
|
||||
.height = render.height,
|
||||
// TODO: this can't be right
|
||||
.offset_x = 0,
|
||||
.offset_y = 0,
|
||||
.offset_y = render.y_offset,
|
||||
.atlas_x = region.x,
|
||||
.atlas_y = region.y,
|
||||
.advance_x = 0,
|
||||
@ -262,8 +250,8 @@ pub const Face = struct {
|
||||
// pixel height but this is a more surefire way to get it.
|
||||
const height_metrics = try ctx.call(js.Object, "measureText", .{js.string("M_")});
|
||||
defer height_metrics.deinit();
|
||||
const asc = try height_metrics.get(f32, "actualBoundingBoxAscent");
|
||||
const desc = try height_metrics.get(f32, "actualBoundingBoxDescent");
|
||||
const asc = try height_metrics.get(f32, "fontBoundingBoxAscent");
|
||||
const desc = try height_metrics.get(f32, "fontBoundingBoxDescent");
|
||||
const cell_height = asc + desc;
|
||||
const cell_baseline = desc;
|
||||
|
||||
@ -291,13 +279,15 @@ pub const Face = struct {
|
||||
fn context(self: Face) !js.Object {
|
||||
// This will return the same context on subsequent calls so it
|
||||
// is important to reset it.
|
||||
const ctx = try self.canvas.call(js.Object, "getContext", .{js.string("2d")});
|
||||
const canvas = try js.global.get(js.Object, "fontCanvas");
|
||||
defer canvas.deinit();
|
||||
const ctx = try canvas.call(js.Object, "getContext", .{js.string("2d")});
|
||||
errdefer ctx.deinit();
|
||||
|
||||
// Clear the canvas
|
||||
{
|
||||
const width = try self.canvas.get(f64, "width");
|
||||
const height = try self.canvas.get(f64, "height");
|
||||
const width = try canvas.get(f64, "width");
|
||||
const height = try canvas.get(f64, "height");
|
||||
try ctx.call(void, "clearRect", .{ 0, 0, width, height });
|
||||
}
|
||||
|
||||
@ -325,6 +315,27 @@ pub const Face = struct {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
pub fn hasColor(_: *const Face) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn isColorGlyph(self: *const Face, cp: u32) bool {
|
||||
// Render the glyph
|
||||
var render = self.renderGlyphInternal(self.alloc, cp) catch unreachable;
|
||||
defer render.deinit();
|
||||
|
||||
// Inspect the image data for any non-zeros in the RGB value.
|
||||
// NOTE(perf): this is an easy candidate for SIMD.
|
||||
var i: usize = 0;
|
||||
while (i < render.bitmap.len) : (i += 4) {
|
||||
if (render.bitmap[i] > 0 or
|
||||
render.bitmap[i + 1] > 0 or
|
||||
render.bitmap[i + 2] > 0) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// An internal (web-canvas-only) format for rendered glyphs
|
||||
/// since we do render passes in multiple different situations.
|
||||
const RenderedGlyph = struct {
|
||||
@ -332,6 +343,7 @@ pub const Face = struct {
|
||||
metrics: js.Object,
|
||||
width: u32,
|
||||
height: u32,
|
||||
y_offset: i32,
|
||||
bitmap: []u8,
|
||||
|
||||
pub fn deinit(self: *RenderedGlyph) void {
|
||||
@ -392,24 +404,34 @@ pub const Face = struct {
|
||||
// Height is our ascender + descender for this char
|
||||
const height = if (!broken_bbox) @as(u32, @intFromFloat(@ceil(asc + desc))) + 1 else width;
|
||||
|
||||
const ctx_temp = try self.context();
|
||||
try ctx_temp.set("textBaseline", js.string("top"));
|
||||
// Get the width and height of the render
|
||||
const metrics_2 = try measure_ctx.call(js.Object, "measureText", .{glyph_str});
|
||||
const top_desc = try metrics_2.get(f32, "actualBoundingBoxDescent") + 1;
|
||||
const y_offset = @as(i32, @intCast(height)) - @as(i32, @intFromFloat(top_desc));
|
||||
ctx_temp.deinit();
|
||||
|
||||
// Note: width and height both get "+ 1" added to them above. This
|
||||
// is important so that there is a 1px border around the glyph to avoid
|
||||
// any clipping in the atlas.
|
||||
|
||||
// Resize canvas to match the glyph size exactly
|
||||
{
|
||||
try self.canvas.set("width", width);
|
||||
try self.canvas.set("height", height);
|
||||
const canvas = try js.global.get(js.Object, "fontCanvas");
|
||||
defer canvas.deinit();
|
||||
try canvas.set("width", width);
|
||||
try canvas.set("height", height);
|
||||
|
||||
const width_str = try std.fmt.allocPrint(alloc, "{d}px", .{width});
|
||||
defer alloc.free(width_str);
|
||||
const height_str = try std.fmt.allocPrint(alloc, "{d}px", .{height});
|
||||
defer alloc.free(height_str);
|
||||
// const width_str = try std.fmt.allocPrint(alloc, "{d}px", .{width});
|
||||
// defer alloc.free(width_str);
|
||||
// const height_str = try std.fmt.allocPrint(alloc, "{d}px", .{height});
|
||||
// defer alloc.free(height_str);
|
||||
|
||||
const style = try self.canvas.get(js.Object, "style");
|
||||
defer style.deinit();
|
||||
try style.set("width", js.string(width_str));
|
||||
try style.set("height", js.string(height_str));
|
||||
// const style = try self.canvas.get(js.Object, "style");
|
||||
// defer style.deinit();
|
||||
// try style.set("width", js.string(width_str));
|
||||
// try style.set("height", js.string(height_str));
|
||||
}
|
||||
|
||||
// Reload our context since we resized the canvas
|
||||
@ -484,6 +506,7 @@ pub const Face = struct {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.bitmap = bitmap,
|
||||
.y_offset = y_offset,
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -494,7 +517,7 @@ pub const Wasm = struct {
|
||||
const alloc = wasm.alloc;
|
||||
|
||||
export fn face_new(ptr: [*]const u8, len: usize, pts: u16, p: u16) ?*Face {
|
||||
return face_new_(ptr, len, pts, p) catch null;
|
||||
return face_new_(ptr, len, @floatFromInt(pts), p) catch null;
|
||||
}
|
||||
|
||||
fn face_new_(ptr: [*]const u8, len: usize, pts: f32, presentation: u16) !*Face {
|
||||
@ -531,25 +554,25 @@ pub const Wasm = struct {
|
||||
};
|
||||
}
|
||||
|
||||
export fn face_debug_canvas(face: *Face) void {
|
||||
face_debug_canvas_(face) catch |err| {
|
||||
log.warn("error adding debug canvas err={}", .{err});
|
||||
};
|
||||
}
|
||||
// export fn face_debug_canvas(face: *Face) void {
|
||||
// face_debug_canvas_(face) catch |err| {
|
||||
// log.warn("error adding debug canvas err={}", .{err});
|
||||
// };
|
||||
// }
|
||||
|
||||
fn face_debug_canvas_(face: *Face) !void {
|
||||
const doc = try js.global.get(js.Object, "document");
|
||||
defer doc.deinit();
|
||||
// fn face_debug_canvas_(face: *Face) !void {
|
||||
// const doc = try js.global.get(js.Object, "document");
|
||||
// defer doc.deinit();
|
||||
|
||||
const elem = try doc.call(
|
||||
?js.Object,
|
||||
"getElementById",
|
||||
.{js.string("face-canvas")},
|
||||
) orelse return error.CanvasContainerNotFound;
|
||||
defer elem.deinit();
|
||||
// const elem = try doc.call(
|
||||
// ?js.Object,
|
||||
// "getElementById",
|
||||
// .{js.string("face-canvas")},
|
||||
// ) orelse return error.CanvasContainerNotFound;
|
||||
// defer elem.deinit();
|
||||
|
||||
try elem.call(void, "append", .{face.canvas});
|
||||
}
|
||||
// try elem.call(void, "append", .{face.canvas});
|
||||
// }
|
||||
|
||||
fn face_render_glyph_(face: *Face, atlas: *font.Atlas, codepoint: u32) !*font.Glyph {
|
||||
const glyph = try face.renderGlyph(alloc, atlas, codepoint, .{});
|
||||
|
@ -33,6 +33,8 @@ comptime {
|
||||
if (builtin.target.isWasm()) {
|
||||
_ = Atlas.Wasm;
|
||||
_ = DeferredFace.Wasm;
|
||||
_ = SharedGrid.Wasm;
|
||||
_ = @import("Collection.zig").Wasm;
|
||||
_ = face.web_canvas.Wasm;
|
||||
_ = shape.web_canvas.Wasm;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
|
||||
const ziglyph = @import("ziglyph");
|
||||
const font = @import("../main.zig");
|
||||
const terminal = @import("../../terminal/main.zig");
|
||||
const SharedGrid = font.SharedGrid;
|
||||
|
||||
const log = std.log.scoped(.font_shaper);
|
||||
|
||||
@ -30,19 +31,19 @@ pub const Shaper = struct {
|
||||
alloc: Allocator,
|
||||
|
||||
/// The shared memory used for shaping results.
|
||||
cell_buf: []font.shape.Cell,
|
||||
cell_buf: std.ArrayListUnmanaged(font.shape.Cell),
|
||||
|
||||
/// The shared memory used for storing information about a run.
|
||||
run_buf: RunBuf,
|
||||
|
||||
/// The cell_buf argument is the buffer to use for storing shaped results.
|
||||
/// This should be at least the number of columns in the terminal.
|
||||
pub fn init(alloc: Allocator, opts: font.shape.Options) !Shaper {
|
||||
pub fn init(alloc: Allocator, _: font.shape.Options) !Shaper {
|
||||
// Note: we do not support opts.font_features
|
||||
|
||||
return Shaper{
|
||||
.alloc = alloc,
|
||||
.cell_buf = opts.cell_buf,
|
||||
.cell_buf = .{},
|
||||
.run_buf = .{},
|
||||
};
|
||||
}
|
||||
@ -61,14 +62,16 @@ pub const Shaper = struct {
|
||||
/// for a Shaper struct since they share state.
|
||||
pub fn runIterator(
|
||||
self: *Shaper,
|
||||
group: *font.GroupCache,
|
||||
row: terminal.Screen.Row,
|
||||
grid: *SharedGrid,
|
||||
screen: *const terminal.Screen,
|
||||
row: terminal.Pin,
|
||||
selection: ?terminal.Selection,
|
||||
cursor_x: ?usize,
|
||||
) font.shape.RunIterator {
|
||||
return .{
|
||||
.hooks = .{ .shaper = self },
|
||||
.group = group,
|
||||
.grid = grid,
|
||||
.screen = screen,
|
||||
.row = row,
|
||||
.selection = selection,
|
||||
.cursor_x = cursor_x,
|
||||
@ -90,21 +93,22 @@ pub const Shaper = struct {
|
||||
const clusters = self.run_buf.items(.cluster);
|
||||
assert(codepoints.len == clusters.len);
|
||||
|
||||
self.cell_buf.clearRetainingCapacity();
|
||||
switch (codepoints.len) {
|
||||
// Special cases: if we have no codepoints (is this possible?)
|
||||
// then our result is also an empty cell run.
|
||||
0 => return self.cell_buf[0..0],
|
||||
0 => return self.cell_buf.items[0..0],
|
||||
|
||||
// If we have only 1 codepoint, then we assume that it is
|
||||
// a single grapheme and just let it through. At this point,
|
||||
// we can't have any more information to do anything else.
|
||||
1 => {
|
||||
self.cell_buf[0] = .{
|
||||
try self.cell_buf.append(self.alloc, .{
|
||||
.x = @intCast(clusters[0]),
|
||||
.glyph_index = codepoints[0],
|
||||
};
|
||||
});
|
||||
|
||||
return self.cell_buf[0..1];
|
||||
return self.cell_buf.items[0..1];
|
||||
},
|
||||
|
||||
else => {},
|
||||
@ -151,10 +155,10 @@ pub const Shaper = struct {
|
||||
switch (len) {
|
||||
// If we have only a single codepoint then just render it
|
||||
// as-is.
|
||||
1 => self.cell_buf[cur] = .{
|
||||
1 => try self.cell_buf.append(self.alloc, .{
|
||||
.x = @intCast(clusters[start]),
|
||||
.glyph_index = codepoints[start],
|
||||
},
|
||||
}),
|
||||
|
||||
// We must have multiple codepoints (see assert above). In
|
||||
// this case we UTF-8 encode the codepoints and send them
|
||||
@ -190,13 +194,13 @@ pub const Shaper = struct {
|
||||
};
|
||||
defer self.alloc.free(cluster);
|
||||
|
||||
var face = try run.group.group.faceFromIndex(run.font_index);
|
||||
var face = try run.grid.resolver.collection.getFace(run.font_index);
|
||||
const index = try face.graphemeGlyphIndex(cluster);
|
||||
|
||||
self.cell_buf[cur] = .{
|
||||
try self.cell_buf.append(self.alloc, .{
|
||||
.x = @intCast(clusters[start]),
|
||||
.glyph_index = index,
|
||||
};
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@ -204,7 +208,7 @@ pub const Shaper = struct {
|
||||
cur += 1;
|
||||
}
|
||||
|
||||
return self.cell_buf[0..cur];
|
||||
return self.cell_buf.items[0..cur];
|
||||
}
|
||||
|
||||
/// The hooks for RunIterator.
|
||||
@ -238,15 +242,12 @@ pub const Wasm = struct {
|
||||
const wasm = @import("../../os/wasm.zig");
|
||||
const alloc = wasm.alloc;
|
||||
|
||||
export fn shaper_new(cap: usize) ?*Shaper {
|
||||
return shaper_new_(cap) catch null;
|
||||
export fn shaper_new() ?*Shaper {
|
||||
return shaper_new_() catch null;
|
||||
}
|
||||
|
||||
fn shaper_new_(cap: usize) !*Shaper {
|
||||
const cell_buf = try alloc.alloc(font.shape.Cell, cap);
|
||||
errdefer alloc.free(cell_buf);
|
||||
|
||||
var shaper = try Shaper.init(alloc, .{ .cell_buf = cell_buf });
|
||||
fn shaper_new_() !*Shaper {
|
||||
var shaper = try Shaper.init(alloc, .{});
|
||||
errdefer shaper.deinit();
|
||||
|
||||
const result = try alloc.create(Shaper);
|
||||
@ -257,7 +258,6 @@ pub const Wasm = struct {
|
||||
|
||||
export fn shaper_free(ptr: ?*Shaper) void {
|
||||
if (ptr) |v| {
|
||||
alloc.free(v.cell_buf);
|
||||
v.deinit();
|
||||
alloc.destroy(v);
|
||||
}
|
||||
@ -266,45 +266,130 @@ pub const Wasm = struct {
|
||||
/// Runs a test to verify shaping works properly.
|
||||
export fn shaper_test(
|
||||
self: *Shaper,
|
||||
group: *font.GroupCache,
|
||||
grid: *SharedGrid,
|
||||
str: [*]const u8,
|
||||
len: usize,
|
||||
) void {
|
||||
shaper_test_(self, group, str[0..len]) catch |err| {
|
||||
shaper_test_(self, grid, str[0..len]) catch |err| {
|
||||
log.warn("error during shaper test err={}", .{err});
|
||||
};
|
||||
}
|
||||
const js = @import("zig-js");
|
||||
|
||||
fn shaper_test_(self: *Shaper, group: *font.GroupCache, str: []const u8) !void {
|
||||
// Create a terminal and print all our characters into it.
|
||||
var term = try terminal.Terminal.init(alloc, self.cell_buf.len, 80);
|
||||
fn createImageData(self: *font.Atlas) !js.Object {
|
||||
// We need to draw pixels so this is format dependent.
|
||||
const buf: []u8 = switch (self.format) {
|
||||
// RGBA is the native ImageData format
|
||||
.rgba => self.data,
|
||||
|
||||
.grayscale => 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);
|
||||
@memset(buf, 0);
|
||||
for (self.data, 0..) |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 arr = arr: {
|
||||
const Uint8ClampedArray = try js.global.get(js.Object, "Uint8ClampedArray");
|
||||
defer Uint8ClampedArray.deinit();
|
||||
const arr = try Uint8ClampedArray.new(.{ mem_buf, buf.ptr, buf.len });
|
||||
if (!wasm.shared_mem) break :arr arr;
|
||||
|
||||
// If we're sharing memory then we have to copy the data since
|
||||
// we can't set ImageData directly using a SharedArrayBuffer.
|
||||
defer arr.deinit();
|
||||
break :arr try arr.call(js.Object, "slice", .{});
|
||||
};
|
||||
defer arr.deinit();
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
return image_data;
|
||||
}
|
||||
|
||||
fn shaper_test_(self: *Shaper, grid: *SharedGrid, str: []const u8) !void {
|
||||
// Make a screen with some data
|
||||
var term = try terminal.Terminal.init(alloc, .{ .cols = 20, .rows = 5 });
|
||||
defer term.deinit(alloc);
|
||||
try term.printString(str);
|
||||
|
||||
// Iterate over unicode codepoints and add to terminal
|
||||
{
|
||||
const view = try std.unicode.Utf8View.init(str);
|
||||
var iter = view.iterator();
|
||||
while (iter.nextCodepoint()) |c| {
|
||||
try term.print(c);
|
||||
}
|
||||
}
|
||||
// Get our run iterator
|
||||
|
||||
// Iterate over the rows and print out all the runs we get.
|
||||
var rowIter = term.screen.rowIterator(.viewport);
|
||||
var row_it = term.screen.pages.rowIterator(.right_down, .{ .viewport = .{} }, null);
|
||||
var y: usize = 0;
|
||||
while (rowIter.next()) |row| {
|
||||
const Render = struct {
|
||||
render: SharedGrid.Render,
|
||||
y: usize,
|
||||
x: usize,
|
||||
};
|
||||
var cell_list: std.ArrayListUnmanaged(Render) = .{};
|
||||
defer cell_list.deinit(wasm.alloc);
|
||||
while (row_it.next()) |row| {
|
||||
defer y += 1;
|
||||
|
||||
var iter = self.runIterator(group, row, null, null);
|
||||
while (try iter.next(alloc)) |run| {
|
||||
var it = self.runIterator(grid, &term.screen, row, null, null);
|
||||
while (try it.next(alloc)) |run| {
|
||||
const cells = try self.shape(run);
|
||||
log.info("y={} run={d} shape={any} idx={}", .{
|
||||
y,
|
||||
run.cells,
|
||||
cells,
|
||||
run.font_index,
|
||||
for (cells) |cell| {
|
||||
const render = try grid.renderGlyph(wasm.alloc, run.font_index, cell.glyph_index, .{});
|
||||
try cell_list.append(wasm.alloc, .{ .render = render, .x = cell.x, .y = y });
|
||||
|
||||
log.info("y={} x={} width={} height={} ax={} ay={} base={}", .{
|
||||
y * grid.metrics.cell_height,
|
||||
cell.x * grid.metrics.cell_width,
|
||||
render.glyph.width,
|
||||
render.glyph.height,
|
||||
render.glyph.atlas_x,
|
||||
render.glyph.atlas_y,
|
||||
grid.metrics.cell_baseline,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const colour_data = try createImageData(&grid.atlas_color);
|
||||
const gray_data = try createImageData(&grid.atlas_grayscale);
|
||||
|
||||
const doc = try js.global.get(js.Object, "document");
|
||||
defer doc.deinit();
|
||||
const canvas = try doc.call(js.Object, "getElementById", .{js.string("shaper-canvas")});
|
||||
errdefer canvas.deinit();
|
||||
const ctx = try canvas.call(js.Object, "getContext", .{js.string("2d")});
|
||||
defer ctx.deinit();
|
||||
for (cell_list.items) |cell| {
|
||||
const x_start = -@as(isize, @intCast(cell.render.glyph.atlas_x));
|
||||
const y_start = -@as(isize, @intCast(cell.render.glyph.atlas_y));
|
||||
try ctx.call(void, "putImageData", .{
|
||||
if (cell.render.presentation == .emoji) colour_data else gray_data,
|
||||
x_start + @as(isize, @intCast(cell.x * grid.metrics.cell_width)) - cell.render.glyph.offset_x,
|
||||
y_start + @as(isize, @intCast(cell.y * grid.metrics.cell_height)) - cell.render.glyph.offset_y,
|
||||
cell.render.glyph.atlas_x,
|
||||
cell.render.glyph.atlas_y,
|
||||
cell.render.glyph.width,
|
||||
cell.render.glyph.height,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -6,6 +6,7 @@ const Link = @This();
|
||||
|
||||
const oni = @import("oniguruma");
|
||||
const Mods = @import("key.zig").Mods;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
/// The regular expression that will be used to match the link. Ownership
|
||||
/// of this memory is up to the caller. The link will never free this memory.
|
||||
|
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
pub const cell = @import("cell.zig");
|
||||
pub const cursor = @import("cursor.zig");
|
||||
pub const key = @import("key.zig");
|
||||
@ -6,7 +7,7 @@ pub const page = @import("page.zig");
|
||||
pub const termio = @import("termio.zig");
|
||||
|
||||
pub const Cell = cell.Cell;
|
||||
pub const Inspector = @import("Inspector.zig");
|
||||
pub const Inspector = if (builtin.cpu.arch != .wasm32) @import("Inspector.zig") else struct {};
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
|
@ -11,16 +11,79 @@ comptime {
|
||||
_ = @import("App.zig").Wasm;
|
||||
}
|
||||
|
||||
pub const std_options = struct {
|
||||
const renderer = @import("renderer.zig");
|
||||
const Surface = @import("Surface.zig");
|
||||
const App = @import("App.zig");
|
||||
const apprt = @import("apprt.zig");
|
||||
|
||||
const wasm = @import("os/wasm.zig");
|
||||
const alloc = wasm.alloc;
|
||||
const cli = @import("cli.zig");
|
||||
const Config = @import("config/Config.zig");
|
||||
|
||||
export fn run(str: [*]const u8, len: usize) void {
|
||||
run_(str[0..len]) catch |err| {
|
||||
std.log.err("err: {?}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
var surf: ?*Surface = null;
|
||||
export fn draw() void {
|
||||
surf.?.renderer.drawFrame(surf.?.rt_surface) catch |err| {
|
||||
std.log.err("err: {?}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
fn run_(str: []const u8) !void {
|
||||
var config = try Config.default(alloc);
|
||||
var fbs = std.io.fixedBufferStream(str);
|
||||
var iter = cli.args.lineIterator(fbs.reader());
|
||||
try config.loadIter(alloc, &iter);
|
||||
try config.finalize();
|
||||
std.log.err("font-size {}", .{config.@"font-size"});
|
||||
const app = try App.create(alloc);
|
||||
// Create our runtime app
|
||||
var app_runtime = try apprt.App.init(app, .{});
|
||||
const surface = try alloc.create(Surface);
|
||||
const apprt_surface = try alloc.create(apprt.Surface);
|
||||
try surface.init(alloc, &config, app, &app_runtime, apprt_surface);
|
||||
std.log.err("{}", .{surface.size});
|
||||
try surface.renderer.setScreenSize(surface.size);
|
||||
surf = surface;
|
||||
// const esc = "\x1b[";
|
||||
// surface.io.processOutput("M_yhelloaaaaaaaaa\n\r🐏\n\r👍🏽\n\rM_ghostty" ++ esc ++ "2;2H" ++ esc ++ "48;2;240;40;40m" ++ esc ++ "38;2;23;255;80mhello");
|
||||
// // try surface.renderer_state.terminal.printString("M_yhelloaaaaaaaaa\n🐏\n👍🏽\nM_ghostty");
|
||||
// // surface.renderer_state.terminal.setCursorPos(4, 2);
|
||||
// // try surface.renderer_state.terminal.setAttribute(.{ .direct_color_bg = .{
|
||||
// // .r = 240,
|
||||
// // .g = 40,
|
||||
// // .b = 40,
|
||||
// // } });
|
||||
// // try surface.renderer_state.terminal.setAttribute(.{ .direct_color_fg = .{
|
||||
// // .r = 255,
|
||||
// // .g = 255,
|
||||
// // .b = 255,
|
||||
// // } });
|
||||
// // try surface.renderer_state.terminal.printString("hello");
|
||||
// try surface.renderer.updateFrame(apprt_surface, &surface.renderer_state, false);
|
||||
// try surface.renderer.drawFrame(apprt_surface);
|
||||
// try surface.renderer.updateFrame(apprt_surface, &surface.renderer_state, false);
|
||||
// try surface.renderer.drawFrame(apprt_surface);
|
||||
|
||||
// // const webgl = try renderer.OpenGL.init(alloc, .{ .config = try renderer.OpenGL.DerivedConfig.init(alloc, &config) });
|
||||
// // _ = webgl;
|
||||
}
|
||||
|
||||
pub const std_options: std.Options = .{
|
||||
// Set our log level. We try to get as much logging as possible but in
|
||||
// ReleaseSmall mode where we're optimizing for space, we elevate the
|
||||
// log level.
|
||||
pub const log_level: std.log.Level = switch (builtin.mode) {
|
||||
.log_level = switch (builtin.mode) {
|
||||
.Debug => .debug,
|
||||
.ReleaseSmall => .warn,
|
||||
else => .info,
|
||||
};
|
||||
},
|
||||
|
||||
// Set our log function
|
||||
pub const logFn = @import("os/wasm/log.zig").log;
|
||||
.logFn = @import("os/wasm/log.zig").log,
|
||||
};
|
||||
|
@ -56,6 +56,8 @@ pub fn launchedFromDesktop() bool {
|
||||
// iPhone/iPad is always launched from the "desktop"
|
||||
.ios => true,
|
||||
|
||||
.freestanding, .wasi => false,
|
||||
|
||||
else => @compileError("unsupported platform"),
|
||||
};
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ pub inline fn home(buf: []u8) !?[]u8 {
|
||||
// iOS doesn't have a user-writable home directory
|
||||
.ios => null,
|
||||
|
||||
.wasi => null,
|
||||
|
||||
else => @compileError("unimplemented"),
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const posix = std.posix;
|
||||
|
||||
pub const HostnameParsingError = error{
|
||||
@ -57,6 +58,7 @@ pub const LocalHostnameValidationError = error{
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
const HOST_NAME_MAX = (if (builtin.cpu.arch == .wasm32) 64 else posix.HOST_NAME_MAX);
|
||||
/// Checks if a hostname is local to the current machine. This matches
|
||||
/// both "localhost" and the current hostname of the machine (as returned
|
||||
/// by `gethostname`).
|
||||
@ -65,7 +67,8 @@ pub fn isLocalHostname(hostname: []const u8) LocalHostnameValidationError!bool {
|
||||
if (std.mem.eql(u8, "localhost", hostname)) return true;
|
||||
|
||||
// If hostname is not "localhost" it must match our hostname.
|
||||
var buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
if (builtin.cpu.arch == .wasm32) return false;
|
||||
var buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const ourHostname = try posix.gethostname(&buf);
|
||||
return std.mem.eql(u8, hostname, ourHostname);
|
||||
}
|
||||
@ -73,7 +76,7 @@ pub fn isLocalHostname(hostname: []const u8) LocalHostnameValidationError!bool {
|
||||
test "bufPrintHostnameFromFileUri succeeds with ascii hostname" {
|
||||
const uri = try std.Uri.parse("file://localhost/");
|
||||
|
||||
var buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
var buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const actual = try bufPrintHostnameFromFileUri(&buf, uri);
|
||||
try std.testing.expectEqualStrings("localhost", actual);
|
||||
}
|
||||
@ -81,7 +84,7 @@ test "bufPrintHostnameFromFileUri succeeds with ascii hostname" {
|
||||
test "bufPrintHostnameFromFileUri succeeds with hostname as mac address" {
|
||||
const uri = try std.Uri.parse("file://12:34:56:78:90:12");
|
||||
|
||||
var buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
var buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const actual = try bufPrintHostnameFromFileUri(&buf, uri);
|
||||
try std.testing.expectEqualStrings("12:34:56:78:90:12", actual);
|
||||
}
|
||||
@ -89,7 +92,7 @@ test "bufPrintHostnameFromFileUri succeeds with hostname as mac address" {
|
||||
test "bufPrintHostnameFromFileUri succeeds with hostname as a mac address and the last section is < 10" {
|
||||
const uri = try std.Uri.parse("file://12:34:56:78:90:05");
|
||||
|
||||
var buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
var buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const actual = try bufPrintHostnameFromFileUri(&buf, uri);
|
||||
try std.testing.expectEqualStrings("12:34:56:78:90:05", actual);
|
||||
}
|
||||
@ -98,21 +101,21 @@ test "bufPrintHostnameFromFileUri returns only hostname when there is a port com
|
||||
// First: try with a non-2-digit port, to test general port handling.
|
||||
const four_port_uri = try std.Uri.parse("file://has-a-port:1234");
|
||||
|
||||
var four_port_buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
var four_port_buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const four_port_actual = try bufPrintHostnameFromFileUri(&four_port_buf, four_port_uri);
|
||||
try std.testing.expectEqualStrings("has-a-port", four_port_actual);
|
||||
|
||||
// Second: try with a 2-digit port to test mac-address handling.
|
||||
const two_port_uri = try std.Uri.parse("file://has-a-port:12");
|
||||
|
||||
var two_port_buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
var two_port_buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const two_port_actual = try bufPrintHostnameFromFileUri(&two_port_buf, two_port_uri);
|
||||
try std.testing.expectEqualStrings("has-a-port", two_port_actual);
|
||||
|
||||
// Third: try with a mac-address that has a port-component added to it to test mac-address handling.
|
||||
const mac_with_port_uri = try std.Uri.parse("file://12:34:56:78:90:12:1234");
|
||||
|
||||
var mac_with_port_buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
var mac_with_port_buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const mac_with_port_actual = try bufPrintHostnameFromFileUri(&mac_with_port_buf, mac_with_port_uri);
|
||||
try std.testing.expectEqualStrings("12:34:56:78:90:12", mac_with_port_actual);
|
||||
}
|
||||
@ -120,7 +123,7 @@ test "bufPrintHostnameFromFileUri returns only hostname when there is a port com
|
||||
test "bufPrintHostnameFromFileUri returns NoHostnameInUri error when hostname is missing from uri" {
|
||||
const uri = try std.Uri.parse("file:///");
|
||||
|
||||
var buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
var buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const actual = bufPrintHostnameFromFileUri(&buf, uri);
|
||||
try std.testing.expectError(HostnameParsingError.NoHostnameInUri, actual);
|
||||
}
|
||||
@ -138,7 +141,7 @@ test "isLocalHostname returns true when provided hostname is localhost" {
|
||||
}
|
||||
|
||||
test "isLocalHostname returns true when hostname is local" {
|
||||
var buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||
var buf: [HOST_NAME_MAX]u8 = undefined;
|
||||
const localHostname = try posix.gethostname(&buf);
|
||||
try std.testing.expect(try isLocalHostname(localHostname));
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ const mouse = @import("mouse.zig");
|
||||
const openpkg = @import("open.zig");
|
||||
const pipepkg = @import("pipe.zig");
|
||||
const resourcesdir = @import("resourcesdir.zig");
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
|
||||
// Namespaces
|
||||
pub const args = @import("args.zig");
|
||||
|
@ -18,6 +18,7 @@ pub const winsize = extern struct {
|
||||
pub const Pty = switch (builtin.os.tag) {
|
||||
.windows => WindowsPty,
|
||||
.ios => NullPty,
|
||||
.freestanding, .wasi => NullPty,
|
||||
else => PosixPty,
|
||||
};
|
||||
|
||||
@ -41,7 +42,7 @@ pub const Mode = packed struct {
|
||||
// a termio that doesn't use a pty. This isn't used in any user-facing
|
||||
// artifacts, this is just a stopgap to get compilation to work on iOS.
|
||||
const NullPty = struct {
|
||||
pub const Fd = posix.fd_t;
|
||||
pub const Fd = i32;
|
||||
|
||||
master: Fd,
|
||||
slave: Fd,
|
||||
|
@ -44,7 +44,7 @@ pub const Impl = enum {
|
||||
) Impl {
|
||||
if (target.cpu.arch == .wasm32) {
|
||||
return switch (wasm_target) {
|
||||
.browser => .webgl,
|
||||
.browser => .opengl,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -460,6 +460,9 @@ pub fn surfaceInit(surface: *apprt.Surface) !void {
|
||||
// to compile for OpenGL targets but libghostty is strictly
|
||||
// broken for rendering on this platforms.
|
||||
},
|
||||
apprt.browser => {
|
||||
gl.glad.context.init();
|
||||
},
|
||||
}
|
||||
|
||||
// These are very noisy so this is commented, but easy to uncomment
|
||||
@ -574,6 +577,10 @@ pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void {
|
||||
// to compile for OpenGL targets but libghostty is strictly
|
||||
// broken for rendering on this platforms.
|
||||
},
|
||||
apprt.browser => {
|
||||
log.err("context init", .{});
|
||||
gl.glad.context.init();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,6 +604,7 @@ pub fn threadExit(self: *const OpenGL) void {
|
||||
apprt.embedded => {
|
||||
// TODO: see threadEnter
|
||||
},
|
||||
apprt.browser => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,6 +683,7 @@ pub fn updateFrame(
|
||||
) !void {
|
||||
_ = surface;
|
||||
|
||||
std.log.err("update frame", .{});
|
||||
// Data we extract out of the critical area.
|
||||
const Critical = struct {
|
||||
full_rebuild: bool,
|
||||
@ -693,6 +702,7 @@ pub fn updateFrame(
|
||||
|
||||
state.mutex.lock();
|
||||
defer state.mutex.unlock();
|
||||
std.log.err("critical", .{});
|
||||
|
||||
// If we're in a synchronized output state, we pause all rendering.
|
||||
if (state.terminal.modes.get(.synchronized_output)) {
|
||||
@ -2219,7 +2229,14 @@ fn flushAtlasSingle(
|
||||
/// the cells.
|
||||
pub fn drawFrame(self: *OpenGL, surface: *apprt.Surface) !void {
|
||||
// If we're in single-threaded more we grab a lock since we use shared data.
|
||||
if (single_threaded_draw) self.draw_mutex.lock();
|
||||
// wasm can't lock a mutex on the main thread because it uses Atomic.wait
|
||||
if (single_threaded_draw) {
|
||||
if (builtin.cpu.arch == .wasm32) {
|
||||
if (!self.draw_mutex.tryLock()) return;
|
||||
} else {
|
||||
self.draw_mutex.lock();
|
||||
}
|
||||
}
|
||||
defer if (single_threaded_draw) self.draw_mutex.unlock();
|
||||
const gl_state: *GLState = if (self.gl_state) |*v| v else return;
|
||||
|
||||
@ -2278,6 +2295,7 @@ pub fn drawFrame(self: *OpenGL, surface: *apprt.Surface) !void {
|
||||
apprt.glfw => surface.window.swapBuffers(),
|
||||
apprt.gtk => {},
|
||||
apprt.embedded => {},
|
||||
apprt.browser => {},
|
||||
else => @compileError("unsupported runtime"),
|
||||
}
|
||||
}
|
||||
@ -2473,10 +2491,10 @@ fn drawCells(
|
||||
// Our allocated buffer on the GPU is smaller than our capacity.
|
||||
// We reallocate a new buffer with the full new capacity.
|
||||
if (self.gl_cells_size < cells.capacity) {
|
||||
log.info("reallocating GPU buffer old={} new={}", .{
|
||||
self.gl_cells_size,
|
||||
cells.capacity,
|
||||
});
|
||||
// log.info("reallocating GPU buffer old={} new={}", .{
|
||||
// self.gl_cells_size,
|
||||
// cells.capacity,
|
||||
// });
|
||||
|
||||
try bind.vbo.setDataNullManual(
|
||||
@sizeOf(CellProgram.Cell) * cells.capacity,
|
||||
@ -2526,7 +2544,7 @@ const GLState = struct {
|
||||
const arena_alloc = arena.allocator();
|
||||
|
||||
// Load our custom shaders
|
||||
const custom_state: ?custom.State = custom: {
|
||||
const custom_state: ?custom.State = if (builtin.cpu.arch == .wasm32) null else custom: {
|
||||
const shaders: []const [:0]const u8 = shadertoy.loadFromFiles(
|
||||
arena_alloc,
|
||||
config.custom_shaders,
|
||||
|
@ -232,7 +232,7 @@ fn threadMain_(self: *Thread) !void {
|
||||
self.startDrawTimer();
|
||||
|
||||
// Run
|
||||
log.debug("starting renderer thread", .{});
|
||||
log.err("starting renderer thread", .{});
|
||||
defer log.debug("starting renderer thread shutdown", .{});
|
||||
_ = try self.loop.run(.until_done);
|
||||
}
|
||||
@ -437,6 +437,7 @@ fn wakeupCallback(
|
||||
};
|
||||
|
||||
const t = self_.?;
|
||||
log.err("wakeup", .{});
|
||||
|
||||
// When we wake up, we check the mailbox. Mailbox producers should
|
||||
// wake up our thread after publishing.
|
||||
|
@ -3,6 +3,7 @@ const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const gl = @import("opengl");
|
||||
const wuffs = @import("wuffs");
|
||||
const internal_os = @import("../../os/main.zig");
|
||||
|
||||
/// Represents a single image placement on the grid. A placement is a
|
||||
/// request to render an instance of an image.
|
||||
|
@ -1,27 +1,27 @@
|
||||
#version 330 core
|
||||
#version 300 es
|
||||
|
||||
in vec2 glyph_tex_coords;
|
||||
in mediump vec2 glyph_tex_coords;
|
||||
flat in uint mode;
|
||||
|
||||
// The color for this cell. If this is a background pass this is the
|
||||
// background color. Otherwise, this is the foreground color.
|
||||
flat in vec4 color;
|
||||
flat in mediump vec4 color;
|
||||
|
||||
// The position of the cells top-left corner.
|
||||
flat in vec2 screen_cell_pos;
|
||||
flat in mediump vec2 screen_cell_pos;
|
||||
|
||||
// Position the fragment coordinate to the upper left
|
||||
layout(origin_upper_left) in vec4 gl_FragCoord;
|
||||
// layout(origin_upper_left) in vec4 gl_FragCoord;
|
||||
|
||||
// Must declare this output for some versions of OpenGL.
|
||||
layout(location = 0) out vec4 out_FragColor;
|
||||
out mediump vec4 out_FragColor;
|
||||
|
||||
// Font texture
|
||||
uniform sampler2D text;
|
||||
uniform sampler2D text_color;
|
||||
|
||||
// Dimensions of the cell
|
||||
uniform vec2 cell_size;
|
||||
uniform highp vec2 cell_size;
|
||||
|
||||
// See vertex shader
|
||||
const uint MODE_BG = 1u;
|
||||
@ -31,7 +31,7 @@ const uint MODE_FG_COLOR = 7u;
|
||||
const uint MODE_FG_POWERLINE = 15u;
|
||||
|
||||
void main() {
|
||||
float a;
|
||||
highp float a;
|
||||
|
||||
switch (mode) {
|
||||
case MODE_BG:
|
||||
@ -42,7 +42,7 @@ void main() {
|
||||
case MODE_FG_CONSTRAINED:
|
||||
case MODE_FG_POWERLINE:
|
||||
a = texture(text, glyph_tex_coords).r;
|
||||
vec3 premult = color.rgb * color.a;
|
||||
highp vec3 premult = color.rgb * color.a;
|
||||
out_FragColor = vec4(premult.rgb*a, a);
|
||||
break;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#version 330 core
|
||||
#version 300 es
|
||||
|
||||
// These are the possible modes that "mode" can be set to. This is
|
||||
// used to multiplex multiple render modes into a single shader.
|
||||
@ -11,33 +11,33 @@ const uint MODE_FG_COLOR = 7u;
|
||||
const uint MODE_FG_POWERLINE = 15u;
|
||||
|
||||
// The grid coordinates (x, y) where x < columns and y < rows
|
||||
layout (location = 0) in vec2 grid_coord;
|
||||
in vec2 grid_coord;
|
||||
|
||||
// Position of the glyph in the texture.
|
||||
layout (location = 1) in vec2 glyph_pos;
|
||||
in vec2 glyph_pos;
|
||||
|
||||
// Width/height of the glyph
|
||||
layout (location = 2) in vec2 glyph_size;
|
||||
in vec2 glyph_size;
|
||||
|
||||
// Offset of the top-left corner of the glyph when rendered in a rect.
|
||||
layout (location = 3) in vec2 glyph_offset;
|
||||
in vec2 glyph_offset;
|
||||
|
||||
// The color for this cell in RGBA (0 to 1.0). Background or foreground
|
||||
// depends on mode.
|
||||
layout (location = 4) in vec4 color_in;
|
||||
in vec4 color_in;
|
||||
|
||||
// Only set for MODE_FG, this is the background color of the FG text.
|
||||
// This is used to detect minimal contrast for the text.
|
||||
layout (location = 5) in vec4 bg_color_in;
|
||||
in vec4 bg_color_in;
|
||||
|
||||
// The mode of this shader. The mode determines what fields are used,
|
||||
// what the output will be, etc. This shader is capable of executing in
|
||||
// multiple "modes" so that we can share some logic and so that we can draw
|
||||
// the entire terminal grid in a single GPU pass.
|
||||
layout (location = 6) in uint mode_in;
|
||||
in uint mode_in;
|
||||
|
||||
// The width in cells of this item.
|
||||
layout (location = 7) in uint grid_width;
|
||||
in uint grid_width;
|
||||
|
||||
// The background or foreground color for the fragment, depending on
|
||||
// whether this is a background or foreground pass.
|
||||
@ -168,22 +168,22 @@ void main() {
|
||||
|
||||
// Scaled for wide chars
|
||||
vec2 cell_size_scaled = cell_size;
|
||||
cell_size_scaled.x = cell_size_scaled.x * grid_width;
|
||||
cell_size_scaled.x = cell_size_scaled.x * float(grid_width);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_BG:
|
||||
// If we're at the edge of the grid, we add our padding to the background
|
||||
// to extend it. Note: grid_padding is top/right/bottom/left.
|
||||
if (grid_coord.y == 0 && padding_vertical_top) {
|
||||
if (grid_coord.y == 0. && padding_vertical_top) {
|
||||
cell_pos.y -= grid_padding.r;
|
||||
cell_size_scaled.y += grid_padding.r;
|
||||
} else if (grid_coord.y == grid_size.y - 1 && padding_vertical_bottom) {
|
||||
} else if (grid_coord.y == grid_size.y - 1. && padding_vertical_bottom) {
|
||||
cell_size_scaled.y += grid_padding.b;
|
||||
}
|
||||
if (grid_coord.x == 0) {
|
||||
if (grid_coord.x == 0.) {
|
||||
cell_pos.x -= grid_padding.a;
|
||||
cell_size_scaled.x += grid_padding.a;
|
||||
} else if (grid_coord.x == grid_size.x - 1) {
|
||||
} else if (grid_coord.x == grid_size.x - 1.) {
|
||||
cell_size_scaled.x += grid_padding.g;
|
||||
}
|
||||
|
||||
@ -205,7 +205,7 @@ void main() {
|
||||
// The glyph_offset.y is the y bearing, a y value that when added
|
||||
// to the baseline is the offset (+y is up). Our grid goes down.
|
||||
// So we flip it with `cell_size.y - glyph_offset.y`.
|
||||
glyph_offset_calc.y = cell_size_scaled.y - glyph_offset_calc.y;
|
||||
glyph_offset_calc.y = -glyph_offset_calc.y;
|
||||
|
||||
// If this is a constrained mode, we need to constrain it!
|
||||
// We also always constrain colored glyphs since we should have
|
||||
@ -214,7 +214,7 @@ void main() {
|
||||
if (mode == MODE_FG_CONSTRAINED || mode == MODE_FG_COLOR) {
|
||||
if (glyph_size.x > cell_size_scaled.x) {
|
||||
float new_y = glyph_size.y * (cell_size_scaled.x / glyph_size.x);
|
||||
glyph_offset_calc.y = glyph_offset_calc.y + ((glyph_size.y - new_y) / 2);
|
||||
glyph_offset_calc.y = glyph_offset_calc.y + ((glyph_size.y - new_y) / 2.);
|
||||
glyph_size_calc.y = new_y;
|
||||
glyph_size_calc.x = cell_size_scaled.x;
|
||||
}
|
||||
@ -238,8 +238,8 @@ void main() {
|
||||
text_size = textureSize(text_color, 0);
|
||||
break;
|
||||
}
|
||||
vec2 glyph_tex_pos = glyph_pos / text_size;
|
||||
vec2 glyph_tex_size = glyph_size / text_size;
|
||||
vec2 glyph_tex_pos = glyph_pos / vec2(text_size);
|
||||
vec2 glyph_tex_size = glyph_size / vec2(text_size);
|
||||
glyph_tex_coords = glyph_tex_pos + glyph_tex_size * position;
|
||||
|
||||
// If we have a minimum contrast, we need to check if we need to
|
||||
|
@ -1,4 +1,4 @@
|
||||
#version 330 core
|
||||
#version 300 es
|
||||
|
||||
void main(){
|
||||
vec2 position;
|
||||
|
@ -1,12 +1,12 @@
|
||||
#version 330 core
|
||||
#version 300 es
|
||||
|
||||
in vec2 tex_coord;
|
||||
in mediump vec2 tex_coord;
|
||||
|
||||
layout(location = 0) out vec4 out_FragColor;
|
||||
out mediump vec4 out_FragColor;
|
||||
|
||||
uniform sampler2D image;
|
||||
|
||||
void main() {
|
||||
vec4 color = texture(image, tex_coord);
|
||||
mediump vec4 color = texture(image, tex_coord);
|
||||
out_FragColor = vec4(color.rgb * color.a, color.a);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#version 330 core
|
||||
#version 300 es
|
||||
|
||||
layout (location = 0) in vec2 grid_pos;
|
||||
layout (location = 1) in vec2 cell_offset;
|
||||
layout (location = 2) in vec4 source_rect;
|
||||
layout (location = 3) in vec2 dest_size;
|
||||
in vec2 grid_pos;
|
||||
in vec2 cell_offset;
|
||||
in vec4 source_rect;
|
||||
in vec2 dest_size;
|
||||
|
||||
out vec2 tex_coord;
|
||||
|
||||
@ -13,7 +13,7 @@ uniform mat4 projection;
|
||||
|
||||
void main() {
|
||||
// The size of the image in pixels
|
||||
vec2 image_size = textureSize(image, 0);
|
||||
vec2 image_size = vec2(textureSize(image, 0));
|
||||
|
||||
// Turn the cell position into a vertex point depending on the
|
||||
// gl_VertexID. Since we use instanced drawing, we have 4 vertices
|
||||
|
@ -328,9 +328,15 @@ fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action {
|
||||
}
|
||||
|
||||
// A numeric value. Add it to our accumulator.
|
||||
if (builtin.cpu.arch == .wasm32) {
|
||||
if (self.param_acc_idx > 0) {
|
||||
self.param_acc *= 10;
|
||||
}
|
||||
} else {
|
||||
if (self.param_acc_idx > 0) {
|
||||
self.param_acc *|= 10;
|
||||
}
|
||||
}
|
||||
self.param_acc +|= c - '0';
|
||||
|
||||
// Increment our accumulator index. If we overflow then
|
||||
|
@ -108,7 +108,7 @@ pub const LoadingImage = struct {
|
||||
path: []const u8,
|
||||
) !void {
|
||||
// windows is currently unsupported, does it support shm?
|
||||
if (comptime builtin.target.os.tag == .windows) {
|
||||
if (comptime builtin.target.os.tag == .windows or builtin.cpu.arch == .wasm32) {
|
||||
return error.UnsupportedMedium;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
|
||||
const terminal = @import("../main.zig");
|
||||
const internal_os = @import("../../os/main.zig");
|
||||
const point = @import("../point.zig");
|
||||
const size = @import("../size.zig");
|
||||
const command = @import("graphics_command.zig");
|
||||
|
@ -11,6 +11,7 @@ const assert = std.debug.assert;
|
||||
const Allocator = mem.Allocator;
|
||||
const RGB = @import("color.zig").RGB;
|
||||
const kitty = @import("kitty.zig");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const log = std.log.scoped(.osc);
|
||||
|
||||
@ -871,7 +872,11 @@ pub const Parser = struct {
|
||||
self.complete = true;
|
||||
|
||||
const idx = self.buf_idx - self.buf_start;
|
||||
if (builtin.cpu.arch == .wasm32) {
|
||||
if (idx > 0) self.temp_state.num *= 10;
|
||||
} else {
|
||||
if (idx > 0) self.temp_state.num *|= 10;
|
||||
}
|
||||
self.temp_state.num +|= c - '0';
|
||||
},
|
||||
';' => {
|
||||
|
@ -320,7 +320,7 @@ pub const Page = struct {
|
||||
/// when runtime safety is enabled. This is a no-op when runtime
|
||||
/// safety is disabled. This uses the libc allocator.
|
||||
pub fn assertIntegrity(self: *const Page) void {
|
||||
if (comptime build_config.slow_runtime_safety) {
|
||||
if (comptime build_config.slow_runtime_safety and builtin.cpu.arch != .wasm32) {
|
||||
self.verifyIntegrity(std.heap.c_allocator) catch |err| {
|
||||
log.err("page integrity violation, crashing. err={}", .{err});
|
||||
@panic("page integrity violation");
|
||||
|
@ -13,6 +13,7 @@ const osc = @import("osc.zig");
|
||||
const sgr = @import("sgr.zig");
|
||||
const UTF8Decoder = @import("UTF8Decoder.zig");
|
||||
const MouseShape = @import("mouse_shape.zig").MouseShape;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const log = std.log.scoped(.stream);
|
||||
|
||||
@ -242,8 +243,13 @@ pub fn Stream(comptime Handler: type) type {
|
||||
0x18, 0x1A => self.parser.state = .ground,
|
||||
// A parameter digit:
|
||||
'0'...'9' => if (self.parser.params_idx < 16) {
|
||||
if (builtin.cpu.arch == .wasm32) {
|
||||
self.parser.param_acc *= 10;
|
||||
self.parser.param_acc += c - '0';
|
||||
} else {
|
||||
self.parser.param_acc *|= 10;
|
||||
self.parser.param_acc +|= c - '0';
|
||||
}
|
||||
// The parser's CSI param action uses param_acc_idx
|
||||
// to decide if there's a final param that needs to
|
||||
// be consumed or not, but it doesn't matter really
|
||||
|
@ -126,7 +126,7 @@ pub fn threadEnter(
|
||||
|
||||
// Start our read thread
|
||||
const read_thread = try std.Thread.spawn(
|
||||
.{},
|
||||
.{ .allocator = alloc },
|
||||
if (builtin.os.tag == .windows) ReadThread.threadMainWindows else ReadThread.threadMainPosix,
|
||||
.{ pty_fds.read, io, pipe[0] },
|
||||
);
|
||||
@ -686,11 +686,18 @@ const Subprocess = struct {
|
||||
/// a potential execution on the host.
|
||||
const FlatpakHostCommand = if (build_config.flatpak) internal_os.FlatpakHostCommand else void;
|
||||
|
||||
const c = @cImport({
|
||||
const c = if (builtin.cpu.arch != .wasm32) @cImport({
|
||||
@cInclude("errno.h");
|
||||
@cInclude("signal.h");
|
||||
@cInclude("unistd.h");
|
||||
});
|
||||
}) else struct {
|
||||
pub const pid_t = Command.PidT;
|
||||
pub const ESRCH = 0x03;
|
||||
pub fn getpgid(pid: pid_t) pid_t {
|
||||
_ = pid;
|
||||
return 100;
|
||||
}
|
||||
};
|
||||
|
||||
arena: std.heap.ArenaAllocator,
|
||||
cwd: ?[]const u8,
|
||||
@ -744,7 +751,7 @@ const Subprocess = struct {
|
||||
|
||||
// Assume that the resources directory is adjacent to the terminfo
|
||||
// database
|
||||
var buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
var buf: [if (builtin.cpu.arch == .wasm32) 4096 else std.fs.max_path_bytes]u8 = undefined;
|
||||
const dir = try std.fmt.bufPrint(&buf, "{s}/terminfo", .{
|
||||
std.fs.path.dirname(base) orelse unreachable,
|
||||
});
|
||||
@ -762,8 +769,8 @@ const Subprocess = struct {
|
||||
|
||||
// Add our binary to the path if we can find it.
|
||||
ghostty_path: {
|
||||
var exe_buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
const exe_bin_path = std.fs.selfExePath(&exe_buf) catch |err| {
|
||||
var exe_buf: [if (builtin.cpu.arch == .wasm32) 4096 else std.fs.max_path_bytes]u8 = undefined;
|
||||
const exe_bin_path = if (builtin.cpu.arch == .wasm32) "ghostty-wasm.wasm" else std.fs.selfExePath(&exe_buf) catch |err| {
|
||||
log.warn("failed to get ghostty exe path err={}", .{err});
|
||||
break :ghostty_path;
|
||||
};
|
||||
@ -848,6 +855,7 @@ const Subprocess = struct {
|
||||
|
||||
// Setup our shell integration, if we can.
|
||||
const integrated_shell: ?shell_integration.Shell, const shell_command: []const u8 = shell: {
|
||||
if (builtin.cpu.arch == .wasm32) break :shell .{ null, "" };
|
||||
const default_shell_command = cfg.command orelse switch (builtin.os.tag) {
|
||||
.windows => "cmd.exe",
|
||||
else => "sh",
|
||||
@ -1247,6 +1255,7 @@ const Subprocess = struct {
|
||||
|
||||
_ = try command.wait(false);
|
||||
},
|
||||
.freestanding, .wasi => {},
|
||||
|
||||
else => if (getpgid(pid)) |pgid| {
|
||||
// It is possible to send a killpg between the time that
|
||||
@ -1415,6 +1424,7 @@ pub const ReadThread = struct {
|
||||
// child process dies. To be safe, we just break the loop
|
||||
// and let our poll happen.
|
||||
if (n == 0) break;
|
||||
std.log.err("{} {} {}", .{ buf[0], n, @intFromPtr(&buf) });
|
||||
|
||||
// log.info("DATA: {d}", .{n});
|
||||
@call(.always_inline, termio.Termio.processOutput, .{ io, buf[0..n] });
|
||||
|
@ -554,6 +554,7 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void {
|
||||
// use a timer under the covers
|
||||
if (std.time.Instant.now()) |now| cursor_reset: {
|
||||
if (self.last_cursor_reset) |last| {
|
||||
log.err("now: {} last: {}", .{ now, last });
|
||||
if (now.since(last) <= (500 * std.time.ns_per_ms)) {
|
||||
break :cursor_reset;
|
||||
}
|
||||
@ -571,6 +572,11 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void {
|
||||
// process a byte at a time alternating between the inspector handler
|
||||
// and the termio handler. This is very slow compared to our optimizations
|
||||
// below but at least users only pay for it if they're using the inspector.
|
||||
std.log.err("to print {s}", .{buf});
|
||||
if (builtin.cpu.arch == .wasm32) {
|
||||
self.terminal_stream.nextSlice(buf) catch |err|
|
||||
log.err("error processing terminal data: {}", .{err});
|
||||
} else {
|
||||
if (self.renderer_state.inspector) |insp| {
|
||||
for (buf, 0..) |byte, i| {
|
||||
insp.recordPtyRead(buf[i .. i + 1]) catch |err| {
|
||||
@ -584,6 +590,7 @@ fn processOutputLocked(self: *Termio, buf: []const u8) void {
|
||||
self.terminal_stream.nextSlice(buf) catch |err|
|
||||
log.err("error processing terminal data: {}", .{err});
|
||||
}
|
||||
}
|
||||
|
||||
// If our stream handling caused messages to be sent to the mailbox
|
||||
// thread, then we need to wake it up so that it processes them.
|
||||
|
@ -1102,7 +1102,7 @@ pub const StreamHandler = struct {
|
||||
// See https://www.rfc-editor.org/rfc/rfc793#section-3.1.
|
||||
const PORT_NUMBER_MAX_DIGITS = 5;
|
||||
// Make sure there is space for a max length hostname + the max number of digits.
|
||||
var host_and_port_buf: [posix.HOST_NAME_MAX + PORT_NUMBER_MAX_DIGITS]u8 = undefined;
|
||||
var host_and_port_buf: [(if (builtin.cpu.arch == .wasm32) 64 else posix.HOST_NAME_MAX) + PORT_NUMBER_MAX_DIGITS]u8 = undefined;
|
||||
const hostname_from_uri = internal_os.hostname.bufPrintHostnameFromFileUri(
|
||||
&host_and_port_buf,
|
||||
uri,
|
||||
|
Reference in New Issue
Block a user