4

I'm drawing an image from openCV full screen, this is a large image at 60fps so I needed a faster way than the openCV gui.

Using OpenGL I do:

void paintGL() {
    glClear (GL_COLOR_BUFFER_BIT);
    glClearColor (0.0,0.0,0.0,1.0);

    glDisable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0,width,height,0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glEnable(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, the_image_data );
    glBegin(GL_QUADS);
    glTexCoord2i(0,0); glVertex2i(0,height);
    glTexCoord2i(0,1); glVertex2i(0,0);
    glTexCoord2i(1,1); glVertex2i(width,0);
    glTexCoord2i(1,0); glVertex2i(width,height);
    glEnd();
    glDisable(GL_TEXTURE_2D);
}

Now I want to draw two images side:side - using the openGL hardware to scale them.
I can shrink the image by changing the quad size I don't understand how to load two images with glTexImage2() since there is no handle or id associated with the image.

OpenGL newbie
  • 43
  • 1
  • 1
  • 3

2 Answers2

11

The reason why you cannot see how to add another texture is because you are missing two critical functions in the code that you posted: glGenTextures and glBindTexture. The first will generate texture objects in the OpenGL context (places for textures to exist on the graphics hardware). The second "selects" one of those texture objects for subsequent calls (glTex..) to affect it.

First of all, the functions like glTexParameteri and glTexImage2D do not need to be called again at every rendering loop... but I guess in your case, you should do that because the images are always changing. By default, in your code, the texture object used is the zeroth object (a reserved one for the default). You should create two texture objects and bind them one after the other to achieve the desired result:

GLuint tex_obj[2]; //create two names for the texture (should not be global variables, but just for sake of this example).

void initGL() {
    glClearColor (0.0,0.0,0.0,1.0);

    glDisable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0,width,height,0);

    glEnable(GL_TEXTURE_2D);
    glGenTextures(2,tex_obj); //generate 2 texture objects with names tex_obj[0] and [1]

    glBindTexture(GL_TEXTURE_2D, tex_obj[0]); //bind the first texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //set its parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    glBindTexture(GL_TEXTURE_2D, tex_obj[1]); //bind the second texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //set its parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}

void paintGL() {
    glClear (GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glBindTexture(GL_TEXTURE_2D,tex_obj[0]); //bind the first texture.
    //then load it into the graphics hardware:
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width0, height0, 0, GL_RGB, GL_UNSIGNED_BYTE, the_image_data0 );
    glBegin(GL_QUADS);
    glTexCoord2i(0,0); glVertex2i(0,height);  //you should probably change these vertices.
    glTexCoord2i(0,1); glVertex2i(0,0);
    glTexCoord2i(1,1); glVertex2i(width,0);
    glTexCoord2i(1,0); glVertex2i(width,height);
    glEnd();

    glBindTexture(GL_TEXTURE_2D, tex_obj[1]); //bind the second texture.
    //then load it into the graphics hardware:
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGB, GL_UNSIGNED_BYTE, the_image_data1 );
    glBegin(GL_QUADS);
    glTexCoord2i(0,0); glVertex2i(0,height);  //you should probably change these vertices.
    glTexCoord2i(0,1); glVertex2i(0,0);
    glTexCoord2i(1,1); glVertex2i(width,0);
    glTexCoord2i(1,0); glVertex2i(width,height);
    glEnd();
}

That is basically how it is done. But I have to warn you that my knowledge of OpenGL is a bit outdated, so there might be more efficient ways to do this (I know at least that glBegin/glEnd is deprecated in C++, replaced by VBOs).

Community
  • 1
  • 1
Mikael Persson
  • 18,174
  • 6
  • 36
  • 52
  • Doesn't work - I have to do gluOrtho2D(0,width,height,0); in every paint or nothing shows up - and it still only paints whichever glTexImage2D() I do first. What associates a particular glTexImage2D() with a texture ID? – OpenGL newbie Jan 31 '11 at 22:54
  • Ok I'm an idiot - I had the Quads for the second image wrong (start and end width were the same!) but I still need to do an gluOrtho2D( full window coords) on every call – OpenGL newbie Jan 31 '11 at 23:09
  • 2
    Once the textures are created, just update the data using glTexSubImage2D. This is a lot faster than glTexImage which goes through full reinitialization everytime. In fact you can pass NULL to the data parameter of glTexImage to tell you only want to initialize and then supply the data later through glTexSubImage – datenwolf Feb 01 '11 at 11:23
2

Remember openGL is a state machine - you put it into a state, give it a command and it replays the states later.

One nice thing about textures is that you can do things outside the paint call - so if in your image processing step you generate image 1 you can load it into the card at that point.

glBindTexture(GL_TEXTURE_2D,tex_obj[1]);  // select image 1 slot
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGB, GL_UNSIGNED_BYTE, the_image_data1 ); // load it into the graphics card memory

And then recall it in the paint call

glBindTexture(GL_TEXTURE_2D,tex_obj[1]); // select pre loaded image 1
glBegin(GL_QUADS); // draw it
Martin Beckett
  • 94,801
  • 28
  • 188
  • 263