glfw input callback to modify an object with a member function - c++

As you know, glfw works with callbacks for inputs and callback functions have certain signatures that users need to match. Here is an example from the documentation:
void key_callback(GLFWwindow* window, int key, int scancode, int action, int
mods)
{
if (key == GLFW_KEY_E && action == GLFW_PRESS)
activate_airship();
}
Now, activate airship seems to be a global function here. What I really want to do is, to modify some object, possibly, at each input stage. So I want something like:
void key_callback(Airship a, GLFWwindow* window, int key, int scancode, int
action, int mods)
{
if (key == GLFW_KEY_W && action == GLFW_PRESS)
a.render_Wireframe();
}
As you can see, I want to pass the object I am trying to modify, Airship here. But this time, callback signature is distrupted. I can't use it anymore. What is the best way to achieve this? I am trying to come up with ideas but in the future, I might want to change this to work with not just airships but a new object I add as well. What should be the design here?
The thing is, with the ability to set one callback for whole program, I don't know how to achieve the following. Let's say I have two objects Airship and Battlesip. I want both of them to have their own input handling mechanism. Pressing W should do something if Airship is the picked object in the scene and something else if Battleship is the picked object.
So I want to have something like following in the end;
class Airship : public SceneObject
{
...
void input_handle(){
if(is_picked && pressed == GLFW_KEY_W)
launch_missile();
}
}
class Battleship : public SceneObject
{
...
void input_handle(){
if(is_picked && pressed == GLFW_KEY_W)
do_something_else();
}
}
And in my main loop, I have a vector of SceneObject and I call input_handle on each frame, for each object. I don't know how can I handle something like this with a single callback scheme of glfw. I can't pass those things as callback functions to a window even if I matched the signature because they are class members. Well nothing would change if I could pass class members, since I can only set one callback.

Here is how I ended up solving this issue in a simplified manner. I am not sure if this is the correct design but it might be of help to a future viewer. I have a scene graph like object, say SceneGraph that holds all the SceneObjects mentioned in the question. I ended up making this SceneGraph object a singleton. I have one scene graph per run so it seemed logical to me to make it a singleton.
class SceneGraph
{
// ...
// many more code
friend void key_callback(GLFWwindow* window, int key, int scancode,
int action, int mods)
{
// get the singleton instance, singleton is static and this is
// a friend function, so I can register this as a callback
SceneGraph* d = SceneGraph::handle();
d->input_handle();
}
void input_handle()
{
for(auto& s : objs)
s.input_handle()
}
private:
std::vector<SceneObject> objs;
}
Of course, you can pass button state etc. to your input routines. I just wanted show the bare minimum design that I went with. Object picking example that I talked about in the original question can also be handled now.

Related

Using The State Pattern in games

