00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
00056
00057 setReleasable(false);
00058
00059 CBitmap::resize(width, height, CBitmap::RGBA);
00060
00061
00062 setUploadFormat(ITexture::RGBA8888);
00063 setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff);
00064
00065
00066 _Blocks.resize(nBlocks);
00067 _EmptyBlocks.resize(nBlocks);
00068 sint i;
00069 for(i=0;i<(sint)_Blocks.size();i++)
00070 {
00071
00072 _Blocks[i].PosX= (i%_WBlock) * NL_DLM_BLOCK_SIZE;
00073 _Blocks[i].PosY= (i/_WBlock) * NL_DLM_BLOCK_SIZE;
00074
00075
00076 _EmptyBlocks[i]=i;
00077 }
00078
00079
00080 for(i=0;i<(sint)NL_DLM_LIGHTMAP_TYPE_SIZE;i++)
00081 {
00082 _FreeBlocks[i]= NULL;
00083 }
00084
00085
00086
00087 nlassert(NL_DLM_BLOCK_SIZE==10 || NL_DLM_BLOCK_SIZE==18);
00088 CRGBA *ptr= (CRGBA*)(&CBitmap::getPixels(0)[0]);
00089
00090 ptr[width*height-1]= CRGBA::Black;
00091
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
00109 width= getPowerOf2(width-1);
00110 height= getPowerOf2(height-1);
00111 #ifdef NL_DLM_TILE_RES
00112
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
00127 if(_FreeBlocks[getTypeForSize(w,h)])
00128 return true;
00129
00130
00131 return _EmptyBlocks.size()>0;
00132 }
00133
00134
00135
00136 void CTextureDLM::linkFreeBlock(uint lMapType, CBlock *block)
00137 {
00138
00139 block->FreeNext= _FreeBlocks[lMapType];
00140 block->FreePrec= NULL;
00141
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
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
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
00167 if(!canCreateLightMap(w, h))
00168 return false;
00169
00170
00171 uint lMapType= getTypeForSize(w,h);
00172
00173
00174
00175 if(_FreeBlocks[lMapType]==NULL)
00176 {
00177
00178 nlassert(_EmptyBlocks.size()>0);
00179
00180
00181 CBlock *block= &_Blocks[_EmptyBlocks.back()];
00182 _EmptyBlocks.pop_back();
00183
00184
00185 nlassert(block->FreeSpace==0);
00186
00187 block->Width= w;
00188 block->Height= h;
00189
00190
00191 linkFreeBlock(lMapType, block);
00192 }
00193
00194
00195 CBlock *block= _FreeBlocks[lMapType];
00196
00197
00198
00199
00200
00201 uint nLMapOnX= NL_DLM_BLOCK_SIZE / block->Width;
00202 uint nLMapOnY= NL_DLM_BLOCK_SIZE / block->Height;
00203 uint nLMapPerBlock= nLMapOnX * nLMapOnY;
00204
00205 nlassert(nLMapPerBlock<=64);
00206
00207
00208 uint i;
00209 for(i= 0;i<nLMapPerBlock; i++)
00210 {
00211 uint mask= 1<<i;
00212
00213 if( (block->FreeSpace & mask)==0 )
00214 {
00215
00216 block->FreeSpace|= mask;
00217
00218 break;
00219 }
00220 }
00221 nlassert(i<nLMapPerBlock);
00222
00223
00224 x= block->PosX + (i%nLMapOnX) * w;
00225 y= block->PosY + (i/nLMapOnX) * h;
00226
00227
00228
00229
00230
00231 if( block->FreeSpace == (uint)(1<<nLMapPerBlock)-1 )
00232 {
00233
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
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
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
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
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
00276 CRGBA *dst= (CRGBA*)&(*getPixels().begin());
00277 dst+= y*getWidth()+x;
00278
00279
00280 CFastMem::precache(textMap, w*h*sizeof(CRGBA));
00281 CFastMem::precache(modColor, w*h*sizeof(uint16));
00282
00283
00284 for(sint n= h;n>0;n--, dst+= (getWidth()-w) )
00285 {
00286
00287 for(sint nc= w;nc>0;nc--, textMap++, modColor++, dst++)
00288 {
00289 uint16 tc= *modColor;
00290
00291 dst->R= ( (tc>>11) * textMap->R)>>5;
00292
00293 dst->G= (((tc>>5)&63) * textMap->G)>>6;
00294
00295 dst->B= ( (tc&31) * textMap->B)>>5;
00296 }
00297 }
00298
00299
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
00308 CRGBA *dst= (CRGBA*)&(*getPixels().begin());
00309 dst+= y*getWidth()+x;
00310
00311
00312 CFastMem::precache(textMap, w*h*sizeof(CRGBA));
00313 CFastMem::precache(modColor, w*h*sizeof(CRGBA));
00314
00315
00316 for(sint n= h;n>0;n--, dst+= (getWidth()-w) )
00317 {
00318
00319 for(sint nc= w;nc>0;nc--, textMap++, modColor++, dst++)
00320 {
00321 CRGBA mc= *modColor;
00322
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
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
00338 CRGBA *dst= (CRGBA*)&(*getPixels().begin());
00339 dst+= y*getWidth()+x;
00340
00341
00342 CFastMem::precache(textMap, w*h*sizeof(CRGBA));
00343
00344
00345 for(sint n= h;n>0;n--, dst+= (getWidth()-w) )
00346 {
00347
00348 for(sint nc= w;nc>0;nc--, textMap++, dst++)
00349 {
00350
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
00358 ITexture::touchRect(CRect(x, y, w, h));
00359 }
00360
00361
00362
00363 void CTextureDLM::releaseLightMap(uint x, uint y)
00364 {
00365
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
00371 uint nLMapOnX= NL_DLM_BLOCK_SIZE / block->Width;
00372 uint nLMapOnY= NL_DLM_BLOCK_SIZE / block->Height;
00373 uint nLMapPerBlock= nLMapOnX * nLMapOnY;
00374
00375 bool wasFull= (block->FreeSpace == (uint)(1<<nLMapPerBlock)-1);
00376
00377 uint lMapType= getTypeForSize(block->Width, block->Height);
00378
00379
00380
00381 x-= block->PosX;
00382 y-= block->PosY;
00383
00384
00385 uint bitX= x/block->Width;
00386 uint bitY= y/block->Height;
00387
00388 nlassert(x == bitX*block->Width);
00389 nlassert(y == bitY*block->Height);
00390
00391
00392 uint bitId= bitY * nLMapOnX + bitX;
00393 uint mask= 1<<bitId;
00394
00395
00396 nlassert(block->FreeSpace & mask);
00397 block->FreeSpace&= ~mask;
00398
00399
00400
00401
00402 bool isEmpty= block->FreeSpace==0;
00403
00404
00405 if(wasFull && isEmpty)
00406 {
00407
00408 _EmptyBlocks.push_back(blockId);
00409 }
00410
00411 else if(wasFull && !isEmpty)
00412 {
00413 linkFreeBlock(lMapType, block);
00414 }
00415
00416 else if(!wasFull && isEmpty)
00417 {
00418
00419 unlinkFreeBlock(lMapType, block);
00420
00421 _EmptyBlocks.push_back(blockId);
00422 }
00423
00424
00425 }
00426
00427
00428 }