# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

texture_dlm.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000-2002 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 #include "3d/texture_dlm.h"
00029 #include "nel/misc/common.h"
00030 #include "nel/misc/fast_mem.h"
00031 
00032 
00033 using namespace std;
00034 using namespace NLMISC;
00035 
00036 
00037 namespace NL3D 
00038 {
00039 
00040 
00041 // ***************************************************************************
00042 CTextureDLM::CTextureDLM(uint width, uint height)
00043 {
00044         nlassert(width>=NL_DLM_BLOCK_SIZE);
00045         nlassert(height>=NL_DLM_BLOCK_SIZE);
00046         nlassert(NLMISC::isPowerOf2(width));
00047         nlassert(NLMISC::isPowerOf2(height));
00048 
00049         // verify there is sufficient blocks.
00050         _WBlock= width/NL_DLM_BLOCK_SIZE;
00051         uint    nBlocks= _WBlock * (height/NL_DLM_BLOCK_SIZE);
00052         nlassert(nBlocks>=NL_DLM_LIGHTMAP_TYPE_SIZE);
00053 
00054 
00055         // The DLM texture always reside in memory...
00056         // NB: this is simplier like that, and this is not a problem, since actually only 256Ko is allocated :o)
00057         setReleasable(false);
00058         // create the bitmap.
00059         CBitmap::resize(width, height, CBitmap::RGBA);
00060         // Format of texture, 32 bits and no mipmaps.
00061         // NB: 16 bits is not a good idea, because implies lot of flicking
00062         setUploadFormat(ITexture::RGBA8888);
00063         setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff);
00064 
00065         // Fill the array of blocks.
00066         _Blocks.resize(nBlocks);
00067         _EmptyBlocks.resize(nBlocks);
00068         sint i;
00069         for(i=0;i<(sint)_Blocks.size();i++)
00070         {
00071                 // compute position of the block in the texture
00072                 _Blocks[i].PosX= (i%_WBlock) * NL_DLM_BLOCK_SIZE;
00073                 _Blocks[i].PosY= (i/_WBlock) * NL_DLM_BLOCK_SIZE;
00074 
00075                 // This block is free!!
00076                 _EmptyBlocks[i]=i;
00077         }
00078 
00079         // init list to NULL.
00080         for(i=0;i<(sint)NL_DLM_LIGHTMAP_TYPE_SIZE;i++)
00081         {
00082                 _FreeBlocks[i]= NULL;
00083         }
00084 
00085         // Since NL_DLM_BLOCK_SIZE is 10 or 18 (a factor of prime number 5 or 3 respectively), we are sure there is 
00086         // at least one pixel which is not used by blcks. The last pixel is filled with black (see CTextureDLm doc)
00087         nlassert(NL_DLM_BLOCK_SIZE==10 || NL_DLM_BLOCK_SIZE==18);
00088         CRGBA   *ptr= (CRGBA*)(&CBitmap::getPixels(0)[0]);
00089         // fill last pixel with black.
00090         ptr[width*height-1]= CRGBA::Black;
00091         // Also, to ensure the texture do not wrap around, disable Tiling.
00092         ITexture::setWrapS(ITexture::Clamp);
00093         ITexture::setWrapT(ITexture::Clamp);
00094 }
00095 
00096 
00097 // ***************************************************************************
00098 uint                            CTextureDLM::getTypeForSize(uint width, uint height)
00099 {
00100 #ifdef NL_DLM_TILE_RES
00101         nlassert(width==3 || width==5 || width==9 || width==17);
00102         nlassert(height==3 || height==5 || height==9 || height==17);
00103 #else
00104         nlassert(width==2 || width==3 || width==5 || width==9);
00105         nlassert(height==2 || height==3 || height==5 || height==9);
00106 #endif
00107 
00108         // 0 for 2, 1 for 3, 2 for 5, and 3 for 9, and 4 for 17
00109         width= getPowerOf2(width-1);
00110         height= getPowerOf2(height-1);
00111 #ifdef NL_DLM_TILE_RES
00112         // 0 for 3, 1 for 5, 2, for 9, and 3 for 17
00113         width--; height--;
00114 #endif
00115 
00116         uint id= width + height*4;
00117         nlassert(id<NL_DLM_LIGHTMAP_TYPE_SIZE);
00118 
00119         return id;
00120 }
00121 
00122 
00123 // ***************************************************************************
00124 bool                    CTextureDLM::canCreateLightMap(uint w, uint h)
00125 {
00126         // First test if the list is not empty.
00127         if(_FreeBlocks[getTypeForSize(w,h)])
00128                 return true;
00129 
00130         // If empty, test if there is an empty block.
00131         return _EmptyBlocks.size()>0;
00132 }
00133 
00134 
00135 // ***************************************************************************
00136 void                    CTextureDLM::linkFreeBlock(uint lMapType, CBlock *block)
00137 {
00138         // link me to others
00139         block->FreeNext= _FreeBlocks[lMapType];
00140         block->FreePrec= NULL;
00141         // link other to me
00142         if(_FreeBlocks[lMapType])
00143                 _FreeBlocks[lMapType]->FreePrec= block;
00144         _FreeBlocks[lMapType]= block;
00145 }
00146 
00147 // ***************************************************************************
00148 void                    CTextureDLM::unlinkFreeBlock(uint lMapType, CBlock *block)
00149 {
00150         // unlink other from me
00151         if(block->FreeNext)
00152                 block->FreeNext->FreePrec= block->FreePrec;
00153         if(block->FreePrec)
00154                 block->FreePrec->FreeNext= block->FreeNext;
00155         else
00156                 _FreeBlocks[lMapType]= block->FreeNext;
00157         // reset me
00158         block->FreePrec= NULL;
00159         block->FreeNext= NULL;
00160 }
00161 
00162 
00163 // ***************************************************************************
00164 bool                    CTextureDLM::createLightMap(uint w, uint h, uint &x, uint &y)
00165 {
00166         // at least cna create it??
00167         if(!canCreateLightMap(w, h))
00168                 return false;
00169 
00170         // the type of lightmap.
00171         uint    lMapType= getTypeForSize(w,h);
00172 
00173         // First manage case list is empty.
00174         //===================
00175         if(_FreeBlocks[lMapType]==NULL)
00176         {
00177                 // list is empty => allocate a block from _EmptyBlocks.
00178                 nlassert(_EmptyBlocks.size()>0);
00179 
00180                 // pop a block from empty list
00181                 CBlock  *block= &_Blocks[_EmptyBlocks.back()];
00182                 _EmptyBlocks.pop_back();
00183 
00184                 // init this block.
00185                 nlassert(block->FreeSpace==0);
00186                 // set size of lightmaps for this blocks.
00187                 block->Width= w;
00188                 block->Height= h;
00189 
00190                 // Link this block to the list.
00191                 linkFreeBlock(lMapType, block);
00192         }
00193 
00194         // Get the block from the list.
00195         CBlock  *block= _FreeBlocks[lMapType];
00196 
00197         // Allocate block lightmap.
00198         //===================
00199 
00200         // compute block info.
00201         uint    nLMapOnX= NL_DLM_BLOCK_SIZE / block->Width;
00202         uint    nLMapOnY= NL_DLM_BLOCK_SIZE / block->Height;
00203         uint    nLMapPerBlock= nLMapOnX * nLMapOnY;
00204         // bit must fit in a uint64
00205         nlassert(nLMapPerBlock<=64);
00206 
00207         // get an id in the FreeSpace bitField.
00208         uint    i;
00209         for(i= 0;i<nLMapPerBlock; i++)
00210         {
00211                 uint    mask= 1<<i;
00212                 // If the bit is not set, then this id is free.
00213                 if( (block->FreeSpace & mask)==0 )
00214                 {
00215                         // take this id, hence set this bit
00216                         block->FreeSpace|= mask;
00217                         // stop, found.
00218                         break;
00219                 }
00220         }
00221         nlassert(i<nLMapPerBlock);
00222 
00223         // compute x/y texture pos for this id.
00224         x= block->PosX + (i%nLMapOnX) * w;
00225         y= block->PosY + (i/nLMapOnX) * h;
00226 
00227 
00228         // if lightmap full
00229         //===================
00230         // if bitfield is full
00231         if( block->FreeSpace == (uint)(1<<nLMapPerBlock)-1 )
00232         {
00233                 // Must remove it from free list.
00234                 unlinkFreeBlock(lMapType, block);
00235         }
00236 
00237         return true;
00238 }
00239 
00240 // ***************************************************************************
00241 void                    CTextureDLM::copyRect(uint x, uint y, uint w, uint h, CRGBA  *textMap)
00242 {
00243         // copy image.
00244         CRGBA   *src= textMap;
00245         CRGBA   *dst= (CRGBA*)&(*getPixels().begin());
00246         dst+= y*getWidth()+x;
00247         for(sint n= h;n>0;n--, src+= w, dst+= getWidth())
00248         {
00249                 memcpy(dst, src, w*sizeof(CRGBA));
00250         }
00251 
00252         // Invalidate the rectangle.
00253         ITexture::touchRect(CRect(x, y, w, h));
00254 }
00255 
00256 // ***************************************************************************
00257 void                    CTextureDLM::fillRect(uint x, uint y, uint w, uint h, uint8 value)
00258 {
00259         // copy image.
00260         CRGBA   *dst= (CRGBA*)&(*getPixels().begin());
00261         dst+= y*getWidth()+x;
00262         for(sint n= h;n>0;n--, dst+= getWidth())
00263         {
00264                 memset(dst, value, w*sizeof(CRGBA));
00265         }
00266 
00267         // Invalidate the rectangle.
00268         ITexture::touchRect(CRect(x, y, w, h));
00269 }
00270 
00271 
00272 // ***************************************************************************
00273 void                    CTextureDLM::modulateAndfillRect565(uint x, uint y, uint w, uint h, CRGBA  *textMap, uint16 *modColor)
00274 {
00275         // compute start dst to copy.
00276         CRGBA   *dst= (CRGBA*)&(*getPixels().begin());
00277         dst+= y*getWidth()+x;
00278 
00279         // precahce Data in memory (best CPU support)
00280         CFastMem::precache(textMap, w*h*sizeof(CRGBA));
00281         CFastMem::precache(modColor, w*h*sizeof(uint16));
00282 
00283         // For all lines
00284         for(sint n= h;n>0;n--, dst+= (getWidth()-w) )
00285         {
00286                 // For all the line.
00287                 for(sint nc= w;nc>0;nc--, textMap++, modColor++, dst++)
00288                 {
00289                         uint16  tc= *modColor;
00290                         // modulate R.
00291                         dst->R= ( (tc>>11) * textMap->R)>>5;
00292                         // modulate G.
00293                         dst->G= (((tc>>5)&63) * textMap->G)>>6;
00294                         // modulate B.
00295                         dst->B= ( (tc&31) * textMap->B)>>5;
00296                 }
00297         }
00298 
00299         // Invalidate the rectangle.
00300         ITexture::touchRect(CRect(x, y, w, h));
00301 }
00302 
00303 
00304 // ***************************************************************************
00305 void                    CTextureDLM::modulateAndfillRect8888(uint x, uint y, uint w, uint h, CRGBA  *textMap, CRGBA *modColor)
00306 {
00307         // compute start dst to copy.
00308         CRGBA   *dst= (CRGBA*)&(*getPixels().begin());
00309         dst+= y*getWidth()+x;
00310 
00311         // precahce Data in memory (best CPU support)
00312         CFastMem::precache(textMap, w*h*sizeof(CRGBA));
00313         CFastMem::precache(modColor, w*h*sizeof(CRGBA));
00314 
00315         // For all lines
00316         for(sint n= h;n>0;n--, dst+= (getWidth()-w) )
00317         {
00318                 // For all the line.
00319                 for(sint nc= w;nc>0;nc--, textMap++, modColor++, dst++)
00320                 {
00321                         CRGBA           mc= *modColor;
00322                         // modulate RGB only
00323                         dst->R= ( mc.R * textMap->R)>>8;
00324                         dst->G= ( mc.G * textMap->G)>>8;
00325                         dst->B= ( mc.B * textMap->B)>>8;
00326                 }
00327         }
00328 
00329         // Invalidate the rectangle.
00330         ITexture::touchRect(CRect(x, y, w, h));
00331 }
00332 
00333 
00334 // ***************************************************************************
00335 void                    CTextureDLM::modulateConstantAndfillRect(uint x, uint y, uint w, uint h, CRGBA  *textMap, CRGBA mc)
00336 {
00337         // compute start dst to copy.
00338         CRGBA   *dst= (CRGBA*)&(*getPixels().begin());
00339         dst+= y*getWidth()+x;
00340 
00341         // precahce Data in memory (best CPU support)
00342         CFastMem::precache(textMap, w*h*sizeof(CRGBA));
00343 
00344         // For all lines
00345         for(sint n= h;n>0;n--, dst+= (getWidth()-w) )
00346         {
00347                 // For all the line.
00348                 for(sint nc= w;nc>0;nc--, textMap++, dst++)
00349                 {
00350                         // modulate RGB only
00351                         dst->R= ( mc.R * textMap->R)>>8;
00352                         dst->G= ( mc.G * textMap->G)>>8;
00353                         dst->B= ( mc.B * textMap->B)>>8;
00354                 }
00355         }
00356 
00357         // Invalidate the rectangle.
00358         ITexture::touchRect(CRect(x, y, w, h));
00359 }
00360 
00361 
00362 // ***************************************************************************
00363 void                    CTextureDLM::releaseLightMap(uint x, uint y)
00364 {
00365         // Search what block is under this pos.
00366         uint    blockId= (y/NL_DLM_BLOCK_SIZE)*_WBlock + (x/NL_DLM_BLOCK_SIZE);
00367         nlassert(blockId<_Blocks.size());
00368         CBlock  *block= &_Blocks[blockId];
00369 
00370         // compute block info.
00371         uint    nLMapOnX= NL_DLM_BLOCK_SIZE / block->Width;
00372         uint    nLMapOnY= NL_DLM_BLOCK_SIZE / block->Height;
00373         uint    nLMapPerBlock= nLMapOnX * nLMapOnY;
00374         // was Full (ie all bits set) before this release
00375         bool    wasFull= (block->FreeSpace == (uint)(1<<nLMapPerBlock)-1);
00376         // the type of lightmap.
00377         uint    lMapType= getTypeForSize(block->Width, block->Height);
00378 
00379 
00380         // get relative pos to the block.
00381         x-= block->PosX;
00382         y-= block->PosY;
00383 
00384         // compute bit number.
00385         uint    bitX= x/block->Width;
00386         uint    bitY= y/block->Height;
00387         // assert good pos param.
00388         nlassert(x == bitX*block->Width);
00389         nlassert(y == bitY*block->Height);
00390 
00391         // compute bitId, as done in createLightMap()
00392         uint    bitId= bitY * nLMapOnX + bitX;
00393         uint    mask= 1<<bitId;
00394 
00395         // Free this bit in the block.
00396         nlassert(block->FreeSpace & mask);
00397         block->FreeSpace&= ~mask;
00398 
00399 
00400         // Free the block if necessary.
00401         //=======================
00402         bool    isEmpty= block->FreeSpace==0;
00403 
00404         // If wasFull and now it is empty (nLMapPerBlock==1 case), just append to EmptyBlocks.
00405         if(wasFull && isEmpty)
00406         {
00407                 // add the id to the empty list.
00408                 _EmptyBlocks.push_back(blockId);
00409         }
00410         // if wasFull, but still have some lightmap now, must insert into FreeList
00411         else if(wasFull && !isEmpty)
00412         {
00413                 linkFreeBlock(lMapType, block);
00414         }
00415         // if was not full but now it is empty, must remove from free list and insert into EmptyBlocks
00416         else if(!wasFull && isEmpty)
00417         {
00418                 // remove the block from Free List
00419                 unlinkFreeBlock(lMapType, block);
00420                 // add the id to the empty list.
00421                 _EmptyBlocks.push_back(blockId);
00422         }
00423         // else (!wasFull && !isEmpty) no-op, since must be kept in the FreeList.
00424 
00425 }
00426 
00427 
00428 } // NL3D