# 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  

mesh_base_instance.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 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/mesh_base_instance.h"
00029 #include "3d/mesh_base.h"
00030 #include "3d/scene.h"
00031 #include "3d/animation.h"
00032 #include "nel/misc/debug.h"
00033 #include "3d/anim_detail_trav.h"
00034 #include "3d/texture_file.h"
00035 #include "3d/async_texture_manager.h"
00036 
00037 
00038 using namespace NLMISC;
00039 
00040 namespace NL3D 
00041 {
00042 
00043 
00044 // ***************************************************************************
00045 CMeshBaseInstance::CMeshBaseInstance()
00046 {
00047         IAnimatable::resize(AnimValueLast);
00048         _OwnerScene= NULL;
00049         _AsyncTextureToLoadRefCount= 0;
00050         _AsyncTextureMode= false;
00051         _AsyncTextureReady= true;
00052         _AsyncTextureDirty= false;
00053         _AsyncTextureDistance= 0;
00054 
00055         // I am a CMeshBaseInstance!!
00056         CTransform::setIsMeshBaseInstance(true);
00057 }
00058 
00059 // ***************************************************************************
00060 CMeshBaseInstance::~CMeshBaseInstance()
00061 {
00062         // If AsyncTextureMode, must disable. This ensure that async loading stop, and that no ref still exist
00063         // in the AsyncTextureManager
00064         if(_AsyncTextureMode)
00065                 enableAsyncTextureMode(false);
00066 }
00067 
00068 
00069 // ***************************************************************************
00070 void            CMeshBaseInstance::registerBasic()
00071 {
00072         CMOT::registerModel(MeshBaseInstanceId, TransformShapeId, CMeshBaseInstance::creator);
00073         CMOT::registerObs(AnimDetailTravId, MeshBaseInstanceId, CMeshBaseInstanceAnimDetailObs::creator);
00074 }
00075 
00076 
00077 // ***************************************************************************
00078 void            CMeshBaseInstance::registerToChannelMixer(CChannelMixer *chanMixer, const std::string &prefix)
00079 {
00080         uint32 i;
00081         CTransformShape::registerToChannelMixer(chanMixer, prefix);
00082 
00083         // Add any materials.
00084         for (i = 0; i < _AnimatedMaterials.size(); i++)
00085         {
00086                 // append material  matname.*
00087                 _AnimatedMaterials[i].registerToChannelMixer(chanMixer, prefix + _AnimatedMaterials[i].getMaterialName() + ".");
00088         }
00089 
00090         // Add any morph
00091         for (i = 0; i < _AnimatedMorphFactor.size(); i++)
00092         {
00093                 _AnimatedMorphFactor[i].registerToChannelMixer(chanMixer, prefix + _AnimatedMorphFactor[i].getName());
00094         }
00095 }
00096 
00097 
00098 // ***************************************************************************
00099 ITrack*         CMeshBaseInstance::getDefaultTrack (uint valueId)
00100 {
00101         // Pointer on the CMeshBase
00102         CMeshBase* pMesh=(CMeshBase*)(IShape*)Shape;
00103 
00104         // Switch the value
00105         switch (valueId)
00106         {
00107         case CTransform::PosValue:                      
00108                 return pMesh->getDefaultPos();
00109         case CTransform::RotEulerValue:         
00110                 return pMesh->getDefaultRotEuler();
00111         case CTransform::RotQuatValue:          
00112                 return pMesh->getDefaultRotQuat();
00113         case CTransform::ScaleValue:            
00114                 return pMesh->getDefaultScale();
00115         case CTransform::PivotValue:            
00116                 return pMesh->getDefaultPivot();
00117         default:
00118                 // Problem, new values ?
00119                 nlstop;
00120         };
00121         return NULL;
00122 }
00123 
00124 
00125 // ***************************************************************************
00126 uint32 CMeshBaseInstance::getNbLightMap()
00127 {
00128         CMeshBase* pMesh=(CMeshBase*)(IShape*)Shape;
00129         return pMesh->_LightInfos.size();
00130 }
00131 
00132 // ***************************************************************************
00133 void CMeshBaseInstance::getLightMapName( uint32 nLightMapNb, std::string &LightMapName )
00134 {
00135         CMeshBase* pMesh=(CMeshBase*)(IShape*)Shape;
00136         if( nLightMapNb >= pMesh->_LightInfos.size() )
00137                 return;
00138         CMeshBase::TLightInfoMap::iterator itMap = pMesh->_LightInfos.begin();
00139         for( uint32 i = 0; i < nLightMapNb; ++i ) ++itMap;
00140         LightMapName = itMap->first;
00141 }
00142 
00143 // ***************************************************************************
00144 void CMeshBaseInstance::setLightMapFactor( const std::string &LightMapName, CRGBA Factor )
00145 {
00146         CMeshBase* pMesh=(CMeshBase*)(IShape*)Shape;
00147         CMeshBase::TLightInfoMap::iterator itMap = pMesh->_LightInfos.find( LightMapName );
00148         if( itMap == pMesh->_LightInfos.end() )
00149                 return;
00150         CMeshBase::CLightInfoMapList::iterator itList = itMap->second.begin();
00151         uint32 nNbElt = itMap->second.size();
00152         for( uint32 i = 0; i < nNbElt; ++i )
00153         {
00154                 Materials[itList->nMatNb].setLightMapFactor( itList->nStageNb, Factor );
00155                 ++itList;
00156         }
00157 }
00158 
00159 // ***************************************************************************
00160 uint32 CMeshBaseInstance::getNbBlendShape()
00161 {
00162         return _AnimatedMorphFactor.size();
00163 }
00164 
00165 // ***************************************************************************
00166 void CMeshBaseInstance::getBlendShapeName (uint32 nBlendShapeNb, std::string &BlendShapeName )
00167 {
00168         if (nBlendShapeNb >= _AnimatedMorphFactor.size())
00169                 return;
00170         BlendShapeName = _AnimatedMorphFactor[nBlendShapeNb].getName();
00171 }
00172 
00173 // ***************************************************************************
00174 void CMeshBaseInstance::setBlendShapeFactor (const std::string &BlendShapeName, float rFactor)
00175 {
00176         for (uint32 i = 0; i < _AnimatedMorphFactor.size(); ++i)
00177                 if (BlendShapeName == _AnimatedMorphFactor[i].getName())
00178                 {
00179                         _AnimatedMorphFactor[i].setFactor (rFactor);
00180                 }
00181 }
00182 
00183 
00184 // ***************************************************************************
00185 void CMeshBaseInstanceAnimDetailObs::traverse(IObs *caller)
00186 {
00187         
00188         CMeshBaseInstance       *mi = (CMeshBaseInstance*)Model;
00189         CMeshBase                       *mb = NLMISC::safe_cast<CMeshBase *>((IShape *) mi->Shape);
00190 
00191         // if the base instance uses automatic animations, we must also setup the date of the channel mixer controlling this object
00192         if (mb->getAutoAnim())
00193         {
00194                 // setup the channel mixer date
00195                 CChannelMixer *chanMix = mi->getChannelMixer();
00196                 if (chanMix)
00197                 {                       
00198                         ITravScene      *ts = NLMISC::safe_cast<ITravScene *>(Trav);
00199                         nlassert(ts->Scene);
00200                         const CAnimation *anim = chanMix->getSlotAnimation(0);
00204                         if (anim)
00205                         {
00206                                 float animLenght = anim->getEndTime() - anim->getBeginTime();
00207                                 if (animLenght > 0)
00208                                 {
00209                                         float currTime = (TAnimationTime) ts->Scene->getCurrentTime();
00210                                         float startTime = (uint) (currTime / animLenght) * animLenght;
00211                                         // Set the channel mixer date using the global date of the scene
00212                                         chanMix->setSlotTime(0, anim->getBeginTime() + currTime - startTime);
00213                                 }
00214                                 else
00215                                 {
00216                                         chanMix->setSlotTime(0, anim->getBeginTime());
00217                                 }
00218 
00223                                 chanMix->eval(false);
00224                         }
00225                 }
00226         }
00227 
00228         CTransformAnimDetailObs::traverse(caller);
00229 
00230         
00231         // update animated materials.
00232         // test if animated materials must be updated.
00233         if(mi->IAnimatable::isTouched(CMeshBaseInstance::OwnerBit))
00234         {
00235                 // must test / update all AnimatedMaterials.
00236                 for(uint i=0;i<mi->_AnimatedMaterials.size();i++)
00237                 {
00238                         // This test and update the pointed material.
00239                         mi->_AnimatedMaterials[i].update();
00240                 }
00241 
00242                 mi->IAnimatable::clearFlag(CMeshBaseInstance::OwnerBit);
00243         }
00244 
00245         // Lightmap automatic animation
00246         for( uint i = 0; i < mi->_AnimatedLightmap.size(); ++i )
00247         {
00248                 const char *LightGroupName = strchr( mi->_AnimatedLightmap[i]->getName().c_str(), '.' )+1;
00249                 mi->setLightMapFactor(  LightGroupName,
00250                                                                 mi->_AnimatedLightmap[i]->getFactor() );
00251         }
00252 }
00253 
00254 
00255 // ***************************************************************************
00256 void CMeshBaseInstance::selectTextureSet(uint id)
00257 {
00258         nlassert(Shape);
00259         CMeshBase *mb = NLMISC::safe_cast<CMeshBase *>((IShape *) Shape);
00260         const uint numMat = mb->getNbMaterial();
00261         nlassert(numMat == Materials.size());
00262         // see which material are selectable
00263         for(uint k = 0; k < numMat; ++k)
00264         {
00265                 CMaterial &mat = mb->getMaterial(k);
00266                 for(uint l = 0; l < IDRV_MAT_MAXTEXTURES; ++l)
00267                 {
00268                         if (mat.getTexture(l) && mat.getTexture(l)->isSelectable())
00269                         {
00270                                 // use a smartPtr so the textFile will be released if just used to set the name for AsyncTextures.
00271                                 CSmartPtr<ITexture>             texNSV= mat.getTexture(l)->buildNonSelectableVersion(id);
00272 
00273                                 // std case: just replace the texture.
00274                                 if(!_AsyncTextureMode)
00275                                 {
00276                                         Materials[k].setTexture(l, texNSV);
00277                                 }
00278                                 // Async case
00279                                 else
00280                                 {
00281                                         // If texture file, must copy the texture name
00282                                         if(AsyncTextures[k].IsTextureFile[l])
00283                                         {
00284                                                 CTextureFile    *textFile= safe_cast<CTextureFile*>((ITexture*)texNSV);
00285                                                 AsyncTextures[k].TextureNames[l]= textFile->getFileName();
00286                                         }
00287                                         // else replace the texture.
00288                                         else
00289                                                 Materials[k].setTexture(l, texNSV);
00290                                 }
00291                         }
00292                 }
00293         }
00294 
00295         // Flag the instance as AsyncTextureDirty if in this mode
00296         if(_AsyncTextureMode)
00297         {
00298                 setAsyncTextureDirty(true);
00299         }
00300 }
00301 
00302 
00303 // ***************************************************************************
00304 void CMeshBaseInstance::setAnimatedLightmap (CAnimatedLightmap *alm)
00305 {
00306         _AnimatedLightmap.push_back( alm );
00307         // Must be traversed in AnimDetail, even if no channel mixer registered
00308         CTransform::setIsForceAnimDetail(true);
00309 }
00310 
00311 
00312 // ***************************************************************************
00313 uint CMeshBaseInstance::getNumMaterial () const
00314 {
00315         return Materials.size ();
00316 }
00317 
00318 
00319 // ***************************************************************************
00320 const CMaterial *CMeshBaseInstance::getMaterial (uint materialId) const
00321 {
00322         return &(Materials[materialId]);
00323 }
00324 
00325 
00326 // ***************************************************************************
00327 CMaterial       *CMeshBaseInstance::getMaterial (uint materialId)
00328 {
00329         return &(Materials[materialId]);
00330 }
00331 
00332 
00333 // ***************************************************************************
00334 // ***************************************************************************
00335 // Async texture loading
00336 // ***************************************************************************
00337 // ***************************************************************************
00338 
00339 
00340 // ***************************************************************************
00341 void                    CMeshBaseInstance::enableAsyncTextureMode(bool enable)
00342 {
00343         // if same, no-op.
00344         if(_AsyncTextureMode==enable)
00345                 return;
00346         _AsyncTextureMode= enable;
00347 
00348         // if comes to async texture mode, must prepare AsyncTexturing
00349         if(_AsyncTextureMode)
00350         {
00351                 _AsyncTextureReady= true;
00352 
00353                 // For all TextureFiles in material
00354                 for(uint i=0;i<Materials.size();i++)
00355                 {
00356                         for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
00357                         {
00358                                 // test if really a CTextureFile
00359                                 CTextureFile    *text= dynamic_cast<CTextureFile*>(Materials[i].getTexture(stage));
00360                                 if(text)
00361                                 {
00362                                         // Must setup the AsyncTextures
00363                                         AsyncTextures[i].IsTextureFile[stage]= true;
00364                                         AsyncTextures[i].TextureNames[stage]= text->getFileName();
00365                                         // Now, must copy the textureFile, to Avoid writing in CMeshBase TextureFile descriptor !!!
00366                                         CTextureFile *tf = new CTextureFile(*text);
00367                                         // setup a dummy texture => Instance won't block rendering because texture not yet ready
00368                                         tf->setFileName("blank.tga");
00369                                         Materials[i].setTexture(stage, tf);
00370                                 }
00371                                 else
00372                                 {
00373                                         AsyncTextures[i].IsTextureFile[stage]= false;
00374                                 }
00375                         }
00376                 }
00377 
00378                 // For convenience, flag the instance as Dirty.
00379                 setAsyncTextureDirty(true);
00380         }
00381         // else, AsyncTextureMode disabled
00382         else
00383         {
00384                 // first, must stop and release all textures in the async manager.
00385                 releaseCurrentAsyncTextures();
00386                 nlassert(_AsyncTextureToLoadRefCount==0);
00387                 // clear the array => ensure good work if enableAsyncTextureMode(true) is made later
00388                 contReset(_CurrentAsyncTextures);
00389 
00390                 // For all TextureFiles in material, copy User setup from AsyncTextures, to real fileName
00391                 for(uint i=0;i<Materials.size();i++)
00392                 {
00393                         for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
00394                         {
00395                                 // if an async texture file
00396                                 if(AsyncTextures[i].IsTextureFile[stage])
00397                                 {
00398                                         // copy the texture name into the texture file.
00399                                         CTextureFile    *text= safe_cast<CTextureFile*>(Materials[i].getTexture(stage));
00400                                         text->setFileName(AsyncTextures[i].TextureNames[stage]);
00401                                         // clear string space
00402                                         AsyncTextures[i].TextureNames[stage].clear();
00403                                 }
00404                         }
00405                 }
00406         }
00407 }
00408 
00409 
00410 // ***************************************************************************
00411 void                    CMeshBaseInstance::startAsyncTextureLoading()
00412 {
00413         if(!getAsyncTextureMode())
00414                 return;
00415 
00416         // If the async texutre manager is not setuped in the scene, abort.
00417         CAsyncTextureManager    *asyncTextMgr= _OwnerScene->getAsyncTextureManager();
00418         if(!asyncTextMgr)
00419                 return;
00420 
00421         uint    i;
00422 
00423 
00424         /* for all new texture names to load, add them to the manager
00425                 NB: done first before release because of RefCount Management (in case of same texture name).
00426         */
00427         for(i=0;i<AsyncTextures.size();i++)
00428         {
00429                 for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
00430                 {
00431                         if(AsyncTextures[i].IsTextureFile[stage])
00432                         {
00433                                 uint    id;
00434                                 id= asyncTextMgr->addTextureRef(AsyncTextures[i].TextureNames[stage], this);
00435                                 AsyncTextures[i].TextIds[stage]= id;
00436                         }
00437                 }
00438         }
00439 
00440         /* For all old textures (0 for the first time...), release them.
00441         */
00442         releaseCurrentAsyncTextures();
00443 
00444         // OK! bkup the setup
00445         _CurrentAsyncTextures= AsyncTextures;
00446 
00447         // texture async is not ready.
00448         _AsyncTextureReady= false;
00449 }
00450 
00451 // ***************************************************************************
00452 void                    CMeshBaseInstance::releaseCurrentAsyncTextures()
00453 {
00454         // If the async texutre manager is not setuped in the scene, abort.
00455         CAsyncTextureManager    *asyncTextMgr= _OwnerScene->getAsyncTextureManager();
00456         if(!asyncTextMgr)
00457                 return;
00458 
00459         // release all texture in the manager
00460         for(uint i=0;i<_CurrentAsyncTextures.size();i++)
00461         {
00462                 for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
00463                 {
00464                         if(_CurrentAsyncTextures[i].IsTextureFile[stage])
00465                         {
00466                                 asyncTextMgr->releaseTexture(_CurrentAsyncTextures[i].TextIds[stage], this);
00467                         }
00468                 }
00469         }
00470 }
00471 
00472 // ***************************************************************************
00473 bool                    CMeshBaseInstance::isAsyncTextureReady()
00474 {
00475         // if ok, just quit
00476         if(_AsyncTextureReady)
00477                 return true;
00478 
00479         // test if async loading ended
00480         if(_AsyncTextureToLoadRefCount==0)
00481         {
00482                 // must copy all fileNames into the actual Texture Files. Those are the valid ones now!
00483                 for(uint i=0;i<_CurrentAsyncTextures.size();i++)
00484                 {
00485                         for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
00486                         {
00487                                 if(_CurrentAsyncTextures[i].IsTextureFile[stage])
00488                                 {
00489                                         // copy the texture name into the texture file.
00490                                         CTextureFile    *text= safe_cast<CTextureFile*>(Materials[i].getTexture(stage));
00491                                         // Since the texture is really uploaded in the driver, the true driver Texture Id will
00492                                         // be bound to this texture.
00493                                         text->setFileName(_CurrentAsyncTextures[i].TextureNames[stage]);
00494                                         /* Since driver setup will only occurs when object become visible, it is a good idea to release
00495                                            Old driver info, because it may points to old driver texture data (eg: old shared textureFile).
00496                                            thus doing so release VRAM Texture Memory
00497                                         */
00498                                         text->releaseDriverSetup();
00499                                 }
00500                         }
00501                 }
00502 
00503                 // Ok, we are now ready.
00504                 _AsyncTextureReady= true;
00505                 return true;
00506         }
00507         else
00508                 return false;
00509 }
00510 
00511 
00512 // ***************************************************************************
00513 sint                    CMeshBaseInstance::getAsyncTextureId(uint matId, uint stage) const
00514 {
00515         if(matId>=_CurrentAsyncTextures.size())
00516                 return -1;
00517         if(!_CurrentAsyncTextures[matId].isTextureFile(stage))
00518                 return -1;
00519         return _CurrentAsyncTextures[matId].TextIds[stage];
00520 }
00521 
00522 
00523 
00524 } // NL3D