1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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
;
49 // ---------------------------------------------------------------------------
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;
66 DontCastShadowForInterior
= false;
67 DontCastShadowForExterior
= false;
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 * ***********************************************/
83 - DontCastShadowForExterior
85 - DontCastShadowForInterior
95 // Serial a version number
96 sint version
=f
.serialVersion (7);
103 // DontCastShadowForExterior
105 f
.serial(DontCastShadowForExterior
);
107 DontCastShadowForExterior
= false;
109 // DontCastShadowForInterior
111 f
.serial(DontCastShadowForInterior
);
113 DontCastShadowForInterior
= false;
115 // Serial the LocalAmbientId.
118 f
.serial(LocalAmbientId
);
120 else if(f
.isReading())
122 LocalAmbientId
= 0xFF;
125 // Serial the StaticLight
128 f
.serial (AvoidStaticLightPreCompute
);
129 f
.serial (DontCastShadow
);
130 f
.serial (StaticLightEnabled
);
131 f
.serial (SunContribution
);
132 nlassert(CInstanceGroup::NumStaticLightPerInstance
==2);
136 else if(f
.isReading())
138 AvoidStaticLightPreCompute
= false;
139 StaticLightEnabled
= false;
140 DontCastShadow
= false;
143 // Serial the gamedev data
146 f
.serial (InstanceName
);
147 f
.serial (DontAddToScene
);
150 // Serial the clusters
152 f
.serialCont (Clusters
);
157 // Serial the position vector
160 // Serial the rotation vector
163 // Serial the scale vector
166 // Serial the parent location in the vector (-1 if no parent)
170 // ---------------------------------------------------------------------------
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
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())
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);
273 _ClusterSystemForInstances
= NULL
;
274 _ParentClusterSystem
= NULL
;
275 _RealTimeSunContribution
= true;
276 _AddToSceneState
= StateNotAdded
;
277 _TransformName
= NULL
;
278 _AddRemoveInstance
= NULL
;
279 _IGAddBeginCallback
= 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
;
303 _InstancesInfos
= array
;
306 _ClusterInfos
= Clusters
;
308 // Link portals and clusters
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;
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)
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
360 _IGSurfaceLight
.clear();
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
;
392 Clusters
= _ClusterInfos
;
393 // Must reset links to all portals and clusters.
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 * ***********************************************/
415 f
.serialCheck (NELID("TPRG"));
419 _ _RealTimeSunContribution
425 // Serial a version number
426 sint version
=f
.serialVersion (5);
429 // _RealTimeSunContribution
432 f
.serial(_RealTimeSunContribution
);
434 else if(f
.isReading())
436 _RealTimeSunContribution
= true;
440 // Serial the IGSurfaceLight
443 f
.serial(_IGSurfaceLight
);
445 else if(f
.isReading())
447 _IGSurfaceLight
.clear();
451 // Serial the PointLights info
454 f
.serial(_PointLightArray
);
456 else if(f
.isReading())
458 _PointLightArray
.clear();
462 f
.serial(_GlobalPos
);
466 f
.serialCont (_ClusterInfos
);
467 f
.serialCont (_Portals
);
472 for (i
= 0; i
< _ClusterInfos
.size(); ++i
)
475 f
.serial (nNbPortals
);
476 _ClusterInfos
[i
]._Portals
.resize (nNbPortals
);
477 // Recreate clusters to portals links
478 for (j
= 0; j
< nNbPortals
; ++j
)
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
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
);
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
);
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
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
;
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 // ***************************************************************************
617 bool CInstanceGroup::addToSceneWhenAllShapesLoaded (CScene
& scene
, IDriver
*driver
, uint selectedTexture
)
621 vector
<CInstance
>::iterator it
= _InstancesInfos
.begin();
622 for (i
= 0; i
< _InstancesInfos
.size(); ++i
, ++it
)
624 CInstance
&rInstanceInfo
= *it
;
626 if (!rInstanceInfo
.DontAddToScene
)
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();
637 _Instances
[i
]->hide();
639 if (scene
.getWaterCallback())
641 CWaterModel
*wm
= dynamic_cast<CWaterModel
*>(_Instances
[i
]);
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
)
653 for(numPointLights
= 0; numPointLights
<CInstanceGroup::NumStaticLightPerInstance
; numPointLights
++)
655 if(rInstanceInfo
.Light
[numPointLights
]==0xFF)
659 numPointLights
= min(numPointLights
, (uint
)NL3D_MAX_LIGHT_CONTRIBUTION
);
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
;
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
);
685 // Flush shape's texture with this driver
686 _Instances
[i
]->Shape
->flushTextures (*driver
, selectedTexture
);
692 _Instances
[i
] = NULL
;
696 // Setup the hierarchy
697 // We just have to set the traversal HRC (Hierarchy)
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
] );
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
);
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
])
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
] );
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);
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
);
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.
815 // Register the instanceGroup for light animation
817 // If some PointLight to animate
818 if(!_PointLightArray
.getPointLights().empty())
819 scene
.addInstanceGroupForLightAnimation(this);
821 _AddToSceneState
= StateAdded
;
823 if (_AddRemoveInstance
)
824 _AddRemoveInstance
->instanceGroupAdded();
828 // ***************************************************************************
829 bool CInstanceGroup::addToSceneAsync (CScene
& scene
, IDriver
*driver
, uint selectedTexture
)
831 // Init the scene lights
832 _PointLightArray
.initAnimatedLightIndex (scene
);
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;
884 _AddToSceneSignal
= false;
885 //CAsyncFileManager::getInstance().signal (&_AddToSceneSignal);
890 // ***************************************************************************
891 void CInstanceGroup::stopAddToSceneAsync ()
893 if (_AddToSceneState
!= StateAdding
)
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
)
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;
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
)
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))
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
];
992 _ParentClusterSystem
= pFather
;
997 // ***************************************************************************
998 bool CInstanceGroup::removeFromScene (CScene
& scene
)
1003 for (i
= 0; i
< _Instances
.size(); ++i
)
1005 CTransformShape
*pTShape
= _Instances
[i
];
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
] )
1026 nlassert (j
!=_ClusterInstances
.size());
1027 _Portals
[i
]._Clusters
[k
] = &_ClusterInfos
[j
];
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
);
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();
1055 // ***************************************************************************
1056 void CInstanceGroup::getLights( set
<string
> &LightNames
)
1059 for( uint32 i
= 0; i
< _Instances
.size(); ++i
)
1061 CMeshInstance
*pMI
= dynamic_cast<CMeshInstance
*>(_Instances
[i
]);
1064 uint32 nNbLM
= pMI
->getNbLightMap();
1065 for( uint32 j
= 0; j
< nNbLM
; ++j
)
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
]);
1086 uint32 nNbBS
= pMBI
->getNbBlendShape();
1087 for( uint32 j
= 0; j
< nNbBS
; ++j
)
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
]);
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 ();
1152 // ***************************************************************************
1153 void CInstanceGroup::setPos (const CVector
&pos
)
1156 /// \todo Make this work (precision): _Root->setPos (_GlobalPos+pos);
1157 _Root
->setPos (pos
);
1160 // ***************************************************************************
1161 void CInstanceGroup::setRotQuat (const CQuat
&quat
)
1164 _Root
->setRotQuat (quat
);
1167 // ***************************************************************************
1168 CVector
CInstanceGroup::getPos ()
1171 return _Root
->getPos ();
1173 return CVector(0.0f
, 0.0f
, 0.0f
);
1176 // ***************************************************************************
1177 CQuat
CInstanceGroup::getRotQuat ()
1180 return _Root
->getRotQuat ();
1185 // ***************************************************************************
1186 void CInstanceGroup::linkRoot (CScene
&/* scene */, CTransform
*father
)
1190 father
->hrcLinkSon( _Root
);
1194 // ***************************************************************************
1195 void CInstanceGroup::freezeHRC()
1197 // For all instances.
1198 for (uint i
=0; i
< _Instances
.size(); i
++)
1201 _Instances
[i
]->freezeHRC();
1208 // ***************************************************************************
1209 void CInstanceGroup::unfreezeHRC()
1211 // For all instances.
1212 for (uint i
=0; i
< _Instances
.size(); i
++)
1215 _Instances
[i
]->unfreezeHRC();
1218 _Root
->unfreezeHRC();
1221 // ***************************************************************************
1222 // ***************************************************************************
1223 // ***************************************************************************
1224 // ***************************************************************************
1227 // ***************************************************************************
1228 void CInstanceGroup::buildPointLightList(const std::vector
<CPointLightNamed
> &pointLightList
,
1229 std::vector
<uint
> &plRemap
)
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
)
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)
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
)
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
;
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
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
);
1343 for(i
=0;i
<_ClusterInstances
.size();i
++)
1345 CCluster
*cluster
= _ClusterInstances
[i
];
1348 uint numTotalVertices
= 0;
1350 // **** Build a set of polys representing the volume (slow but debug!)
1351 static std::vector
<CPolygon
> polygons
;
1353 polygons
.resize(cluster
->_Volume
.size());
1354 // for each plane, build the associated polygon
1356 for(j
=0;j
<polygons
.size();j
++)
1358 // Start with a big quad centered on bbox center
1359 CPlane p
= cluster
->_Volume
[j
];
1361 CVector quadCenter
= p
.project(cluster
->_BBox
.getCenter());
1363 // choose a basis on this plane
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
++)
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
)
1407 // build the cluster geometry
1408 clusterTriangles
.setNumIndexes(maxVertices
*3);
1409 clusterLines
.setNumIndexes(maxVertices
*2);
1412 CVertexBufferReadWrite 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)
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);
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();
1459 clusterTriangles
.setNumIndexes(numTriIndexes
);
1460 clusterLines
.setNumIndexes(numLineIndexes
);
1462 // build the portal geometry
1463 portalTriangles
.setNumIndexes(maxVertices
*3);
1464 portalLines
.setNumIndexes(maxVertices
*2);
1467 CIndexBufferReadWrite ibaPT
;
1468 portalTriangles
.lock (ibaPT
);
1469 CIndexBufferReadWrite ibaPL
;
1470 portalLines
.lock (ibaPL
);
1475 for(j
=0;j
<cluster
->_Portals
.size();j
++)
1477 std::vector
<CVector
> &portalVerts
= cluster
->_Portals
[j
]->_Poly
;
1478 if(portalVerts
.size()>=3)
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);
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();
1512 portalTriangles
.setNumIndexes(numTriIndexes
);
1513 portalLines
.setNumIndexes(numLineIndexes
);
1516 // render 2 pass with or without ZBuffer (for clearness)
1517 for(uint pass
=0;pass
<2;pass
++)
1521 clusterMat
.setZFunc(CMaterial::always
);
1522 portalMat
.setZFunc(CMaterial::always
);
1523 lineMat
.setZFunc(CMaterial::always
);
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
1550 CComputedString computedStr
;
1555 bkFontSize
= txtCtx
->getFontSize();
1557 txtCtx
->setFontSize(24);
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
];
1570 fontMatrix
.setPos(cluster
->_BBox
.getCenter());
1571 txtCtx
->computeString(cluster
->Name
, computedStr
);
1572 computedStr
.render3D(*drv
, fontMatrix
);
1577 txtCtx
->setFontSize(bkFontSize
);