GLFW and OpenGL in Zig on Windows

Jun 27, 2020

I ran into some issues getting a sample OpenGL application with GLFW working with Zig on Windows, so I figured I’d write a short post outlining what’s needed to get it working.

Build GLFW

Download GLFW and build it from source. The pre-built windows static libraries available for download are compiled with a flag that is incompatible with the way Zig builds libraries. I discovered this by opening an issue on the Zig repo.

After you’ve cloned the source from https://github.com/glfw/glfw, build it using CMake. If you don’t know how to do that using Visual Studio, here’s what I did:

  1. Open a Visual Studio developer tools terminal
  2. cd to the directory where you cloned glfw
  3. mkdir build && cd build
  4. cmake .. -DUSE_MSVC_RUNTIME_LIBRARY_DLL=OFF
  5. Open the generated GLFW.sln in Visual Studio and build it. I set the Configuration to Release. The static library glfw3.lib was generated at build/src/Release/glfw3.lib.

Build Zig using GLFW

In your build.zig, add the GLFW includes and lib folder:

exe.addIncludeDir("/path/to/glfw/include");
exe.addLibPath("/path/to/glfw/build/src/Release");

Link against the following system libraries:

exe.linkSystemLibrary("glfw3");
exe.linkSystemLibrary("c");
exe.linkSystemLibrary("user32");
exe.linkSystemLibrary("gdi32");
exe.linkSystemLibrary("shell32");

After all these steps, linking should succeed. Here’s a complete trivial sample that also includes the OpenGL lib:

build.zig

const Builder = @import("std").build.Builder;
const builtin = @import("builtin");

pub fn build(b: *Builder) void {
    const mode = b.standardReleaseOptions();
    const exe = b.addExecutable("main", "src/main.zig");
    exe.setBuildMode(mode);

    exe.addIncludeDir("/path/to/glfw/include");
    exe.addLibPath("/path/to/glfw/build/src/Release");

    exe.linkSystemLibrary("glfw3");
    exe.linkSystemLibrary("c");
    exe.linkSystemLibrary("opengl32");
    exe.linkSystemLibrary("user32");
    exe.linkSystemLibrary("gdi32");
    exe.linkSystemLibrary("shell32");

    exe.install();

    const run_cmd = exe.run();
    run_cmd.step.dependOn(b.getInstallStep());

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}

main.zig

const c = @cImport({
    @cInclude("GLFW/glfw3.h");
});

const std = @import("std");
const warn = std.debug.warn;
const panic = std.debug.panic;

var window: *c.GLFWwindow = undefined;

export fn errorCallback(err: c_int, description: [*c]const u8) void {
    panic("Error: {}\n", .{description});
}

pub fn main() u8 {
    _ = c.glfwSetErrorCallback(errorCallback);

    if (c.glfwInit() == c.GL_FALSE) {
        warn("Failed to initialize GLFW\n", .{});
        return 1;
    }

    return 0;
}

Adding Custom Properties With Godot Rust

Jun 21, 2020

I ran into a bit of trouble getting a custom property defined in a godot-rust project to show up in the Godot editor. It finally turned out that my difficulties were unrelated to Godot or godot-rust and actually a library misconfiguration error (I renamed my library’s name in Cargo.toml and forgot to fix the .gdnlib) but in the process I discovered that godot-rust’s documentation is rather lacking when it comes to the actual glue layer that ties Godot and the rust bindings together. So, here’s how you add a basic property:

  1. Tag the variable with a property macro:
    #[property(path = "camera/speed", default = 5.0)]
    translation_speed: f32

The path of the property will dictate how it appears in the inspector. If you specify a path of base, the property will appear as-is under Script Variables. If you specify a different path, the variable will appear under a group with that name. Properties with a common path will appear under the same group.

  1. The tagged property will show up in the Inspector for the scene object to which your script is attached.

Here’s what the code looks like:

use gdnative::*;

