# 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  

lod_character_manager.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 "nel/misc/common.h"
00029 #include "3d/lod_character_manager.h"
00030 #include "3d/lod_character_shape.h"
00031 #include "3d/lod_character_shape_bank.h"
00032 #include "3d/lod_character_instance.h"
00033 #include "nel/misc/hierarchical_timer.h"
00034 #include "3d/fast_floor.h"
00035 #include "3d/lod_character_texture.h"
00036 #include "nel/misc/file.h"
00037 
00038 
00039 using   namespace std;
00040 using   namespace NLMISC;
00041 
00042 namespace NL3D 
00043 {
00044 
00045 
00046 H_AUTO_DECL ( NL3D_CharacterLod_Render )
00047 
00048 
00049 // ***************************************************************************
00050 // Dest is without Normal because precomputed
00051 #define NL3D_CLOD_VERTEX_FORMAT (CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag | CVertexBuffer::PrimaryColorFlag)
00052 #define NL3D_CLOD_VERTEX_SIZE   24
00053 #define NL3D_CLOD_UV_OFF                12
00054 #define NL3D_CLOD_COLOR_OFF             20
00055 
00056 // size (in block) of the big texture.
00057 #define NL3D_CLOD_TEXT_NLOD_WIDTH       16
00058 #define NL3D_CLOD_TEXT_NLOD_HEIGHT      16
00059 #define NL3D_CLOD_TEXT_NUM_IDS          NL3D_CLOD_TEXT_NLOD_WIDTH*NL3D_CLOD_TEXT_NLOD_HEIGHT
00060 #define NL3D_CLOD_BIGTEXT_WIDTH         NL3D_CLOD_TEXT_NLOD_WIDTH*NL3D_CLOD_TEXT_WIDTH
00061 #define NL3D_CLOD_BIGTEXT_HEIGHT        NL3D_CLOD_TEXT_NLOD_HEIGHT*NL3D_CLOD_TEXT_HEIGHT
00062 
00063 // Default texture color. Alpha must be 255
00064 #define NL3D_CLOD_DEFAULT_TEXCOLOR      CRGBA(255,255,255,255)
00065 
00066 
00067 // ***************************************************************************
00068 CLodCharacterManager::CLodCharacterManager()
00069 {
00070         _Driver= NULL;
00071         _MaxNumVertices= 3000;
00072         _Rendering= false;
00073 
00074         // Setup the format of render
00075         _VBuffer.setVertexFormat(NL3D_CLOD_VERTEX_FORMAT);
00076 
00077         // NB: addRenderCharacterKey() loop hardCoded for Vertex+UV+Normal+Color only.
00078         nlassert( NL3D_CLOD_UV_OFF == _VBuffer.getTexCoordOff());
00079         nlassert( NL3D_CLOD_COLOR_OFF == _VBuffer.getColorOff());
00080 
00081         // setup the texture.
00082         _BigTexture= new CTextureBlank;
00083         // The texture always reside in memory... This take 1Mo of RAM. (16*32*16*32 * 4)
00084         // NB: this is simplier like that, and this is not a problem, since only 1 or 2 Mo are allocated :o)
00085         _BigTexture->setReleasable(false);
00086         // create the bitmap.
00087         _BigTexture->resize(NL3D_CLOD_BIGTEXT_WIDTH, NL3D_CLOD_BIGTEXT_HEIGHT, CBitmap::RGBA);
00088         // Format of texture, 16 bits and no mipmaps.
00089         _BigTexture->setUploadFormat(ITexture::RGB565);
00090         _BigTexture->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff);
00091         _BigTexture->setWrapS(ITexture::Clamp);
00092         _BigTexture->setWrapT(ITexture::Clamp);
00093 
00094         // Alloc free Ids
00095         _FreeIds.resize(NL3D_CLOD_TEXT_NUM_IDS);
00096         for(uint i=0;i<_FreeIds.size();i++)
00097         {
00098                 _FreeIds[i]= i;
00099         }
00100 
00101         // setup the material
00102         _Material.initUnlit();
00103         _Material.setAlphaTest(true);
00104         _Material.setDoubleSided(true);
00105         _Material.setTexture(0, _BigTexture);
00106 
00107         // setup for lighting, Default for Ryzom setup
00108         _LightCorrectionMatrix.rotateZ((float)Pi/2);
00109         _LightCorrectionMatrix.invert();
00110 }
00111 
00112 
00113 // ***************************************************************************
00114 CLodCharacterManager::~CLodCharacterManager()
00115 {
00116         reset();
00117 }
00118 
00119 // ***************************************************************************
00120 void                    CLodCharacterManager::reset()
00121 {
00122         // delete shapeBanks.
00123         for(uint i=0;i<_ShapeBankArray.size();i++)
00124         {
00125                 if(_ShapeBankArray[i])
00126                         delete _ShapeBankArray[i];
00127         }
00128 
00129         // clears containers
00130         contReset(_ShapeBankArray);
00131         contReset(_ShapeMap);
00132 
00133         // reset render part.
00134         deleteVertexBuffer();
00135         _Driver= NULL;
00136 }
00137 
00138 // ***************************************************************************
00139 uint32                  CLodCharacterManager::createShapeBank()
00140 {
00141         // search a free entry
00142         for(uint i=0;i<_ShapeBankArray.size();i++)
00143         {
00144                 // if ree, use it.
00145                 if(_ShapeBankArray[i]==NULL)
00146                 {
00147                         _ShapeBankArray[i]= new CLodCharacterShapeBank;
00148                         return i;
00149                 }
00150         }
00151 
00152         // no free entrey, resize array.
00153         _ShapeBankArray.push_back(new CLodCharacterShapeBank);
00154         return _ShapeBankArray.size()-1;
00155 }
00156 
00157 // ***************************************************************************
00158 const CLodCharacterShapeBank    *CLodCharacterManager::getShapeBank(uint32 bankId) const
00159 {
00160         if(bankId>=_ShapeBankArray.size())
00161                 return NULL;
00162         else
00163                 return _ShapeBankArray[bankId];
00164 }
00165 
00166 // ***************************************************************************
00167 CLodCharacterShapeBank  *CLodCharacterManager::getShapeBank(uint32 bankId)
00168 {
00169         if(bankId>=_ShapeBankArray.size())
00170                 return NULL;
00171         else
00172                 return _ShapeBankArray[bankId];
00173 }
00174 
00175 // ***************************************************************************
00176 void                    CLodCharacterManager::deleteShapeBank(uint32 bankId)
00177 {
00178         if(bankId>=_ShapeBankArray.size())
00179         {
00180                 if(_ShapeBankArray[bankId])
00181                 {
00182                         delete _ShapeBankArray[bankId];
00183                         _ShapeBankArray[bankId]= NULL;
00184                 }
00185         }
00186 }
00187 
00188 // ***************************************************************************
00189 sint32                  CLodCharacterManager::getShapeIdByName(const std::string &name) const
00190 {
00191         CstItStrIdMap   it= _ShapeMap.find(name);
00192         if(it==_ShapeMap.end())
00193                 return -1;
00194         else
00195                 return it->second;
00196 }
00197 
00198 // ***************************************************************************
00199 const CLodCharacterShape        *CLodCharacterManager::getShape(uint32 shapeId) const
00200 {
00201         // split the id
00202         uint    bankId= shapeId >> 16;
00203         uint    shapeInBankId= shapeId &0xFFFF;
00204 
00205         // if valid bankId
00206         const CLodCharacterShapeBank    *shapeBank= getShapeBank(bankId);
00207         if(shapeBank)
00208         {
00209                 // return the shape from the bank
00210                 return shapeBank->getShape(shapeInBankId);
00211         }
00212         else
00213                 return NULL;
00214 }
00215 
00216 // ***************************************************************************
00217 bool                    CLodCharacterManager::compile()
00218 {
00219         bool    error= false;
00220 
00221         // clear the map
00222         contReset(_ShapeMap);
00223 
00224         // build the map
00225         for(uint i=0; i<_ShapeBankArray.size(); i++)
00226         {
00227                 if(_ShapeBankArray[i])
00228                 {
00229                         // Parse all Shapes
00230                         for(uint j=0; j<_ShapeBankArray[i]->getNumShapes(); j++)
00231                         {
00232                                 // build the shape Id
00233                                 uint    shapeId= (i<<16) + j;
00234 
00235                                 // get the shape
00236                                 const CLodCharacterShape        *shape= _ShapeBankArray[i]->getShape(j);
00237                                 if(shape)
00238                                 {
00239                                         const string &name= shape->getName();
00240                                         ItStrIdMap      it= _ShapeMap.find(name);
00241                                         if(it == _ShapeMap.end())
00242                                                 // insert the id in the map
00243                                                 _ShapeMap.insert(make_pair(name, shapeId));
00244                                         else
00245                                         {
00246                                                 error= true;
00247                                                 nlwarning("Found a Character Lod with same name in the manager: %s", name.c_str());
00248                                         }
00249                                 }
00250                         }
00251                 }
00252         }
00253 
00254         return error;
00255 }
00256 
00257 // ***************************************************************************
00258 // ***************************************************************************
00259 // Render
00260 // ***************************************************************************
00261 // ***************************************************************************
00262 
00263 
00264 // ***************************************************************************
00265 void                    CLodCharacterManager::setMaxVertex(uint32 maxVertex)
00266 {
00267         // we must not be beewteen beginRender() and endRender()
00268         nlassert(!isRendering());
00269         _MaxNumVertices= maxVertex;
00270 }
00271 
00272 // ***************************************************************************
00273 void                    CLodCharacterManager::deleteVertexBuffer()
00274 {
00275         // test (refptr) if the object still exist in memory.
00276         if(_VBHard!=NULL)
00277         {
00278                 // A vbufferhard should still exist only if driver still exist.
00279                 nlassert(_Driver!=NULL);
00280 
00281                 // must unlock VBhard before. ATI: No need to update any vertices.
00282                 _VBHard->unlock(0,0);
00283 
00284                 // delete it from driver.
00285                 _Driver->deleteVertexBufferHard(_VBHard);
00286                 _VBHard= NULL;
00287         }
00288 
00289         // delete the soft one.
00290         _VBuffer.deleteAllVertices();
00291 }
00292 
00293 
00294 // ***************************************************************************
00295 void                    CLodCharacterManager::beginRender(IDriver *driver, const CVector &managerPos)
00296 {
00297         H_AUTO_USE ( NL3D_CharacterLod_Render )
00298 
00299         // we must not be beewteen beginRender() and endRender()
00300         nlassert(!isRendering());
00301 
00302         // Reset render
00303         //=================
00304         _CurrentVertexId=0;
00305         _CurrentTriId= 0;
00306 
00307         // update Driver.
00308         //=================
00309         nlassert(driver);
00310 
00311         // test change of driver.
00312         nlassert(driver);
00313         if( _Driver==NULL || driver!=_Driver )
00314         {
00315                 // must restart build of VB.
00316                 deleteVertexBuffer();
00317                 _Driver= driver;
00318                 _VBHardOk= _Driver->supportVertexBufferHard();
00319         }
00320 
00321         // If the vbhard exist, but size is different from cur max size, reset.
00322         if(_VBHard && _VBHard->getNumVertices()!=_MaxNumVertices)
00323                 deleteVertexBuffer();
00324 
00325         // If VBHard is possible, and if not already allocated, try to create it.
00326         if(_VBHardOk && _VBHard==NULL)
00327         {
00328                 _VBHard= driver->createVertexBufferHard(_VBuffer.getVertexFormat(), _VBuffer.getValueTypePointer(), 
00329                         _MaxNumVertices, IDriver::VBHardAGP);
00330         }
00331 
00332         // Last try to create a std VertexBuffer if the VBHard does not exist.
00333         if(_VBHard==NULL)
00334         {
00335                 // just resize the std VB.
00336                 _VBuffer.setNumVertices(_MaxNumVertices);
00337         }
00338 
00339         // prepare for render.
00340         //=================
00341 
00342         // Lock Buffer.
00343         if(_VBHard)
00344         {
00345                 _VertexData= (uint8*)_VBHard->lock();
00346                 _VertexSize= _VBHard->getVertexSize();
00347         }
00348         else
00349         {
00350                 _VertexData= (uint8*)_VBuffer.getVertexCoordPointer();
00351                 _VertexSize= _VBuffer.getVertexSize();
00352         }
00353         // NB: addRenderCharacterKey() loop hardCoded for Vertex+UV+Normal+Color only.
00354         nlassert( _VertexSize == NL3D_CLOD_VERTEX_SIZE );       // Vector + Normal + UV + RGBA
00355 
00356 
00357         // Alloc a minimum of primitives (2*vertices), to avoid as possible reallocation in addRenderCharacterKey
00358         if(_Triangles.size()<_MaxNumVertices * 2)
00359                 _Triangles.resize(_MaxNumVertices * 2);
00360 
00361         // Local manager matrix
00362         _ManagerMatrixPos= managerPos;
00363 
00364         // Ok, start rendering
00365         _Rendering= true;
00366 }
00367 
00368 
00369 // ***************************************************************************
00370 static inline CRGBA     computeLodLighting(const CVector &lightObjectSpace, const CVector &normalPtr, CRGBA ambient, CRGBA diffuse)
00371 {
00372         // \todo yoyo: TODO_OPTIMIZE
00373         float   f= lightObjectSpace * normalPtr;
00374         f= max(0.f,f);
00375         sint    f8= OptFastFloor(f*255);
00376         CRGBA   lightRes;
00377         lightRes.modulateFromuiRGBOnly(diffuse, f8);
00378         lightRes.addRGBOnly(lightRes, ambient);
00379         return lightRes;
00380 }
00381 
00382 
00383 // ***************************************************************************
00384 bool                    CLodCharacterManager::addRenderCharacterKey(CLodCharacterInstance &instance, const CMatrix &worldMatrix, 
00385         CRGBA ambient, CRGBA diffuse, const CVector &lightDir)
00386 {
00387         H_AUTO_USE ( NL3D_CharacterLod_Render )
00388 
00389         nlassert(_Driver);
00390         // we must be beewteen beginRender() and endRender()
00391         nlassert(isRendering());
00392 
00393         CVector         unPackScaleFactor;
00394         uint            numVertices;
00395 
00396         // Get the Shape and current key.
00397         //=============
00398 
00399         // get the shape
00400         const CLodCharacterShape        *clod= getShape(instance.ShapeId);
00401         // if not found quit, return true
00402         if(!clod)
00403                 return true;
00404 
00405         // get UV/Normal array. NULL => error
00406         const CVector   *normalPtr= clod->getNormals();
00407         // get UV of the instance
00408         const CUV               *uvPtr= instance.getUVs();
00409         // uvPtr is NULL means that initInstance() has not been called!!
00410         nlassert(normalPtr && uvPtr);
00411 
00412         // get the anim key
00413         const CLodCharacterShape::CVector3s             *vertPtr;
00414         vertPtr= clod->getAnimKey(instance.AnimId, instance.AnimTime, instance.WrapMode, unPackScaleFactor);
00415         // if not found quit, return true
00416         if(!vertPtr)
00417                 return true;
00418         // get num verts
00419         numVertices= clod->getNumVertices();
00420 
00421         // empty shape??
00422         if(numVertices==0)
00423                 return true;
00424 
00425         // If too many vertices, quit, returning false.
00426         if(_CurrentVertexId+numVertices > _MaxNumVertices)
00427                 return false;
00428 
00429         // verify colors.
00430         bool    vertexColor= instance.VertexColors.size() == numVertices;
00431         // if error, take white as global color.
00432 
00433 
00434         // Transform and Add vertices.
00435         //=============
00436 
00437         // Get matrix pos.
00438         CVector         matPos= worldMatrix.getPos();
00439         // compute in manager space.
00440         matPos -= _ManagerMatrixPos;
00441         // Get rotation line vectors
00442         float   a00= worldMatrix.get()[0]; float        a01= worldMatrix.get()[4]; float        a02= worldMatrix.get()[8]; 
00443         float   a10= worldMatrix.get()[1]; float        a11= worldMatrix.get()[5]; float        a12= worldMatrix.get()[9]; 
00444         float   a20= worldMatrix.get()[2]; float        a21= worldMatrix.get()[6]; float        a22= worldMatrix.get()[10];
00445 
00446         // get the light in object space.
00447         CVector         lightObjectSpace;
00448         // Multiply light dir with transpose of worldMatrix. This may be not exact (not uniform scale) but sufficient.
00449         lightObjectSpace.x= a00 * lightDir.x + a10 * lightDir.y + a20 * lightDir.z;
00450         lightObjectSpace.y= a01 * lightDir.x + a11 * lightDir.y + a21 * lightDir.z;
00451         lightObjectSpace.z= a02 * lightDir.x + a12 * lightDir.y + a22 * lightDir.z;
00452         // animation User correction
00453         lightObjectSpace= _LightCorrectionMatrix.mulVector(lightObjectSpace);
00454         // normalize, and neg for Dot Product.
00455         lightObjectSpace.normalize();
00456         lightObjectSpace= -lightObjectSpace;
00457 
00458         // multiply matrix with scale factor for Pos.
00459         a00*= unPackScaleFactor.x; a01*= unPackScaleFactor.y; a02*= unPackScaleFactor.z; 
00460         a10*= unPackScaleFactor.x; a11*= unPackScaleFactor.y; a12*= unPackScaleFactor.z; 
00461         a20*= unPackScaleFactor.x; a21*= unPackScaleFactor.y; a22*= unPackScaleFactor.z; 
00462 
00463 
00464         // get dst Array.
00465         uint8   *dstPtr;
00466         dstPtr= _VertexData + _CurrentVertexId * _VertexSize;
00467 
00468         // 2 modes, with or without per vertexColor
00469         if(vertexColor)
00470         {
00471                 // get color array
00472                 const CRGBA             *colorPtr= &instance.VertexColors[0];
00473                 for(;numVertices>0;numVertices--)
00474                 {
00475                         // NB: order is important for AGP filling optimisation
00476                         // transform vertex, and store.
00477                         CVector         *dstVector= (CVector*)dstPtr;
00478                         dstVector->x= a00 * vertPtr->x + a01 * vertPtr->y + a02 * vertPtr->z + matPos.x;
00479                         dstVector->y= a10 * vertPtr->x + a11 * vertPtr->y + a12 * vertPtr->z + matPos.y;
00480                         dstVector->z= a20 * vertPtr->x + a21 * vertPtr->y + a22 * vertPtr->z + matPos.z;
00481                         // Copy UV
00482                         *(CUV*)(dstPtr + NL3D_CLOD_UV_OFF)= *uvPtr;
00483 
00484                         // Compute Lighting.
00485                         CRGBA   lightRes= computeLodLighting(lightObjectSpace, *normalPtr, ambient, diffuse);
00486                         // modulate color and store.
00487                         ((CRGBA*)(dstPtr + NL3D_CLOD_COLOR_OFF))->modulateFromColorRGBOnly(*colorPtr, lightRes);
00488                         // Copy Alpha.
00489                         ((CRGBA*)(dstPtr + NL3D_CLOD_COLOR_OFF))->A= colorPtr->A;
00490 
00491                         // next
00492                         vertPtr++;
00493                         uvPtr++;
00494                         normalPtr++;
00495                         colorPtr++;
00496                         dstPtr+= NL3D_CLOD_VERTEX_SIZE;
00497                 }
00498         }
00499         else
00500         {
00501                 for(;numVertices>0;numVertices--)
00502                 {
00503                         // NB: order is important for AGP filling optimisation
00504                         // transform vertex, and store.
00505                         CVector         *dstVector= (CVector*)dstPtr;
00506                         dstVector->x= a00 * vertPtr->x + a01 * vertPtr->y + a02 * vertPtr->z + matPos.x;
00507                         dstVector->y= a10 * vertPtr->x + a11 * vertPtr->y + a12 * vertPtr->z + matPos.y;
00508                         dstVector->z= a20 * vertPtr->x + a21 * vertPtr->y + a22 * vertPtr->z + matPos.z;
00509                         // Copy UV
00510                         *(CUV*)(dstPtr + NL3D_CLOD_UV_OFF)= *uvPtr;
00511 
00512                         // Compute Lighting.
00513                         CRGBA   lightRes= computeLodLighting(lightObjectSpace, *normalPtr, ambient, diffuse);
00514                         lightRes.A= 255;
00515                         // store global color
00516                         *(CRGBA*)(dstPtr + NL3D_CLOD_COLOR_OFF)= lightRes;
00517 
00518                         // next
00519                         vertPtr++;
00520                         uvPtr++;
00521                         normalPtr++;
00522                         dstPtr+= NL3D_CLOD_VERTEX_SIZE;
00523                 }
00524         }
00525 
00526 
00527         // Add Primitives.
00528         //=============
00529 
00530         // get number of tri indexes
00531         uint    numTriIdxs= clod->getNumTriangles() * 3;
00532 
00533         // realloc tris if needed.
00534         if(_CurrentTriId+numTriIdxs > _Triangles.size())
00535         {
00536                 _Triangles.resize(_CurrentTriId+numTriIdxs);
00537         }
00538 
00539         // reindex and copy tris
00540         const uint32    *srcIdx= clod->getTriangleArray();
00541         uint32                  *dstIdx= &_Triangles[_CurrentTriId];
00542         for(;numTriIdxs>0;numTriIdxs--, srcIdx++, dstIdx++)
00543         {
00544                 *dstIdx= *srcIdx + _CurrentVertexId;
00545         }
00546 
00547 
00548         // Next
00549         //=============
00550 
00551         // Inc Vertex count.
00552         _CurrentVertexId+= clod->getNumVertices();
00553         // Inc Prim count.
00554         _CurrentTriId+= clod->getNumTriangles() * 3;
00555 
00556 
00557         // key added
00558         return true;
00559 }
00560 
00561 // ***************************************************************************
00562 void                    CLodCharacterManager::endRender()
00563 {
00564         H_AUTO_USE ( NL3D_CharacterLod_Render )
00565 
00566         nlassert(_Driver);
00567         // we must be beewteen beginRender() and endRender()
00568         nlassert(isRendering());
00569 
00570         // UnLock Buffer.
00571         if(_VBHard)
00572         {
00573                 // ATI: copy only used vertices.
00574                 _VBHard->unlock(0, _CurrentVertexId);
00575         }
00576 
00577         // Render the VBuffer and the primitives.
00578         if(_CurrentTriId>0)
00579         {
00580                 // setup matrix.
00581                 CMatrix         managerMatrix; 
00582                 managerMatrix.setPos(_ManagerMatrixPos);
00583                 _Driver->setupModelMatrix(managerMatrix);
00584 
00585                 // active VB
00586                 if(_VBHard)
00587                         _Driver->activeVertexBufferHard(_VBHard);
00588                 else
00589                         _Driver->activeVertexBuffer(_VBuffer);
00590 
00591                 // render triangles
00592                 _Driver->renderTriangles(_Material, &_Triangles[0], _CurrentTriId/3);
00593         }
00594 
00595         // Ok, end rendering
00596         _Rendering= false;
00597 }
00598 
00599 // ***************************************************************************
00600 void                    CLodCharacterManager::setupNormalCorrectionMatrix(const CMatrix &normalMatrix)
00601 {
00602         _LightCorrectionMatrix= normalMatrix;
00603         _LightCorrectionMatrix.setPos(CVector::Null);
00604         _LightCorrectionMatrix.invert();
00605 }
00606 
00607 
00608 // ***************************************************************************
00609 // ***************************************************************************
00610 // Texturing.
00611 // ***************************************************************************
00612 // ***************************************************************************
00613 
00614 
00615 // ***************************************************************************
00616 CLodCharacterTmpBitmap::CLodCharacterTmpBitmap()
00617 {
00618         reset();
00619 }
00620 
00621 // ***************************************************************************
00622 void                    CLodCharacterTmpBitmap::reset()
00623 {
00624         // setup a 1*1 bitmap
00625         _Bitmap.resize(1);
00626         _Bitmap[0]= CRGBA::Black;
00627         _WidthPower=0;
00628         _UShift= 8;
00629         _VShift= 8;
00630 }
00631 
00632 // ***************************************************************************
00633 void                    CLodCharacterTmpBitmap::build(const NLMISC::CBitmap &bmpIn)
00634 {
00635         uint    width= bmpIn.getWidth();
00636         uint    height= bmpIn.getHeight();
00637         nlassert(width>0 && width<=256);
00638         nlassert(height>0 && height<=256);
00639 
00640         // resize bitmap.
00641         _Bitmap.resize(width*height);
00642         _WidthPower= getPowerOf2(width);
00643         // compute shift
00644         _UShift= 8-getPowerOf2(width);
00645         _VShift= 8-getPowerOf2(height);
00646 
00647         // convert the bitmap.
00648         CBitmap         bmp= bmpIn;
00649         bmp.convertToType(CBitmap::RGBA);
00650         CRGBA   *src= (CRGBA*)&bmp.getPixels()[0];
00651         CRGBA   *dst= _Bitmap.getPtr();
00652         for(sint nPix= width*height;nPix>0;nPix--, src++, dst++)
00653         {
00654                 *dst= *src;
00655         }
00656 }
00657 
00658 // ***************************************************************************
00659 void                    CLodCharacterTmpBitmap::build(CRGBA col)
00660 {
00661         // setup a 1*1 bitmap and set it with col
00662         reset();
00663         _Bitmap[0]= col;
00664 }
00665 
00666 
00667 // ***************************************************************************
00668 void                    CLodCharacterManager::initInstance(CLodCharacterInstance &instance)
00669 {
00670         // first release in (maybe) other manager.
00671         if(instance._Owner)
00672                 instance._Owner->releaseInstance(instance);
00673 
00674         // get the shape
00675         const CLodCharacterShape        *clod= getShape(instance.ShapeId);
00676         // if not found quit
00677         if(!clod)
00678                 return;
00679         // get Uvs.
00680         const CUV       *uvSrc= clod->getUVs();
00681         nlassert(uvSrc);
00682 
00683 
00684         // Ok, init header
00685         instance._Owner= this;
00686         instance._UVs.resize(clod->getNumVertices());
00687 
00688         // allocate an id. If cannot, then fill Uvs with 0 => filled with Black. (see endTextureCompute() why).
00689         if(_FreeIds.empty())
00690         {
00691                 // set a "Not enough memory" id
00692                 instance._TextureId= NL3D_CLOD_TEXT_NUM_IDS;
00693                 CUV             uv(0,0);
00694                 fill(instance._UVs.begin(), instance._UVs.end(), uv);
00695         }
00696         // else OK, can instanciate the Uvs.
00697         else
00698         {
00699                 // get the id.
00700                 instance._TextureId= _FreeIds.back();
00701                 _FreeIds.pop_back();
00702                 // get the x/y.
00703                 uint    xId= instance._TextureId % NL3D_CLOD_TEXT_NLOD_WIDTH;
00704                 uint    yId= instance._TextureId / NL3D_CLOD_TEXT_NLOD_WIDTH;
00705                 // compute the scale/bias to apply to Uvs.
00706                 float   scaleU= 1.0f / NL3D_CLOD_TEXT_NLOD_WIDTH;
00707                 float   scaleV= 1.0f / NL3D_CLOD_TEXT_NLOD_HEIGHT;
00708                 float   biasU= (float)xId / NL3D_CLOD_TEXT_NLOD_WIDTH;
00709                 float   biasV= (float)yId / NL3D_CLOD_TEXT_NLOD_HEIGHT;
00710                 // apply it to each UVs.
00711                 CUV             *uvDst= &instance._UVs[0];
00712                 for(uint i=0; i<instance._UVs.size();i++)
00713                 {
00714                         uvDst[i].U= biasU + uvSrc[i].U*scaleU;
00715                         uvDst[i].V= biasV + uvSrc[i].V*scaleV;
00716                 }
00717         }
00718 }
00719 
00720 // ***************************************************************************
00721 void                    CLodCharacterManager::releaseInstance(CLodCharacterInstance &instance)
00722 {
00723         if(instance._Owner==NULL)
00724                 return;
00725         nlassert(this==instance._Owner);
00726 
00727         // if the id is not a "Not enough memory" id, release it.
00728         if(instance._TextureId>=0 && instance._TextureId<NL3D_CLOD_TEXT_NUM_IDS)
00729                 _FreeIds.push_back(instance._TextureId);
00730 
00731         // reset the instance
00732         instance._Owner= NULL;
00733         instance._TextureId= -1;
00734         contReset(instance._UVs);
00735 }
00736 
00737 
00738 // ***************************************************************************
00739 CRGBA                   *CLodCharacterManager::getTextureInstance(CLodCharacterInstance &instance)
00740 {
00741         nlassert(instance._Owner==this);
00742         nlassert(instance._TextureId!=-1);
00743         // if the texture id is a "not enough memory", quit.
00744         if(instance._TextureId==NL3D_CLOD_TEXT_NUM_IDS)
00745                 return NULL;
00746 
00747         // get the x/y.
00748         uint    xId= instance._TextureId % NL3D_CLOD_TEXT_NLOD_WIDTH;
00749         uint    yId= instance._TextureId / NL3D_CLOD_TEXT_NLOD_WIDTH;
00750 
00751         // get the ptr on the correct pixel.
00752         CRGBA   *pix= (CRGBA*)&_BigTexture->getPixels(0)[0];
00753         return pix + yId*NL3D_CLOD_TEXT_HEIGHT*NL3D_CLOD_BIGTEXT_WIDTH + xId*NL3D_CLOD_TEXT_WIDTH;
00754 }
00755 
00756 
00757 // ***************************************************************************
00758 bool                    CLodCharacterManager::startTextureCompute(CLodCharacterInstance &instance)
00759 {
00760         CRGBA   *dst= getTextureInstance(instance);
00761         if(!dst)
00762                 return false;
00763 
00764         // erase the texture with 0,0,0,255. Alpha is actually the min "Quality" part of the CTUVQ.
00765         CRGBA   col= NL3D_CLOD_DEFAULT_TEXCOLOR;
00766         for(uint y=0;y<NL3D_CLOD_TEXT_HEIGHT;y++)
00767         {
00768                 // erase the line
00769                 for(uint x=0;x<NL3D_CLOD_TEXT_WIDTH;x++)
00770                         dst[x]= col;
00771                 // Next line
00772                 dst+= NL3D_CLOD_BIGTEXT_WIDTH;
00773         }
00774 
00775         return true;
00776 }
00777 
00778 // ***************************************************************************
00779 void                    CLodCharacterManager::addTextureCompute(CLodCharacterInstance &instance, const CLodCharacterTexture &lodTexture)
00780 {
00781         CRGBA   *dst= getTextureInstance(instance);
00782         if(!dst)
00783                 return;
00784 
00785         // get lookup ptr.
00786         nlassert(lodTexture.Texture.size()==NL3D_CLOD_TEXT_SIZE);
00787         const CLodCharacterTexture::CTUVQ               *lookUpPtr= &lodTexture.Texture[0];
00788 
00789         // apply the lodTexture, taking only better quality (ie nearer 0)
00790         for(uint y=0;y<NL3D_CLOD_TEXT_HEIGHT;y++)
00791         {
00792                 // erase the line
00793                 for(uint x=0;x<NL3D_CLOD_TEXT_WIDTH;x++)
00794                 {
00795                         CLodCharacterTexture::CTUVQ             lut= *lookUpPtr;
00796                         // if this quality is better than the one stored
00797                         if(lut.Q<dst[x].A)
00798                         {
00799                                 // get what texture to read, and read the pixel.
00800                                 CRGBA   col= _TmpBitmaps[lut.T].getPixel(lut.U, lut.V);
00801                                 // set quality.
00802                                 col.A= lut.Q;
00803                                 // set in dest
00804                                 dst[x]= col;
00805                         }
00806 
00807                         // next lookup
00808                         lookUpPtr++;
00809                 }
00810                 // Next line
00811                 dst+= NL3D_CLOD_BIGTEXT_WIDTH;
00812         }
00813 }
00814 
00815 // ***************************************************************************
00816 void                    CLodCharacterManager::endTextureCompute(CLodCharacterInstance &instance, uint numBmpToReset)
00817 {
00818         CRGBA   *dst= getTextureInstance(instance);
00819         if(!dst)
00820                 return;
00821 
00822         // reset All Alpha values to 255 => no AlphaTest problems
00823         for(uint y=0;y<NL3D_CLOD_TEXT_HEIGHT;y++)
00824         {
00825                 // erase the line
00826                 for(uint x=0;x<NL3D_CLOD_TEXT_WIDTH;x++)
00827                 {
00828                         dst[x].A= 255;
00829                 }
00830                 // Next line
00831                 dst+= NL3D_CLOD_BIGTEXT_WIDTH;
00832         }
00833 
00834         // If the id == 0 then must reset the 0,0 Pixel to black. for the "Not Enough memory" case in initInstance().
00835         if(instance._TextureId==0)
00836                 *(CRGBA*)&_BigTexture->getPixels(0)[0]= NL3D_CLOD_DEFAULT_TEXCOLOR;
00837 
00838         // get the x/y.
00839         uint    xId= instance._TextureId % NL3D_CLOD_TEXT_NLOD_WIDTH;
00840         uint    yId= instance._TextureId / NL3D_CLOD_TEXT_NLOD_WIDTH;
00841         // touch the texture for Driver update.
00842         _BigTexture->touchRect(
00843                 CRect(xId*NL3D_CLOD_TEXT_WIDTH, yId*NL3D_CLOD_TEXT_HEIGHT, NL3D_CLOD_TEXT_WIDTH, NL3D_CLOD_TEXT_HEIGHT) );
00844 
00845         // reset tmpBitmaps / free memory.
00846         for(uint i=0; i<numBmpToReset; i++)
00847         {
00848                 _TmpBitmaps[i].reset();
00849         }
00850 
00851         // TestYoyo
00852         /*NLMISC::COFile        f("tam.tga");
00853         _BigTexture->writeTGA(f,32);*/
00854 }
00855 
00856 
00857 } // NL3D