如何正确设置和检索回调函数的 glfw WindowUserPointer

发布于 2025-01-16 05:22:40 字数 4338 浏览 4 评论 0原文

考虑一个简单的MouseInputHandler,它用作InputHandler 类的成员。 MouseInputHandlerInputHandler 都有一个成员 InputConfig* conf 来访问灵敏度和鼠标速度等内容。

这似乎工作正常,直到我引入了滚动回调功能,该功能在 MouseInputHandler 的构造函数中初始化。我使用MouseInputHandler的成员函数scrollXCallback作为scrollback函数。为此,我需要使用 glfwSetWindowUserPointer 设置 glfwWindowUserPointer 并将其设置为 MouseInputHandler 的实例。另外,我需要定义一个函数“func”来获取窗口用户指针并调用实际的回调函数。

我遇到的问题是,当调用滚动回调时,程序崩溃。

我发现在成员回滚函数中访问的 InputConf *conf 的内存地址与我从 rotate 访问 *conf 时的内存地址不同> 会员功能。

我想这与我在非成员回调“func”中使用的 static_cast 有关,但我不知道如何解决这个问题。有人可以准确解释这里发生了什么吗?

mouse.hpp
#ifndef A_MOUSEINPUT_HPP
#define A_MOUSEINPUT_HPP

#include "InputConfig.hpp"
#include "camera.hpp"

#include <glfw/glfw3.h>

struct InputConfig
{
    float speed = 0.05f;
    float defaultSpeed = 0.05f;
    float fastSpeed = 0.2f;
    float sensitivity = 150.0f;

    bool invertX = true;
    bool invertY = false;
};


class MouseInputHandler 
{
private:
    GLFWwindow *window;
    Camera *camera;
    InputConfig *conf;

    bool firstClick = true;

    // mouse state
    Vector<double, 2> lastMousePos;
    Vector<double, 2> mousePos;
    Vector<double, 3> rotationCenter;

public:
    MouseInputHandler(GLFWwindow *window, Camera *camera, InputConfig *conf):
        window(window), camera(camera), conf(conf)
    {
        // scroll callback
        // -----------
        glfwSetWindowUserPointer(window, this);

        auto func = [](GLFWwindow* w, double, double yOffset)
        {
            static_cast<MouseInputHandler*>(glfwGetWindowUserPointer(w))->scrollX_callback(yOffset);
        };
        glfwSetScrollCallback(window, func);
    }


    void scrollX_callback(double yoffset)
    {
        float fac = conf->sensitivity; // <<<<<<<<< THIS FAILS, conf has different address here than in rotate()???
        camera->zoom(fac/10.0*yoffset);
    }

    void operator()()
    {
        updateMousePos();

        // Handles mouse inputs
        if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) 
        { 
            rotate(); 
        }

        if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) 
        { 
            pan(); 
        }

        if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE && glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_RELEASE) 
        {
            firstClick = true;
        }
    }

private:
    void updateMousePos()
    {
        // Stores the coordinates of the cursor
        double mouseX, mouseY;

        // Fetches the coordinates of the cursor
        glfwGetCursorPos(window, &mouseX, &mouseY);

        // prevent jumping view on first click
        if(firstClick) 
        {
            mousePos = Vector<double, 2>(mouseX, mouseY);
            firstClick = false;
        }
        lastMousePos = mousePos;
        mousePos = Vector<double, 2>(mouseX, mouseY);
    }

    void rotate()
    {
        std::cout << conf << std::endl;
        camera->rotateX( - conf->sensitivity * dy());
        camera->rotateY( - conf->sensitivity * dx());
    }

    void pan()
    {
        camera->moveX(-conf->sensitivity/10.0*dx()); 
        camera->moveY(conf->sensitivity/10.0*dy());
    }

    float dx()
    {
        return (mousePos.x() - lastMousePos.x())/lastMousePos.x(); 
    }

    float dy()
    {
        return (mousePos.y() - lastMousePos.y())/lastMousePos.y(); 
    }

};

class InputHandler
{
private:
    GLFWwindow *window;
    InputConfig *conf;
    MouseInputHandler mouse;

public:
    InputHandler(GLFWwindow *window, Camera *camera):
        window(window), conf(new InputConfig), mouse(window, camera, conf)
    {
        std::cout << conf << std::endl; 
    }

    ~InputHandler()
    {
        delete conf;
        conf = nullptr;
    }

    GLFWwindow *getWindow()
    {
        return window;
    }

    InputConfig *getConfig()
    {
        return conf;
    }

