lugre_texatlas.cpp

Go to the documentation of this file.
00001 #include "lugre_prefix.h"
00002 #include "lugre_texatlas.h"
00003 #include <stdlib.h>
00004 #include <Ogre.h>
00005 
00006 
00007 
00008 namespace Lugre {
00009 
00010 // see also  http://www.ogre3d.org/phpBB2/viewtopic.php?t=29905
00011 // see also  http://www.ogre3d.org/phpBB2/viewtopic.php?t=37999
00012 // ***** ***** ***** ***** ***** cTexAtlas
00013     
00014 cTexAtlas::cTexAtlas        (const int iW,const int iH, const int iMaxSubW, const int iMaxSubH) 
00015         : miW(iW), miH(iH), miMaxSubW(iMaxSubW), miMaxSubH(iMaxSubH), miMinFreeSpaceSize(8) {
00016             
00017     miFormat = Ogre::PF_BYTE_RGBA; // Ogre::PF_BYTE_BGRA;
00018     // Ogre::Root::getSingleton().getRenderSystem()->getColourVertexElementType() Dx:VET_COLOUR_ARGB Ogl:VET_COLOUR_ABGR 
00019     mData.resize(miW*miH,0);
00020 
00021     miCurrentLineH = -1;
00022     miBrushX = 0;
00023     miBrushY = 0;
00024             
00025     // printf("cTexAtlas(%d,%d,%d,%d)\n",miW,miH,miMaxSubW,miMaxSubH);
00026 }
00027 
00028 bool                cTexAtlas::AddImage     (Ogre::Image& pSrc,Ogre::Rectangle& pOutTexCoords,const int iBorderPixels,const bool bWrap) {
00029     // request an area in the atlas big enough to fit including border 
00030     int w = pSrc.getWidth();
00031     int h = pSrc.getHeight();
00032     int e = iBorderPixels;
00033     int wb = e + w + e;
00034     int hb = e + h + e;
00035     int l,r,t,b;
00036     bool bOk = RequestArea(wb,hb,l,r,t,b); // outrect is in pixel-coordinates here
00037     
00038     // printf("AddImage(%d,%d,%d,%d,%d,%d)\n",wb,hb,l,r,t,b);
00039     
00040     if (!bOk) return false; // not enough space left
00041     
00042     // we've got an area, now draw image and border
00043     for (int y=t;y<b;++y)
00044     for (int x=l;x<r;++x) {
00045         int src_x = x-l-e;
00046         int src_y = y-t-e;
00047         if (bWrap) {
00048             while (src_x < 0) src_x += w;
00049             while (src_y < 0) src_y += h;
00050             src_x = src_x % w;
00051             src_y = src_y % h;
00052         } else { // clamped
00053             src_x = mymax(0,mymin(w-1,src_x)); 
00054             src_y = mymax(0,mymin(h-1,src_y));
00055         }
00056         Ogre::ColourValue src_col = pSrc.getColourAt(src_x,src_y,0); // read from source
00057         Ogre::PixelUtil::packColour(src_col,miFormat,GetPixelPointer(x,y)); // write to buffer
00058     }
00059     
00060     // transform outrect from pixels to texcoords
00061     pOutTexCoords.left   = (l  +e) / float(miW);
00062     pOutTexCoords.right  = (l+w+e) / float(miW);
00063     pOutTexCoords.top    = (t  +e) / float(miH);
00064     pOutTexCoords.bottom = (t+h+e) / float(miH);
00065     return true;
00066 }
00067 
00068 // mainly for debugging purpose
00069 void    cTexAtlas::FillRect(const int x, const int y, const int w, const int h, const float r, const float g, const float b, const float a){
00070     Ogre::ColourValue c(r,g,b,a);
00071 
00072     for (int yy=y;yy<y+h;++yy)
00073     for (int xx=x;xx<x+w;++xx) {
00074         int d_x = mymax(0,mymin(miW-1,xx)); // clamped
00075         int d_y = mymax(0,mymin(miH-1,yy)); // clamped
00076         Ogre::PixelUtil::packColour(c,miFormat,GetPixelPointer(d_x,d_y)); // write to buffer
00077     }
00078     
00079 }
00080 
00081 
00082 Ogre::TexturePtr    cTexAtlas::MakeTexture  (const Ogre::String &name, const Ogre::String &group) {
00083     Ogre::DataStreamPtr buf; // For auto-delete, as in Ogre::Image::scale
00084     buf.bind(new Ogre::MemoryDataStream(GetBasePointer(),Ogre::PixelUtil::getMemorySize(miW,miH,1,miFormat)));
00085     return Ogre::TextureManager::getSingleton().loadRawData(name,group,buf,miW,miH,miFormat);
00086 }
00087 
00088 void    cTexAtlas::MakeImage    (Ogre::Image& pDest) {
00089     
00090     Ogre::uchar* buf = (Ogre::uchar*)OGRE_MALLOC(GetBufferSize(), Ogre::MEMCATEGORY_GENERAL);
00091     memcpy(buf,GetBasePointer(),GetBufferSize()); // copy buffer so that the image is still valid after the texatlas is destroyed
00092 
00093     pDest.loadDynamicImage(buf,miW,miH,1,miFormat,true); // autoDelete
00094 }
00095 
00096 
00097 void    cTexAtlas::MarkAsFreeSpace(const int x,const int y,const int w,const int h){
00098     // skip too small spaces
00099     if(w < miMinFreeSpaceSize || h < miMinFreeSpaceSize)return;
00100         
00101     // printf("MarkAsFreeSpace(%d,%d,%d,%d)\n",x,y,w,h);
00102     
00103     cFreeSpaceCell c(x,y,w,h);
00104     mlFreeSpace.push_back(c);
00105 
00106     // FillRect(c.x,c.y,c.w,c.h,1.0,0.0,0.0,1.0);
00107     // FillRect(c.x+1,c.y+1,c.w-2,c.h-2,0.5,0.5,0.5,1.0);
00108 }
00109 
00110 bool    cTexAtlas::RequestArea      (const int w,const int h,int& l,int& r,int& t,int& b) {
00111     // printf("RequestArea(%d,%d)\n",w,h);
00112     
00113     // is there a free space big enough to store this?
00114     for (std::list<cFreeSpaceCell>::iterator itor=mlFreeSpace.begin();itor!=mlFreeSpace.end();++itor){
00115         if((*itor).w >= w && (*itor).h >= h){
00116             // printf("use free space!!!!!!!!!\n");
00117             // enough space
00118 
00119             // assign space
00120             l = (*itor).x;
00121             t = (*itor).y;
00122             r = l+w;
00123             b = t+h;
00124             
00125 
00126             // mark remaining space as free
00127             // below the image
00128             MarkAsFreeSpace(l,b,w,(*itor).h-h);
00129             MarkAsFreeSpace(r,t,(*itor).w-w,(*itor).h);
00130 
00131             // remove freespace
00132             mlFreeSpace.erase(itor);
00133             
00134             return true;
00135         }
00136     }
00137     
00138     // oki there is not freespace big enough
00139     // so paint in at the brush
00140     
00141     // remaining unused pixels
00142     int restw = miW - miBrushX;
00143     int resth = miH - miBrushY;
00144     
00145     // printf("no freespace found, %d %d %d %d %d %d %d\n",w,h,miBrushX,miBrushY,restw,resth,miW,miH);
00146     
00147     // is there enough space in the atlas?
00148     if(h > resth){
00149         // oki this image will never fit
00150         // printf("not enough space left!!\n");
00151         return false;
00152     }
00153     
00154     // is there enough space in the line?
00155     if(w <= restw && ((miCurrentLineH < 0) || (h <= miCurrentLineH))){
00156         // printf("add to line\n");
00157 
00158         // add this to the line
00159         
00160         // is this the first in line?
00161         if(miCurrentLineH < 0){
00162             // set line height
00163             miCurrentLineH = h;
00164         }
00165         
00166         // assign space
00167         l = miBrushX;
00168         t = miBrushY;
00169         r = l+w;
00170         b = t+h;
00171 
00172         // add unused space in this block as freespace
00173         MarkAsFreeSpace(miBrushX,miBrushY+h,w,miCurrentLineH-h);
00174 
00175         // move brush
00176         miBrushX += w;
00177         
00178         return true;
00179     } else {
00180         // printf("next line %d,%d,%d,%d\n",miBrushX,miBrushY,restw,miCurrentLineH);
00181         
00182         // mark end of line as freespace
00183         MarkAsFreeSpace(miBrushX,miBrushY,restw,miCurrentLineH);
00184         
00185         // open next line
00186         miBrushX = 0;
00187         miBrushY += miCurrentLineH;
00188         miCurrentLineH = -1;
00189         
00190         // atlas full?
00191         if( miBrushY >= miH){
00192             // no space left for this big one
00193             // printf("FULL!!");
00194             return false;
00195         } else {
00196             // oki repeat search for a new space
00197             // printf("recursive\n");
00198             return RequestArea(w,h,l,r,t,b);
00199         }
00200     }
00201 }
00202 
00203 };

Generated on Wed May 23 06:00:15 2012 for cpp by  doxygen 1.5.6