OpenGL FBO with MRT writing to back buffer - c++

I have a confusing situation in OpenGL 3.3 on the Mac. I have created an FBO with five attachment points sized at 512x512 apiece. I constructed a shader that writes to gl_FragData[0-4] for diffuse, normal, position, specular and emissive for my geometry. When I render the scene the back buffer AND the render targets are being updated even though I’ve only bound the FBO!
Here’s some code:
void OpenGLESDriver::setFrameBufferAttachments( u32 nAttachments, const u32* aAttachments ){
pushText( "setFrameBufferAttachments" );
#if USE_MRT
GLint max;
glGetIntegerv( GL_MAX_DRAW_BUFFERS, &max );
GLenum aBuffers[max];
if( nAttachments > max ){
nAttachments = max;
}
for( u32 i=0; i<nAttachments; ++i ){
aBuffers[i] = GL_COLOR_ATTACHMENT0+aAttachments[i];
}
for( u32 i=nAttachments; i<max; ++i ){
aBuffers[i] = GL_NONE;
}
glDrawBuffers( max, aBuffers );
glAssert();
#else
glDrawBuffer( GL_COLOR_ATTACHMENT0+aAttachments[0] );
glAssert();
#endif
popText();
}
And the FBO binder:
bool OpenGLESDriver::setFrameBuffer( const FrameBuffer::handle& hFrameBuffer ){
if( hFrameBuffer ){
pushText( "setFrameBuffer" );
glBindFramebuffer( GL_FRAMEBUFFER, hFrameBuffer->toFBO() );
glAssert();
if( !hFrameBuffer->toColorTargets().empty() ){
u32 nAttachments = hFrameBuffer->toColorTargets().size();
u32 aAttachments[nAttachments];
for( u32 i=0; i<nAttachments; ++i ){
aAttachments[i] = i;
}
setFrameBufferAttachments( nAttachments, aAttachments );
}else{
setFrameBufferAttachments( 0, 0 );
}
int w = hFrameBuffer->toDepthTexture()->toWidth();
int h = hFrameBuffer->toDepthTexture()->toHeight();
glViewport( 0, 0, w, h );
glAssert();
//clear out all texture stages because we don't want a left over
//frame buffer texture being bound to the shader.
for( u32 i=0; i<Material::kMaxSamplers; ++i ){
setTextureStage( i, 0 );
}
popText();
return true;
}
return false;
}
I create the FBO with:
FrameBuffer::handle OpenGLESDriver::createFrameBuffer( const FrameBuffer::ColorTargets& vColorTargets, const DepthTarget::handle& hDT ){
//--------------------------------------------------------------------
// Save off default FBO.
//--------------------------------------------------------------------
if( s_iFBOMaster < 0 ){
glGetIntegerv( GL_FRAMEBUFFER_BINDING, &s_iFBOMaster );
glAssert();
}
//--------------------------------------------------------------------
// Generate frame buffer object.
//--------------------------------------------------------------------
GLuint fbo;
glGenFramebuffers( 1, &fbo );
glAssert();
glBindFramebuffer( GL_FRAMEBUFFER, fbo );
glAssert();
//--------------------------------------------------------------------
// Attach color RBO.
//--------------------------------------------------------------------
FrameBuffer::ColorTargets::const_iterator itCT = vColorTargets.getIterator();
u32 mrtIndex = 0;
while( itCT ){
const ColorTarget::handle& hCT = itCT++;
if( !hCT ){
continue;
}
if( hCT->toTexID() ){
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0+mrtIndex,
GL_TEXTURE_2D,
hCT->toTexID(),
0 );
}else if( hCT->toRBO() ){
glFramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0+mrtIndex,
GL_RENDERBUFFER,
hCT->toRBO() );
}else{
DEBUG_ASSERT_ALWAYS( "No color texture or RBO to attach!" );
}
glAssert();
++mrtIndex;
if( !checkFBStatus() ){
e_log( "GL", "Couldn't create color attachment!" );
hCT.as<ColorTarget>()->toFlags()->bFailed = true;
}
}
//--------------------------------------------------------------------
// Attach depth RBO.
//--------------------------------------------------------------------
if( hDT ){
if( hDT->toTexID() ){
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D,
hDT->toTexID(),
0 );
}else if( hDT->toRBO() ){
glFramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
hDT->toRBO() );
}else{
DEBUG_ASSERT_ALWAYS( "No depth texture or RBO to attach!" );
}
glAssert();
if( !checkFBStatus() ){
e_log( "GL", "Couldn't create depth attachment!" );
hDT.as<DepthTarget>()->toFlags()->bFailed = true;
}
}
//--------------------------------------------------------------------
// New handle.
//--------------------------------------------------------------------
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glAssert();
FrameBuffer::handle hFrameBuffer = e_new( FrameBuffer );
hFrameBuffer->setColorTargets( vColorTargets );
hFrameBuffer->setDepthTarget( hDT );
hFrameBuffer->setFBO( u32( fbo ));
return hFrameBuffer;
}
And I go back to the back buffer with:
void OpenGLESDriver::setDefaultTarget(){
pushText( "setDefaultTarget" );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );//s_iFBOMaster );
glAssert();
glViewport( 0, 0, IEngine::cxView(), IEngine::cyView() );
glAssert();
popText();
}
So the final rendering code looks like:
pushText( "Render MRT pass" );
if( setFrameBuffer( m_tPostFx.buffers[0] )){
setColorMask( true, true, true, true );
clearZ();
enableZBuffer( false );
setColor( color );
clearMRT( m_tPostFx.clearMRTShader );
enableZBuffer( true );
drawMRTPass();
}
popText();
And for some reason the back buffer is being rendered to as well as the FBO. I must be missing something but haven’t got a clue what. Can anyone see what I’m doing wrong?

