1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
30 using namespace NLMISC
;
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
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
)
76 CTransformShape::registerToChannelMixer(chanMixer
, prefix
);
79 for (i
= 0; i
< _AnimatedMaterials
.size(); i
++)
81 // append material matname.*
82 _AnimatedMaterials
[i
].registerToChannelMixer(chanMixer
, prefix
+ _AnimatedMaterials
[i
].getMaterialName() + ".");
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
;
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();
113 // Problem, new values ?
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() )
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())
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;
173 node
= node
->hrcGetParent();
176 // setup the channel mixer date
177 CChannelMixer
*chanMix
= getChannelMixer();
180 const CAnimation
*anim
= chanMix
->getSlotAnimation(0);
181 /** We perform wrapping ourselves.
182 * We avoid using a playlist, to not create one more obj.
186 // Animation offset are setuped before clipping, they will be used for detail too.
187 float animLength
= anim
->getEndTime() - anim
->getBeginTime();
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
);
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
);
254 CRGBA factor
= getOwnerScene ()->getLightmapGroupColor (groupInfo
.LightGroup
);
255 Materials
[ite
->MatId
].setLightMapFactor ( ite
->StageId
, factor
);
264 // ***************************************************************************
265 void CMeshBaseInstance::selectTextureSet(uint id
)
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
);
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.
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 ();
326 // Resize the index array
327 _AnimatedLightmap
.resize (count
);
329 for (i
=0; i
<count
; i
++)
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())
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
)
387 if(_AsyncTextureMode
==enable
)
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
)));
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
);
417 AsyncTextures
[i
].IsTextureFile
[stage
]= false;
422 // For convenience, flag the instance as Dirty.
423 setAsyncTextureDirty(true);
425 // else, AsyncTextureMode disabled
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())
460 // If the async texutre manager is not setuped in the scene, abort.
461 CAsyncTextureManager
*asyncTextMgr
= getOwnerScene()->getAsyncTextureManager();
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
])
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();
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()
520 if(_AsyncTextureReady
)
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;
556 // ***************************************************************************
557 sint
CMeshBaseInstance::getAsyncTextureId(uint matId
, uint stage
) const
559 if(matId
>=_CurrentAsyncTextures
.size())
561 if(!_CurrentAsyncTextures
[matId
].isTextureFile(stage
))
563 return _CurrentAsyncTextures
[matId
].TextIds
[stage
];