Load image with GDAL Libraries (VC++) - c++

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.

Related

SDL_TTF rendering garbage to texture

I am attempting to use OpenGL and SDL, using SDL_ttf to render text to a texture, but the code is rendering garbage.
My "Render to texture code":
GLuint textToTexture(std::string & text, TTF_Font* font, glm::vec4 textColour, glm::vec4 bgColour)
{
if (!TTF_WasInit())
{
if (TTF_Init() == -1)
exit(6);
}
SDL_Color colour = { (Uint8)(textColour.r*255), (Uint8)(textColour.g*255), (Uint8)(textColour.b*255), (Uint8)(textColour.a*255) };
SDL_Color bg = { (Uint8)(bgColour.r*255), (Uint8)(bgColour.g*255), (Uint8)(bgColour.b*255), (Uint8)(bgColour.a*255) };
SDL_Surface *stringImage = NULL;
stringImage = TTF_RenderText_Blended(font, text.c_str(), colour);
if (stringImage == NULL)
{
exit(5);
}
GLuint trueH = powerofTwo(stringImage->h);
GLuint trueW = powerofTwo(stringImage->w);
unsigned char* pixels = NULL;
GLuint w = stringImage->w;
GLuint h = stringImage->h;
GLuint colours = stringImage->format->BytesPerPixel;
pixels = padTexture((unsigned char*)stringImage->pixels, w, h, pixels, trueW, trueH, colours);
GLuint format, internalFormat;
if (colours == 4) {
if (stringImage->format->Rmask == 0x000000ff)
format = GL_RGBA;
else
format = GL_BGRA;
}
else {
// no alpha
if (stringImage->format->Rmask == 0x000000ff)
format = GL_RGB;
else
format = GL_BGR;
}
internalFormat = (colours == 4) ? GL_RGBA : GL_RGB;
GLuint texId = 0;
//GLuint texture;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueW, trueH, 0,format, GL_UNSIGNED_BYTE, pixels);
// SDL surface was used to generate the texture but is no longer
// required. Release it to free memory
SDL_FreeSurface(stringImage);
free(pixels)
return texId;
}
The code for computing the correct dimensions for padding:
int powerofTwo(int num)
{
if (num != 0)
{
num--;
num |= num >> 1; // Divide by 2^k for consecutive doublings of k up to 32,
num |= num >> 2; // and then or the results.
num |= num >> 4;
num |= num >> 8;
num |= num >> 16;
num++;
}
return num;
}
and finally, the code that copies the bytes to a texture of the correct dimensions:
unsigned char* padTexture(unsigned char * src, int srcW, int srcH, unsigned char * dest, int width, int height, int bpp)
{
dest = (unsigned char*)calloc(1, width*height*bpp);
for (int i = 0; i < srcH; i++)
{
memcpy(dest + (width*i*bpp),src + (srcW*i*bpp), srcW*bpp);
}
return dest;
}
The result of this code is as follows: [![Garbled Texture][1]][1]
I have confirmed and error checked that SDL_TTF is properly initialized elsewhere in the codebase, and that the font is also being loaded.
I have tested with three different ttf fonts, with the same results.
Also, if I use any other TTF_rendering function (Shaded, Solid etc), A solid quad is rendered, and the "colours" variable in the textToTexture function also ends up as 1.
Additional:
As I previously stated, I tested with three ttf fonts:
MavenPro-Regular,
HelveticaNeueLTStd-Th
and another I found off the internet.
I was trying to render the string "Select Scenario".
The pre padded image dimensions are 138x25 pixels.
The post padded image dimensions are 256x32 pixels.
Update 1:
After fixing the bpp issue the new texture is as follows:
This image changes everytime I run the program.
Update 2:
After fixing the additional spotted errors with padding the image, and setting the pixel data to the texture itself, when I use TTF_RenderText_Blended all I get is a black quad, and when I use TTF_RenderText_Shaded I get:
Update 3:
I used SDL_SaveBMP immedietly before calling the GL code and after calling SDL_RenderText_Blended, the result was a completely white image, (given which text colour).
When I do the same using TTF_RenderText_Solid, The saved image is as it should be, but is rendered by opengl like the images you see above.
SDL_TTF initialized fine, the fonts load without error, and the text rendering returns no errors, so I can't think what to do next.
Update 4:
I have since refactored all the ttf code into a single function and removed the padding code (as modern opengl doesn't seem to care about it). However, despite all project settings and code now being identical to a test project that is known to work on the same hardware, the problem persists.
GLuint textToTexture(const char * text, const char * font, glm::vec4 textColour, glm::vec4 bgColour, unsigned int & texID)
{
if (!TTF_WasInit()) {
if (TTF_Init() == -1)
exit(6);
}
SDL_Color colour = { (Uint8)(textColour.r * 255), (Uint8)(textColour.g * 255), (Uint8)(textColour.b * 255),(Uint8)(textColour.a * 255) };
SDL_Color bg = { (Uint8)(bgColour.r * 255), (Uint8)(bgColour.g * 255), (Uint8)(bgColour.b * 255),255 };
TTF_Font* fontObj = TTF_OpenFont(font, 24);
if (!fontObj)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
"Texture Error",
"Cannot load font to create texture.",
NULL);
return 0;
}
SDL_Surface *image = NULL;
image = TTF_RenderText_Blended(fontObj, text, colour);
if (image == NULL)
{
exit(5);
//exitFatalError("String surface not created.");
std::cout << "String surface not created." << std::endl;
}
unsigned char* pixels = NULL;
GLuint w = image->w;
GLuint h = image->h;
GLuint colours = image->format->BytesPerPixel;
GLuint externalFormat, internalFormat;
SDL_PixelFormat *format = image->format;
if (colours == 4) {
if (image->format->Rmask == 0x000000ff)
externalFormat = GL_RGBA;
else
externalFormat = GL_BGRA;
}
else {
// no alpha
if (image->format->Rmask == 0x000000ff)
externalFormat = GL_RGB;
else
externalFormat = GL_BGR;
}
internalFormat = (colours == 4) ? GL_RGBA : GL_RGB;
GLuint texId = 0;
//GLuint texture;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, externalFormat, GL_UNSIGNED_BYTE, image->pixels);
//glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueW, trueH, 0, externalFormat, GL_UNSIGNED_BYTE, pixels);
glGenerateMipmap(GL_TEXTURE_2D);
//// SDL surface was used to generate the texture but is no longer
//// required. Release it to free memory
SDL_FreeSurface(image);
TTF_CloseFont(fontObj);
return texID;
}
I have a workaround that saves the image to bmp, then reloads it and creates a texture, but only when I use TTF_RenderText_Shaded. If I use TTF_RenderText_Blended, I get an single colour image which corresponds to the text colour.
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueH, trueW, 0,format, GL_UNSIGNED_BYTE, pixels);
trueH and trueW order is reversed
memcpy(src + (srcW*i*bpp), dest + (width*i*bpp), srcW*bpp);
Source and destination order reversed.
dest = (unsigned char*)calloc(0, width*height*bpp);
0 elements of size width*height*bpp allocated, which is 0 bytes. Should be 1 instead of 0.
Here is a complete example:
#include <SDL2/SDL.h>
#include <GL/gl.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static unsigned char* padTexture(unsigned char * src, int srcW, int srcH, unsigned char * dest, int width, int height, int bpp, const SDL_Palette *palette)
{
int dst_bpp = (bpp == 1) ? 4 : bpp;
dest = (unsigned char*)calloc(1, width*height*dst_bpp);
if(bpp != 1) {
for (int i = 0; i < srcH; i++)
{
memcpy(dest + (width*i*bpp), src + (srcW*i*bpp), srcW*bpp);
}
} else {
/* indexed - read colours from palette */
for(int i = 0; i < srcH; i++) {
for(int j = 0; j < srcW; j++) {
memcpy(dest + (width*i+j)*dst_bpp,
&palette->colors[src[srcW*i+j]], sizeof(SDL_Color));
}
}
}
return dest;
}
static int powerofTwo(int num) {
if (num != 0)
{
num--;
num |= num >> 1; // Divide by 2^k for consecutive doublings of k up to 32,
num |= num >> 2; // and then or the results.
num |= num >> 4;
num |= num >> 8;
num |= num >> 16;
num++;
}
return num;
}
static GLuint textToTexture(const char *text, TTF_Font* font) {
if (!TTF_WasInit()) {
if (TTF_Init() == -1)
exit(6);
}
SDL_Color colour = { 255, 255, 255, 255 };
SDL_Color bg = { 0, 0, 0, 255 };
SDL_Surface *stringImage = NULL;
// stringImage = TTF_RenderText_Blended(font, text, colour);
stringImage = TTF_RenderText_Shaded(font, text, colour, bg);
if (stringImage == NULL) {
exit(5);
}
GLuint trueH = powerofTwo(stringImage->h);
GLuint trueW = powerofTwo(stringImage->w);
unsigned char* pixels = NULL;
GLuint w = stringImage->w;
GLuint h = stringImage->h;
GLuint colours = stringImage->format->BytesPerPixel;
pixels = padTexture((unsigned char*)stringImage->pixels, w, h, pixels, trueW, trueH,
colours, stringImage->format->palette);
GLuint format, internalFormat;
/* If indexed, want resulting image to be 32bit */
if(colours == 1) {
colours = 4;
}
if (colours == 4) {
if (stringImage->format->Rmask == 0x000000ff)
format = GL_RGBA;
else
format = GL_BGRA;
}
else {
// no alpha
if (stringImage->format->Rmask == 0x000000ff)
format = GL_RGB;
else
format = GL_BGR;
}
internalFormat = (colours == 4) ? GL_RGBA : GL_RGB;
GLuint texId = 0;
//GLuint texture;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, trueW, trueH, 0,format, GL_UNSIGNED_BYTE, pixels);
// SDL surface was used to generate the texture but is no longer
// required. Release it to free memory
SDL_FreeSurface(stringImage);
free(pixels);
return texId;
}
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
SDL_Window *window = SDL_CreateWindow("SDL2 Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 600, 400, SDL_WINDOW_OPENGL);
SDL_GLContext gl_ctx = SDL_GL_CreateContext(window);
TTF_Font *font = TTF_OpenFont(".fonts/tahoma.ttf", 16);
if(font) {
printf("font loaded\n");
textToTexture("Select Scenario", font);
TTF_CloseFont(font);
}
int quit = 0;
while(!quit) {
SDL_Event ev;
while(SDL_PollEvent(&ev)) {
if(ev.type == SDL_QUIT || ev.type == SDL_KEYUP) {
quit = 1;
}
}
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0, 1);
glVertex2f(-0.5, -0.5);
glTexCoord2f(0, 0);
glVertex2f(-0.5, 0.5);
glTexCoord2f(1, 0);
glVertex2f(0.5, 0.5);
glTexCoord2f(1, 1);
glVertex2f(0.5, -0.5);
glEnd();
glFlush();
SDL_GL_SwapWindow(window);
}
SDL_GL_DeleteContext(gl_ctx);
SDL_DestroyWindow(window);
TTF_Quit();
SDL_Quit();
return 0;
}

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