After some poking around I finally found the answer. My renderer uses a vector of RenderNode objects which I fill up during rendering. I wasn't clearing that vector after I finished my post-effect. For some reason that unfilled vector was being rendered with the next FBO target, which drew all the first lot of geometry again in the second FBO. By clearing the vector at the beginning of the render pass and at the end I got rid of the problem. I'm still trying to track down who was committing all the render nodes again. Hopefully the code I pasted will help anyone who's looking to do FBOs because it does work after all. :)

Related

OpenGL lazy function(opengl function is delayed only at first frame)

At 'first' frame of my application, I don't know why 'glGetTextureLevelParameterivEXT()' function is delayed. After first frame, this phenomenon doesn't occur.
That function is called in framebuffer bind method. Also, this phenomenon only occurs at summed-area table rendering 2nd pass using ping-pong technique. In this pass, render method exchanges src and dst textures. After calling glFramebufferTexture2D() and glDrawBuffers(), width() calls 'glGetTextureLevelParameterivEXT()' function. I already replaced this code constant. But, next function was also delayed...... Strangely, this phenomenon is only occurred at 'first' frame of my application.
Here is my code in framebuffer bind method.
uint numDrawBuffers=0;
for( int k=0; k < MAX_COLOR_ATTACHMENTS; k++ )
{
gl::Texture* t=textureList[k]; GLint L=t?layerList[k]:0, M=t?mipLevelList[k]:0; GLuint tex=t?t->ID:0;
bool bnone = activeTargets[k]==NULL&&t==NULL;
GLenum target = activeTargets[k] = (t?t->target:activeTargets[k]); if(t) numDrawBuffers++;
if(bnone){ /* do nothing */ }
else if(target==GL_TEXTURE_1D) glFramebufferTexture1D( GL_FRAMEBUFFER, drawBuffers[k], target, tex, M );
else if(target==GL_TEXTURE_2D) glFramebufferTexture2D( GL_FRAMEBUFFER, drawBuffers[k], target, tex, M );
else if(target==GL_TEXTURE_3D) glFramebufferTextureLayer( GL_FRAMEBUFFER, drawBuffers[k], tex, M, L );
else if(target==GL_TEXTURE_1D_ARRAY) glFramebufferTextureLayer( GL_FRAMEBUFFER, drawBuffers[k], tex, M, L );
else if(target==GL_TEXTURE_2D_ARRAY) glFramebufferTextureLayer( GL_FRAMEBUFFER, drawBuffers[k], tex, M, L );
if(t==NULL) activeTargets[k] = NULL;
}
// if nothing bound, unbind depth buffer and return
if(numDrawBuffers==0){ glBindRenderbuffer(GL_RENDERBUFFER,0); glBindFramebuffer(GL_FRAMEBUFFER,0); return; }
else glDrawBuffers( numDrawBuffers, drawBuffers );
GLint width=t0->width(mipLevel0), height=t0->height(mipLevel0);

