c++glfwmetalmetalkit

How to use metal-cpp with GLFW?


I'm trying to use the official metal-cpp headers to make an entirely C++ metal app using GLFW. I don't want to write any objective-c if possible.

#define GLFW_EXPOSE_NATIVE_COCOA
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>

#include <Metal/Metal.hpp>
#include <MetalKit/MetalKit.hpp>
#include <QuartzCore/QuartzCore.hpp>

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);

    GLFWwindow* window = glfwCreateWindow( 1280, 720, "Hello World", nullptr, nullptr);

    auto nswindow = glfwGetCocoaWindow(window);

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window)) {
        /* Render here */

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

I don't know if this is even possible, but my specific hurdle right now is converting the objective-c NSWindow returned from glfwGetCocoaWindow to an NS::Window C++ object.


Solution

  • You can't get rid of Objective-C(++) completely when using GLFW.

    You need a *.h/*.m(m) combination that adds a Metal Layer to the NSWindow.

    #ifndef COCOA_BRIDGE
    #define COCOA_BRIDGE
    #include <metal/metal.hpp>
    struct GLFWwindow;
    
    namespace CA {
        class MetalLayer;
    }
    namespace X {
    
        void add_layer_to_window(GLFWwindow* window, CA::MetalLayer* layer);
    }
    #endif
    
    #import "cocoa_bridge.h"
    #include <GLFW/glfw3.h>
    #define GLFW_EXPOSE_NATIVE_COCOA
    #include <GLFW/glfw3native.h>
    #import <QuartzCore/CAMetalLayer.h>
    namespace X{
    
        void add_layer_to_window(GLFWwindow* window, CA::MetalLayer* layer) {
            NSWindow* cocoa_window = glfwGetCocoaWindow(window);
            CAMetalLayer* native_layer = (__bridge CAMetalLayer*)layer;
            [[cocoa_window contentView] setLayer:native_layer];
            [native_layer setMaximumDrawableCount:2];
            [[cocoa_window contentView] setWantsLayer:YES];
            [[cocoa_window contentView] setNeedsLayout:YES];
        }
    }
    
    auto* window = (GLFWwindow*)get_window();
    layer = NS::TransferPtr(CA::MetalLayer::layer());
    layer->setDevice(device.get());
    layer->setFramebufferOnly(true);
    layer->setPixelFormat(MTL::PixelFormat::PixelFormatBGRA8Unorm_sRGB);
    add_layer_to_window(window, layer.get());
    

    the whole rendering happens then via the layer.