0

The following is code to draw a rectangle, but I am getting an error in glutdisplayFunc(). How can I fix it?

#include <iostream>
#include <glut.h>

using namespace std;

class GUI
{
  public:
    int W,H;
    GUI()
    {
        W = 800;
        H = 600;
        glClearColor(0, 0, 0, 0);
        gluOrtho2D(-W, W, -H, H);
        glMatrixMode(GL_PROJECTION);
    }
    void display()
    {
        glBegin(GL_POLYGON);
        glVertex2d(-500, 300);
        glVertex2d(500, 300);
        glVertex2d(500, -300);
        glVertex2d(-500, -300);
        glEnd();
        glFlush();
    }
};

int main(int argv, char **argc)
{
    GUI ob;

    glutInit(&argv, argc);
    glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
    glutInitWindowSize(ob.W, ob.H);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Queen Problem");
    glutDisplayFunc(ob.display);      //Error
    glutMainLoop();
    return 0;
}

I am using Visual Studio 2010. I created some of the programs in OpenGL, but without any clases. This is my first experience of using classes with OpenGL.

The error is:

Error 1 error C3867: 'GUI::display': function call missing argument list; use '&GUI::display' to create a pointer to member.

I tried to use &GUI::display, but it also resulted in the error.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Arv
  • 1
  • 1
  • 1
  • 2
    Your member function doesn't even use the class. Make it a free function. – chris Aug 31 '13 at 17:23
  • just to be perfectly clear this is a GLUT and C++ problem not a C++ with OpenGL problem. OpenGL itself doesn't have any callbacks in its API. There's other OpenGL helper APIs like glfw out there that don't have this problem – PeterT Aug 31 '13 at 17:40
  • What you're dealing with is a low-level interop issue between C and C++. This has nothing to do with OpenGL, or even GLUT. GLUT is written in C, expects a C function, but you have to work around this in C++ to provide it. If you find the answers provided difficult to comprehend, then the issue is ultimately going to go back to a lack of understanding of C, C++. While I like trial & error, you are spraying and praying which is not easily tolerated in C/C++. – dans3itz Aug 31 '13 at 18:00
  • @PeterT: "OpenGL itself doesn't have any callbacks in its API" glu library has them. See `gluTessCallback` – SigTerm Aug 31 '13 at 21:54
  • @SigTerm glu is not part of OpenGL, it's build on top of OpenGL. Seeing as how the last update to the specification seems to have been 1998 and it has since been deprecated I think it's safe to say that glu shouldn't be used in new projects, especially not with OpenGL versions >=3 – PeterT Aug 31 '13 at 22:16
  • @SigTerm: Wrong OpenGL has callbacks, off the top of my head it has a debug output callback. – Andon M. Coleman Aug 31 '13 at 22:20
  • @AndonM.Coleman: Name one. – SigTerm Aug 31 '13 at 22:20
  • @PeterT: Seeing how reimplementing tesselator from scratch is a major pain in the ***, you're probably incorrect. – SigTerm Aug 31 '13 at 22:21
  • @AndonM.Coleman ah, you're right, forgot about the debug system, I guess there could be plenty more in other ARBs and EXTs . – PeterT Aug 31 '13 at 22:21
  • @PeterT Yeah, I have a feeling the long-standing trend of no callbacks in OpenGL is going to be a thing of the past; though they will still be used sparingly for sure. There are a few useful scenarios in which it could help with robustness, which is a big deal in newer versions of OpenGL. And debug output is no longer an extension, so callbacks have found their way into the core API already. A lot of convention's been thrown out the window recently, mostly for the better :) – Andon M. Coleman Aug 31 '13 at 22:31

4 Answers4

0

C++ has no notion of a concept called "closures". A closure is a tuple consisting of a function, and a scope in which the function is executed with. Class member functions require a class instance to work with. You can't take a function pointer of an instance's member function, due to the lack of this concept in C++.

Furthermore GLUT is a C API, which means, that even if C++ did support closures, GLUT wouldn't know how to work with this.

So what you must so is use a non-member function use that to call a class member function on an instance. Most C APIs allow you to provide a callback parameter (usually in the form of a void*). GLUT however doesn't do this, so effectively you can only call on a global instance of the class.

update