Follow up: Asynchronous off-screen query performance

I recently asked this question:
How to perform asynchronous off-screen queries?
What I've heard, but haven't been able to confirm yet, is that rendering to the window is more expensive than rendering to a framebuffer. First of all, can anyone comment on this? Can I draw multiple scenes to framebuffers faster than I can to the window? Are there other options, e.g., pbuffers or PBOs?
I have started playing around with framebuffers, but I have not been able to get the query to work. Here's some psuedo code for what I have set up so far:
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
window = glfwCreateWindow(1, 1, "OpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
glEnable(GL_DEPTH_TEST);
glGenQueries(numberOfQueries, queries);
for (scene in scenesToRender)
{
glClear(GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_LESS);
drawShadingObjects(scene);
glBeginQuery(GL_SAMPLES_PASSED, queries[index]);
glDepthFunc(GL_LEQUAL);
drawShadedObject(scene);
glEndQuery(GL_SAMPLES_PASSED);
}
collectQueryResults();
deleteBuffers();
So far everything runs, but all of the queries return "0". Is there something about querying when drawing to a framebuffer that is different than when drawing to the window buffer?
Again, my two questions are:
Can I draw multiple scenes to framebuffers faster than I can to the window? Are there other options, e.g., pbuffers or PBOs?
Is there something about querying when drawing to a framebuffer that is different than when drawing to the window buffer?
Try something like this:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
using namespace std;
const unsigned int sz = 1024;
void drawScene( unsigned int multiplier )
{
glViewport( 0, 0, sz, sz );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef( (float)glfwGetTime() * 50.f * multiplier, 0.f, 0.f, 1.f);
glBegin(GL_TRIANGLES);
glColor3f(1.f, 0.f, 0.f);
glVertex3f(-0.6f, -0.4f, 0.f);
glColor3f(0.f, 1.f, 0.f);
glVertex3f(0.6f, -0.4f, 0.f);
glColor3f(0.f, 0.f, 1.f);
glVertex3f(0.f, 0.6f, 0.f);
glEnd();
}
bool available( const vector< GLuint >& queries )
{
for( size_t i = 0; i < queries.size(); ++i )
{
GLuint available = 0;
glGetQueryObjectuiv( queries[i], GL_QUERY_RESULT_AVAILABLE, &available );
if( GL_FALSE == available )
return false;
}
return true;
}
int main()
{
glfwInit();
GLFWwindow* window = glfwCreateWindow( 400, 400, "Simple example", NULL, NULL );
glfwMakeContextCurrent( window );
glewInit();
if( !glewIsSupported( "GL_VERSION_2_1" ) )
return -1;
if( !glewIsSupported( "GL_EXT_framebuffer_object" ) )
return -1;
GLuint fbo = 0;
glGenFramebuffersEXT( 1, &fbo );
glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, fbo );
GLuint rbo0 = 0;
glGenRenderbuffersEXT( 1, &rbo0 );
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rbo0 );
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_RGBA, sz, sz );
glFramebufferRenderbufferEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, rbo0 );
GLuint rbo1 = 0;
glGenRenderbuffersEXT( 1, &rbo1 );
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rbo1 );
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, sz, sz );
glFramebufferRenderbufferEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo1 );
GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
if( status != GL_FRAMEBUFFER_COMPLETE_EXT )
return -1;
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
vector< GLuint > queries( 10 );
glGenQueries( queries.size(), &queries[0] );
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo );
for( size_t i = 0; i < queries.size(); ++i )
{
glBeginQuery( GL_SAMPLES_PASSED, queries[i] );
drawScene( i + 1 );
glEndQuery( GL_SAMPLES_PASSED );
}
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
// wait for queries to become available
unsigned int cnt = 0;
while( !available( queries ) )
{
cnt++;
}
// all queries available, display query results
cout << "cnt: " << cnt << endl;
for( size_t i = 0; i < queries.size(); ++i )
{
GLuint samples = 0;
glGetQueryObjectuiv( queries[i], GL_QUERY_RESULT, &samples );
cout << i << ": " << samples << endl;
}
cout << endl;
glfwDestroyWindow( window );
glfwTerminate();
return 0;
}
Representative output on my system:
cnt: 1884
0: 157288
1: 157288
2: 157289
3: 157288
4: 157287
5: 157286
6: 157292
7: 157286
8: 157289
9: 157288

