Springs code that places all the textures on the 2048x2048 super-texture could be made more efficient. The current code sorts all textures by height (biggest first) and fills up the super-texture in horizontal scanlines. If a texture gets smaller partway down a scanline, that space is wasted. As most textures are powers of 2 in height, this results in half the height wasted for the remainder of that scanline.
If instead you work in both horizontal scanlines across the whole width of the texture and then in vertical scanlines down the height of the first texture of that scanline, you wouldn't waste so much space. Indeed you can take it a step further so that when you work down a vertical scanline, you measure its starting width and ensure that textures are again spaced horizontally to fill that sub-scanline. The only space wasted would be where textures were not sized 2^n, or there was a gap at the end of a scanline.
Here's my implementation of this, first the compare function has to be modified to sort correctly:
Code: Select all
static int CompareTatex2( const void *arg1, const void *arg2 ){
if((*(TexFile**)arg1)->tex.ysize > (*(TexFile**)arg2)->tex.ysize ||
(*(TexFile**)arg1)->tex.ysize == (*(TexFile**)arg2)->tex.ysize &&
(*(TexFile**)arg1)->tex.xsize > (*(TexFile**)arg2)->tex.xsize)
return -1;
return 1;
}
Secondly a section of the CTextureHandler constructor has to be modified:
Code: Select all
CTextureHandler::CTextureHandler()
...
int currentOffsetY=0;
int currentOffsetX=0;
int scanLineOffsetY=0;
int scanLineOffsetX=0;
int scanLineHeight=0;
int subScanLineWidth=bigTexX;
int subScanLineHeight = 0;
for(int a=0;a<numfiles;++a){
CBitmap* curtex=&texfiles[a]->tex;
// reset horizontal sub-scanline when width exceeded
if( currentOffsetX + curtex->xsize > subScanLineWidth )
{
currentOffsetX = 0;
currentOffsetY += subScanLineHeight;
subScanLineHeight = curtex->ysize;
}
// reset vertical sub-scanline when height or maximum width exceeded
if( curtex->xsize > subScanLineWidth ||
currentOffsetY + curtex->ysize > scanLineHeight )
{
scanLineOffsetX += subScanLineWidth;
subScanLineWidth = curtex->xsize;
subScanLineHeight = curtex->ysize;
currentOffsetY = 0;
}
// reset horizontal scanline when image width exceeded
if( scanLineOffsetX + subScanLineWidth > bigTexX )
{
scanLineOffsetX = 0;
scanLineOffsetY += scanLineHeight;
scanLineHeight = curtex->ysize;
}
// break when no more space left
if( scanLineOffsetY + scanLineHeight > bigTexY )
{
MessageBox(0,"To many/large unit textures","Error",0);
break;
}
for(int y=0;y<curtex->ysize;y++){
for(int x=0;x<curtex->xsize;x++){
// if(curtex->mem[(y*curtex->xsize+x)*4]==254 && curtex->mem[(y*curtex->xsize+x)*4+1]==0 && curtex->mem[(y*curtex->xsize+x)*4+2]==254){
// tex[((currentOffsetY+y)*bigTexX+(currentOffsetX+x))*4+3]=0;
// } else {
for(int col=0;col<4;col++){
tex[((currentOffsetY+y)*bigTexX+(currentOffsetX+x))*4+col]=curtex->mem[(y*curtex->xsize+x)*4+col];
// }
}
}
}
UnitTexture* unittex=new UnitTexture;
unittex->xstart=(currentOffsetX+0.5f)/(float)bigTexX;
unittex->ystart=(currentOffsetY+0.5f)/(float)bigTexY;
unittex->xend=(currentOffsetX+curtex->xsize-0.5f)/(float)bigTexX;
unittex->yend=(currentOffsetY+curtex->ysize-0.5f)/(float)bigTexY;
textures[texfiles[a]->name]=unittex;
currentOffsetX+=curtex->xsize;
delete texfiles[a];
}
...
}
I think that should work...