#[derive(NativeClass)]
#[inherit(ClippedCamera)]
#[user_data(user_data::MutexData<CameraController>)]
pub struct CameraController {
    #[property(path = "camera/speed", default = 5.0)]
    translation_speed: f32
}

#[methods]
impl CameraController {
    fn _init(_owner: ClippedCamera) -> Self {
        CameraController {
            translation_speed: 5.0,
        }
    }

    #[export]
    fn _ready(&self, _owner: ClippedCamera) {
         godot_print!("Translation speed is {}", self.translation_speed);
    }
}

And here’s what the root scene object looks like:

[gd_scene load_steps=4 format=2]

[ext_resource path="res://MainCamera.tscn" type="PackedScene" id=1]

[node name="Root" type="Spatial"]

[node name="MainCamera" parent="." instance=ExtResource( 1 )]
camera/move_speed = 6.0

Abandoning Swift Bindings for Godot

Jun 20, 2020

After putting about two weeks of effort into creating Swift bindings for the Godot engine, I’ve decided to abandon the idea. Here’s what I got working:

  • Use api.json to generate Swifty wrappers around Godot’s classes
  • Register custom classes that extend a Godot class (godot-cpp does this) or have a Godot instance as an attachment (godot-rust does this)
  • Register methods associated with these custom classes
  • Callbacks and virtual functions work (_ready, _process etc.)
  • Singletons work (Engine, Input etc.)

However, Swift’s support for metaprogramming is terrible. Reflection is poorly supported (properties only) and there’s no support for macros or anything else that lets you create a metaprogram. Generics are severely crippled (cannot store constrained generics inside variables, cannot use Unmanaged with protocols), closures are extremely restrictive (same problem with constrained generics). All of this to say that there is no way to create convenient wrappers that would let users of my bindings register their own classes and methods without mucking about with Godot’s native API to specify their own constructors, destructors and methods to write to and read from user_data.

I wish Jonathan Blow would go ahead and release Jai into open beta, but in the meantime I plan to give godot-rust a shot.

Swift Build Generates Unexpected File

Jun 5, 2020

Yesterday, I started playing around with Swift 5.2 on Linux (Ubuntu 20.04). This is mostly motivated by my desire to see if I can create a Swift module for the Godot engine. I started - as you’re supposed to - by using the Swift Package Manager to create a new package. The final form of this package is supposed to be a dynamic shared library, one that will be loaded by the game engine. However, in the interest of faster iteration, I created the package as an application rather than a library for initial testing. Once I was satisfied with the initial testing, I changed the product from .application to .library, added a type: .dynamic and expected that would suffice.

However, running swift build continued to produce a binary instead of producing a dynamic library (.dynlib, .dll or .so). The desired .so file was missing. I tried debugging it by creating a brand new package structured as a library from the get-go, and swift build correctly produced a .so file for that. The Package.swift files for both packages were virtually identical. After an hour or so, I discovered that the main difference was the name of the swift source file in the packages. In the package I’d created first - the one that started as an application and then turned into a library - the source file was named main.swift. In the second package - the one that was a library from the outset - the source file was named MyPackage.swift.

I renamed the file in the first package from main.swift to MyPackage.swift, and swift build magically started producing a MyPackage.so shared library.

Outside Looking In

Jan 3, 2020

For about half of my life, I’ve felt like an outsider looking in. As far as I can tell, this started back in middle school when my parents moved me from one school to another. In my previous school I’d been the popular kid and a teachers’ pet, so I naively took all that bluster and confidence with me to the new school. This ultimately culminated in a dressing-down by the class teacher with my classmates taking turns complaining about me. Rather unpleasant as far as experiences go, and the stain of shame stuck with me all the way to graduation.