Load image with GDAL Libraries (VC++)

I have a problem when I try to load an image with GDAL Libraries, and implements it(image) to the OpenGL Control. The problem is on the color as you can see on the picture.
And this is the functions to generate texture from the image:
GLuint COpenGLControl::ReadGDALData(CString filename)
{
BYTE* tempReturn;
GLuint texture;
GDALDataset *poDataset;
GDALAllRegister();
poDataset = (GDALDataset *) GDALOpen((const char *)(CStringA)filename, GA_ReadOnly);
int Height = poDataset->GetRasterXSize(), Width = poDataset->GetRasterYSize();
LONG LineBytes = (Width*8+31)/32*4;
BYTE * pData = (BYTE *)new char[ LineBytes * Height * 3];
if (poDataset == NULL)
{
AfxMessageBox("Couldn't open selected file!");
return NULL;
}
nBands = poDataset->GetRasterCount();
GDALRasterBand **poBand;
poBand = new GDALRasterBand *[nBands];
if (poBand == NULL)
{
AfxMessageBox("Couldn't open the bands!", MB_ICONWARNING);
return NULL;
}
for (int i=0; i<nBands; i++)
{
poBand[i] = poDataset->GetRasterBand(i+1);
if (poBand[i] == NULL)
{
AfxMessageBox("Couldn't open selected bands", MB_ICONWARNING);
return NULL;
}
}
int BandChoice = 2;
nXsize = poBand[BandChoice]->GetXSize();
nYsize = poBand[BandChoice]->GetYSize();
if (BandChoice == 1)
{
poBandBlock_Gray = (BYTE*)CPLMalloc(sizeof(BYTE)*(nXsize*nYsize));
poBand[BandChoice]->RasterIO(GF_Read, 0, 0, nXsize, nYsize, poBandBlock_Gray, nXsize, nYsize, poBand[BandChoice]->GetRasterDataType(), 0, 0);
}
else
{
int nXsize_R, nXsize_G, nXsize_B;
int nYsize_R, nYsize_G, nYsize_B;
int BandChoiceR = 0;
int BandChoiceG = 1;
int BandChoiceB = 2;
nXsize_R = poBand[BandChoiceR]->GetXSize();
nXsize_G = poBand[BandChoiceG]->GetXSize();
nXsize_B = poBand[BandChoiceB]->GetXSize();
nYsize_R = poBand[BandChoiceR]->GetYSize();
nYsize_G = poBand[BandChoiceG]->GetYSize();
nYsize_B = poBand[BandChoiceB]->GetYSize();
nXsize = nXsize_R;
nYsize = nYsize_R;
poBandBlock_R = (BYTE*)CPLMalloc(sizeof(BYTE)*(nXsize_R*nYsize_R));
poBandBlock_G = (BYTE*)CPLMalloc(sizeof(BYTE)*(nXsize_G*nYsize_G));
poBandBlock_B = (BYTE*)CPLMalloc(sizeof(BYTE)*(nXsize_B*nYsize_B));
poBand[BandChoiceR]->RasterIO(GF_Read, 0, 0, nXsize_R, nYsize_R, poBandBlock_R, nXsize_R, nYsize_R, poBand[BandChoiceR]->GetRasterDataType(), 0, 0);
poBand[BandChoiceG]->RasterIO(GF_Read, 0, 0, nXsize_G, nYsize_G, poBandBlock_G, nXsize_G, nYsize_G, poBand[BandChoiceG]->GetRasterDataType(), 0, 0);
poBand[BandChoiceB]->RasterIO(GF_Read, 0, 0, nXsize_B, nYsize_B, poBandBlock_B, nXsize_B, nYsize_B, poBand[BandChoiceB]->GetRasterDataType(), 0, 0);
delete poDataset;
}
if (BandChoice == 1)
{
for ( int i=0; i < Height; i++)
{
for ( int j=0; j < Width; j++)
{
pData[(Height-i-1) * LineBytes + j] = poBandBlock_Gray[i*Width + j];
}
}
CPLFree(poBandBlock_Gray);
}
else
{
int j2 ;
for ( int i=0; i<Height; i++)
{
for ( int j=0, j2=0; j < Width, j2 < 3 * Width; j++, j2+=3)
{
pData[(Height-i-1)*LineBytes + j2+2] = poBandBlock_R[i*Width + j];
pData[(Height-i-1)*LineBytes + j2+1] = poBandBlock_G[i*Width + j];
pData[(Height-i-1)*LineBytes + j2] = poBandBlock_B[i*Width + j];
}
}
CPLFree(poBandBlock_B);
CPLFree(poBandBlock_R);
CPLFree(poBandBlock_G);
}
// allocate a texture name
glGenTextures( 1, &texture );
// select our current texture
glBindTexture( GL_TEXTURE_2D, texture );
// select modulate to mix texture with color for shading
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// when texture area is small, bilinear filter the closest mipmap
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST );
// when texture area is large, bilinear filter the first mipmap
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// if wrap is true, the texture wraps over at the edges (repeat)
// ... false, the texture ends at the edges (clamp)
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, FALSE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, FALSE );
// build our texture mipmaps
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, pData );
// free buffer
free( pData );
return texture;
}
This is the Draw function:
void COpenGLControl::OnDraw(CDC *pDC)
{
// TODO: Camera controls
wglMakeCurrent(hdc,hrc);
// Set color to use when clearing the background.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
// Turn on backface culling
glFrontFace(GL_CCW);
glCullFace(GL_FRONT_AND_BACK);
// Turn on depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear all objects
glEnable( GL_TEXTURE_2D ); // enable texture for 2 dimensions
glPushMatrix();
if (filename.IsEmpty() == false)
{
imgData = ReadGDALData( filename );
glBindTexture( GL_TEXTURE_2D, imgData );
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear all objects
glLoadIdentity ();
gluLookAt (0,0,1,0,0,0,0,1,0);
glTranslatef (m_fPosX, m_fPosY, 0.0f);
glScalef (m_fZoom,m_fZoom,1.0);
glBegin( GL_QUADS ); // apply loaded texture to viewport
glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0);
glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0);
glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
glEnd();
}
glPopMatrix();
glDisable( GL_TEXTURE_2D );
glFlush();
// Swap buffers
SwapBuffers(hdc);
wglMakeCurrent(NULL, NULL);
}
The problem is not so much in the color, but (from what I can tell from the sample) in the way your data is packed. Look into what byte ordering / row padding / color packing your OpenGL buffer expects, and in your GDAL loader what it provides. Just a hunch here, but it seems like your OpenGL expects a 4th (alpha) component in your RGB structs, but your GDAL code doesn't supply that. Also your GDAL loader aligns on 32 bit boundaries it seems, check if your OpenGL texture calls require that, too. Did you copy/paste the GDAL loader from a sample where somebody uses it to draw with BitBlt()? It looks that way.