OpenGL Applying Texture to Tessellation

I'm trying to take a concave polygon and apply an image to it as a texture. The polygon can have multiple contours, both internal holes and external "islands". It can be any shape, but will be smaller than the image and will fit inside it. It does not necessarily touch the edges of the image.
I've successfully displayed the tessellated polygon, and textured a simple square, but can't get the two to work together.
Here's how I'm loading the texture:
GLuint texture;
int width, height;
BYTE * data;
FILE * file;
// open texture data
file = fopen( filename, "rb" );
if ( file == NULL ) return 0;
// allocate buffer
width = 256;
height = 256;
data = (BYTE *)malloc( width * height * 3 );
// read texture data
fread( data, width * height * 3, 1, file );
fclose( file );
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap ? GL_REPEAT : GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap ? GL_REPEAT : GL_CLAMP );
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width,height, GL_RGB, GL_UNSIGNED_BYTE, data );
free( data );
return texture;
Here's the tessellation function:
GLuint tessellate1()
{
GLuint id = glGenLists(1); // create a display list
if(!id) return id; // failed to create a list, return 0
GLUtesselator *tess = gluNewTess(); // create a tessellator
if(!tess) return 0; // failed to create tessellation object, return 0
GLdouble quad1[4][3] = { {-1,3,0}, {0,0,0}, {1,3,0}, {0,2,0} };
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GLTexture::LoadTextureRAW("texture.raw", true));
// register callback functions
gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK *)())tessBeginCB);
gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK *)())tessEndCB);
gluTessCallback(tess, GLU_TESS_ERROR, (void (CALLBACK *)())tessErrorCB);
gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK *)())tessVertexCB);
glNewList(id, GL_COMPILE);
glColor3f(1,1,1);
gluTessBeginPolygon(tess, 0); // with NULL data
gluTessBeginContour(tess);
gluTessVertex(tess, quad1[0], quad1[0]);
gluTessVertex(tess, quad1[1], quad1[1]);
gluTessVertex(tess, quad1[2], quad1[2]);
gluTessVertex(tess, quad1[3], quad1[3]);
gluTessEndContour(tess);
gluTessEndPolygon(tess);
glEndList();
gluDeleteTess(tess); // delete after tessellation
glDisable(GL_TEXTURE_2D);
setCamera(0, 0, 5, 0, 0, 0);
return id; // return handle ID of a display list
}
Here's the tessellation vertex callback function:
// cast back to double type
const GLdouble *ptr = (const GLdouble*)data;
double dImageX = -1, dImageY = -1;
//hardcoded extents of the polygon for the purposes of testing
int minX = 607011, maxX = 616590;
int minY = 4918219, maxY = 4923933;
//get the % coord of the texture for a poly vertex. Assumes image and poly bounds are the same for the purposes of testing
dImageX = (ptr[0] - minX) / (maxX - minX);
dImageY = (ptr[1] - minY) / (maxY - minY);
glTexCoord2d(dImageX, dImageY);
glVertex2d(ptr[0], ptr[1]);
And here's the display callback:
void displayCB()
{
// clear buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// save the initial ModelView matrix before modifying ModelView matrix
glPushMatrix();
// tramsform camera
glTranslatef(0, 0, cameraDistance);
glRotatef(cameraAngleX, 1, 0, 0); // pitch
glRotatef(cameraAngleY, 0, 1, 0); // heading
// draw meshes
glCallList(listId1); //id of the tessellated poly
// draw info messages
showInfo();
glPopMatrix();
glutSwapBuffers();
}
The results of this are a correctly drawn polygon with no texture applied.
// init
glGenTextures( 1, &texture );
// vertex callback
glBindTexture(GL_TEXTURE_2D, 1);
I don't think the first ID returned by glGenTextures() is required to be 1.
Try using texture instead of 1 in your glBindTexture() call.
Also, there's really no reason to enable texturing and re-bind the texture for every vertex. Just do it once before you call into the tesselator.
You're not capturing the texture binding and Enable inside the display list, so it's not going to be taken into account when you replay it. So, either:
Capture the BindTexture and Enable inside the display list, or
BindTexture and Enable(TEXTURE_2D) before calling CallList
The problem was the glDisable(GL_TEXTURE_2D) call in the tessellation function. After removing it, the texture was applied correctly.

