I try to do an animation in OpenGL, my vertices and animations are working, but I would like to put a background image to it, with a file such as a bmp, or whatever.
So after a few reads I try the quads technique, which is simply to show a quad and bind a texture to it.
I use the STB_Image library, and it seems that I correctly point to my file (if I make mistakes on the filename I definitely got a much faster response from my program).
And I implemented a print to see if it catches the right file and it does!
My code look like this, and my result is a white square that appears in the correct coordinates, but no texture appears, the file is correctly loaded (with correct sizes printed), it just doesn't bind or appear on the square...
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
int width, height, nrChannels;
unsigned char* data = stbi_load("test.jpg", &width, &height, &nrChannels, 0);
if (data == NULL) {
printf("Error in loading the image\n");
exit(1);
}
printf("Loaded image with a width of %dpx, a height of %dpx and %d channels\n", width, height, nrChannels);
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
glVertex2f(2.0, 1.0);
glTexCoord2f(2.0, 1.0);
glVertex2f(8.0, 1.0);
glTexCoord2f(8.0, 1.0);
glVertex2f(8.0, 7.0);
glTexCoord2f(8.0, 7.0);
glVertex2f(2.0, 7.0);
glTexCoord2f(2.0, 7.0);
glEnd();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
Any ideas?
glTexImage2D specify the two-dimensional texture image for the texture object. You have to do that the quad is drawn.
Furthermore 2 dimensional texturing has to be enabled by glEnable(GL_TEXTURE_2D).
The texture coordinates have to be in range [0.0, 1.0] (See How do opengl texture coordinates work?).
glTexCoord2f has to be set before glVertex2f, because the current color, normal and texture coordinates are associated with the vertex when glVertex is called.
Since you don't generate mipmaps (glGenerateMipmap), the texture minifying function (GL_TEXTURE_MIN_FILTER) has to be set to GL_LINEAR or GL_NEAREST. Else the texture would be mipmap incomplete.
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
glBindTexture(GL_TEXTURE_2D, 0);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
glEnable(GL_TEXTURE_2D);
glColor4f(1.0, 1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 1.0);
glVertex2f(2.0, 1.0);
glTexCoord2f(1.0, 1.0);
glVertex2f(8.0, 1.0);
glTexCoord2f(1.0, 0.0);
glVertex2f(8.0, 7.0);
glTexCoord2f(0.0, 0.0);
glVertex2f(2.0, 7.0);
glEnd();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glColor3f(1.0, 1.0, 1.0);
Related
I've managed to get my game to read in a PNG file, and successfully texture my objects. To be honest, I can't 100% nail down how it's actually working - and now I'd like to extend it to loading several textures, and using the one I specify.
Here's my PNG loading function:
//Loads PNG to texture
GLuint loadPNG(string name) {
nv::Image img;
GLuint myTextureID;
if (img.loadImageFromFile(name.c_str())) {
glGenTextures(1, &myTextureID);
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, img.getInternalFormat(), img.getWidth(), img.getHeight(), 0, img.getFormat(), img.getType(), img.getLevel(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
}
else {
MessageBox(NULL, L"Failed to load texture", L"Sorry!", MB_OK | MB_ICONINFORMATION);
}
return myTextureID;
}
In my main function, I define the texture like this:
//Load in player texture
testTexture = loadPNG("test.png");
where testTexture is a global variable, of type GLuint. And drawing my rectangles in my main draw loop is done this way:
//Used to draw rectangles
void drawRect(gameObject &p) {
glEnable(GL_TEXTURE_2D);
//Sets PNG transparent background
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBindTexture(GL_TEXTURE_2D, myTexture);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(p.x, p.y);
glTexCoord2f(1.0, 0.0); glVertex2f(p.x + p.width, p.y);
glTexCoord2f(1.0, 1.0); glVertex2f(p.x + p.width, p.y + p.height);
glTexCoord2f(0.0, 1.0); glVertex2f(p.x, p.y + p.height);
glEnd();
glDisable(GL_TEXTURE_2D);
}
This works fine, texturing all my objects with the defined texture. However, I'd like to be able to define more textures, and use those. I tried moving:
glBindTexture(GL_TEXTURE_2D, myTextureID);
from the loadPNG function, into my drawRect, as:
glBindTexture(GL_TEXTURE_2D, testTexture);
However this doesn't apply any texture whatsoever. If anyone has any ideas, I'd really appreciate the help. Thanks!
You have to bind the texture in order to initialize it with glTexImage2D. Don't remove the call to glBindTexture from loadPNG. If you want to render with a different texture, simply bind the texture before rendering the quads.
I'm using opengl to draw the graphics for simple game like space invaders. So far I have it rendering moving meteorites and a gif file quite nicely. I get the basics. But I just cant get the framebuffer working properly which I indent to render bitmap font to.
The first function will be called inside the render function only when the score changes, This will produce a texture containing the score characters. The second function will draw the texture containing the bitmap font characters to the screen every time the render function is called. I thought this would be a more efficient way to draw the score. Right now I'm just trying to get it drawing a square using the frameBuffer, but it seems that the coordinates range from -1 to 0. I thought the coordinates for a texture went from 0 to 1? I commented which vertex effects which corner of the square and it seems to be wrong.
void Score::UpdateScoreTexture(int* success)
{
int length = 8;
char* chars = LongToNumberDigits(count, &length, 0);
glDeleteTextures(1, &textureScore);//last texture containing previous score deleted to make room for new score
glGenTextures(1, &textureScore);
GLuint frameBufferScore;
glGenTextures(1, &textureScore);
glBindTexture(GL_TEXTURE_2D, textureScore);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, &frameBufferScore);
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferScore);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureScore, 0);
GLenum status;
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
std::cout << "status is: ";
std::cout << "\n";
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE:
std::cout << "good";
break;
default:
PrintGLStatus(status);
while (1 == 1);
}
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferScore);
glBegin(GL_POLYGON);
glVertex3f(-1, -1, 0.0);//appears to be the bottom left,
glVertex3f(0, -1, 0.0);//appears to be the bottom right
glVertex3f(0, 0, 0.0);//appears to be the top right
glVertex3f(-1, 0, 0.0);//appears to be the top left
glEnd();
glDisable(GL_TEXTURE_2D);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D,0);
glDeleteFramebuffers(1, &frameBufferScore);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, chars2);
}
void Score::DrawScore(void)
{
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, textureScore);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(0.7, 0.925, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(0.7, 0.975, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(0.975, 0.975, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(0.975, 0.925, 0.0);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
}
Any ideas where I'm going wrong?
You have not set the glViewport, this may give you problems.
Another possibility is that you have the matrix set to something other than identity.
Ensure that you have reset the model-view and projection matrices to identity (or what you want them to be) before glBegin(GL_POLYGON) in UpdateScoreTexture() (You may wish to push the matrices to the stack before you make changes):
glViewport(0,0, framebufferWidth, framebufferHeight)
glMatrixMode(GL_PROJECTION)
glPushMatrix()
glLoadIdentity()
glMatrixMode(GL_MODELVIEW)
glPushMatrix()
glLoadIdentity()
Then put them back at the end of the function:
glViewport(0,0, width, height)
glMatrixMode(GL_PROJECTION)
glPopMatrix()
glMatrixMode(GL_MODELVIEW)
glPopMatrix()
So I've spent past two days looking through different kinds of 'solutions' to my question via google, there aren't all that many and the ones I've find don't seem to work.
I'm exporting a small test image as .c resource file from Gimp, it's size is 64x64 and it has an alpha channel.
Basically looks like:
static const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
char *comment;
unsigned char pixel_data[64 * 64 * 4 + 1];
} ship = {
64, 64, 4,
(char*) 0,
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\237\237\237\377\237\237\237\377\237\237\237\377\237\237"
"\237\377\237\237\237\377\237\237\237\377\237\237\237\377vZI\0vZI\0vZI\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
and goes on like that for quite a while, as you might expect, until finally ending with
"\237\237\377\237\237\237\377\237\237\237\377",
};
So how can I actually use this resource file? If anyone could provide an example, a bare minimum that is needed to create a square with the texture stamped on it, I'd be most appreciative.
Looking at the reference page for glTexImage2D, it is done like (from here) :
GLuint texName1 = 0;
glGenTextures(1, &texName1);
glBindTexture(GL_TEXTURE_2D, texName1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, ship.bytes_per_pixel, ship.width, ship.height, 0, GetDataFormat(), GetDataType(), ship.pixel_data);
glColor3f(1, 1, 0);
glBindTexture(GL_TEXTURE_2D, texName1);
glBegin(GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f (0.0, 0.0, -5.0f);
glTexCoord2f (1.0, 0.0);
glVertex3f (.5, 0.0, -5.0f);
glTexCoord2f (1.0, 1.0);
glVertex3f (.5, .5, -5.0f);
glTexCoord2f (0.0, 1.0);
glVertex3f (0.0, .5, -5.0f);
glEnd();
The key line is this :
glTexImage2D(GL_TEXTURE_2D, 0, ship.bytes_per_pixel, ship.width, ship.height, 0, GetDataFormat(), GetDataType(), ship.pixel_data);
You need to implement GetDataFormat() and GetDataType() yourself, and it returns the data format and type.
One possible implementation :
GLenum GetDataFormat(){
return GL_BGRA;
}
GLenum GetDataType(){
return GL_UNSIGNED_BYTE;
}
add the file to your source code.
ship structure object is created with all info needed.
I got very strange result with texture mapping.
I used 128*128 RGBA bmp image to do texture mapping of a GL_QUADS, then I got the following strange result, test with other images are OK, but for this image, I got very strange result.
Here I want to map a leaf image to a GL_QUADS.
The following is my code:
void init (void)
{
glClearColor(0.6, 0.6, 0.6, 0.0);
glClearDepth(1.0);
glShadeModel(GL_SMOOTH);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glEnable(GL_TEXTURE_2D);
glutSetCursor(GLUT_CURSOR_CROSSHAIR);
}
void display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity ();
gluLookAt(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
GLuint texture[2];
unsigned int outWidth;
unsigned int outHeight;
unsigned int outDepth;
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
unsigned char * data=loadbmp("leaftest.bmp", outWidth, outHeight, outWidth, true);
gluBuild2DMipmaps(GL_TEXTURE_2D, 4, outWidth, outHeight, GL_BGRA, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
glTranslatef(0, 0, 2);
glRotatef(90, 1, 0, 0);
glBegin(GL_QUADS);
glTexCoord2f(0.0,0.0);
glVertex3f(0.0,-0.6,-0.3);
glTexCoord2f(0.0,1.0);
glVertex3f(0.0,0.0,-0.3);
glTexCoord2f(1.0,1.0);
glVertex3f(0.0,0.0,0.3);
glTexCoord2f(1.0,0.0);
glVertex3f(0.0,-0.6,0.3);
glEnd();
glutSwapBuffers();
}
It is maybe because you do
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
before binding any texture target, this is plainly wrong and i wounder why some examples could work.
Check out some tutorials before you guys code, for example this or buy a book or something.
I have some code in OpenGL to render a YUV image onto an OpenGL viewport. The program works without a problem when running on nvidia cards, but it generates an error when running over the Intel HD 3000, which sadly is the target machine. The point where the error is generated is marked in the code.
The shader programs are
// Vertex Shader
#version 120
void main() {
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
// fragment shader
#version 120
uniform sampler2D texY;
uniform sampler2D texU;
uniform sampler2D texV;
void main() {
vec4 color;
float y = texture2D(texY, gl_TexCoord[0].st).r;
float u = texture2D(texU, gl_TexCoord[0].st).r;
float v = texture2D(texV, gl_TexCoord[0].st).r;
color.r = (1.164 * (y - 0.0625)) + (1.596 * (v - 0.5));
color.g = (1.164 * (y - 0.0625)) - (0.391 * (u - 0.5)) - (0.813 * (v - 0.5));
color.b = (1.164 * (y - 0.0625)) + (2.018 * (u - 0.5));
color.a = 1.0;
gl_FragColor = color;
};
Then I run the program like this:
GLuint textures[3];
glGenTextures(3, textures);
glBindTexture(GL_TEXTURE_2D, textures[YTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, textures[UTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, textures[VTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
GLsizei size = width * height;
GLvoid *y = yuv_buffer;
GLvoid *u = (GLubyte *)y + size;
GLvoid *v = (GLubyte *)u + (size >> 2);
glUseProgram(program_id);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE,
GL_UNSIGNED_BYTE, y);
glUniform1i(glGetUniformLocation(program_id, "texY"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width >> 1, height >> 1, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, u);
glUniform1i(glGetUniformLocation(program_id, "texU"), 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, textures[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width >> 1, height >> 1, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, u);
glUniform1i(glGetUniformLocation(program_id, "texV"), 2);
glBegin(GL_QUADS);
glTexCoord2f(texLeft, texTop);
glVertex2i(left, top);
glTexCoord2f(texLeft, texBottom);
glVertex2i(left, bottom);
glTexCoord2f(texRight, texBottom);
glVertex2i(right, bottom);
glTexCoord2f(texRight, texTop);
glVertex2i(right, top);
glEnd();
// glError() returns 0x506 here
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glUseProgram(0);
update since the error happens with frame buffers, I discover they are used like this:
when the program is instantiated, a frame buffer is created like this:
glViewport(0, 0, (GLint)width, (GLint)height);
glGenFramebuffers(1, &fbo_id);
glGenTextures(1, &fbo_texture);
glGenRenderbuffers(1, &rbo_id);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo_id);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, rbo_id);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glPushAttrib(GL_TEXTURE_BIT);
glBindTexture(GL_TEXTURE_2D, m_frameTexture->texture());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glPopAttrib();
The YUV image comes spliced in tiles, which are assembled by rendering in this fbo. Whenever a frame starts, this is performed:
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK);
glViewport(0, 0, (GLint)width, (GLint)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (double)width, 0.0, (double)height, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo_id);
Then the code above is executed, and after all the tiles had been assembled together
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glPushAttrib(GL_VIEWPORT_BIT | GL_TEXTURE_BIT | GL_ENABLE_BIT);
glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, (double)width, 0.0, (double)height, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glBegin(GL_QUADS);
glTexCoord2i(0, 0);
glVertex2f(renderLeft, renderTop);
glTexCoord2i(0, 1);
glVertex2f(renderLeft, renderTop + renderHeight);
glTexCoord2i(1, 1);
glVertex2f(renderLeft + renderWidth, renderTop + renderHeight);
glTexCoord2i(1, 0);
glVertex2f(renderLeft + renderWidth, renderTop);
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
What's the value of status after:
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
If the value is anything other than GL_FRAMEBUFFER_COMPLETE, OpenGL will probably choke when it tries to read from the FBO.
The glCheckFramebufferStatus docs describes other (error) values it can return, and what causes them.
Of particular interest might be:
If the currently bound framebuffer is not framebuffer complete, then
it is an error to attempt to use the framebuffer for writing or
reading. This means that rendering commands (glDrawArrays and
glDrawElements) as well as commands that read the framebuffer
(glReadPixels, glCopyTexImage2D, and glCopyTexSubImage2D) will
generate the error GL_INVALID_FRAMEBUFFER_OPERATION if called while
the framebuffer is not framebuffer complete.
(emphasis mine)
edit based on your comments:
To paraphrase the docs wrt GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
Not all framebuffer attachment points are framebuffer attachment complete.
This means that one of the following is happening:
At least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero,
The color attachment point has a non-color-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565.
The depth attachment point has a non-depth-renderable image attached. GL_DEPTH_COMPONENT16 is the only depth-renderable format.
The stencil attachment point has a non-stencil-renderable image attached. GL_STENCIL_INDEX8 is the only stencil-renderable format.
We can rule out the last 2 bullets, because it doesn't appear that you're using depth or stencil attachements. That leaves two calls to examine:
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo_id);
From the opengl.org wiki on FBOs:
You get GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT when any of the attachments are 'incomplete'. Criteria for completeness are:
The source object for the image still exists and has the same type it was attached with.
The image has a non-zero width and height.
The layer for 3D or array textures attachments is less than the depth of the texture.
The image's format must match the attachment point's requirements, as defined above. Color-renderable formats for color attachments, etc.
The wiki says of GL_COLOR_ATTACHMENTi​:
These attachment points can only have images bound to them with
color-renderable formats. All compressed image formats are not
color-renderable, and thus cannot be attached to an FBO.
Double check that the fbo_texture and rbo_id are still valid, and that their height/width aren't 0. Finally, it could be fbo_texture's format. You've got it set to GL_RGBA8, but the docs say valid options include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. I'm not sure whether or not that excludes all other formats (like your GL_RGBA8). The wiki seems to suggest that any non-compressed format should work. Try switching it to GL_RGBA4, and see if that works out.
glGetError error codes "stick" and are not automatically cleared. If something at the beginning your program generates OpenGL error AND you check for error code 1000 opengl calls later, error will be still here.
So if you want to understand what's REALLY going on, check for errors after every OpenGL call, or call glGetError in a loop, until all error codes are returned (as OpenGL documentation suggests).
I solved the problem. It was an extensions problem which made the render buffer object disappear. I basically changed this
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo_id);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, rbo_id);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
for this
glBindRenderbuffer(GL_RENDERBUFFER, rbo_id);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TURE_2D, fbo_texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, rbo_id);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
and then it worked. I still wonder exactly what the problem was, but so far I am happy with the result. Special thanks to #luke who's answer helped to locate the exact point of the problem.
Exactly, what command raises error? Try to replace GL_QUADS with GL_TRIANGLE_FAN.