Edit: Updated code. Now works well enough.
Foreword. I am an OpenGL newb tasked with maintaining an app that, among other things, uses wxWidgets and OpenGL to display a variety of image formats as backgrounds for reference in overlaying user items.
The original code for displaying images broke up the image into 512x512 chunks and made textures out of them, throwing away any part of the image that didn't fit into a whole chunk. I need to change this behavior. I increased the size of the array that will hold my named textures, I handled the edge cases of my loops, wherin I set a different size subimage to grab, or I change the texture coordinates to map properly on the partial chunks.
However, build2DMipmaps pukes when I try to pass it a pointer to my subimage when my subimage doesn't have enough data to fill a 512x512 chunk. The amount of data pointed to by pointer being fed to that function is the only thing that is different on the last iteration of each column. It was my intent later to set correct texture coordinate mapping to account for less data. Why does build2dmipmaps puke? Am I using it wrong? Am I doing something somewhere else wrong?
So far, my problem is in the first set of nested for loops. when the inner loop is on its last iteration, say, htiles is 7 and y is 6, the subimage grabbed is a valid subimage (according to wxWidgets) meaning that it has data in it, but then we get to mipmaps and I get an access violation error.
Below you will find the code. Thanks in advance for your time.
int width,height,wtiles,htiles;
width=bg.GetWidth();
height=bg.GetHeight();
bgwidth = width;
bgheight = height;
wtiles=(int)floor((float)width/(float)MAX_TEX);
htiles=(int)floor((float)height/(float)MAX_TEX);
glEnable(GL_TEXTURE_2D);
//there are two types of tiles here, whole tiles and partial tiles
//wtiles and htiles are the number of whole tiles
//there is one row and one column of partial tiles
unsigned int h_error,w_error;
w_error=width % MAX_TEX;
h_error=height % MAX_TEX;
//Below, if the image dimensions break neatly into MAX_TEX chunks,
//then there is no error(leftover). This usage here allows me to take advantage
//of the logic already made. If there is error, keep it and add a tile count
//if there is not, then make MAX_TEX the default dimension for ALL texture dimensions
(w_error == 0) ? w_error = MAX_TEX : wtiles++;
(h_error == 0) ? h_error = MAX_TEX : htiles++;
ntiles=wtiles*htiles;
bgtiles=new unsigned int[ntiles];
glGenTextures(ntiles, bgtiles);
float dialogFactor = ntiles / 100.0;
//now to split the tiles out
for(int x=0;x<wtiles;x++)
for(int y=0;y<htiles;y++){
dialog.Update((int) ((x*htiles + y) / dialogFactor), "Generating Textures");
wxImage bloc=bg.GetSubImage(wxRect(x*MAX_TEX,y*MAX_TEX,
(x == wtiles-1) ? w_error : MAX_TEX,
(y == htiles-1) ? h_error : MAX_TEX
)
);
glBindTexture(GL_TEXTURE_2D, bgtiles[x+(htiles-(y+1))*wtiles]);
unsigned char *dat=(unsigned char *)bloc.GetData();
//printf("%d\n",dat[25]);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
//gluBuild2DMipmaps(GL_TEXTURE_2D,GL_COMPRESSED_RGB_ARB,
//(x == wtiles-1) ? w_error : MAX_TEX,
//(y == htiles-1) ? h_error : MAX_TEX,
//GL_RGB,GL_UNSIGNED_BYTE,(GLvoid *)dat);
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_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_ARB,
(x == wtiles-1) ? w_error : MAX_TEX,
(y == htiles-1) ? h_error : MAX_TEX,
0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)dat);
}
//marvelous, now make a simple display list to blit out the whole mess
background=glGenLists(1);//dlist made!
glNewList(background, GL_COMPILE);
glEnable(GL_TEXTURE_2D);
glColor4f(1,1,1,1);
float h_offset,w_offset;
glDisable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
{
glPushMatrix();
for(int x=0;x<wtiles;x++)
for(int y=0;y<htiles;y++){
dialog.Update((int) ((x*htiles + y) / dialogFactor), "Generating Display List");
//if(x==wtiles-1 && y==htiles-1)printf("%f %f\n",(x+1)*MAX_TEX - width *.5,(y+1)*MAX_TEX - height *.5);
glBindTexture(GL_TEXTURE_2D, bgtiles[x+(y)*wtiles]);
glBegin(GL_QUADS);
//if we are on our last column or row, adjust the texture size accordingly.
//unless the image has been divided evenly, in which case there is no need for offset.
(w_error != 0 && x == wtiles - 1) ? w_offset = MAX_TEX - w_error : w_offset = 0;
(h_error != 0 && y == 0) ? h_offset = MAX_TEX - h_error : h_offset = 0;
//apparently, if NPOTS textures are supported, their tex map coords are normalized
// aka 0-1.
//god this is an ugly mess.
//for some reason, the ordering of vertices is correct,
//but the texture coords need to be this way. It looks wrong but the program functions
//the offset garbage is to handle placement of the sections of textures that aren't a full
//MAX_TEX x MAX_TEX
//conveinently, if the image does break up into even full squares, the errors are still 0.. fuck
glTexCoord2d(0,1); glVertex3f(x*MAX_TEX - width *.5,(y*MAX_TEX - height *.5)+h_offset,0);
glTexCoord2d(1,1); glVertex3f(((x+1)*MAX_TEX - width *.5)-w_offset,(y*MAX_TEX - height *.5)+h_offset,0);
glTexCoord2d(1,0); glVertex3f(((x+1)*MAX_TEX - width *.5)-w_offset,(y+1)*MAX_TEX - height *.5,0);
glTexCoord2d(0,0); glVertex3f(x*MAX_TEX - width *.5,(y+1)*MAX_TEX - height *.5,0);
glEnd();
}
glPopMatrix();
}
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEndList();
//that's that
glDisable(GL_TEXTURE_2D);