How can I fix the argument type mismatch between my key-callback function and glfwSetKeyCallback?

61 Views Asked by At

I have created a Camera class containing a keymap of std::map<int, void(Camera::*)() to facilitate an in-game option for key bindings and higher performance key-action lookup than what could be accomplished with switch statements.

I have trouble accessing the action-functions from the keymap with the glfwSetKeyCallback function and I keep running into a signature mismatch between my keyCallback function and GLFWkeyfun.

This is the Camera class:

class Camera {
    Camera();
private:
    void Mouse_Input();
    void Joystick_input();
    void keyCallBack(GLFWwindow* window, int key, int scancode, int action, int mods);

    void forward() {
        position += velocity * Orientation;
    }
    void backward() {
        position -= velocity * Orientation;
    }
    void left() {// Left
        position -= velocity * glm::normalize(glm::cross(Orientation, Up));
    }
    void right() {
        position += velocity * glm::normalize(glm::cross(Orientation, Up));
    }
    void up() {
        position += velocity * Up;
    }
    void down() {
        position -= velocity * Up;
    }
    void sprint() {
        velocity *= 2.f;
    }

    void noclip() {
        noClip = !noClip;
        if (!noClip) {
            gravity(position, velocity);
        }
    }
    void close() {
        glfwSetWindowShouldClose(Window::handle, true);
    }
public:
    alignas(16) glm::mat4 view;
    alignas(16) glm::mat4 proj;
    alignas(16) glm::vec3 position;

    void update(float FOVdeg, float nearPlane, float farPlane);
protected:
    bool noClip = true;
    bool firstClick = true;

    float velocity = 0.05f;
    float sensitivity = 1.75f;
    glm::vec3 Orientation;
    glm::vec3 Up;

    using pfunc = void (Camera::*)();
    std::map<int, pfunc> keyboard_map
    {
        { GLFW_KEY_W, &Camera::forward },
        { GLFW_KEY_A, &Camera::left },
        { GLFW_KEY_S, &Camera::backward },
        { GLFW_KEY_D, &Camera::right },
        { GLFW_KEY_SPACE, &Camera::up },
        { GLFW_KEY_LEFT_CONTROL, &Camera::down },
        { GLFW_KEY_LEFT_SHIFT, &Camera::sprint },
        { GLFW_KEY_V, &Camera::noclip },
        { GLFW_KEY_ESCAPE, &Camera::close }
    };
};

These are the relevant function definitions from my cpp file:

void Camera::keyCallBack(GLFWwindow* window, int key, int scancode, int action, int mods) {
    if (!GLFW_PRESS | !GLFW_REPEAT) {
        return;
    }
    auto afunc = keyboard_map[key];//gets camera action function from map
    (this->*afunc)();//executes action function
}
void Camera::update(float FOVdeg, float nearPlane, float farPlane)
{
    if (glfwJoystickPresent(GLFW_JOYSTICK_1)) {//Check for joystick
        std::jthread t_Console([&] { Joystick_input(); });
    }
    std::jthread t_PC([this] { glfwSetKeyCallback(Window::handle, &Camera::keyCallBack); }); //Line causing the error
    std::jthread t_mouse([&] { Mouse_Input(); });

    if (!noClip) {
        gravity(position, velocity);
    }
    view = glm::lookAt(position, position + Orientation, Up);
    proj = glm::perspective(glm::radians(FOVdeg), (float)GPU::Extent.width / GPU::Extent.height, nearPlane, farPlane);
    proj[1][1] *= -1;
}

I tried this solution which allowed me to compile the program, but the program crashes without producing an error code when calling the line auto afunc = keyboard_map[key]; of the keyCallBack function.

std::jthread t_test([this]()
    {
        glfwSetKeyCallback(Window::handle,
        [](GLFWwindow* window, int key, int scancode, int action, int mods)
            {
                auto* instance = static_cast<Camera*>(glfwGetWindowUserPointer(window));
                if (instance) {
                    instance->keyCallBack(window, key, scancode, action, mods);
                }
            });
    }
);

I am completely lost for a solution to this problem. Could someone help me understand why there is a signature mismatch in my original method, why accessing the map is causing the program to crash with the other method I tried, and how I can get this set up to work as intended?

Edit:

Error 31 C2664 GLFWkeyfun glfwSetKeyCallback(GLFWwindow *,GLFWkeyfun): cannot convert argument 2 from void (__cdecl vk::Camera::* )(GLFWwindow *,int,int,int,int) to GLFWkeyfun

1

There are 1 best solutions below

1
Remy Lebeau On

You are trying to use a non-static class method for your glfwSetKeyCallback() callback. That will not work, as glfwSetKeyCallback() expects a C-style function pointer instead. So, you will have to either:

  • make keyCallBack() be static
  • remove keyCallBack() from the Camera class altogether and make it a standalone function
  • use a non-capturing lambda, as you discovered.

Either way, as you already know, you can use glfwSetWindowUserPointer() to store a Camera* pointer into the GLWindow, and then use glfwGetWindowUserPointer() inside your callback to get back to your Camera object. However, the code you have shown is not calling glfwSetWindowUserPointer() anywhere.