Tile Map Usage Much CPU With OpenGL and SDL

I been working in a method to draw a map based on tiles with OpenGL and SDL. And I finally coded but when I execute the basic program where it draw a tile map of 25x16, and I check the use of CPU, it says that consume 25% but without drawing the map consume by much 1% of CPU.
So exists another method to draw the map or why is the use of CPU so high.
This is the code for drawing the map.
void CMapManager::drawMap(Map *map)
{
vector<ImagePtr> tempImages = CGameApplication::getInstance()->getGameApp()->getImages();
GLuint texture = tempImages.at(1)->getTexture();
glColor3f(1.0f, 1.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture( GL_TEXTURE_2D, texture );
glBegin( GL_QUADS );
for (int i = 0; i < map->getHeight(); i++)
{
for (int j = 0; j < map->getWidth(); j++)
{
ImagePtr imgDraw = tempImages.at(map->getMapTiles()[i][j]->getTypeTile());
glTexCoord2i( 0, 0 );
glVertex3f( imgDraw->getPosX() + (imgDraw->getWidth()*j), imgDraw->getPosY() + (imgDraw->getHeight()*i), 0.f );
//Bottom-left vertex (corner)
glTexCoord2i( 1, 0 );
glVertex3f( imgDraw->getOffsetX() + (imgDraw->getWidth()*j), imgDraw->getPosY() + (imgDraw->getHeight()*i), 0.f );
//Bottom-right vertex (corner)
glTexCoord2i( 1, 1 );
glVertex3f( imgDraw->getOffsetX() + (imgDraw->getWidth()*j), imgDraw->getOffsetY() + (imgDraw->getHeight()*i), 0.f );
//Top-right vertex (corner)
glTexCoord2i( 0, 1 );
glVertex3f( imgDraw->getPosX() + (imgDraw->getWidth()*j), imgDraw->getOffsetY() + (imgDraw->getHeight()*i), 0.f );
}
}
glEnd();
glDisable(GL_BLEND);
}
And in this method I call the function:
void CGameApplication::renderApplication()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glEnable(GL_TEXTURE_2D);
vector<ImagePtr> tempImages = GApp->getImages();
vector<ImagePtr>::iterator iterImage;
for (iterImage = tempImages.begin(); iterImage != tempImages.end(); ++iterImage)
{
CImageM->drawSprites( (*iterImage)->getTexture(), (*iterImage)->getPosX(), (*iterImage)->getPosY(),
(*iterImage)->getOffsetX(), (*iterImage)->getOffsetY() );
}
vector<TextPtr> tempTexts = GApp->getTexts();
vector<TextPtr>::iterator iterText;
for (iterText = tempTexts.begin(); iterText != tempTexts.end(); ++iterText)
{
CTextM->drawFonts( (*iterText) );
}
CMapM->drawMap(GApp->getCurrentMap());
glDisable(GL_TEXTURE_2D);
}
I already set a Timer that after this function:
GameApplication->getCKeyboardHandler()->inputLogic();
GameApplication->renderApplication();
SDL_GL_SwapBuffers();
GameApplication->getGameApp()->getTimer()->delay();
And the delay function is:
void Timer::delay()
{
if( this->getTicks() < 1000 / FRAMES_PER_SECOND )
{
SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - this->getTicks() );
}
}
The const FRAMES_PER_SECOND it's 5 in this moment.
And the function for convert image to GL texture is:
GLuint CImageManager::imageToGLTexture(std::string name)
{
GLuint texture;
SDL_Surface *surface;
GLenum texture_format;
GLint nOfColors;
if ( (surface = IMG_Load(name.c_str())) ) {
// Check that the image's width is a power of 2
if ( (surface->w & (surface->w - 1)) != 0 ) {
printf("warning: image.bmp's width is not a power of 2\n");
}
// Also check if the height is a power of 2
if ( (surface->h & (surface->h - 1)) != 0 ) {
printf("warning: image.bmp's height is not a power of 2\n");
}
// get the number of channels in the SDL surface
nOfColors = surface->format->BytesPerPixel;
if (nOfColors == 4) // contains an alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA_EXT;
}
else if (nOfColors == 3) // no alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR_EXT;
}
else {
printf("warning: the image is not truecolor.. this will probably break\n");
// this error should not go unhandled
}
SDL_SetAlpha(surface, 0, 0);
// Have OpenGL generate a texture object handle for us
glGenTextures( 1, &texture );
// Bind the texture object
glBindTexture( GL_TEXTURE_2D, texture );
// Set the texture's stretching properties
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// Edit the texture object's image data using the information SDL_Surface gives us
glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0,
texture_format, GL_UNSIGNED_BYTE, surface->pixels );
}
else {
printf("SDL could not load the image: %s\n", SDL_GetError());
SDL_Quit();
exit(1);
}
if ( surface ) {
SDL_FreeSurface( surface );
}
return texture;
}
Thanks before hand for the help.
After all, avoid state changes. Combine all your tiles into one texture and render using only one glBegin/glEnd block.
If you don't want to make many changes try display lists. OpenGL will be able to optimize your calls but there is no guarantee it will run much faster.
If your map doesn't change a lot use VBOs. It's the fastest way.

