0
votes

I have looked around and read a lot about static functions and variables, I have understood that one can not simply call a non-static variable/function in an static function and so on, so my question is how can I solve this problem I'm having with GLFW key_callback.

In GLFW we have this:

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    glfwSetWindowShouldClose(window, GL_TRUE);
}

and we add this like other window related calls:

glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, window_key_callback);

But now I want to be able to call another class function if 'space' key is pressed in the key_callback like this:

in .h file I have

#include "A.h"

...

private: 
        A *anotherClass;

and in .cpp file I have in the constructor

anotherClass = new A();

and the rest

 static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
  if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
    antoherClass->draw();
}

and this anotherClass is not static, I just want to start drawing if space is pressed.

Can someone help me with this?

3

3 Answers

2
votes

You need to make antherClass a global variable, there is no other way around this. Usually a callback function should take a user provided data pointer to allow passing outside information in, it appears there is an API deficiency here.

Edit: Turn out you can use glfwSetWindowUserPointer and glfwGetWindowUserPointer to do this.

1
votes

As yngum pointed, you can use glfwSetWindowUserPointer and glfwGetWindowUserPointer to have access the the void * pointer of your choice.

Here is a simple example for those that pass around like me:

int main(void)
{
    t_MyDatas     datas;
    GLFWwindow    *window = glfwCreateWindow(640, 480, "My Title", NULL, NULL);
    //[...]
    glfwSetWindowUserPointer(window, (void *)&datas);
    glfwSetKeyCallback(window, &KeyCallback);
}

void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    t_MyDatas *datas;
    datas = (t_MyDatas *)glfwGetWindowUserPointer(window);
    //[...]
}

The important point to remember is the cast from (void *) then the cast back to the original structure.

0
votes

I would create a class with your (non-static) keyCallback method interactivity, then create an instance of your application class and call the keycallback method on the application instance inside of another, static, keycallback function that then get passed to glfwSetKeyCallback. Here is an template that I frequently build upon when starting new projects that utilizes this:

#include <iostream>
#include <string>
#include <GLFW/glfw3.h>

// obviously create headers with declarations seperate from definitions
// when spanning across multiple files, but for sake of brevity they
// have not been used.

// application.cpp
class Application {
public:
    GLFWwindow *window;

    Application(std::string title) {

      // boilerplate stuff (ie. basic window setup, initialize OpenGL) occurs in abstract class
      glfwInit();
      window = glfwCreateWindow(640, 480, title.c_str(), NULL, NULL);
      glfwMakeContextCurrent(window);

    }
    void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
      // basic window handling
      if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
      {
        std::cout << "exiting..." << std::endl;
        glfwSetWindowShouldClose(window, GL_TRUE);
      }
    }
    // must be overridden in derived class
    virtual void update() = 0;

    void gameLoop() {
      while (!glfwWindowShouldClose(window)) {
        //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // update function gets called here
        update();

        glfwPollEvents();
        glfwSwapBuffers(window);
      }
      glfwTerminate();
    }
};

// myapp.cpp
class MyApp : public Application {
public:
    MyApp(std::string title) : Application(title) {
      // my application specific state gets initialized here
    }
    void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
        Application::keyCallback(window, key, scancode, action, mods);
        if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) {
            // anotherClass.Draw();
            std::cout << "space pressed!" << std::endl;
        }
    }

    void update() override {
      // player.Update();
      // anotherClass.Draw();
    }
};

 Application* getApplication() {
     return new MyApp("MyApp");
 }

// main.cpp
// extern Application* getApplication();
Application *app;

static void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) {
    MyApp* myApp = (MyApp*)app;
    myApp->keyCallback(window, key, scancode, action, mods);
}

int main() {
    app = getApplication();
    glfwSetKeyCallback(app->window, keyCallback);
    app->gameLoop();
}