error C2664 and C2597 in OpenGL and DevIL in C++

1.1k Views Asked by At

I guess this is a two part problem, which is why I couldn't find a more suitable title for the post.

I am loading an image using DevIL and then converting it to a familiar format. Here is the part of my code I am having troubles with:

//Copy to OpenGL texture
if(!ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE))
{
    throw runtime_error(std::string("Unable to convert image") +filename +std::string(" to display friendly format"));
}
glGenTextures(1, &Main::texture);
glBindTexture(GL_TEXTURE_2D, Main::texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Use nice (linear) scaling 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Use nice (linear) scaling 
glTexImage2D(GL_TEXTURE_2D, 0, ilGetInteger(IL_IMAGE_BPP), width, height, 0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());

Now, for the glGenTextures() method, I get

error C2664: 'glGenTextures' : cannot convert parameter 2 from 'GLuint Main::* ' to 'GLuint *'

and for glBindTexure()

error C2597: illegal reference to non-static member 'Main::texture'

I have tried declaring texture in many different ways,

static Gluint Main::texture;
static Gluint texture;
Gluint texture;
Gluint Main::texture;

both in my .cpp file and my .h file, but none of it works. If I try to declare it in the .h file as static Gluint Main::texture, I get the LNK2019: unresolved external symbol__imp_ error for every DevIL function (let me know if you want me to post them as well).

I am pretty it is something in the code as opposed to my dependencies or my .lib or .dll files not being in the right place. So what am I doing wrong?

EDIT: This is my code so far

The header file

class Main
{
private: 
    static GLuint texture;
public:
    static void Init(int argc, char ** argv);
    static void DisplayScene();
    static void Idle();
static void Resize(int w, int h);
};

void main(int argc, char ** argv)
{
    Main::Init(argc, argv);
}

The .cpp file

#include <IL\il.h>
#include <IL\ilu.h>
#include <IL\ilut.h>

GLuint Main::texture = 0;
double xRes, yRes;

void Main::Init(int argc, char ** argv) //Initialisation method
{
    ////Window Management
    glutInit( &argc, argv); //Initialises GLUT and processes any command line arguements.
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); //Specifies whether to use an RGBA or colour-index colour model. Can also specify whether to use a single or a double buffered window.
    glutInitWindowSize(1024, 768);
    glutCreateWindow("Adventure"); //Creates a window with an OpenGL context. It returns a unique identifier for the new window. Until glutMainLoop() is called, the window is not yet displayed.
    /// Set up OpenGL for 2d rendering 
    gluOrtho2D(0.0, xRes, yRes, 0.0); //1.0 0.0
    /// Enable textures 
    glEnable(GL_TEXTURE_2D); 
    /// Enable blending 
    glEnable(GL_BLEND); 
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    ilInit(); //Initialise DevIL.
    glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); //Specifies the coordinate system OpenGL assumes as it draws the final image and how the image is mapped to the screen.

    ///The Display Callback
    glutDisplayFunc(Main::DisplayScene); //Defines all the routines needed to draw the scene.
    glutIdleFunc(Main::Idle);

    ///Running The Program
    glutMainLoop(); //All windows that have been created are now shown, and rendering to those windows is now effective.
}

void Main::Idle()
{
    glutPostRedisplay();
}

void Main::DisplayScene()
{
///Declarations
int x = 0;
int y = 0;
//float alpha;
const char* filename = "back.bmp";
ILboolean ilLoadImage(const char *filename);
//GLuint texture;

///Generate DevIL image and make it current context
ILuint image;
ilGenImages(1, &image);
ilBindImage(image);

///Load the image
if (!ilLoadImage(filename))
{
    throw runtime_error(std::string("Unable to load image") +filename);
}

int width = ilGetInteger(IL_IMAGE_WIDTH);
int height = ilGetInteger(IL_IMAGE_HEIGHT);

///Copy to OpenGL texture
if(!ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE))
{
    throw runtime_error(std::string("Unable to convert image") +filename +std::string(" to display friendly format"));
}
glGenTextures(1, &Main::texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Use nice (linear) scaling 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Use nice (linear) scaling 
glTexImage2D(GL_TEXTURE_2D, 0, ilGetInteger(IL_IMAGE_BPP), width, height, 0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData()); 

/// Free DevIL image since we have it in a texture now 
ilDeleteImages(1, &image);
}
2

There are 2 best solutions below

3
On

Your error appear because you don't have an instance (object) of type Main, but of course you need a Main before you can use anything from it.

Now you have several options to fix this - and it appears like you already tried a few. You can make the texture variable global, either by making it static at class-scope, or by using an "ordinary" global at namespace scope.

For the first case, you'd declare the variable as static GLuint texture; in your class in your .h file and you define it as GLuint Main::texture = 0; in your .cpp file. It seems you didn't define the variable when you tried this. For the second case, you declare it as extern GLuint texture; in your .h outside of your class and define it as GLuint texture outside of any function.

Both solutions aren't very good style, so it would be better if you just added a GLuint texture to your Main class, then create a Main instance and used its member variable - preferably from a function within Main, so you can use this.

Ideally, you'd have something like a Texture class like this:

class Texture
{
  Texture() {glGenTextures(1, &id);}
  ~Texture() {glDeleteTextures(1, &id);}
  void Bind() {glBindTexture(GL_TEXTURE_2D, id);}
private:
  GLuint id;  
};

void someFunction()
{
  Texture myTexture;
  myTexture.Bind();
  // do stuff with the texture - like glTexParameteri, glTexImage
}

bonus points for moving more functionality into the Texture class, but that requires dealing more with OpenGLs stupid bind mechanic.

1
On

error C2664: 'glGenTextures' : cannot convert parameter 2 from 'GLuint Main::* ' to 'GLuint *'

&Main::texture is what we call a member field pointer, not a pointer. You'd need to point to an actual instance of a texture, so

 Main* mymain; /* = new Main(...); somewehere in the code */
 glGenTextures(1, &mymain->texture);

Extra / bonus

In the unlikely event that you actully wanted to use a member pointer, here is an example (codepad link):

#include <stdio.h>

struct A
{
    int p,q,r;

    int getp() { return p; }
};

int main()
{
    int x;
    A a[] = {
        { 1,2,3 },
        { 4,5,6 },
        { 7,8,9 }
    };

    // ---- pointer to member functions

    int A::* member;

    member = &A::p;
    printf("member p: %i\n", a[2].*member);
    member = &A::q;
    printf("member q: %i\n", a[2].*member);
    member = &A::r;
    printf("member r: %i\n", a[2].*member);

    // ---- pointer to member functions

    int (A::*getter)();

    getter = &A::getp;

    x = (a[1].*getter)();
    printf("getter: %i\n", x);

    x = (a[2].*getter)();
    printf("getter: %i\n", x);

    return 0;
}