Reputation: 1044
My goal is to be able to scale textures when they are loaded, so I don't have to do it on every frame the sprite gets rendered. I figured the best method would be to render the scaled texture onto another texture, basically caching it. However, with the following code, I only get red quads (due to the glClearColor) so I know that the FBO is working, just not my method for rendering the new texture
Texture *Graphics::loadTexture(const std::string& filename, int scale = 0) {
SDL_Surface *surface;
GLuint texture;
if((surface = IMG_Load(filename.c_str()))) {
// Get the number of colors
GLint numberOfColors = surface->format->BytesPerPixel;
GLenum format;
// Set the format of the texture based on the number of channels
if(numberOfColors == 4) {
if(surface->format->Rmask == 0x000000ff) {
format = GL_RGBA;
} else {
format = GL_BGRA;
}
} else if(numberOfColors == 3) {
if(surface->format->Rmask == 0x000000FF) {
format = GL_RGB;
} else {
format = GL_BGR;
}
} else {
throw Exception("Invalid image type for image " + filename);
}
// Generate texture id
glGenTextures(1, &texture);
// Bind the texture
glBindTexture(GL_TEXTURE_2D, texture);
// Texture stretching properties
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Create the image
glTexImage2D(GL_TEXTURE_2D, 0, 4, surface->w, surface->h,
0, format, GL_UNSIGNED_BYTE, surface->pixels);
glBindTexture(GL_TEXTURE_2D, 0);
} else {
return NULL;
}
Texture *result;
if(scale > 1) {
GLuint scaledTexture;
GLuint fbo;
GLuint fbod;
// First we setup the depth buffer //
// Create the framebuffer
glGenRenderbuffersEXT(1, &fbod);
// Bind the render buffer
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbod);
// Set the render buffer storage to be a depth component
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, surface->w*scale, surface->h*scale);
// Set the render buffer of this buffer to the depth buffer
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbod);
// Unbind the render buffer
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// Next we setup the texture //
glGenTextures(1, &scaledTexture);
glBindTexture(GL_TEXTURE_2D, scaledTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w*scale, surface->h*scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// Setup the frame buffer //
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
// Attach the texture and render buffer to the frame buffer
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, scaledTexture, 0);
// Attach the depth buffer
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbod);
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
glViewport(0, 0, surface->w*scale, surface->h*scale);
glLoadIdentity();
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
glPushMatrix();
glBegin(GL_QUADS);
glTexCoord2i( 0, 0 );
glVertex3f( 0.f, 0.f, 0.0f );
glTexCoord2i( 1, 0 );
glVertex3f( (GLfloat)surface->w*scale, 0.0f, 0.0f );
glTexCoord2i( 1, 1 );
glVertex3f( (GLfloat)surface->w*scale, (GLfloat)surface->h*scale, 0.f );
glTexCoord2i( 0, 1 );
glVertex3f( 0.0f, (GLfloat)surface->h*scale, 0.f );
glEnd();
glPopMatrix();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glPopAttrib();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
result = new Texture(scaledTexture, surface->w, surface->h);
} else {
result = new Texture(texture, surface->w, surface->h);
}
//Texture *result = new Texture(texture, surface->w, surface->h);
if(surface) {
SDL_FreeSurface(surface);
}
return result;
}
Upvotes: 3
Views: 2032
Reputation: 5351
If not trying to tell you what to do, but instead to tell you the simplest way to do what you indent to do (scale the texture) - the answer is:
glBlitFramebuffer(sx0,sy0,sx1,sy1,dx0,dy0,dx1,dy1, GL_COLOR_BUFFER_BIT, GL_LINEAR)
It will automatically scale the read image if the size doesn't match In order to make it work you should setup GL_READ_FRAMEBUFFER, GL_DRAW_FRAMEBUFFER and glDrawBuffer() for each of them.
Upvotes: 1
Reputation: 1044
Okay, what I decided to do was instead of implementing scaling at the time of loading the texture I implemented it in the sprite object. So when I submit the vertex data to the GPU, it scales the sprite by it's verts instead of scaling the actual texture.
Upvotes: 1
Reputation: 9547
Several comments :
But anyway, clear both matrices and you should see your texture in the upper right part of the screen (or whatever polygon on which you're using the generated texture) ; you'll just have to fix the UVs et Graphics::loadTexture :
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
This should work, but I think you should do the scaling in software.
Upvotes: 1