Recently, I've tried to create Snake game in SFML. However, I also wanted to use some design pattern to make some good habits for future programming - it was The State Pattern. But - there is some problem that I am unable to solve.
To make everything clear, I've tried to make several Menus - one main menu, and others, like "Options", or something like this. The first option of the main menu would take the player to the "Playing State". But then, the problem appears - I think the whole game should be an independent module implemented to program. So, what should I do with the actual state which program is in? (for example, let's call this state "MainMenu").
Should I make an additional state called "PlayingState", which would represent the whole game? How would I do it? How is it possible to add new functionality to a single state? Do you have any ideas?
The State Pattern allows you, for example, to have an object of a class Game and alter its behavior when the game state changes providing the illusion that this Game object had changed its type.
As an example, imagine a game that has an initial menu and can be paused while playing if you press the space bar. When the game is paused, you can either go back to the initial menu by pressing the backspace key or continue playing by pressing the space bar again:
First, we define an abstract class, GameState:
struct GameState {
virtual GameState* handleEvent(const sf::Event&) = 0;
virtual void update(sf::Time) = 0;
virtual void render() = 0;
virtual ~GameState() = default;
};
All the state classes – i.e., MenuState, PlayingState, PausedState – will publicly derive from this GameState class. Note that handleEvent() returns a GameState *; this is for providing the transitions between the states (i.e., the next state, if a transition occurs).
Let's focus for the moment on the Game class instead. Eventually, our intention is to use the Game class as in the following way:
auto main() -> int {
Game game;
game.run();
}
That is, it has basically a run() member function that returns when the game is over. We define the Game class:
class Game {
public:
Game();
void run();
private:
sf::RenderWindow window_;
MenuState menuState_;
PausedState pausedState_;
PlayingState playingState_;
GameState *currentState_; // <-- delegate to the object pointed
};
The key point here is the currentState_ data member. At all times, currentState_ points to one of the three possible states for the game (i.e., menuState_, pausedState_, playingState_).
The run() member function relies on delegation; it delegates to the object pointed by currentState_:
void Game::run() {
sf::Clock clock;
while (window_.isOpen()) {
// handle user-input
sf::Event event;
while (window_.pollEvent(event)) {
GameState* nextState = currentState_->handleEvent(event);
if (nextState) // must change state?
currentState_ = nextState;
}
// update game world
auto deltaTime = clock.restart();
currentState_->update(deltaTime);
currentState_->render();
}
}
Game::run() calls the GameState::handleEvent(), GameState::update() and GameState::render() member functions that every concrete class that derives from GameState must override. That is, Game does not implement the logic for handling the events, updating the game state and rendering; it just delegates these responsabilities to the GameState object pointed by its data member currentState_. The illusion that Game appears to change its type when its internal state is altered is achieved through this delegation.
Now, back to the concrete states. We define the PausedState class:
class PausedState: public GameState {
public:
PausedState(MenuState& menuState, PlayingState& playingState):
menuState_(menuState), playingState_(playingState) {}
GameState* handleEvent(const sf::Event&) override;
void update(sf::Time) override;
void render() override;
private:
MenuState& menuState_;
PlayingState& playingState_;
};
PlayingState::handleEvent() must at some time return the next state to transition into, and this will correspond to either Game::menuState_ or Game::playingState_. Therefore, this implementation contains references to both MenuState and PlayingState objects; they will be set to point to Game::menuState_ and Game::playingState_ data members at PlayState's construction. Also, when the game is paused, we ideally want to render the screen corresponding to the playing state as the starting point, as we will see below.
The implementation of PauseState::update() consists of doing nothing, the game world simply remains the same:
void PausedState::update(sf::Time) { /* do nothing */ }
PausedState::handleEvent() only reacts to the events of either pressing the space bar or the backspace:
GameState* PausedState::handleEvent(const sf::Event& event) {
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::Space)
return &playingState_; // change to playing state
if (event.key.code == sf::Keyboard::Backspace) {
playingState_.reset(); // clear the play state
return &menuState_; // change to menu state
}
}
// remain in the current state
return nullptr; // no transition
}
PlayingState::reset() is for clearing the PlayingState to its initial state after construction as we go back to the initial menu before we start to play.
Finally, we define PausedState::render():
void PausedState::render() {
// render the PlayingState screen
playingState_.render();
// render a whole window rectangle
// ...
// write the text "Paused"
// ...
}
First, this member function renders the screen corresponding to the playing state. Then, on top of this rendered screen of the playing state, it renders a rectangle with a transparent background that fits the whole window; this way, we darken the screen. On top of this rendered rectangle, it can render something like the "Pause" text.
A stack of states
Another architecture consists of a stack of states: states stack up on top of other states. For example, the pause state will live on top of the playing state. Events are delivered from the topmost state to the bottommost, and so are states updated as well. The rendering is performed from the bottom to the top.
This variation can be considered a generalization of the case exposed above as you can always have – as a particular case – a stack that consists of just a single state object, and this case would correspond to the ordinary State Pattern.
If you are interested in learning more about this other architecture, I would recommend reading the fifth chapter of the book SFML Game Development.
For you design, i think you can use incremented loop for the different state:
Simple example:
// main loop
while (window.isOpen()) {
// I tink you can simplify this "if tree"
if (state == "MainMenu")
state = run_main_menu(/* args */);
else if (state == "Play")
state = run_game(/* args */);
// Other state here
else
// error state unknow
// exit the app
}
And when the game is running:
state run_game(/* args */)
{
// loading texture, sprite,...
// or they was passe in args
while (window.isOpen()) {
while (window.pollEvent(event)) {
// checking event for your game
}
// maybe modifying the state
// Display your game
// Going to the end game menu if the player win/loose
if (state == "End")
return run_end_menu(/* args */);
// returning the new state, certainly MainMenu
else if (state != "Play")
return state;
}
}
You have a main menu and the game, your state by default is "MainMenu".
When you enter in your main menu you click the play button, then the state returns "Play" and you go back to the main loop.
The state is "Play" so you go to the game menu and your start your game.
When the game ends, you change your state to "EndGame" and go out of the game menu to the end menu.
The end menu returns the new menu to display, so you go back to the main loop and check every available menu.
With this design you can add a new menu without changing the entire architecture.

