Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / 3d / mesh_base_instance.cpp
blob33037393ed6fb8098fb5392027cebe4f711a9c32
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/mesh_base_instance.h"
20 #include "nel/3d/mesh_base.h"
21 #include "nel/3d/scene.h"
22 #include "nel/3d/animation.h"
23 #include "nel/misc/debug.h"
24 #include "nel/3d/anim_detail_trav.h"
25 #include "nel/3d/texture_file.h"
26 #include "nel/3d/async_texture_manager.h"
28 #include <limits>
30 using namespace NLMISC;
32 #ifdef DEBUG_NEW
33 #define new DEBUG_NEW
34 #endif
36 namespace NL3D
40 // ***************************************************************************
41 CMeshBaseInstance::CMeshBaseInstance()
43 IAnimatable::resize(AnimValueLast);
44 _AsyncTextureToLoadRefCount= 0;
45 _AsyncTextureMode= false;
46 _AsyncTextureReady= true;
47 _AsyncTextureDirty= false;
48 _AsyncTextureDistance= 0;
49 _VPWindTreeFixed = false;
51 // I am a CMeshBaseInstance!!
52 CTransform::setIsMeshBaseInstance(true);
55 // ***************************************************************************
56 CMeshBaseInstance::~CMeshBaseInstance()
58 // If AsyncTextureMode, must disable. This ensure that async loading stop, and that no ref still exist
59 // in the AsyncTextureManager
60 if(_AsyncTextureMode)
61 enableAsyncTextureMode(false);
65 // ***************************************************************************
66 void CMeshBaseInstance::registerBasic()
68 CScene::registerModel(MeshBaseInstanceId, TransformShapeId, CMeshBaseInstance::creator);
72 // ***************************************************************************
73 void CMeshBaseInstance::registerToChannelMixer(CChannelMixer *chanMixer, const std::string &prefix)
75 uint32 i;
76 CTransformShape::registerToChannelMixer(chanMixer, prefix);
78 // Add any materials.
79 for (i = 0; i < _AnimatedMaterials.size(); i++)
81 // append material matname.*
82 _AnimatedMaterials[i].registerToChannelMixer(chanMixer, prefix + _AnimatedMaterials[i].getMaterialName() + ".");
85 // Add any morph
86 for (i = 0; i < _AnimatedMorphFactor.size(); i++)
88 _AnimatedMorphFactor[i].registerToChannelMixer(chanMixer, prefix + _AnimatedMorphFactor[i].getName());
93 // ***************************************************************************
94 ITrack* CMeshBaseInstance::getDefaultTrack (uint valueId)
96 // Pointer on the CMeshBase
97 CMeshBase* pMesh=(CMeshBase*)(IShape*)Shape;
99 // Switch the value
100 switch (valueId)
102 case CTransform::PosValue:
103 return pMesh->getDefaultPos();
104 case CTransform::RotEulerValue:
105 return pMesh->getDefaultRotEuler();
106 case CTransform::RotQuatValue:
107 return pMesh->getDefaultRotQuat();
108 case CTransform::ScaleValue:
109 return pMesh->getDefaultScale();
110 case CTransform::PivotValue:
111 return pMesh->getDefaultPivot();
112 default:
113 // Problem, new values ?
114 nlstop;
116 return NULL;
120 // ***************************************************************************
121 uint32 CMeshBaseInstance::getNbLightMap()
123 CMeshBase* pMesh=(CMeshBase*)(IShape*)Shape;
124 return (uint32)pMesh->_LightInfos.size();
127 // ***************************************************************************
128 void CMeshBaseInstance::getLightMapName( uint32 nLightMapNb, std::string &LightMapName )
130 CMeshBase* pMesh=(CMeshBase*)(IShape*)Shape;
131 if( nLightMapNb >= pMesh->_LightInfos.size() )
132 return;
133 LightMapName = pMesh->_LightInfos[nLightMapNb].AnimatedLight;
136 // ***************************************************************************
137 uint32 CMeshBaseInstance::getNbBlendShape()
139 return (uint32)_AnimatedMorphFactor.size();
142 // ***************************************************************************
143 void CMeshBaseInstance::getBlendShapeName (uint32 nBlendShapeNb, std::string &BlendShapeName )
145 if (nBlendShapeNb >= _AnimatedMorphFactor.size())
146 return;
147 BlendShapeName = _AnimatedMorphFactor[nBlendShapeNb].getName();
150 // ***************************************************************************
151 void CMeshBaseInstance::setBlendShapeFactor (const std::string &BlendShapeName, float rFactor)
153 for (uint32 i = 0; i < _AnimatedMorphFactor.size(); ++i)
154 if (BlendShapeName == _AnimatedMorphFactor[i].getName())
156 _AnimatedMorphFactor[i].setFactor (rFactor);
160 // ***************************************************************************
161 void CMeshBaseInstance::traverseHrc()
163 CMeshBase *mb = NLMISC::safe_cast<CMeshBase *>((IShape *) Shape);
165 // if the base instance uses automatic animations, we must also setup the date of the channel mixer controlling this object
166 if (mb->getAutoAnim())
168 // Unfreeze HRC for those models
169 CTransform *node = this;
170 while (node)
172 node->unfreezeHRC();
173 node = node->hrcGetParent();
176 // setup the channel mixer date
177 CChannelMixer *chanMix = getChannelMixer();
178 if (chanMix)
180 const CAnimation *anim = chanMix->getSlotAnimation(0);
181 /** We perform wrapping ourselves.
182 * We avoid using a playlist, to not create one more obj.
184 if (anim)
186 // Animation offset are setuped before clipping, they will be used for detail too.
187 float animLength = anim->getEndTime() - anim->getBeginTime();
188 if (animLength > 0)
190 float currTime = (TAnimationTime) getOwnerScene()->getCurrentTime();
191 float startTime = (uint) (currTime / animLength) * animLength;
192 // Set the channel mixer date using the global date of the scene
193 chanMix->setSlotTime(0, anim->getBeginTime() + currTime - startTime);
195 else
197 chanMix->setSlotTime(0, anim->getBeginTime());
200 /** Eval non detail animation
202 chanMix->eval(false);
207 CTransformShape::traverseHrc();
210 // ***************************************************************************
211 void CMeshBaseInstance::traverseAnimDetail()
213 CMeshBase *mb = NLMISC::safe_cast<CMeshBase *>((IShape *) Shape);
215 CTransformShape::traverseAnimDetail();
218 // update animated materials.
219 // test if animated materials must be updated.
220 if(IAnimatable::isTouched(CMeshBaseInstance::OwnerBit))
222 // must test / update all AnimatedMaterials.
223 for(uint i=0;i<_AnimatedMaterials.size();i++)
225 // This test and update the pointed material.
226 _AnimatedMaterials[i].update();
229 IAnimatable::clearFlag(CMeshBaseInstance::OwnerBit);
232 // Lightmap automatic animation
234 // Animated lightmap must have the same size than shape info lightmap.
235 const uint count0 = (uint)_AnimatedLightmap.size();
236 const uint count1 = (uint)mb->_LightInfos.size ();
237 nlassert (count0 == count1);
238 if (count0 == count1)
240 for ( uint i = 0; i < count0; ++i )
242 CMeshBase::CLightMapInfoList &groupInfo = mb->_LightInfos[i];
243 std::list<CMeshBase::CLightMapInfoList::CMatStage>::iterator ite = groupInfo.StageList.begin ();
244 while (ite != groupInfo.StageList.end ())
246 sint animatedLightmap = _AnimatedLightmap[i];
247 if (animatedLightmap != -1)
249 CRGBA factor = getOwnerScene ()->getAnimatedLightFactor (animatedLightmap, groupInfo.LightGroup);
250 Materials[ite->MatId].setLightMapFactor ( ite->StageId, factor );
252 else
254 CRGBA factor = getOwnerScene ()->getLightmapGroupColor (groupInfo.LightGroup);
255 Materials[ite->MatId].setLightMapFactor ( ite->StageId, factor );
257 ite++;
264 // ***************************************************************************
265 void CMeshBaseInstance::selectTextureSet(uint id)
267 nlassert(Shape);
268 CMeshBase *mb = NLMISC::safe_cast<CMeshBase *>((IShape *) Shape);
269 const uint numMat = mb->getNbMaterial();
270 nlassert(numMat == Materials.size());
271 // see which material are selectable
272 for(uint k = 0; k < numMat; ++k)
274 CMaterial &mat = mb->getMaterial(k);
275 for(uint l = 0; l < IDRV_MAT_MAXTEXTURES; ++l)
277 if (mat.getTexture(uint8(l)) && mat.getTexture(uint8(l))->isSelectable())
279 // use a smartPtr so the textFile will be released if just used to set the name for AsyncTextures.
280 CSmartPtr<ITexture> texNSV= mat.getTexture(uint8(l))->buildNonSelectableVersion(id);
282 // std case: just replace the texture.
283 if(!_AsyncTextureMode)
285 Materials[k].setTexture(uint8(l), texNSV);
287 // Async case
288 else
290 // If texture file, must copy the texture name
291 if(AsyncTextures[k].IsTextureFile[l])
293 CTextureFile *textFile= safe_cast<CTextureFile*>((ITexture*)texNSV);
294 AsyncTextures[k].TextureNames[l]= textFile->getFileName();
296 // else replace the texture.
297 else
298 Materials[k].setTexture(uint8(l), texNSV);
304 // Flag the instance as AsyncTextureDirty if in this mode
305 if(_AsyncTextureMode)
307 setAsyncTextureDirty(true);
312 // ***************************************************************************
313 void CMeshBaseInstance::initAnimatedLightIndex (const CScene &scene)
315 /* Scan lightmaps used by the shape, and for each, bind the transform shape to an
316 * animated lightmap index from the scene. This index will be used at runtime to
317 * get quickly a lightmap factor. This index is not set in the CShape because
318 * the CShape can be used with several CScene.
321 // For each lightmap in the shape
322 CMeshBase *pMB = static_cast<CMeshBase*> (static_cast<IShape*> (Shape));
323 const uint count = (uint)pMB->_LightInfos.size ();
324 uint i;
326 // Resize the index array
327 _AnimatedLightmap.resize (count);
329 for (i=0; i<count; i++)
331 // The light info
332 CMeshBase::CLightMapInfoList &lightInfo = pMB->_LightInfos[i];
334 // Get the lightmap info
335 _AnimatedLightmap[i] = scene.getAnimatedLightNameToIndex (lightInfo.AnimatedLight);
338 // Must be traversed in AnimDetail, even if no channel mixer registered
339 CTransform::setIsForceAnimDetail (count != 0);
343 // ***************************************************************************
344 uint CMeshBaseInstance::getNumMaterial () const
346 return (uint)Materials.size ();
350 // ***************************************************************************
351 const CMaterial *CMeshBaseInstance::getMaterial (uint materialId) const
353 return &(Materials[materialId]);
357 // ***************************************************************************
358 CMaterial *CMeshBaseInstance::getMaterial (uint materialId)
360 return &(Materials[materialId]);
364 // ***************************************************************************
365 bool CMeshBaseInstance::fastIntersect(const NLMISC::CVector &p0, const NLMISC::CVector &dir, float &dist2D, float &distZ, bool computeDist2D)
367 if(!Shape || !supportFastIntersect())
368 return false;
370 // Use the system geometry to test the intersection
371 CMeshBase *pMB = static_cast<CMeshBase*> (static_cast<IShape*> (Shape));
372 return pMB->getSystemGeometry().fastIntersect(getWorldMatrix(), p0, dir, dist2D, distZ, computeDist2D);
376 // ***************************************************************************
377 // ***************************************************************************
378 // Async texture loading
379 // ***************************************************************************
380 // ***************************************************************************
383 // ***************************************************************************
384 void CMeshBaseInstance::enableAsyncTextureMode(bool enable)
386 // if same, no-op.
387 if(_AsyncTextureMode==enable)
388 return;
389 _AsyncTextureMode= enable;
391 // if comes to async texture mode, must prepare AsyncTexturing
392 if(_AsyncTextureMode)
394 _AsyncTextureReady= true;
396 // For all TextureFiles in material
397 for(uint i=0;i<Materials.size();i++)
399 for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
401 // test if really a CTextureFile
402 CTextureFile *text= dynamic_cast<CTextureFile*>(Materials[i].getTexture(uint8(stage)));
403 if(text)
405 // Must setup the AsyncTextures
406 AsyncTextures[i].IsTextureFile[stage]= true;
407 AsyncTextures[i].TextureNames[stage]= text->getFileName();
408 AsyncTextures[i].TextIds[stage]= std::numeric_limits<uint>::max();
409 // Now, must copy the textureFile, to Avoid writing in CMeshBase TextureFile descriptor !!!
410 CTextureFile *tf = new CTextureFile(*text);
411 // setup a dummy texture => Instance won't block rendering because texture not yet ready
412 tf->setFileName("blank.tga");
413 Materials[i].setTexture(uint8(stage), tf);
415 else
417 AsyncTextures[i].IsTextureFile[stage]= false;
422 // For convenience, flag the instance as Dirty.
423 setAsyncTextureDirty(true);
425 // else, AsyncTextureMode disabled
426 else
428 // first, must stop and release all textures in the async manager.
429 releaseCurrentAsyncTextures();
430 nlassert(_AsyncTextureToLoadRefCount==0);
431 // clear the array => ensure good work if enableAsyncTextureMode(true) is made later
432 contReset(_CurrentAsyncTextures);
434 // For all TextureFiles in material, copy User setup from AsyncTextures, to real fileName
435 for(uint i=0;i<Materials.size();i++)
437 for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
439 // if an async texture file
440 if(AsyncTextures[i].IsTextureFile[stage])
442 // copy the texture name into the texture file.
443 CTextureFile *text= safe_cast<CTextureFile*>(Materials[i].getTexture(uint8(stage)));
444 text->setFileName(AsyncTextures[i].TextureNames[stage]);
445 // clear string space
446 AsyncTextures[i].TextureNames[stage].clear();
454 // ***************************************************************************
455 void CMeshBaseInstance::startAsyncTextureLoading(const NLMISC::CVector &position)
457 if(!getAsyncTextureMode())
458 return;
460 // If the async texutre manager is not setuped in the scene, abort.
461 CAsyncTextureManager *asyncTextMgr= getOwnerScene()->getAsyncTextureManager();
462 if(!asyncTextMgr)
463 return;
465 uint i;
468 /* for all new texture names to load, add them to the manager
469 NB: done first before release because of RefCount Management (in case of same texture name).
471 for(i=0;i<AsyncTextures.size();i++)
473 for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
475 if(AsyncTextures[i].IsTextureFile[stage])
477 uint id;
478 id= asyncTextMgr->addTextureRef(AsyncTextures[i].TextureNames[stage], this, position);
479 AsyncTextures[i].TextIds[stage]= id;
484 /* For all old textures (0 for the first time...), release them.
486 releaseCurrentAsyncTextures();
488 // OK! bkup the setup
489 _CurrentAsyncTextures= AsyncTextures;
491 // texture async is not ready.
492 _AsyncTextureReady= false;
495 // ***************************************************************************
496 void CMeshBaseInstance::releaseCurrentAsyncTextures()
498 // If the async texutre manager is not setuped in the scene, abort.
499 CAsyncTextureManager *asyncTextMgr= getOwnerScene()->getAsyncTextureManager();
500 if(!asyncTextMgr)
501 return;
503 // release all texture in the manager
504 for(uint i=0;i<_CurrentAsyncTextures.size();i++)
506 for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
508 if(_CurrentAsyncTextures[i].IsTextureFile[stage])
510 asyncTextMgr->releaseTexture(_CurrentAsyncTextures[i].TextIds[stage], this);
516 // ***************************************************************************
517 bool CMeshBaseInstance::isAsyncTextureReady()
519 // if ok, just quit
520 if(_AsyncTextureReady)
521 return true;
523 // test if async loading ended
524 if(_AsyncTextureToLoadRefCount==0)
526 // must copy all fileNames into the actual Texture Files. Those are the valid ones now!
527 for(uint i=0;i<_CurrentAsyncTextures.size();i++)
529 for(uint stage=0;stage<IDRV_MAT_MAXTEXTURES;stage++)
531 if(_CurrentAsyncTextures[i].IsTextureFile[stage])
533 // copy the texture name into the texture file.
534 CTextureFile *text= safe_cast<CTextureFile*>(Materials[i].getTexture(uint8(stage)));
535 // Since the texture is really uploaded in the driver, the true driver Texture Id will
536 // be bound to this texture.
537 text->setFileName(_CurrentAsyncTextures[i].TextureNames[stage]);
538 /* Since driver setup will only occurs when object become visible, it is a good idea to release
539 Old driver info, because it may points to old driver texture data (eg: old shared textureFile).
540 thus doing so release VRAM Texture Memory
542 text->releaseDriverSetup();
547 // Ok, we are now ready.
548 _AsyncTextureReady= true;
549 return true;
551 else
552 return false;
556 // ***************************************************************************
557 sint CMeshBaseInstance::getAsyncTextureId(uint matId, uint stage) const
559 if(matId>=_CurrentAsyncTextures.size())
560 return -1;
561 if(!_CurrentAsyncTextures[matId].isTextureFile(stage))
562 return -1;
563 return _CurrentAsyncTextures[matId].TextIds[stage];
568 } // NL3D