There are further problems with your code. You instanciate GUI before there is a OpenGL context. The OpenGL context gets created by glutCreateWindow. But the `GUI' constructor makes OpenGL calls, which are invalid without a constructor available.

And to make matters worse: All those calls in the constructor actually belong in the drawing code.

Community
  • 1
  • 1
datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • A static member function isn't required to work. An `extern "C"` free function is. See http://stackoverflow.com/questions/1738313/c-using-class-method-as-a-function-pointer-type – chris Aug 31 '13 at 17:30
  • @chris: Thanks. One reason for me more to dislike C++ ;) – datenwolf Aug 31 '13 at 18:35
  • Yeah, I wish I didn't have to use C interfaces to use it with any other language (at least the easy way). – chris Aug 31 '13 at 19:00
  • @chris: using C interface is the easy way. Make OOP interface, and two different programmers will never agree whose class hieararchy/coding style is "right". – SigTerm Aug 31 '13 at 21:51
  • 2
    "so is use a extern "C"" This is incorrect. Extern "C" deals with name mangling only. Which is only important when you're making dlls. As long as calling convention matches calling convention required by glut, extern "C" won't make any difference. – SigTerm Aug 31 '13 at 22:05
  • @SigTerm, Ok, well it wasn't too long ago that I found out about the static member issue and I got the impression from it to use `extern "C"` as well. Thanks for clearing that up. And true enough people would argue (COM comes to mind). – chris Sep 01 '13 at 04:50
0

C++ and C do not share the same linkage and ABI. Additionally, for classes, there is what is called the 'implicit' parameter known as the 'this' pointer, the argument is hidden and resolved for you. Internally, this will change the function signature from what you expect and the compiler takes care of the details making sure this works. The C function call expects a reference to a function with the expected signature. It also has no way to interop this directly and you'll have to bridge this in some fashion.

dans3itz
  • 1,605
  • 14
  • 12
0
  • The reason why you are getting the error message is because you either defined the function display() as a member function of GUI class or you did not defined the display() function as a member of GUI class and you are trying to call it from the GUI class.
  • To fix the problem, you need to define display() function as a non-member function of GUI with no input parameters. If it`s a non-member function you cannot do this ob.display. glutDisplayFunc does not take a member function.
  • To refer to the non-member function display() on GUI class, you need to call it this way;
  • glutDisplayFunc(&display);
Juniar
  • 1,269
  • 1
  • 15
  • 24
0

Solution

  1. Make display static.
  2. Or get rid of the GUI class. If you have only one window, you don't really need it.
  3. Make single global instance of GUI class, and call its display() method from the glut display callback.
  4. Or use different library to initialize OpenGL.
  5. Or find a way to pass the "this" pointer through glut.

Explanation

In C++ class methods have hidden this parameter, unless it is static. You can't call non-static class member without having this pointer.

GLUT expects a function without the this parameter.

If you do not know what the this" pointer is, you need to get a C++ book and study more.

Either make "display" static (in which case you won't be able to access class members from within the method), or find some way to pass "this" pointer to be used within.

Passing the this pointer through glut and forwarding the call to a class would look like this:

class Gui{
public:
    void display();
};

void* getWindowData(int id);
void setWindowData(int id, void* p);

void displayForwarded(){
    Gui *gui = (Gui*)getWindowData();      
    if (gui)
        gui->display();
}

int main(int argc, char** argv){
    ....
    int windowId = glutCreateWindow();       
    Gui gui;
    setWindowData(windowId, &gui);
    glutDisplayFunc(displayForwarder);
}

The problem is content of getWindowData() and setWindowData(). If you were using OpenGLUT, you could've used glutSetWindowData function in them.

In FreeGLUT you could either abuse the window title to pass a pointer through it (bad idea, don't do that), but that's a bad taste.

So what's left is to create a global map that'll convert window ids to user data pointers and user data through that.

typedef int WindowId;
typedef std::map<WindowId, Gui*> GuiMap;

namespace Internal{
     GuiMap guiMap;
}
class Gui{
public:
    ...
    void display();
}

void setWindowGui(WindowId id, Gui* p){
     Inertnal::guiMap[id] = p; // guiMap.insert(std::make_pair(id, p))
}

Gui* getWindowGui(WindowId id){
     GuiMap::iterator found = Internal.guiMap.find(id);
     if (found == Internal.guiMap.end())
         return 0;
     return found.second;
}

void displayForwarder(){
     WindowId = getGetWindow();//glut function
     Gui *gui = getWindowGui(id);
     if (!gui)
         throw std::string("gui not found");
     gui->display();
}

int main(int argc, char** argv){
    ...
    Gui gui;
    WindowId window = glutCreateWindow(.....);...
    setWindowGuiwindow, &gui);
    glutDisplayFunc(displayForwarder);
    ...
    ...
}

If you don't understand the answer, get a C++ book and read it.

Community
  • 1
  • 1
SigTerm
  • 26,089
  • 6
  • 66
  • 115