Open GL texturing , texture coordinates are incorrect to what is rendered

I'm rendering a scene using opengl with textures loaded using some sample code and the FreeImage API.
Here is a link to what i'm seeing
[Image Removed]
I can confirm that all texture coordinates are provided to glTexCoord2f between 0.0f and 1.0f as required along with the vertex coordinates.
Each of the rendered triangles appears to have the full texture pasted across it (and repeated) not the area of the texture specified by the coordinates.
The texture is 1024x1024.
This is the function for loading the texture
bool loadImageToTexture(const char* image_path, unsigned int &handle)
{
if(!image_path)
return false;
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
FIBITMAP* dib(0);
BYTE* bits(0);
unsigned int width(0), height(0);
//open the file
fif = FreeImage_GetFileType(image_path, 0);
if(fif == FIF_UNKNOWN)
fif = FreeImage_GetFIFFromFilename(image_path);
if(fif == FIF_UNKNOWN)
return false;
if(FreeImage_FIFSupportsReading(fif))
dib = FreeImage_Load(fif, image_path);
if(!dib)
return false;
//is the file of the correct type
FREE_IMAGE_COLOR_TYPE type = FreeImage_GetColorType(dib);
if(FIC_RGBALPHA != type)
{
//convert to type
FIBITMAP* ndib = FreeImage_ConvertTo32Bits(dib);
dib = ndib;
}
//get data for glTexImage2D
bits = FreeImage_GetBits(dib);
width = FreeImage_GetWidth(dib);
height = FreeImage_GetHeight(dib);
if((bits == 0) || (width == 0) || (height == 0))
return false;
//create the texture in open gl
glGenTextures(1, &handle);
glBindTexture(GL_TEXTURE_2D, handle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glPixelStorei(GL_TEXTURE_2D, 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, bits);
//unload the image now loaded
FreeImage_Unload(dib);
return true;
}
These are the functions for rendering
inline void glTexture(float textureSize, float t, float u)
{
glTexCoord2f(u/textureSize, (textureSize - t)/textureSize);
}
void processTriangle(const btVector3* triangle, const textureCoord* tc, const btVector3& normal,
const int partId, const int triangleIndex, const bool wireframe)
{
if(wireframe)
{
glBegin(GL_LINES);
glColor3f(1, 0, 0);
glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ());
glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ());
glColor3f(0, 1, 0);
glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ());
glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ());
glColor3f(0, 0, 1);
glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ());
glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ());
glEnd();
}
else
{
glBegin(GL_TRIANGLES);
glColor3f(1, 1, 1);
//Normals are per triangle
glNormal3f(normal.getX(), normal.getY(), normal.getZ());
glTexture(1024.0f, tc[0].t, tc[0].u);
glVertex3d(triangle[0].getX(), triangle[0].getY(), triangle[0].getZ());
glTexture(1024.0f, tc[1].t, tc[1].u);
glVertex3d(triangle[1].getX(), triangle[1].getY(), triangle[1].getZ());
glTexture(1024.0f, tc[2].t, tc[2].u);
glVertex3d(triangle[2].getX(), triangle[2].getY(), triangle[2].getZ());
glEnd();
}
}
void processAllTriangles(const btVector3& worldBoundsMin, const btVector3& worldBoundsMax)
{
btVector3 triangle[3];
textureCoord tc[3];
//go through the index list build triangles and draw them
unsigned int k = 0;
for(unsigned int i = 0; i<dVertices.size(); i+=3, k++)
{
//first vertex
triangle[0] = dVertices[i];
tc[0] = dTexCoords[i];
//second vertex
triangle[1] = dVertices[i+1];
tc[1] = dTexCoords[i+1];
//third vertex
triangle[2] = dVertices[i+2];
tc[2] = dTexCoords[i+2];
processTriangle(triangle, tc, dNormals[k], 0, 0, false);
}
}
//draw the world given the players position
void render(btScalar* m, const btCollisionShape* shape, const btVector3& color, int debugMode,
const btVector3& worldBoundsMin, const btVector3& worldBoundsMax)
{
//render the world using the generated OpenGL lists
//enable and specify pointers to vertex arrays
glPushMatrix();
glMultMatrixf(m);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, m_texturehandle);
processAllTriangles(worldBoundsMin, worldBoundsMax);
glPopMatrix();
}
I'm working in a larger code base and texturing is being done differently in different areas mean state from those other textured objects was not being disabled.
Before per vertex texturing is done make sure to turn off other varieties of texturing.
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);

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.