Can GLFW lambdas accept capture arguments? - c++

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.

Related

glfw input callback to modify an object with a member function

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.

Access Violation Error when accessing D object from D-to-C callback

I've recently begun to dip my toes into DerelictGLFW. I have two classes, one of them a Window class, and another an InputHandler class (a event manager for window events). In my cursor position callback, I take the window user pointer and try to set the position, but I get an Access Violation Error immediately upon attempting to set any value outside of the callback and GLFW. GLFW is initialized, and does not report any errors. Thank you for your time.
Class Window
{
private:
double cursorX;
...other stuffs...
#property
void cursorX(double x) nothrow
{
cursorX = x;
}
}
extern(C) void mousePosCallback(GLFWwindow* window, double x, double y)
{
Window* _window = window.userPointer
//userPointer is a static function that gets the window user pointer
//and casts it to a Window*
_window.cursorX = x;
}
static Window* userPointer(GLFWwindow* window)
{
return cast(Window*) glfwGetWindowUserPointer(window);
}
Edits:
Added extern(C) to callback, error persists.
Corrected "immediately upon entering the callback" to "immediately upon attempting to set any value outside of the callback and GLFW".
Added userPointer function to question
mousePosCallback must be declared in a extern(C) block. This is to make the calling convention match.
extern (C) void mousePosCallback(GLFWwindow* window, double x, double y)
{
Window* _window = window.userPointer
//userPointer is a static function that gets the window user pointer
//and casts it to a Window*
_window.cursorX = x;
}
It seems I have discovered the source of the error. During initialization of the window, I attempt to set the user pointer with this. I'm not sure why, but moving it into a different function that is not called from the constructor appears to remedy the problem. The problem is solved, but could anyone help me to understand why? It seems rather odd to me.

Qt : reference to non-static member function must be called

I am new to Qt, and today I've been trying to adapt my application to work with QFuture to concurrently run some tasks off the main thread.
I have a method which changes the saturation value of a QImage which returns a QPixmap object to be drawn to my QGraphicsView. This all worked fine not using threads, but obviously it is extremely intensive on the main thread so I wanted to move it off.
I read a few articles regarding Threading in Qt, and found that v5 supports a concurrent run functionality, this sounded perfect for my use case as I thought I would just be able to dispatch my functions onto a new thread as in the snippet below:
void MainWindow::on_slideSaturation_valueChanged(int value)
{
QFuture<QPixmap> future = QtConcurrent::run(slider->modifySaturation, value, image);
future.waitForFinished();
image = future.result();
renderImageToCanvas();
modified = true;
}
However I get the error reference to non-static member function must be called.
This error is being called from my Sliders class, I know I haven't declared the method as static, but when I do it causes a whole heap of errors - is there any way I can pass this method to my concurrent call without it being declared as static?
Sliders.h
class Sliders
{
public:
Sliders();
enum Member { RED, GREEN, BLUE, BRIGHTNESS, CONTRAST, HUE, SATURATION, LIGHTNESS };
QPixmap modifySaturation(int, QPixmap);
void setMember(enum Member, int);
int getMember(enum Member);
private:
int m_redValue;
int m_greenValue;
int m_blueValue;
int m_brightnessValue;
int m_contrastValue;
int m_hueValue;
int m_saturationValue;
int m_lightnessValue;
};
You should call QtConcurrent::run like this:
QFuture<QPixmap> future = QtConcurrent::run(slider,
&Sliders::modifySaturation,
value, image);
But I think you are using it wrong anyway. Your on_slideSaturation_valueChanged slot, which I assume to be executed in the main thread, will be blocked until future.waitForFinished() returns.

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.

How do I pass an OpenGL context from Qt4?

I'm currently developing a game in the LeadWerks 2 engine and I've decided to use Qt4 as the GUI and window manager. What I want to do is create a Qt QGLWidget window and have the LeadWerks engine run inside of that.
There is some information of building a basic QGLWidget application here.
I'm really struggling to understand how to do this exactly. I can create a custom GL buffer within the LeadWerks engine and I believe what I need to do is give that buffer the GL context Qt created.
As for the LeadWerks side of things, the main thing I need to do is call a method called CreateCustomBuffer and pass it a few things:
virtual void Buffer::CreateCustom( byte* getsize, byte* makecurrent)
Creates and returns a new custom buffer. GetSize (defined as void _stdcall GetSize(int* width, int* height)) and MakeCurrent (defined as void _stdcall MakeCurrent(void)) are callback functions for the buffer. GetSize should return (by changing the value provided with a pointer) the size of the custum OpenGL buffer/context used. MakeCurrent should set the custom buffer as the current OpenGL context.
and MakeCurrent (defined as void _stdcall MakeCurrent(void)) are callback functions for the buffer
If I understand it correct, this callback will be called whenever LeadWerks wants the context to become active (it doesn't manage it itself then), similar the getsize callback is to obtain the size of the available window. So normally you'd use this to activate the context from another interface you've access for.
Unfortunately those callbacks don't allow for passing a pointer, which means, you can't pass the QGLWidget class instance pointer, so that you could delegate the call to a class member function. Not being able to pass user data to callbacks is a sign of bad API design, because it makes things hard, which would be easy otherwise.
There is a library called ffcall which provides a mechanism to get around this http://www.gnu.org/s/libffcall/callback.html
So you'd write a delegator function
void qglwidget_makecurrent(void *data, va_list alist)
{
GQLWidget *widget = (QGLWidget*) data;
widget->makeCurrent();
}
void qglwidget_getsize(void *data, va_list alist)
{
int *widthptr, *heightptr;
GQLWidget *widget = (QGLWidget*) data;
va_start_ptr(alist, void);
widthptr = va_arg_ptr(alist, int*);
heightptr = va_arg_ptr(alist, int*);
va_return_void(alist);
*widthptr = widget->width();
*heightptr = widget->height();
}
create callback wrappers (as in your QGLWidget derives class' constructor) as class member variables:
class MyGLWidget : QGLWidget {
/* ... */
__TR_function qglwidget_makecurrent_callback;
__TR_function qglwidget_getsize_callback;
}
MyGLWidget::MyGLWidget() {
qglwidget_makecurrent_callback = alloc_callback(qglwidget_makecurrent, (void)this);
qglwidget_getsize_callback = alloc_callback(qglwidget_makecurrent, (void*)this);
}
And those you can pass to LeadEngine:
buffer->CreateCustom((void(*)(int, int))qglwidget_getsize_callback, (void(*)(void))qglwidget_makecurrent_callback);