Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / scene_group.cpp
blob4867209e7f440794cd7cf74ed0e9b4db456ef18c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
22 #include "nel/3d/scene_group.h"
23 #include "nel/misc/stream.h"
24 #include "nel/misc/matrix.h"
25 #include "nel/3d/scene.h"
26 #include "nel/3d/transform_shape.h"
27 #include "nel/3d/mesh_instance.h"
28 #include "nel/3d/shape_bank.h"
29 #include "nel/3d/u_instance_group.h"
30 #include "nel/3d/vertex_buffer.h"
31 #include "nel/3d/index_buffer.h"
32 #include "nel/3d/text_context.h"
33 #include "nel/3d/water_model.h"
34 #include "nel/3d/water_shape.h"
35 #include "nel/misc/polygon.h"
36 #include "nel/misc/path.h"
39 using namespace NLMISC;
40 using namespace std;
42 #ifdef DEBUG_NEW
43 #define new DEBUG_NEW
44 #endif
46 namespace NL3D
49 // ---------------------------------------------------------------------------
50 // CInstance
51 // ---------------------------------------------------------------------------
53 // ***************************************************************************
54 CInstanceGroup::CInstance::CInstance ()
56 /* ***********************************************
57 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
58 * It can be loaded/called through CAsyncFileManager for instance
59 * ***********************************************/
61 DontAddToScene = false;
62 AvoidStaticLightPreCompute= false;
63 StaticLightEnabled= false;
64 DontCastShadow= false;
65 LocalAmbientId= 0xFF;
66 DontCastShadowForInterior= false;
67 DontCastShadowForExterior= false;
68 Visible= true;
71 // ***************************************************************************
72 void CInstanceGroup::CInstance::serial (NLMISC::IStream& f)
74 /* ***********************************************
75 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
76 * It can be loaded/called through CAsyncFileManager for instance
77 * ***********************************************/
80 Version 7:
81 - Visible
82 Version 6:
83 - DontCastShadowForExterior
84 Version 5:
85 - DontCastShadowForInterior
86 Version 4:
87 - LocalAmbientId.
88 Version 3:
89 - StaticLight.
90 Version 2:
91 - gameDev data.
92 Version 1:
93 - Clusters
95 // Serial a version number
96 sint version=f.serialVersion (7);
99 // Visible
100 if (version >= 7)
101 f.serial(Visible);
103 // DontCastShadowForExterior
104 if (version >= 6)
105 f.serial(DontCastShadowForExterior);
106 else
107 DontCastShadowForExterior= false;
109 // DontCastShadowForInterior
110 if (version >= 5)
111 f.serial(DontCastShadowForInterior);
112 else
113 DontCastShadowForInterior= false;
115 // Serial the LocalAmbientId.
116 if (version >= 4)
118 f.serial(LocalAmbientId);
120 else if(f.isReading())
122 LocalAmbientId= 0xFF;
125 // Serial the StaticLight
126 if (version >= 3)
128 f.serial (AvoidStaticLightPreCompute);
129 f.serial (DontCastShadow);
130 f.serial (StaticLightEnabled);
131 f.serial (SunContribution);
132 nlassert(CInstanceGroup::NumStaticLightPerInstance==2);
133 f.serial (Light[0]);
134 f.serial (Light[1]);
136 else if(f.isReading())
138 AvoidStaticLightPreCompute= false;
139 StaticLightEnabled= false;
140 DontCastShadow= false;
143 // Serial the gamedev data
144 if (version >= 2)
146 f.serial (InstanceName);
147 f.serial (DontAddToScene);
150 // Serial the clusters
151 if (version >= 1)
152 f.serialCont (Clusters);
154 // Serial the name
155 f.serial (Name);
157 // Serial the position vector
158 f.serial (Pos);
160 // Serial the rotation vector
161 f.serial (Rot);
163 // Serial the scale vector
164 f.serial (Scale);
166 // Serial the parent location in the vector (-1 if no parent)
167 f.serial (nParent);
170 // ---------------------------------------------------------------------------
171 // CInstanceGroup
172 // ---------------------------------------------------------------------------
174 // ***************************************************************************
176 uint CInstanceGroup::getNumInstance () const
178 return (uint)_InstancesInfos.size();
181 // ***************************************************************************
183 const string& CInstanceGroup::getShapeName (uint instanceNb) const
185 // Return the name of the n-th instance
186 return _InstancesInfos[instanceNb].Name;
189 // ***************************************************************************
191 const string& CInstanceGroup::getInstanceName (uint instanceNb) const
193 // Return the name of the n-th instance
194 return _InstancesInfos[instanceNb].InstanceName;
197 // ***************************************************************************
199 const CVector& CInstanceGroup::getInstancePos (uint instanceNb) const
201 // Return the position vector of the n-th instance
202 return _InstancesInfos[instanceNb].Pos;
205 // ***************************************************************************
207 const CQuat& CInstanceGroup::getInstanceRot (uint instanceNb) const
209 // Return the rotation vector of the n-th instance
210 return _InstancesInfos[instanceNb].Rot;
213 // ***************************************************************************
215 const CVector& CInstanceGroup::getInstanceScale (uint instanceNb) const
217 // Return the scale vector of the n-th instance
218 return _InstancesInfos[instanceNb].Scale;
221 // ***************************************************************************
223 void CInstanceGroup::getInstanceMatrix(uint instanceNb,NLMISC::CMatrix &dest) const
225 dest.identity();
226 dest.translate(getInstancePos(instanceNb));
227 dest.rotate(getInstanceRot(instanceNb));
228 dest.scale(getInstanceScale(instanceNb));
233 // ***************************************************************************
235 sint32 CInstanceGroup::getInstanceParent (uint instanceNb) const
237 // Return the scale vector of the n-th instance
238 return _InstancesInfos[instanceNb].nParent;
242 // ***************************************************************************
243 const CInstanceGroup::CInstance &CInstanceGroup::getInstance(uint instanceNb) const
245 return _InstancesInfos[instanceNb];
248 // ***************************************************************************
249 CInstanceGroup::CInstance &CInstanceGroup::getInstance(uint instanceNb)
251 return _InstancesInfos[instanceNb];
254 // ***************************************************************************
255 CTransformShape *CInstanceGroup::getTransformShape(uint instanceNb) const
257 if(instanceNb>_Instances.size())
258 return NULL;
259 return _Instances[instanceNb];
262 // ***************************************************************************
263 CInstanceGroup::CInstanceGroup()
265 /* ***********************************************
266 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
267 * It can be loaded/called through CAsyncFileManager for instance
268 * ***********************************************/
270 _IGSurfaceLight.setOwner(this);
271 _GlobalPos = CVector(0,0,0);
272 _Root = NULL;
273 _ClusterSystemForInstances = NULL;
274 _ParentClusterSystem = NULL;
275 _RealTimeSunContribution= true;
276 _AddToSceneState = StateNotAdded;
277 _TransformName = NULL;
278 _AddRemoveInstance = NULL;
279 _IGAddBeginCallback = NULL;
280 _UserIg= NULL;
283 // ***************************************************************************
284 CInstanceGroup::~CInstanceGroup()
286 /* ***********************************************
287 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
288 * It can be loaded/called through CAsyncFileManager for instance
289 * ***********************************************/
293 // ***************************************************************************
294 void CInstanceGroup::build (const CVector &vGlobalPos, const TInstanceArray& array,
295 const std::vector<CCluster>& Clusters,
296 const std::vector<CPortal>& Portals,
297 const std::vector<CPointLightNamed> &pointLightList,
298 const CIGSurfaceLight::TRetrieverGridMap *retrieverGridMap,
299 float igSurfaceLightCellSize)
301 _GlobalPos = vGlobalPos;
302 // Copy the array
303 _InstancesInfos = array;
305 _Portals = Portals;
306 _ClusterInfos = Clusters;
308 // Link portals and clusters
309 uint32 i, j, k;
310 for (i = 0; i < _Portals.size(); ++i)
312 for (j = 0; j < _ClusterInfos.size(); ++j)
314 bool bPortalInCluster = true;
315 for (k = 0; k < _Portals[i]._Poly.size(); ++k)
316 if (!_ClusterInfos[j].isIn (_Portals[i]._Poly[k]) )
318 bPortalInCluster = false;
319 break;
321 if (bPortalInCluster)
323 _Portals[i].setCluster(&_ClusterInfos[j]);
324 _ClusterInfos[j].link (&_Portals[i]);
329 // Create Meta Cluster if needed
331 CCluster clusterTemp;
332 bool mustAdd = false;
333 for (i = 0; i < _Portals.size(); ++i)
334 if (_Portals[i].getNbCluster() == 1)
336 mustAdd = true;
337 break;
339 if (mustAdd)
341 CCluster clusterTemp;
342 _ClusterInfos.push_back(clusterTemp);
343 CCluster *pMetaCluster = &_ClusterInfos[_ClusterInfos.size()-1];
344 pMetaCluster->setMetaCluster();
345 for (i = 0; i < _Portals.size(); ++i)
346 if (_Portals[i].getNbCluster() == 1)
348 _Portals[i].setCluster(pMetaCluster);
349 pMetaCluster->link(&_Portals[i]);
354 // Build the list of light. NB: sort by LightGroupName the array.
355 std::vector<uint> plRemap;
356 buildPointLightList(pointLightList, plRemap);
358 // Build IgSurfaceLight
359 // clear
360 _IGSurfaceLight.clear();
361 if(retrieverGridMap)
363 //build
364 _IGSurfaceLight.build(*retrieverGridMap, igSurfaceLightCellSize, plRemap);
369 // ***************************************************************************
370 void CInstanceGroup::build (const CVector &vGlobalPos, const TInstanceArray& array,
371 const std::vector<CCluster>& Clusters,
372 const std::vector<CPortal>& Portals)
374 // empty pointLightList
375 std::vector<CPointLightNamed> pointLightList;
377 build(vGlobalPos, array, Clusters, Portals, pointLightList);
381 // ***************************************************************************
382 void CInstanceGroup::retrieve (CVector &vGlobalPos, TInstanceArray& array,
383 std::vector<CCluster>& Clusters,
384 std::vector<CPortal>& Portals,
385 std::vector<CPointLightNamed> &pointLightList) const
387 // Just copy infos. NB: light information order have change but is still valid
388 vGlobalPos= _GlobalPos;
389 array= _InstancesInfos;
391 Portals= _Portals;
392 Clusters= _ClusterInfos;
393 // Must reset links to all portals and clusters.
394 uint i;
395 for(i=0; i<Portals.size(); i++)
396 Portals[i].resetClusterLinks();
397 for(i=0; i<Clusters.size(); i++)
398 Clusters[i].resetPortalLinks();
401 pointLightList= getPointLightList();
405 // ***************************************************************************
407 void CInstanceGroup::serial (NLMISC::IStream& f)
409 /* ***********************************************
410 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
411 * It can be loaded/called through CAsyncFileManager for instance
412 * ***********************************************/
414 // Serial a header
415 f.serialCheck (NELID("TPRG"));
418 Version 5:
419 _ _RealTimeSunContribution
420 Version 4:
421 _ IGSurfaceLight
422 Version 3:
423 - PointLights
425 // Serial a version number
426 sint version=f.serialVersion (5);
429 // _RealTimeSunContribution
430 if (version >= 5)
432 f.serial(_RealTimeSunContribution);
434 else if(f.isReading())
436 _RealTimeSunContribution= true;
440 // Serial the IGSurfaceLight
441 if (version >= 4)
443 f.serial(_IGSurfaceLight);
445 else if(f.isReading())
447 _IGSurfaceLight.clear();
451 // Serial the PointLights info
452 if (version >= 3)
454 f.serial(_PointLightArray);
456 else if(f.isReading())
458 _PointLightArray.clear();
461 if (version >= 2)
462 f.serial(_GlobalPos);
464 if (version >= 1)
466 f.serialCont (_ClusterInfos);
467 f.serialCont (_Portals);
468 // Links
469 if (f.isReading())
471 uint32 i, j;
472 for (i = 0; i < _ClusterInfos.size(); ++i)
474 uint32 nNbPortals;
475 f.serial (nNbPortals);
476 _ClusterInfos[i]._Portals.resize (nNbPortals);
477 // Recreate clusters to portals links
478 for (j = 0; j < nNbPortals; ++j)
480 sint32 nPortalNb;
481 f.serial (nPortalNb);
482 _ClusterInfos[i]._Portals[j] = &_Portals[nPortalNb];
483 _Portals[nPortalNb].setCluster (&_ClusterInfos[i]);
487 else // We are writing to the stream
489 uint32 i, j;
490 for (i = 0; i < _ClusterInfos.size(); ++i)
492 uint32 nNbPortals = (uint32)_ClusterInfos[i]._Portals.size();
493 f.serial (nNbPortals);
494 for (j = 0; j < nNbPortals; ++j)
496 sint32 nPortalNb = (sint32)(_ClusterInfos[i]._Portals[j] - &_Portals[0]);
497 f.serial (nPortalNb);
503 // Serial the array
504 f.serialCont (_InstancesInfos);
507 // ***************************************************************************
508 void CInstanceGroup::createRoot (CScene& scene)
510 _Root = (CTransform*)scene.createModel (TransformId);
511 _Root->setDontUnfreezeChildren (true);
512 setPos (CVector(0,0,0));
515 // ***************************************************************************
516 void CInstanceGroup::setTransformNameCallback (ITransformName *pTN)
518 _TransformName = pTN;
522 // ***************************************************************************
523 void CInstanceGroup::setAddRemoveInstanceCallback(IAddRemoveInstance *callback)
525 _AddRemoveInstance = callback;
528 // ***************************************************************************
529 void CInstanceGroup::setIGAddBeginCallback(IIGAddBegin *callback)
531 _IGAddBeginCallback = callback;
534 // ***************************************************************************
535 bool CInstanceGroup::addToScene (CScene& scene, IDriver *driver, uint selectedTexture)
537 // Init the scene lights
538 _PointLightArray.initAnimatedLightIndex (scene);
540 uint32 i, j;
542 // Test if portals are linked to their 2 clusters
543 for (i = 0; i < _Portals.size(); ++i)
544 for (j = 0; j < 2; ++j)
546 if (_Portals[i]._Clusters[j] == NULL)
548 nlwarning("Portal %d (name:%s) is not linked to 2 clusters. Instance Group Not Added To Scene.", i, _Portals[i].getName().c_str());
552 _Instances.resize (_InstancesInfos.size(), NULL);
554 if (_IGAddBeginCallback)
555 _IGAddBeginCallback->startAddingIG((uint)_InstancesInfos.size());
557 // Creation and positionning of the new instance
559 vector<CInstance>::iterator it = _InstancesInfos.begin();
561 // Water surface may have a callback when they are created, and this callback need their position
562 // Their position isn't set right now however, so must call that callback later
563 IWaterSurfaceAddedCallback *oldCallback = scene.getWaterCallback();
564 scene.setWaterCallback(NULL);
565 for (i = 0; i < _InstancesInfos.size(); ++i, ++it)
567 // Get the shape name
568 string shapeName;
569 getShapeName (i, shapeName);
570 if (!shapeName.empty ())
572 if (!_InstancesInfos[i].DontAddToScene)
574 // TMP FIX : some pacs_prim files where exported ...
575 if (nlstricmp(NLMISC::CFile::getExtension(shapeName), "pacs_prim") == 0)
577 nlwarning("Can't read %s (not a shape)", shapeName.c_str());
578 _Instances[i] = NULL;
580 else
582 _Instances[i] = scene.createInstance (shapeName);
584 if (_Instances[i] == NULL)
586 nlwarning("Not found '%s' file", shapeName.c_str());
592 scene.setWaterCallback(oldCallback);
593 return addToSceneWhenAllShapesLoaded (scene, driver, selectedTexture);
596 // ***************************************************************************
598 void CInstanceGroup::getShapeName (uint instanceIndex, std::string &shapeName) const
600 const CInstance &rInstanceInfo = _InstancesInfos[instanceIndex];
601 shapeName = rInstanceInfo.Name;
603 // If there is a callback added to this instance group then transform
604 // the name of the shape to load.
605 if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty())
607 shapeName = _TransformName->transformName (instanceIndex, rInstanceInfo.InstanceName, rInstanceInfo.Name);
610 toLowerAscii(shapeName);
611 if (!shapeName.empty() && shapeName.find('.') == std::string::npos)
612 shapeName += ".shape";
615 // ***************************************************************************
616 // Private method
617 bool CInstanceGroup::addToSceneWhenAllShapesLoaded (CScene& scene, IDriver *driver, uint selectedTexture)
619 uint32 i, j;
621 vector<CInstance>::iterator it = _InstancesInfos.begin();
622 for (i = 0; i < _InstancesInfos.size(); ++i, ++it)
624 CInstance &rInstanceInfo = *it;
626 if (!rInstanceInfo.DontAddToScene)
628 if (_Instances[i])
630 _Instances[i]->setPos (rInstanceInfo.Pos);
631 _Instances[i]->setRotQuat (rInstanceInfo.Rot);
632 _Instances[i]->setScale (rInstanceInfo.Scale);
633 _Instances[i]->setPivot (CVector::Null);
634 if(rInstanceInfo.Visible)
635 _Instances[i]->show();
636 else
637 _Instances[i]->hide();
639 if (scene.getWaterCallback())
641 CWaterModel *wm = dynamic_cast<CWaterModel *>(_Instances[i]);
642 if (wm)
644 const CWaterShape *ws = safe_cast<const CWaterShape *>((const IShape *) wm->Shape);
645 scene.getWaterCallback()->waterSurfaceAdded(ws->getShape(), wm->getMatrix(), ws->isSplashEnabled(), ws->getUseSceneWaterEnvMap(0) || ws->getUseSceneWaterEnvMap(1));
648 // Static Light Setup
649 if( rInstanceInfo.StaticLightEnabled )
651 // Count lights.
652 uint numPointLights;
653 for(numPointLights= 0; numPointLights<CInstanceGroup::NumStaticLightPerInstance; numPointLights++)
655 if(rInstanceInfo.Light[numPointLights]==0xFF)
656 break;
658 // Max allowed.
659 numPointLights= min(numPointLights, (uint)NL3D_MAX_LIGHT_CONTRIBUTION);
661 // Get pl ptrs.
662 CPointLight *pls[CInstanceGroup::NumStaticLightPerInstance];
663 for(uint j=0; j<numPointLights;j++)
665 uint plId= rInstanceInfo.Light[j];
666 pls[j]= (CPointLight*)(&_PointLightArray.getPointLights()[plId]);
669 // get frozenAmbientlight.
670 CPointLight *frozenAmbientlight;
671 if(rInstanceInfo.LocalAmbientId == 0xFF)
672 // must take the sun one.
673 frozenAmbientlight= NULL;
674 else
675 // ok, take the local ambient one.
676 frozenAmbientlight= (CPointLight*)(&_PointLightArray.getPointLights()[rInstanceInfo.LocalAmbientId]);
678 // Setup the instance.
679 _Instances[i]->freezeStaticLightSetup(pls, numPointLights, rInstanceInfo.SunContribution, frozenAmbientlight);
682 // Driver not NULL ?
683 if (driver)
685 // Flush shape's texture with this driver
686 _Instances[i]->Shape->flushTextures (*driver, selectedTexture);
690 else
692 _Instances[i] = NULL;
696 // Setup the hierarchy
697 // We just have to set the traversal HRC (Hierarchy)
698 if (_Root == NULL)
700 createRoot (scene);
702 it = _InstancesInfos.begin();
703 for (i = 0; i < _InstancesInfos.size(); ++i, ++it)
704 if (!_InstancesInfos[i].DontAddToScene && _Instances[i] != NULL)
706 CInstance &rInstanceInfo = *it;
707 if( rInstanceInfo.nParent != -1 ) // Is the instance get a parent
708 _Instances[rInstanceInfo.nParent]->hrcLinkSon( _Instances[i] );
709 else
710 _Root->hrcLinkSon( _Instances[i] );
712 // Attach the root of the instance group to the root of the hierarchy traversal
713 scene.getRoot()->hrcLinkSon( _Root );
715 // Cluster / Portals
716 // -----------------
718 CClipTrav *pClipTrav = &scene.getClipTrav();
719 _ClipTrav = pClipTrav;
721 // Create the MOT links (create the physical clusters)
722 _ClusterInstances.resize (_ClusterInfos.size());
723 for (i = 0; i < _ClusterInstances.size(); ++i)
725 _ClusterInstances[i] = (CCluster*)scene.createModel (ClusterId);
726 _ClusterInstances[i]->Group = this;
727 _ClusterInstances[i]->_Portals = _ClusterInfos[i]._Portals;
728 _ClusterInstances[i]->_LocalVolume = _ClusterInfos[i]._LocalVolume;
729 _ClusterInstances[i]->_LocalBBox = _ClusterInfos[i]._LocalBBox;
730 _ClusterInstances[i]->_Volume = _ClusterInfos[i]._Volume;
731 _ClusterInstances[i]->_BBox = _ClusterInfos[i]._BBox;
732 _ClusterInstances[i]->FatherVisible = _ClusterInfos[i].FatherVisible;
733 _ClusterInstances[i]->VisibleFromFather = _ClusterInfos[i].VisibleFromFather;
734 _ClusterInstances[i]->FatherAudible = _ClusterInfos[i].FatherAudible;
735 _ClusterInstances[i]->AudibleFromFather = _ClusterInfos[i].AudibleFromFather;
736 _ClusterInstances[i]->Name = _ClusterInfos[i].Name;
737 _ClusterInstances[i]->setSoundGroup(_ClusterInfos[i].getSoundGroup());
738 _ClusterInstances[i]->setEnvironmentFx(_ClusterInfos[i].getEnvironmentFx());
739 pClipTrav->registerCluster (_ClusterInstances[i]);
740 _ClusterInstances[i]->clipUnlinkFromAll();
743 // Relink portals with newly created clusters
744 for (i = 0; i < _Portals.size(); ++i)
745 for (j = 0; j < 2; ++j)
747 if (_Portals[i]._Clusters[j])
749 sint32 nClusterNb;
750 nClusterNb = (sint32)(_Portals[i]._Clusters[j] - &_ClusterInfos[0]);
751 _Portals[i]._Clusters[j] = _ClusterInstances[nClusterNb];
755 // Link shapes to clusters
756 for (i = 0; i < _Instances.size(); ++i)
757 if (_Instances[i] != NULL && !_InstancesInfos[i].DontAddToScene)
759 if (!_InstancesInfos[i].Clusters.empty())
761 _Instances[i]->clipUnlinkFromAll();
762 for (j = 0; j < _InstancesInfos[i].Clusters.size(); ++j)
764 uint32 clusterInst = _InstancesInfos[i].Clusters[j];
765 if (clusterInst < _ClusterInstances.size())
766 _ClusterInstances[clusterInst]->clipAddChild( _Instances[i] );
767 else
768 nlwarning("IG: BUG: Cluster infos size %u, indexing %u", (uint32)_ClusterInstances.size(), clusterInst);
770 // For the first time we have to set all the instances to NOT move (and not be rebinded)
771 _Instances[i]->freeze();
772 _Instances[i]->setClusterSystem (this);
774 else
776 // These instances are not attached to a cluster at this level so we cannot freeze them
777 // Moreover we must set their clustersystem they will be tested against
778 _Instances[i]->setClusterSystem (_ClusterSystemForInstances);
781 _Root->freeze();
783 // HRC OBS like
784 for (i = 0; i < _ClusterInstances.size(); ++i)
786 _ClusterInstances[i]->setWorldMatrix (_Root->getMatrix());
788 for (j = 0; j < _ClusterInstances[i]->getNbPortals(); ++j)
790 CPortal *pPortal = _ClusterInstances[i]->getPortal(j);
791 pPortal->setWorldMatrix (_Root->getMatrix());
794 // Re affect the cluster to the accelerator if not the root
795 if (!_ClusterInstances[i]->isRoot())
797 _ClipTrav->unregisterCluster(_ClusterInstances[i]);
798 _ClipTrav->registerCluster (_ClusterInstances[i]);
803 // Link the instance group to the parent
804 linkToParent (scene.getGlobalInstanceGroup());
806 // Attach the clusters to the root of the instance group
807 for (i = 0; i < _ClusterInstances.size(); ++i)
808 _Root->hrcLinkSon( _ClusterInstances[i] );
811 // Default: freezeHRC all instances.
812 freezeHRC();
815 // Register the instanceGroup for light animation
816 // -----------------
817 // If some PointLight to animate
818 if(!_PointLightArray.getPointLights().empty())
819 scene.addInstanceGroupForLightAnimation(this);
821 _AddToSceneState = StateAdded;
823 if (_AddRemoveInstance)
824 _AddRemoveInstance->instanceGroupAdded();
825 return true;
828 // ***************************************************************************
829 bool CInstanceGroup::addToSceneAsync (CScene& scene, IDriver *driver, uint selectedTexture)
831 // Init the scene lights
832 _PointLightArray.initAnimatedLightIndex (scene);
834 uint32 i;
836 _AddToSceneState = StateAdding;
837 _AddToSceneTempScene = &scene;
838 _AddToSceneTempDriver = driver;
839 _AddToSceneTempSelectTexture = selectedTexture;
841 _Instances.resize (_InstancesInfos.size(), NULL);
843 if (_IGAddBeginCallback)
844 _IGAddBeginCallback->startAddingIG((uint)_InstancesInfos.size());
846 // Creation and positionning of the new instance
848 vector<CInstance>::iterator it = _InstancesInfos.begin();
849 set<string> allShapesToLoad;
850 _AddToSceneSignal = false;
851 bool loadAsyncStarted = false;
852 for (i = 0; i < _InstancesInfos.size(); ++i, ++it)
854 CInstance &rInstanceInfo = *it;
855 if (!rInstanceInfo.DontAddToScene)
857 string shapeName = rInstanceInfo.Name;
858 if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty())
860 shapeName = _TransformName->transformName (i, rInstanceInfo.InstanceName, rInstanceInfo.Name);
863 toLowerAscii(shapeName);
865 if (!shapeName.empty() && shapeName.find('.') == std::string::npos)
866 shapeName += ".shape";
869 if (allShapesToLoad.find(shapeName) == allShapesToLoad.end())
871 allShapesToLoad.insert (shapeName);
872 if (scene.getShapeBank()->getPresentState(shapeName) != CShapeBank::Present)
874 // Load it from file asynchronously
875 scene.getShapeBank()->loadAsync (shapeName, scene.getDriver(), rInstanceInfo.Pos, &_AddToSceneSignal, selectedTexture);
876 loadAsyncStarted = true;
881 if (!loadAsyncStarted)
882 _AddToSceneSignal = true;
883 else
884 _AddToSceneSignal = false;
885 //CAsyncFileManager::getInstance().signal (&_AddToSceneSignal);
887 return true;
890 // ***************************************************************************
891 void CInstanceGroup::stopAddToSceneAsync ()
893 if (_AddToSceneState != StateAdding)
894 return;
895 vector<CInstance>::iterator it = _InstancesInfos.begin();
896 CAsyncFileManager::getInstance().cancelSignal (&_AddToSceneSignal);
897 for (uint32 i = 0; i < _InstancesInfos.size(); ++i, ++it)
899 CInstance &rInstanceInfo = *it;
900 if (!rInstanceInfo.DontAddToScene)
902 string shapeName;
905 bool getShapeName = true;
907 if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty())
909 shapeName = _TransformName->transformName (i, rInstanceInfo.InstanceName, rInstanceInfo.Name);
910 if (shapeName != rInstanceInfo.Name)
911 getShapeName = false;
915 if (getShapeName)
917 if (rInstanceInfo.Name.find('.') == std::string::npos)
918 shapeName = rInstanceInfo.Name + ".shape";
919 else // extension has already been added
920 shapeName = rInstanceInfo.Name;
923 toLowerAscii(shapeName);
924 _AddToSceneTempScene->getShapeBank()->cancelLoadAsync (shapeName);
927 _AddToSceneState = StateNotAdded;
930 // ***************************************************************************
931 CInstanceGroup::TState CInstanceGroup::getAddToSceneState ()
933 // If we are adding but we have finished loading shapes (all shapes are here)
934 if (_AddToSceneState == StateAdding)
936 if (_AddToSceneSignal)
938 addToScene (*_AddToSceneTempScene, _AddToSceneTempDriver, _AddToSceneTempSelectTexture);
941 return _AddToSceneState;
944 // ***************************************************************************
945 // Search in the hierarchy of ig the most low level (child) ig that contains the clusters that
946 // are flagged to be visible from father or which father is visible
947 bool CInstanceGroup::linkToParent (CInstanceGroup *pFather)
949 uint32 i, j;
950 bool ret;
952 for (i = 0; i < pFather->_ClusterInstances.size(); ++i)
954 for(j = 0; j < pFather->_ClusterInstances[i]->Children.size(); ++j)
956 if (linkToParent(pFather->_ClusterInstances[i]->Children[j]->Group))
957 return true;
961 ret = false;
962 if (this != pFather)
964 for (j = 0; j < this->_ClusterInstances.size(); ++j)
966 if ((this->_ClusterInstances[j]->FatherVisible) ||
967 (this->_ClusterInstances[j]->VisibleFromFather))
969 for (i = 0; i < pFather->_ClusterInstances .size(); ++i)
971 // If my cluster j is in the cluster i of the father
972 if (pFather->_ClusterInstances[i]->isIn(this->_ClusterInstances[j]->getBBox()))
974 if (this->_ClusterInstances[j]->Father != pFather->_ClusterInstances[i]) // and not already son of the father cluster ?
976 // unlink from parent
977 this->_ClusterInstances[j]->unlinkFromParent();
979 // relink to the new father found
980 pFather->_ClusterInstances[i]->Children.push_back(this->_ClusterInstances[j]);
981 this->_ClusterInstances[j]->Father = pFather->_ClusterInstances[i];
983 ret = true;
990 // store new parent
991 if(ret)
992 _ParentClusterSystem= pFather;
994 return ret;
997 // ***************************************************************************
998 bool CInstanceGroup::removeFromScene (CScene& scene)
1000 uint32 i, j, k;
1002 // Remove shapes
1003 for (i = 0; i < _Instances.size(); ++i)
1005 CTransformShape *pTShape = _Instances[i];
1006 if(pTShape)
1008 // For security, unfreeze any StaticLightSetup setuped.
1009 pTShape->unfreezeStaticLightSetup();
1010 // delete the instance
1011 scene.deleteInstance (pTShape);
1012 _Instances[i] = NULL;
1016 // Relink portals with old clusters
1017 for (i = 0; i < _Portals.size(); ++i)
1018 for (k = 0; k < 2; ++k)
1020 if (_Portals[i]._Clusters[k])
1022 for (j = 0; j < _ClusterInstances.size(); ++j)
1023 if( _Portals[i]._Clusters[k] == _ClusterInstances[j] )
1024 break;
1026 nlassert (j!=_ClusterInstances.size());
1027 _Portals[i]._Clusters[k] = &_ClusterInfos[j];
1031 // Remove clusters
1032 CClipTrav *pClipTrav = &scene.getClipTrav();
1033 for (i = 0; i < _ClusterInstances.size(); ++i)
1035 pClipTrav->unregisterCluster (_ClusterInstances[i]);
1036 scene.deleteModel (_ClusterInstances[i]);
1039 scene.deleteModel (_Root);
1040 _Root = NULL;
1043 // UnRegister the instanceGroup for light animation
1044 // -----------------
1045 // If some PointLight to animate
1046 if(!_PointLightArray.getPointLights().empty())
1047 scene.removeInstanceGroupForLightAnimation(this);
1049 if (_AddRemoveInstance)
1050 _AddRemoveInstance->instanceGroupRemoved();
1051 return true;
1055 // ***************************************************************************
1056 void CInstanceGroup::getLights( set<string> &LightNames )
1058 LightNames.clear();
1059 for( uint32 i = 0; i < _Instances.size(); ++i )
1061 CMeshInstance *pMI = dynamic_cast<CMeshInstance*>(_Instances[i]);
1062 if( pMI != NULL )
1064 uint32 nNbLM = pMI->getNbLightMap();
1065 for( uint32 j = 0; j < nNbLM; ++j )
1067 string sTmp;
1068 pMI->getLightMapName( j, sTmp );
1069 set<string>::iterator itSet = LightNames.find(sTmp);
1070 if( itSet == LightNames.end() )
1071 LightNames.insert( sTmp );
1077 // ***************************************************************************
1078 void CInstanceGroup::getBlendShapes( set<string> &BlendShapeNames )
1080 BlendShapeNames.clear();
1081 for( uint32 i = 0; i < _Instances.size(); ++i )
1083 CMeshBaseInstance *pMBI = dynamic_cast<CMeshBaseInstance*>(_Instances[i]);
1084 if (pMBI != NULL)
1086 uint32 nNbBS = pMBI->getNbBlendShape();
1087 for( uint32 j = 0; j < nNbBS; ++j )
1089 string sTmp;
1090 pMBI->getBlendShapeName( j, sTmp );
1091 set<string>::iterator itSet = BlendShapeNames.find(sTmp);
1092 if( itSet == BlendShapeNames.end() )
1093 BlendShapeNames.insert( sTmp );
1099 // ***************************************************************************
1100 void CInstanceGroup::setBlendShapeFactor( const string &BlendShapeName, float rFactor )
1102 for( uint32 i = 0; i < _Instances.size(); ++i )
1104 CMeshBaseInstance *pMI = dynamic_cast<CMeshBaseInstance*>(_Instances[i]);
1105 if( pMI != NULL )
1107 pMI->setBlendShapeFactor( BlendShapeName, rFactor );
1112 // ***************************************************************************
1113 void CInstanceGroup::addCluster(CCluster *pCluster)
1115 _ClusterInstances.push_back(pCluster);
1118 // ***************************************************************************
1119 void CInstanceGroup::setClusterSystemForInstances(CInstanceGroup *pIG)
1121 _ClusterSystemForInstances = pIG;
1122 for (uint32 i = 0; i < _Instances.size(); ++i)
1123 if (_Instances[i] && _InstancesInfos[i].Clusters.empty())
1124 _Instances[i]->setClusterSystem (_ClusterSystemForInstances);
1127 // ***************************************************************************
1128 void CInstanceGroup::getDynamicPortals (std::vector<std::string> &names)
1130 for (uint32 i = 0; i < _Portals.size(); ++i)
1131 if (!_Portals[i].getName().empty())
1132 names.push_back (_Portals[i].getName());
1135 // ***************************************************************************
1136 void CInstanceGroup::setDynamicPortal (std::string& name, bool opened)
1138 for (uint32 i = 0; i < _Portals.size(); ++i)
1139 if (_Portals[i].getName() == name)
1140 _Portals[i].open (opened);
1143 // ***************************************************************************
1144 bool CInstanceGroup::getDynamicPortal (std::string& name)
1146 for (uint32 i = 0; i < _Portals.size(); ++i)
1147 if (_Portals[i].getName() == name)
1148 return _Portals[i].isOpened ();
1149 return false;
1152 // ***************************************************************************
1153 void CInstanceGroup::setPos (const CVector &pos)
1155 if (_Root != NULL)
1156 /// \todo Make this work (precision): _Root->setPos (_GlobalPos+pos);
1157 _Root->setPos (pos);
1160 // ***************************************************************************
1161 void CInstanceGroup::setRotQuat (const CQuat &quat)
1163 if (_Root != NULL)
1164 _Root->setRotQuat (quat);
1167 // ***************************************************************************
1168 CVector CInstanceGroup::getPos ()
1170 if (_Root != NULL)
1171 return _Root->getPos ();
1172 else
1173 return CVector(0.0f, 0.0f, 0.0f);
1176 // ***************************************************************************
1177 CQuat CInstanceGroup::getRotQuat ()
1179 if (_Root != NULL)
1180 return _Root->getRotQuat ();
1181 else
1182 return CQuat();
1185 // ***************************************************************************
1186 void CInstanceGroup::linkRoot (CScene &/* scene */, CTransform *father)
1188 if(_Root)
1190 father->hrcLinkSon( _Root );
1194 // ***************************************************************************
1195 void CInstanceGroup::freezeHRC()
1197 // For all instances.
1198 for (uint i=0; i < _Instances.size(); i++)
1200 if(_Instances[i])
1201 _Instances[i]->freezeHRC();
1203 // and for root.
1204 _Root->freezeHRC();
1208 // ***************************************************************************
1209 void CInstanceGroup::unfreezeHRC()
1211 // For all instances.
1212 for (uint i=0; i < _Instances.size(); i++)
1214 if(_Instances[i])
1215 _Instances[i]->unfreezeHRC();
1217 // and for root.
1218 _Root->unfreezeHRC();
1221 // ***************************************************************************
1222 // ***************************************************************************
1223 // ***************************************************************************
1224 // ***************************************************************************
1227 // ***************************************************************************
1228 void CInstanceGroup::buildPointLightList(const std::vector<CPointLightNamed> &pointLightList,
1229 std::vector<uint> &plRemap)
1231 // build.
1232 _PointLightArray.build(pointLightList, plRemap);
1234 // remap Instance precalc lighted.
1235 for(uint i=0; i<_InstancesInfos.size(); i++)
1237 CInstance &inst= _InstancesInfos[i];
1238 // If the instance has no precomputed lighting, skip
1239 if(!inst.StaticLightEnabled)
1240 continue;
1242 // remap pointlights
1243 for(uint l=0; l<CInstanceGroup::NumStaticLightPerInstance; l++)
1245 // If NULL light, break and continue to next instance
1246 if(inst.Light[l]== 0xFF)
1247 break;
1248 else
1250 // Check good index.
1251 nlassert(inst.Light[l] < _PointLightArray.getPointLights().size());
1252 // Remap index, because of light sorting.
1253 inst.Light[l]= uint8(plRemap[inst.Light[l]]);
1257 // remap ambient light
1258 if(inst.LocalAmbientId!=0xFF)
1260 nlassert(inst.LocalAmbientId < _PointLightArray.getPointLights().size());
1261 inst.LocalAmbientId= uint8(plRemap[inst.LocalAmbientId]);
1267 // ***************************************************************************
1268 void CInstanceGroup::setPointLightFactor(const CScene &scene)
1270 _PointLightArray.setPointLightFactor(scene);
1274 // ***************************************************************************
1275 void CInstanceGroup::enableRealTimeSunContribution(bool enable)
1277 _RealTimeSunContribution= enable;
1280 // ***************************************************************************
1281 // ***************************************************************************
1282 // ***************************************************************************
1283 // ***************************************************************************
1286 // ***************************************************************************
1287 void CInstanceGroup::displayDebugClusters(IDriver *drv, class CTextContext *txtCtx)
1289 uint opacity= 50;
1290 CRGBA colorCluster(255, 128, 255, uint8(opacity));
1291 // portals are drawn twice
1292 CRGBA colorPortal(128, 255, 128, uint8(opacity/2));
1294 CMaterial clusterMat;
1295 CMaterial portalMat;
1296 CMaterial lineMat;
1297 clusterMat.initUnlit();
1298 clusterMat.setBlend(true);
1299 clusterMat.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
1300 clusterMat.setZWrite(false);
1301 clusterMat.setDoubleSided(true);
1302 clusterMat.setColor(colorCluster);
1303 portalMat.initUnlit();
1304 portalMat.setBlend(true);
1305 portalMat.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
1306 portalMat.setZWrite(false);
1307 portalMat.setDoubleSided(true);
1308 portalMat.setColor(colorPortal);
1309 lineMat.initUnlit();
1310 lineMat.setBlend(true);
1311 lineMat.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
1312 lineMat.setZWrite(false);
1313 lineMat.setDoubleSided(true);
1314 lineMat.setColor(CRGBA(0,0,0,uint8(opacity)));
1317 // The geometry for each cluster
1318 CVertexBuffer vb;
1319 // too big cluster won't be rendered
1320 const uint maxVertices= 10000;
1321 vb.setVertexFormat(CVertexBuffer::PositionFlag);
1322 vb.setNumVertices(maxVertices);
1323 CIndexBuffer clusterTriangles;
1324 CIndexBuffer clusterLines;
1325 CIndexBuffer portalTriangles;
1326 CIndexBuffer portalLines;
1328 clusterTriangles.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
1329 clusterLines.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
1330 portalTriangles.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
1331 portalLines.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
1333 clusterTriangles.setNumIndexes(maxVertices*3);
1334 clusterLines.setNumIndexes(maxVertices*2);
1335 portalTriangles.setNumIndexes(maxVertices*3);
1336 portalLines.setNumIndexes(maxVertices*2);
1338 // setup identity matrix
1339 drv->setupModelMatrix(CMatrix::Identity);
1341 // For all clusters
1342 uint i;
1343 for(i=0;i<_ClusterInstances.size();i++)
1345 CCluster *cluster= _ClusterInstances[i];
1346 if(cluster)
1348 uint numTotalVertices= 0;
1350 // **** Build a set of polys representing the volume (slow but debug!)
1351 static std::vector<CPolygon> polygons;
1352 polygons.clear();
1353 polygons.resize(cluster->_Volume.size());
1354 // for each plane, build the associated polygon
1355 uint j;
1356 for(j=0;j<polygons.size();j++)
1358 // Start with a big quad centered on bbox center
1359 CPlane p= cluster->_Volume[j];
1360 p.normalize();
1361 CVector quadCenter= p.project(cluster->_BBox.getCenter());
1363 // choose a basis on this plane
1364 CMatrix mat;
1365 mat.setArbitraryRotK(p.getNormal());
1366 mat.setPos(quadCenter);
1368 // Build the initial Big quad
1369 CPolygon &poly= polygons[j];
1370 poly.Vertices.resize(4);
1371 float s= 10 * cluster->_BBox.getRadius();
1372 poly.Vertices[0]= mat * CVector(-s,-s,0);
1373 poly.Vertices[1]= mat * CVector(s,-s,0);
1374 poly.Vertices[2]= mat * CVector(s,s,0);
1375 poly.Vertices[3]= mat * CVector(-s,s,0);
1377 // clip this poly against all the other (ie not me) planes
1378 // This make this algo O(N2) but this is for debug....
1379 for(uint k=0;k<cluster->_Volume.size();k++)
1381 if(j!=k)
1383 poly.clip(&cluster->_Volume[k], 1);
1387 // count the number of vertices / triangles / lines to add
1388 if(poly.Vertices.size()>=3)
1390 numTotalVertices+= (uint)poly.Vertices.size();
1394 // **** count the number of portals vertices
1395 for(j=0;j<cluster->_Portals.size();j++)
1397 numTotalVertices+= (uint)cluster->_Portals[j]->_Poly.size();
1400 // **** Draw those cluster polygons, and portals
1401 // too big clusters won't be rendered
1402 if(numTotalVertices<=maxVertices)
1404 uint iVert= 0;
1405 uint j;
1407 // build the cluster geometry
1408 clusterTriangles.setNumIndexes(maxVertices*3);
1409 clusterLines.setNumIndexes(maxVertices*2);
1411 // Locks
1412 CVertexBufferReadWrite vba;
1413 vb.lock (vba);
1414 CIndexBufferReadWrite ibaCT;
1415 clusterTriangles.lock (ibaCT);
1416 CIndexBufferReadWrite ibaCL;
1417 clusterLines.lock (ibaCL);
1419 uint numTriIndexes = 0;
1420 uint numLineIndexes = 0;
1422 for(j=0;j<polygons.size();j++)
1424 CPolygon &poly= polygons[j];
1425 if(poly.Vertices.size()>=3)
1427 uint k;
1428 // add the vertices
1429 for(k=0;k<poly.Vertices.size();k++)
1430 vba.setVertexCoord(iVert+k, poly.Vertices[k]);
1432 // add the triangles
1433 for(k=0;k<poly.Vertices.size()-2;k++)
1435 if (numTriIndexes<clusterTriangles.capacity())
1437 ibaCT.setTri(numTriIndexes, iVert+0, iVert+k+1, iVert+k+2);
1438 numTriIndexes += 3;
1442 // add the lines
1443 for(k=0;k<poly.Vertices.size();k++)
1445 if (numLineIndexes<clusterLines.capacity())
1447 ibaCL.setLine(numLineIndexes, iVert+k, iVert+ ((k+1)%poly.Vertices.size()) );
1448 numLineIndexes += 2;
1452 iVert+= (uint)poly.Vertices.size();
1456 // Unlocks
1457 ibaCT.unlock ();
1458 ibaCL.unlock ();
1459 clusterTriangles.setNumIndexes(numTriIndexes);
1460 clusterLines.setNumIndexes(numLineIndexes);
1462 // build the portal geometry
1463 portalTriangles.setNumIndexes(maxVertices*3);
1464 portalLines.setNumIndexes(maxVertices*2);
1466 // Locks
1467 CIndexBufferReadWrite ibaPT;
1468 portalTriangles.lock (ibaPT);
1469 CIndexBufferReadWrite ibaPL;
1470 portalLines.lock (ibaPL);
1472 numTriIndexes = 0;
1473 numLineIndexes = 0;
1475 for(j=0;j<cluster->_Portals.size();j++)
1477 std::vector<CVector> &portalVerts= cluster->_Portals[j]->_Poly;
1478 if(portalVerts.size()>=3)
1480 uint k;
1481 // add the vertices
1482 for(k=0;k<portalVerts.size();k++)
1483 vba.setVertexCoord(iVert+k, portalVerts[k]);
1485 // add the triangles
1486 for(k=0;k<portalVerts.size()-2;k++)
1488 if (numTriIndexes<clusterTriangles.capacity())
1490 ibaPT.setTri(numTriIndexes, iVert+0, iVert+k+1, iVert+k+2);
1491 numTriIndexes += 3;
1495 // add the lines
1496 for(k=0;k<portalVerts.size();k++)
1498 if (numTriIndexes<clusterTriangles.capacity())
1500 ibaPL.setLine(numLineIndexes, iVert+k, iVert+ ((k+1)%portalVerts.size()) );
1501 numLineIndexes += 2;
1505 iVert+= (uint)portalVerts.size();
1509 // Unlock
1510 ibaPT.unlock ();
1511 ibaPL.unlock ();
1512 portalTriangles.setNumIndexes(numTriIndexes);
1513 portalLines.setNumIndexes(numLineIndexes);
1514 vba.unlock ();
1516 // render 2 pass with or without ZBuffer (for clearness)
1517 for(uint pass=0;pass<2;pass++)
1519 if(pass==0)
1521 clusterMat.setZFunc(CMaterial::always);
1522 portalMat.setZFunc(CMaterial::always);
1523 lineMat.setZFunc(CMaterial::always);
1525 else
1527 clusterMat.setZFunc(CMaterial::lessequal);
1528 portalMat.setZFunc(CMaterial::lessequal);
1529 lineMat.setZFunc(CMaterial::lessequal);
1532 drv->activeVertexBuffer(vb);
1533 drv->activeIndexBuffer(clusterTriangles);
1534 drv->renderTriangles (clusterMat, 0, clusterTriangles.getNumIndexes()/3);
1535 drv->activeIndexBuffer(clusterLines);
1536 drv->renderLines (lineMat, 0, clusterLines.getNumIndexes()/2);
1537 drv->activeIndexBuffer(portalTriangles);
1538 drv->renderTriangles (portalMat, 0, portalTriangles.getNumIndexes()/3);
1539 drv->activeIndexBuffer(portalLines);
1540 drv->renderLines (lineMat, 0, portalLines.getNumIndexes()/2);
1547 // **** For all clusters, Draw the cluster name at center of the cluster
1548 if(txtCtx)
1550 CComputedString computedStr;
1552 // bkup fontSize
1553 uint bkFontSize;
1554 CMatrix fontMatrix;
1555 bkFontSize= txtCtx->getFontSize();
1556 // to be readable
1557 txtCtx->setFontSize(24);
1559 // the font matrix
1560 fontMatrix.setRot(drv->getViewMatrix().inverted());
1561 fontMatrix.normalize(CMatrix::YZX);
1562 fontMatrix.scale(10);
1564 // parse all clusters
1565 for(i=0;i<_ClusterInstances.size();i++)
1567 CCluster *cluster= _ClusterInstances[i];
1568 if(cluster)
1570 fontMatrix.setPos(cluster->_BBox.getCenter());
1571 txtCtx->computeString(cluster->Name, computedStr);
1572 computedStr.render3D(*drv, fontMatrix);
1576 // restore fontsize
1577 txtCtx->setFontSize(bkFontSize);
1583 } // NL3D