Ziggified GLFW bindings with 100% API coverage, zero-fuss installation, cross compilation, and more.
Find a file
2021-10-31 11:50:09 -07:00
.github glfw: CI: update to latest Zig nightly 1444+e2a2e6c14 2021-10-29 12:31:28 -07:00
src glfw: hot patch undefined behavior in GLFW that went unnoticed 6+ years 2021-10-31 11:50:09 -07:00
upstream glfw: hot patch undefined behavior in GLFW that went unnoticed 6+ years 2021-10-31 11:50:09 -07:00
.gitattributes initialize repository 2021-07-04 10:36:34 -07:00
.gitignore gitignore: update to latest from ziglang/zig repo 2021-07-06 20:51:19 -07:00
build.zig glfw: expose system SDK build options 2021-10-30 21:47:48 -07:00
LICENSE LICENSE: note directories with a separate LICENSE file 2021-07-05 12:46:20 -07:00
LICENSE-APACHE initialize repository 2021-07-04 10:36:34 -07:00
LICENSE-MIT initialize repository 2021-07-04 10:36:34 -07:00
README.md glfw: add Vulkan example to README 2021-10-31 01:14:46 -07:00
system_sdk.zig glfw: zig fmt 2021-10-31 01:00:56 -07:00
update-upstream.sh glfw: cleanup vulkan_headers 2021-10-24 05:20:30 -07:00

mach/glfw - Ziggified GLFW bindings CI Hexops logo

Ziggified GLFW bindings that Mach engine uses, with 100% API coverage, zero-fuss installation, cross compilation, and more.

The main Mach repository includes this one as a git subtree. This is a separate repo so that anyone can use this library in their own project / engine if they like!

Zero fuss installation, cross compilation, and more

Just as with Mach, you get zero fuss installation & cross compilation using these GLFW bindings. only zig and git are needed to build from any OS and produce binaries for every OS. No system dependencies at all.

100% API coverage, 130+ tests, etc.

These bindings have 100% API coverage of GLFW v3.3.4. Every function, type, constant, etc. has been wrapped in a ziggified API.

There are 130+ tests, and CI tests on all major platforms as well as cross-compilation between platforms:

platform support table

What does a ziggified GLFW API offer?

Why create a ziggified GLFW wrapper, instead of just using @cImport and interfacing with GLFW directly? You get:

  • Errors as zig errors instead of via a callback function.
  • true and false instead of c.GLFW_TRUE and c.GLFW_FALSE constants.
  • Generics, so you can just use window.hint instead of glfwWindowHint, glfwWindowHintString, etc.
  • Enums, always know what value a GLFW function can accept as everything is strictly typed. And use the nice Zig syntax to access enums, like window.getKey(.escape) instead of c.glfwGetKey(window, c.GLFW_KEY_ESCAPE)
  • Slices instead of C pointers and lengths.
  • packed structs represent bit masks, so you can use if (joystick.down and joystick.right) instead of if (joystick & c.GLFW_HAT_DOWN and joystick & c.GLFW_HAT_RIGHT), etc.
  • Methods, e.g. my_window.hint(...) instead of glfwWindowHint(my_window, ...)

How do I use OpenGL, Vulkan, WebGPU, etc. with this?

You'll need to bring your own library for this. Some are:

Examples

A minimal Vulkan example can be found in the mach-glfw-vulkan-example repository:

image

Getting started

In a libs subdirectory of the root of your project:

git clone https://github.com/hexops/mach-glfw

Then in your build.zig add:

const glfw = @import("libs/mach-glfw/build.zig");

pub fn build(b: *Builder) void {
    ...
    exe.addPackagePath("glfw", "libs/mach-glfw/src/main.zig");
    glfw.link(b, exe, .{});
}

Now in your code you may import and use GLFW:

const glfw = @import("glfw");

pub fn main() !void {
    try glfw.init();
    defer glfw.terminate();

    // Create our window
    const window = try glfw.Window.create(640, 480, "Hello, mach-glfw!", null, null);
    defer window.destroy();

    // Wait for the user to close the window.
    while (!window.shouldClose()) {
        glfw.pollEvents();
    }
}

A warning about error handling

Unless the action you're performing is truly critical to your application continuing further, you should avoid using try.

This is because GLFW unfortunately must return errors for a large portion of its functionality on some platforms, but especially for Wayland - so ideally your application is resiliant to such errors and merely e.g. logs failures that are not critical.

Instead of try window.getPos() for example, you may use:

const pos = window.getPos() catch |err| {
    std.log.err("failed to get window position: error={}\n", err);
    return;
}

Here is a rough list of functionality Wayland does not support:

  • Window.setIcon
  • Window.setPos, Window.getPos
  • Window.iconify, Window.focus
  • Monitor.setGamma
  • Monitor.getGammaRamp, Monitor.setGammaRamp

Issues

Issues are tracked in the main Mach repository.

Contributing

Contributions are very welcome. If possible, please send pull requests to the main repository and once merged the change will get sync'd here.

We track the latest stable release of GLFW, if you need a newer version we can start a development branch / figure that out - just open an issue.