Going to college helped me fit in with my peers, but the feeling of being an outsider returned after I graduated from college and joined the workforce. I was the youngest kid in the company I was working at, and working with middle-aged parents wasn’t exactly the most fun experience ever. In high school I’d felt inferior to my classmates, here I felt superior to my colleagues who had no hobbies or interests. In both cases, I didn’t see myself fitting in and subsequently felt misunderstood and alone. Part of this was a cultural clash - the path most self-respecting Indians followed in life was:

  1. Get pushed out a vagina
  2. Go to school and study
  3. Go to college and study
  4. Get a job
  5. Marry the person your parents picked for you and pop out a few kids
  6. Sacrifice the rest of your life so your kids can follow this algorithm

Unfortunately, I grew up reading books written by western authors about life in the west. While my peers were watching the sappy trash that Bollywood puts out at a regular cadence, I grew up with movies like The Pursuit of Happyness and Serendipity. As a result, I wanted a life where I could pursue my dreams. I wanted to find someone and fall madly in love rather than have a business-like marriage. Did I feel superior to everyone else around me? Yes, most definitely, and I’m not proud of it. But a part of me also envied the people around me. I sort of felt like Cipher from the Matrix. Having taken the red pill, wide awake to the reality around me and wishing like hell that I could go back to sleep and languish in ignorance.

The feeling of being an outsider came back stronger than ever when I moved to the states. I expected the opposite to happen - after all, this was the life I’d been pining for all along. It should’ve felt like I’d finally reached my destination. But all of my insecurities came crawling out of the woodwork - insecurity about my heavy Indian accent, my early baldness, even the color of my skin. I looked for help online, found some recommendations to work out and started lifting. Losing fat and gaining muscles turned out to be exactly what I needed - I shed some of my body image issues and became a tad more confident in public. Graduating and joining Amazon in Seattle helped out more - I was lucky enough to get into a team of friendly engineers who welcomed me warmly and helped me feel at home. Talking to a therapist helped me identify some of the negative self-talk I’d been indulging in and set me on a path of constantly expanding my comfort zone. Life became exciting again, and I felt like I finally belonged; not because my environment had changed, but because I had. I felt secure in my identity, and no longer felt the need to change myself to appease others.

Which brings us to the here and now, dear reader. A few weeks ago I had the privilege of being dumped rather abruptly and unceremoniously by someone I’m crazy about. She didn’t have a strong reason for breaking up with me, just that she didn’t feel “that spark”. And the lack of a strong reason for being dumped simply left me agonizing over everything I said and did, wondering which combination of actions led to the breakup - a downward spiral I was stuck in until a friend assured me that it wasn’t anything I’d done. An unexpected side-effect of being dumped in this fashion - by someone I did feel “that spark” for - is that the feeling of being an outsider has reared its ugly head once more. Looking back at the last paragraph, I suspect this is because I’d been thinking about what I could’ve done differently to prevent being dumped, and this feeling of “I’m not good enough” is somehow tied to the feeling of not belonging. The onset was rather unexpected and sudden (similar to the break-up I guess, which was also unexpected and sudden): one moment I was at a pub devouring a po’boy and chatting with a friend, the next I was looking around at a sea of perfectly happy faces - with perfect teeth, clear, white skin, brown hair and blue/green eyes - and feeling like something the cat had dragged in. The feeling was so palpable that part of me wanted to just get up and bolt from that place. Thankfully, calmer heads prevailed and the urge passed soon enough.

One of the last things my therapist said to me (she had a baby and decided to take a break from work) is “you deserve to be loved, same as everyone else”. It wasn’t the first time she’d said something to that effect, but it didn’t really resonate with me. What does that even mean? You “deserve” something if you’ve earned it in some way. One can deserve love in a particular relationship, I don’t think it’s possible to generically deserve love in a non-specific manner. Maybe it’s just a matter of semantics though; if she’d told me that I’m lovable, I probably would’ve burst into tears. Because I think that’s one of my major hang-ups: at particularly low points in life (like this one I guess) I believe that I am inherently unlovable.