Can GLFW lambdas accept capture arguments?

I'm creating a GLFWKeyCallback and because of how simple it is I've decided to use a lambda. This callback modifies a member variable, so I have to pass this into the capture list. Here is what my code looks like so far:
glfwSetKeyCallback(window,
[this](GLFWwindow* window, int key, int scancode, int action, int mods)
{
if(action == GLFW_PRESS)
{
//use a mutex
//Modify member variable
}
});
The problem is that whenever I pass this into the capture list, Visual Studio 2019 displays the following error:
no suitable conversion function from "lambda [] void (GLFWwindow *window, int key, int scancode, int action, int mods)->void" to GLFWKeyfun" exists
Have I missed something or is this code just invalid?
The GLFW callbacks don't take lambdas, or function objects: they take plain old function pointers. A non-capturing lambda can be converted to a function pointer, but not a capturing one.
However, you can get a similar effect by using glfwSetUserPointer and glfwGetUserPointer. The lambda still can't be capturing, but you can recover the this pointer.
For example,
struct MyClass {
GLFWwindow* window;
MyClass(GLFWwindow* window) : window(window) {
glfwSetWindowUserPointer(window, static_cast<void*>(this));
glfwSetKeyCallback(window,
[](GLFWwindow* window, int key, int scancode, int action, int mods) {
auto self = static_cast<MyClass*>(glfwGetWindowUserPointer(window));
// can access member variables through `self`
});
}
// make sure that either the class will last as long as GLFW will
// or clean up the user pointer and callbacks in here
~MyClass() {
// clean up
}
// don't be able to copy, probably, or bad things will happen
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
// other things...
};
Adding onto the other answer.
I see glfwSetWindowUserPointer brought up a lot as a solution to this issue. It works fine (and I use it myself, since I don't know of any other solution), but it comes with a caveat that I haven't seen anyone mention:
You can only store one pointer per Window using this method. If some other code sets a different pointer to your window, all of a sudden your lambda won't work anymore. I can think of two workarounds here:
When you retrieve the pointer in your lambda body, set it to a static variable. This way, it will persist across calls to the lambda, even if someone else sets a different pointer. Note: the static variable won't initialize until the first call to the lambda, so you'd be best to call the lambda once, yourself, after defining it.
Define a object or map of pointers. Give GLFWSetUserPointer a pointer to that map. I can't think of any way to enforce this pattern, but if you have complete control over your app, you can store multiple pointers in associated with a Window this way.

Implementing a "window" system and "no deletion of self" rule

I've been trying to program in C++ a sort of simple "window" system for use in a game, which draws windows that can have buttons, etc. in them in the game area (internal to the game's own graphics, i.e. not the OS's GUI windows). The window objects (call it "class Window" for here) have some methods for events like key press, and the ability to hook on a handler to be called upon receipt of that event.
Windows are (or will be) collected in a "window manager", and the window object will have "close()" member that would call the parent window manager's window-deletion routine to delete itself. An event handler hooked to, say, a button on the window might invoke this routine to close the window (think an "OK" box).
The trouble is this sounds like a "delete *this;" statement, which I've heard is a no-no. True, it doesn't do that directly, but the effect is the same: an object has a member function that brings about its own destruction (e.g. the "close()" function, or the event function that triggers the handler leading to the "close()" function being called.). If this is bad, then what is a better way to design this?
There is nothing wrong with an object deleting itself. You must simply tell the window manager to remove the window from it's collection and then delete. If you have the window manager delete the window object, that's even better.
If you really want to avoid this behavior, you can add a bool dead; to each window that initializes to false. When the window is to be closed, set this->dead = true;. Every frame, have the window manager iterate through it's windows and delete the ones that are dead.
Note that this solution still does not fix errors that arise from external systems that have a reference to the deleted window, but it does have the advantage of centralizing the deletion of windows.
I have designed many games' window systems, and in my experience, allowing windows to delete themselves is a very elegant solution, even if it is more error-prone.
A minimal example:
class Window
{
public:
void keyPressCallback(int c)
{
if (c == KEY_ESC)
{
manager.destroy(this);
return;
}
}
WindowManager& manager;
};
class WindowManager
{
public:
void destroy(Window* target)
{
delete target;
windows.erase(std::find(windows.begin(), windows.end(), target));
}
std::vector<Window*> windows;
};
As long as there are no remaining pointers to that window, this method is perfectly safe and semantically sane. When the window receives a signal to close, it closes itself.
The same example with the dead flag:
class Window
{
public:
Window() : dead(false) {}
void keyPressCallback(int c)
{
if (c == KEY_ESC)
{
dead = true;
return;
}
}
bool dead;
};
class WindowManager
{
public:
void cleanup()
{
for (auto iter = windows.begin(); iter != windows.end(); ++iter)
{
if (iter->dead) windows.erase(iter);
}
}
std::vector<Window*> windows;
};

how to use cv::setMouseCallback

I'm trying to use cv::setMouseCallback in my c++ project. I just don't get it.
let that I habe a class Stuff how can tell this class you got a frame and run the cv::setMouseCallback on this frame here is an example of what I'm trying to do :
class Stuff{
public:
Stuff();
void setFrame(cv::Mat);
void mouse (int,int, int, int,void*);
private :
cv::Mat frame;
int key;
};
Stuff::Stuff(){}
void Stuff::setFrame(cv::Mat framex){
frame = framex;
}
int main (){
Stuff obj;
cv::Mat frame = cv::imread ("examople.jpg");
char* name;
cv::imshow(name,frame);
cv::setMouseCallback(name,obj.mouse,&frame) // I' stop here because that's exactlly what just don't work
}
this the error message that get:
Stuff::mouse : function call missing argument list; use '&Stuff::mouse ' to create a pointer to member
the real program is too big to put its code here that why I'm trying to simplify the question
you must declare a mouse handler as static inside your class. For instance, I have a dragger with a member mouser, that I want to be called. I declare an helper static void mouser, that cast the void* received and calls the member:
class dragger {
void mouser(int event, int x, int y) {
current_img = original_img.clone();
Point P(x, y);
...
}
static void mouser(int event, int x, int y, int, void* this_) {
static_cast<dragger*>(this_)->mouser(event, x, y);
}
and instance in dragger constructor in this way
dragger(string w, Mat m) :
window_id(w), status(0), original_img(m), /*black(0, 0, 0),*/ K(5, 5)
{
...
setMouseCallback(w, mouser, this);
}
...
}
First of all you need to create a named window in the main function. namedWindow( "image", 0 ); or something similar will do the job.
The mouse callback function is not associated to the frame variable but it is associated to the window. In your case it would be:
char* name = "image";
cv::namedWindow( name, 0 );
cv::setMousCallback(name, obj.mouse,&frame);
The callbacks are functions that call other functions when an event happens on a window. For the mouse, an event can be the mouse movement, the left, right or middle clicks. Here you can find a list of them, as well as good explanations.
So when this "event" takes place in the window, opencv calls the function whose name was specified in the setMouseCallback as an argument, in your case Stuff::mouse. if you define the function like this:
Stuff::mouse( int event, int x, int y, int flags, void* params )
when it is called the event variable will be filled with the value of the trigger, the x and y with the positions off the mouse on the image etc.
If you want to pass the frame in the mouse function you use it as in this question, if you consider the correction of patxiska's answer.
So with a switch you can find out what kind of event it was:
switch( event ){
case CV_EVENT_LBUTTONDOWN:
//...
break;
case CV_EVENT_RBUTTONDOWN:
//...
break;
case CV_EVENT_FLAG_CTRLKEY:
//...
break;
}
and take your frame typecasting it from void* back to a cv::Mat.
Here you can find another example of Opencv's site on how to use a mouse callback.
Hope I helped, I haven't used opencv for a while and I don't have my sample source files now. Callbacks are simplified in the Opencv GUI but that's the logic of working with any GUI. Input such as mouse and keyboard trigger events and the callback functions pass the events to the functions of your implementation.

C++, (GLUT) - maintaining a global vector of booleans in the display loop - crashes program

I've got a bit of a tricky problem in my opinion. I'm new to C++ and OpenGL/ glut so be gentle!
I'm writing a platform-independent simple program (only 2D) and need a basic UI, so I have a Button class which generates a Button object. This hopefully will be able to be called dynamically (i think that's the right word) from inside the displayFunc() loop in OpenGL/ glut.
Every time the loop starts, it instantiates the correct button objects and then destroys them at the end. Of course, the buttons need to be able to do something, so in the glutMouseFunc function, it checks if the mouse clicked in the place needed to set off the button.
It is allowed access to the button member variables (xMin.. yMax) via get/set functions, which are public. However since the button is instantiated by the display loop, I had to create a global vector of pointers to the buttons which is updated as they are created, and cleaned up, along with the objects, at the end of the display loop. This is all fine and dandy I believe.
The tricky thing comes when I actually want a button to change state. The only thing I can come up with is having std::vector<bool> buttonStates;, which is augmented when the button is created, changed when the button is clicked, and destroyed when the button is.
Of course, this change of state doesn't carry through to the next loop of display, so I tried std::vector<bool> btnStatesCopy;, which maintains a copy of the buttonStates vector by using btnStatesCopy = buttonStates;when it changes, but is not destroyed at the end of the display loop. When the buttons are created, the button states now are copied from the btnStatesCopy vector, which has not changed since the last loop.
Unfortunately, this crashes my program, even when trying to print the btnStatesCopy vector. So I was wondering if you had any idea why it might crash, and what I might do to avoid it! I can post code, but I'm not sure it would help. Is there a better, more obvious way of doing this stuff that I haven't thought of? I would love to hear any ideas! Thanks a lot,
Patrick
Edit: Here's a concise version of the code if it help (keep in mind, I am really new at this stuff!):
//*in global scope*
// Stores pointers to the ui buttons.
std::vector<Button*> buttons;
// Stores button states, which are copied from buttonStates and
// destroyed every time display() runs.
std::vector<bool> buttonStates;
// Stores a copy of buttonstates which is written to when
// a button is pressed.
std::vector<bool> btnStatesCopy;
// Prototype functions:
void init(void);
void display(void);
void key(unsigned char key, int x, int y);
void processHits(GLint hits, GLuint buffer[]);
void click(int button, int state, int x, int y);
void idle(void);
void resize(int width, int height);
void drawMenu(void);
void circle(float x,float y,float size,int segments);
void initialiseButtons();
// Main loop goes here; calls glutDisplayFunc(display);
void display(void) {
initialiseButtons();
drawMenu();
}
bool changeBinaryState(bool state){
/* Changes 1 to 0 and 0 to 1. */
if (state == 0) state = 1;
else state = 0;
return state;
}
void click(int button, int state, int x, int y) {
/* Called when a mouse button is clicked. */
if (button == GLUT_LEFT_BUTTON && state != GLUT_DOWN) {
std::cout<<x<<", "<<y<<std::endl;
for(int i = 0; i<buttons.size();i++){
//put a pointer of a button in variable but
Button* but = buttons.at(i);
if (x > but->getMinX() && x < but->getMaxX()) {
if (y > but->getMinY() && y < but->getMaxY()){
but->buttonFunc();
changeButtonState(buttonStates.at(i));
buttonStates.at(i) = 1;
btnStatesCopy = buttonStates;
}
}
}
}
}
void drawMenu(void) {
// Create a button and its pointer and add pointer to buttons vector.
Button* p_b = new InfoButton("User Manual",20,spacing+yOffset);
buttons.push_back(p_b);
// Add button state of previous button state.
buttonStates.push_back(btnStatesCopy.back());
// Turn on buttons if their state is on.
for (unsigned i = 0; i<buttonStates.size();i++){
if (buttonStates[i]==1) {
Button* but = buttons.at(i);
but->buttonFunc();
}
}
void initialiseButtons(){
for (unsigned i = 0; i < buttons.size();i++)
{
delete buttons[i];
}
buttons.clear();
buttonStates.clear();
}
The title of your question reads
Blockquote C++, (GLUT) - maintaining a global vector of pointers to booleans in the display loop - crashes program
(emphasis added). If I understand you correctly, that means you have
std::vector<bool*> buttonStates;
std::vector<bool*> btnStatesCopy;
and not std::vector<bool>.
If this is indeed the case, and if the bools which these pointers point to are deleted in the display loop, then they will be deleted in the display loop. You are retaining pointers to freed memory, and this is the most likely reason for a crash.
On the other hand, if this were Java (or any other garbage collected language) as opposed to C++, storing a pointer to an object protects it from being garbage collected.