PDA

View Full Version : How to embedding a GLUT simple app into a class file



sandrew
03-12-2002, 03:34 PM
Hi!
I am just wonderring if I could use GLUT for Object Oriented programming?
Instead of .c file I want to use it for my little app writtten in C++. But I dont want to have too many global variables all declared as usaully at the top of my app. I wonder how I could put the whole Glut program into say Main.cpp and Main.h files.
I tried that and get errors. it complains about display func. it is triggered from main by using glutDisplayFunc( display ) and I am sure this is the problem but I am not sure how to solve it! I'll just show you how I did my files! if its ok:

//======== CMain.h =================//
#ifndef _CMAIN_H_ //prevents redefinitions
#define _CMAIN_H_

#include <stdlib.h>
#include <iostream.h>
#include <GL/glut.h>

class CMain
{
public:
CMain();
~CMain();
void reshape(int width, int height);
void display(void);
void init(void);
int main(int argc, char** argv);

private:
int X_CENTRE;
int Y_CENTRE;
int LENGTH;
int R;
};
#endif

//========= CMain.cpp ========//
#include "Main.h"

CMain::CMain()
{
X_CENTRE = 0.0;
Y_CENTRE = 0.0;
LENGTH = 1.0;
R = 10.0;
}

void CMain::reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glMatrixMode( GL_MODELVIEW );
}

void CMain::display(void)
{
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);

glLoadIdentity();

for ( int i = 0; i < 100; i++)
{
glRotatef( R , 0.0, 0.0, 1.0 );

glBegin(GL_LINE_LOOP);
glVertex2f( X_CENTRE - LENGTH / 2, Y_CENTRE - LENGTH / 2);
glVertex2f( X_CENTRE - LENGTH / 2, Y_CENTRE + LENGTH / 2);
glVertex2f( X_CENTRE + LENGTH / 2, Y_CENTRE + LENGTH / 2);
glVertex2f( X_CENTRE + LENGTH / 2, Y_CENTRE - LENGTH / 2);
glEnd();

R+=10.0;
}

glFlush();
}

void CMain::init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
}


int CMain::main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (400, 400);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}

After compiling I get this errors:

: error C2664: 'glutDisplayFunc' : cannot convert parameter 1 from 'void (void)' to 'void (__cdecl *)(void)'
None of the functions with this name in scope match the target type
: error C2664: 'glutReshapeFunc' : cannot convert parameter 1 from 'void (int,int)' to 'void (__cdecl *)(int,int)'
None of the functions with this name in scope match the target type
Error executing cl.exe.

Thank you for any sort of help! http://www.opengl.org/discussion_boards/ubb/smile.gif

[This message has been edited by sandrew (edited 03-12-2002).]

Bob
03-12-2002, 11:22 PM
A member function is not the same as a "regular" function. A member function has a hidden parameter, the this pointer, that allows you to access member variables/function from the object that called the function. A regular function does not have this hidden parameter, cause they don't belong to any class, and it's this kind of function that GLUT wants.