SDL Surface Pixel Format Conversion

I want to convert an SDL_Surface, which was loaded by IMG_Load() to an other pixel format (rgba8) for an OpenGL Texture. How can I do that?
I've read about SDL_ConvertSurface() in the documentation, but I can't figure out, how to put it together.
Give "How To Load an OpenGL Texture from an SDL_Surface" a shot:
GLuint texture; // This is a handle to our texture object
SDL_Surface *surface; // This surface will tell us the details of the image
GLenum texture_format;
GLint nOfColors;
if( (surface = SDL_LoadBMP("image.bmp")) )
{
// Check that the image's width is a power of 2
if( (surface->w & (surface->w - 1)) != 0 )
{
printf("warning: image.bmp's width is not a power of 2\n");
}
// Also check if the height is a power of 2
if( (surface->h & (surface->h - 1)) != 0 )
{
printf("warning: image.bmp's height is not a power of 2\n");
}
// get the number of channels in the SDL surface
nOfColors = surface->format->BytesPerPixel;
if( nOfColors == 4 ) // contains an alpha channel
{
if(surface->format->Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA;
}
else if( nOfColors == 3 ) // no alpha channel
{
if(surface->format->Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR;
}
else
{
printf("warning: the image is not truecolor.. this will probably break\n");
// this error should not go unhandled
}
// Have OpenGL generate a texture object handle for us
glGenTextures( 1, &texture );
// Bind the texture object
glBindTexture( GL_TEXTURE_2D, texture );
// Set the texture's stretching properties
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// Edit the texture object's image data using the information SDL_Surface gives us
glTexImage2D
(
GL_TEXTURE_2D,
0,
nOfColors,
surface->w,
surface->h,
0,
texture_format,
GL_UNSIGNED_BYTE,
surface->pixels
);
}
else
{
printf("SDL could not load image.bmp: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
// Free the SDL_Surface only if it was successfully created
if( surface )
{
SDL_FreeSurface( surface );
}