    // call instance to handle events
    void operator()(bool doMouse, bool doKey)
    {
        if(doMouse) mouse();
    }

};

#endif

Consider a simple MouseInputHandler which is used as a member of a InputHandler class. Both, the MouseInputHandler and the InputHandler have a member InputConfig* conf to access stuff like sensitivity and mouse speed.

This seems to work fine until i introduced the scroll callback functionality, which is initialized in the constructor of MouseInputHandler. I use the member function scrollXCallback of MouseInputHandler as scrollback function. To do this i needed to set the glfwWindowUserPointer with glfwSetWindowUserPointer and set it to the instance of MouseInputHandler. Additionally i needed to define a function ´func´ the gets the window user pointer and calls the actual callback function.

The problem that i am experiencing is that when the scroll callback is called the program crashes.

I found out that the InputConf *conf that is accessed in the member scrollback function has a different memory adress than when i access *conf from the rotate member function.

i guess it has to do with the static_cast i use in the non member callback ´func´ but i do not know how to solve this. Can somebody explain what is happening here exactly?

mouse.hpp
#ifndef A_MOUSEINPUT_HPP
#define A_MOUSEINPUT_HPP

#include "InputConfig.hpp"
#include "camera.hpp"

#include <glfw/glfw3.h>

struct InputConfig
{
    float speed = 0.05f;
    float defaultSpeed = 0.05f;
    float fastSpeed = 0.2f;
    float sensitivity = 150.0f;

    bool invertX = true;
    bool invertY = false;
};


class MouseInputHandler 
{
private:
    GLFWwindow *window;
    Camera *camera;
    InputConfig *conf;

    bool firstClick = true;

    // mouse state
    Vector<double, 2> lastMousePos;
    Vector<double, 2> mousePos;
    Vector<double, 3> rotationCenter;

public:
    MouseInputHandler(GLFWwindow *window, Camera *camera, InputConfig *conf):
        window(window), camera(camera), conf(conf)
    {
        // scroll callback
        // -----------
        glfwSetWindowUserPointer(window, this);

        auto func = [](GLFWwindow* w, double, double yOffset)
        {
            static_cast<MouseInputHandler*>(glfwGetWindowUserPointer(w))->scrollX_callback(yOffset);
        };
        glfwSetScrollCallback(window, func);
    }


    void scrollX_callback(double yoffset)
    {
        float fac = conf->sensitivity; // <<<<<<<<< THIS FAILS, conf has different address here than in rotate()???
        camera->zoom(fac/10.0*yoffset);
    }

    void operator()()
    {
        updateMousePos();

        // Handles mouse inputs
        if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) 
        { 
            rotate(); 
        }

        if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) 
        { 
            pan(); 
        }

        if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE && glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_RELEASE) 
        {
            firstClick = true;
        }
    }

private:
    void updateMousePos()
    {
        // Stores the coordinates of the cursor
        double mouseX, mouseY;

        // Fetches the coordinates of the cursor
        glfwGetCursorPos(window, &mouseX, &mouseY);

        // prevent jumping view on first click
        if(firstClick) 
        {
            mousePos = Vector<double, 2>(mouseX, mouseY);
            firstClick = false;
        }
        lastMousePos = mousePos;
        mousePos = Vector<double, 2>(mouseX, mouseY);
    }

    void rotate()
    {
        std::cout << conf << std::endl;
        camera->rotateX( - conf->sensitivity * dy());
        camera->rotateY( - conf->sensitivity * dx());
    }

    void pan()
    {
        camera->moveX(-conf->sensitivity/10.0*dx()); 
        camera->moveY(conf->sensitivity/10.0*dy());
    }

    float dx()
    {
        return (mousePos.x() - lastMousePos.x())/lastMousePos.x(); 
    }

    float dy()
    {
        return (mousePos.y() - lastMousePos.y())/lastMousePos.y(); 
    }

};

class InputHandler
{
private:
    GLFWwindow *window;
    InputConfig *conf;
    MouseInputHandler mouse;

public:
    InputHandler(GLFWwindow *window, Camera *camera):
        window(window), conf(new InputConfig), mouse(window, camera, conf)
    {
        std::cout << conf << std::endl; 
    }

    ~InputHandler()
    {
        delete conf;
        conf = nullptr;
    }

    GLFWwindow *getWindow()
    {
        return window;
    }

    InputConfig *getConfig()
    {
        return conf;
    }

    // call instance to handle events
    void operator()(bool doMouse, bool doKey)
    {
        if(doMouse) mouse();
    }

};

#endif

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文