To "solve" this, either move your function from the class and make it global, or put the 'static' keyword in front of the member function declaration (might have to put it in front of the function body too, don't remember). The static keyword tells the compiler you want to make it a "regular" function, but a function that still belongs to the class, and the hidden thispointer will not be used.

Either way you won't be able to access any members in the class (apart from static members) though, since you don't get any this pointer.

zeckensack
03-12-2002, 11:53 PM
Hmmm, I think that's not the problem here, then the error messages would have said something like 'cannot convert to void(*__thiscall)(int,int)'.

I can't promise anything, but try substituting

#include <gl/glut.h>with

extern "C" {
#include <gl/glut.h>
}

This kind of 'protection' should be included in glut.h anyway, but maybe it can't detect that you're running a C++ compiler.

porsgl
03-13-2002, 12:10 AM
Hi
At present I dont have GLUT on my current machine so iam not able to debug the things. but what I understood, the problem could be the main(), we need to explicitaly call main()in VC++ (I m working on VS6.0). e.g.

in your main.cpp, we can write:

int main(int argc, char** argv)
{
CMain obj;
return obj.main(argc,argv);// here iam calling ur main() of the class

}

Hope this may solve your problem !! if not pls tell me

sandrew
03-13-2002, 12:32 AM
Bob - I changed the reshape and display mamber functions to static as well as all data members to static and it compiles but there is still a linking error. Do u know whats that?

LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/9.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

Should I open Another file called test.cpp and create an object of CMain class. but.. CMain has already main so I am a bit confused!

Bob
03-13-2002, 12:44 AM
That error is because you don't have a main() function. The compiler doesn't know where the program is supposed to start.

Bob
03-13-2002, 01:00 AM
zeckensack, you are right. The error message should have mentioned __thiscall, but I obviously didn't think about that when I posted my first reply. Can, of course, be that sandrew don't have a very new compiler (some older version of MSVC or so), and the error message simply don't mention it at all. Only that it can't comvert to something, but not from what. And by the way, it should have been "from __thiscall", not "to __thiscall" http://www.opengl.org/discussion_boards/ubb/smile.gif

Anyways, even if that was the problem or not, passing a non-static member function to GLUT doesn't work. OK, it might work if you somehow magane to typecast the function type to _cdecl. But it won't make things better, casue you won't have a valid this pointer, and when trying to dereference an invalid pointer (accessing member variables for example)... I hope you know what that means.

How much you try, and even if you get it to work in some way or another, you will never be able to access the member variables. Either because GLUT can't pass the this pointer, or because you have the function global or static.

[This message has been edited by Bob (edited 03-13-2002).]

sandrew
03-13-2002, 08:21 AM
All errors are produced by Visual C++ 6.
Ok! so you guys suggest not to embed this GLUT code into a class.
The problem is that I am working on one app which has already 5000 lines of code in the main.cpp file which uses GLUT toolkit. So I have quite alot of global variables and therefore I thought of putting the test file (main.cpp) into a class in order to hide some data. I am using a lot of other variables eg. boolean operators, objects etc.. which are all global variables.
I have like 100 lines of just global variables at the top of my file which basicall have to be accesible in every function!
If I could put all that file into a class (header and implementation file) then I would make them (globa variables) all private. What should I do in this case.
which are included in my main.cpp.
I've tried to reduce the number of global variables but there are some of tehm which must be accesible in eg. keyboard() or mouse() function.
any ideas? Is there any other way round?

[This message has been edited by sandrew (edited 03-13-2002).]

Brent Fogarty
03-13-2002, 01:24 PM
I'm not sure you understand how OO programming is supposed to work and I haven't got all day to go over it so here is an easy solution to your problem.

Keep you class CMain as is without the static infront of the methods. (You may want to rename it to something more meaningful) Put this class in separate files (ie CMain.h and CMain.cpp) In another file #include "CMain.h" at the top, then create a global variable like CMain MyMain; Then in this file create main, Display, Keyboard, etc functions and in each one do the following:
eg.
void Display()
{
MyMain.Display()
}

I would recomend a lot of research on OO programming, try looking at other peoples projects, see how many different classes they use.

Hope that made some sense

sandrew
03-14-2002, 08:13 AM
Hi Brent!!
I think you didn't read my question (at the top of the page)
I am trying to deal with GLUT. this is no just a simple question on how to create a class. I know that normally I would just create a header file called Main.h define a class CMain and its data members and member func. then create an implementation file called Main.cpp and the test file called Test.cpp in which I could have a main in which I could create the instance of the CMain class and test the program. I know its an easy stuff if you put cout<< "hello world"; in your display func. But I want to use this:

int CMain::main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (400, 400);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
Here you can see that glutDisplayFunc(display) would normally be a problem if you wanted to implement as u just described. remember that display is a member function of a CMain.cpp its not a variable!!!!

If you cut/ paste the stuff from the top of the page then you'll get what I mean. with Glut things dont work as you said! http://www.opengl.org/discussion_boards/ubb/smile.gif
Well you might have a solution for this. who knows.. If you know then plz let us know!! Thank you!

[This message has been edited by sandrew (edited 03-14-2002).]

[This message has been edited by sandrew (edited 03-14-2002).]

nickels
03-14-2002, 12:21 PM
I have always been against creating a callback function without providing a void * to send client data. If glut had these then
you could get your handle to your little object and not have to have global vars.

Brent Fogarty
03-14-2002, 06:32 PM
Hi sandrew

I do know what you are trying to do, I have done a similar thing with win32. The reason I suggested you do it that way, and I don't think you understood my solution properly but never mind, was because your method has some problems when dealing with glut.

Others have told you how to do it in earlier posts, make all of your methods and variables in your class static and then in function int main(int argc, char *args[]) (NOT CMain::main()) call CMain::main(argc, args); that will start your programme running.

Problem: This class is pretty useless as far as usability goes, it's not very flexible, you can't make your methods polymorphic because they have to be static, so you will have to rewrite a lot of the code each time you use it.

If you must do it this way then here is your code with amendments which do work:

#include <stdlib.h>
#include <GL/glut.h>

/* just linking libs */
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glut32.lib")

class CMain
{
public:
CMain();
~CMain();
static void reshape(int width, int height);
static void display(void);
static void init(void);
static void idle(void);
static int main(int argc, char** argv);

private:
static int X_CENTRE;
static int Y_CENTRE;
static int LENGTH;
static int R;
};

/* Must do this to static variables outside the class */

int CMain::X_CENTRE = 0;
int CMain::Y_CENTRE = 0;
int CMain::LENGTH = 1;
int CMain::R = 10;


//========= CMain.cpp ========//
//#include "Main.h"

CMain::CMain()
{



}

void CMain::reshape(int width, int height)
{

glViewport(0, 0, width, height);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0);
glMatrixMode( GL_MODELVIEW );

}

void CMain::display(void)
{

glClear (GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);

glLoadIdentity();

glBegin(GL_QUADS);
glVertex2d(-5, -5);
glVertex2d(-5, 5);
glVertex2d(5, 5);
glVertex2d(5, -5);
glEnd();

for ( int i = 0; i < 100; i++)
{
glRotatef( R , 0.0, 0.0, 1.0 );

glBegin(GL_LINE_LOOP);
glVertex2f( X_CENTRE - LENGTH / 2, Y_CENTRE - LENGTH / 2);
glVertex2f( X_CENTRE - LENGTH / 2, Y_CENTRE + LENGTH / 2);
glVertex2f( X_CENTRE + LENGTH / 2, Y_CENTRE + LENGTH / 2);
glVertex2f( X_CENTRE + LENGTH / 2, Y_CENTRE - LENGTH / 2);
glEnd();

R+=10.0;
}

glFlush();

}

void CMain::init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
}

void CMain::idle(void)
{
//glutPostRedisplay();
}

int CMain::main(int argc, char** argv)
{
X_CENTRE = 0.0;
Y_CENTRE = 0.0;
LENGTH = 1.0;
R = 10.0;

glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (400, 400);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutMainLoop();


return 0;
}

// NEED this to link!!!
int main(int argc, char *argv[])
{
return CMain::main(argc, argv);
}

sandrew
03-17-2002, 09:23 AM
Hi Brent!
Yes this is exactly the way I wanted this program to work! Thank you very much! I agree that this class will be toatlly useless in the sense you mentioned but using glut I just can't think of anythingelse what could help me to avoid global vars.
I just have them too many so I thought at least if I create a class then I can hide the data ie. make those vars private.